Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a GeoPoint to a Hardware screen point

I would like to convert a GeoPoint to a screen point in order to identify all objects which are above a touch event. So, I've tried this :

Projection projection = this.mapView.getProjection(); 
GeoPoint gie = new GeoPoint(lat, lon);
Point po = new Point();
projection.toPixels(gie, po);

But, po.x and po.y are not the screen coords, but the mapview coords in pixel instead of lat,lon.

From the android developer website :

toPixels(GeoPoint in, android.graphics.Point out) Converts the given GeoPoint to onscreen pixel coordinates, relative to the top-left of the MapView that provided this Projection.

So, is it possible to convert it in the correct screen coords ?

I want to know all the x GeoPoint which are next to the + touch event like on the example above :

----------------------------------------------------------------
(0,0) -----------> x                                           |
  |                                                            |
  |                                                            | 
  |                                                            |  <-- My screen
  |                              + (touch event)               |
 \/                            x (my GeoPoint)                 |
  y                                                            |
                                                               | 
---------------------------------------------------------------- 

I get the touch event like that :

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

Here, in this code, x and y are the real screen coords (the hardware ones, not the mapview ones)

I know that I can also convert x,y screen coordinates in GeoPoint to compare them to my GeoPoint, but, because of the zoom level, I can't get what I want.

like image 572
Bibu Avatar asked May 21 '12 12:05

Bibu


2 Answers

I don't know why you are using onTouchEvent, which is for an event that was not handled by a view. If you use onTouch(View v0, MotionEvent e), this will give you the information relative to the view and you can calculate the screen coordinates by using the view's getLeft and getBottom methods. If you make a project with a mapview that occupies the bottom right of the screen like:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <com.google.android.maps.MapView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/map"
        android:layout_width="220dp"
        android:layout_height="220dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:apiKey="Your API key"
        android:clickable="true" />
</RelativeLayout>

Then run this code

public class GoogleMapsTouchActivity extends MapActivity implements OnTouchListener {

    private MapController mMapCtrlr;
    private MapView mMapVw;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    @Override
    protected void onResume() {
        super.onResume();
        mMapVw = (MapView) findViewById(R.id.map);
        mMapVw.setReticleDrawMode(MapView.ReticleDrawMode.DRAW_RETICLE_OVER);
        mMapCtrlr = mMapVw.getController();
        mMapCtrlr.setZoom(15);
        mMapCtrlr.setCenter(new GeoPoint(53500000, -3000000));
        mMapVw.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v0, MotionEvent e) {
        // Only fires if Mapview touched
        float x = e.getX(); // relative to VIEW
        float y = e.getY(); // relative to VIEW
        float x2; // relative to SCREEN
        float y2; // relative to SCREEN
        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            Toast.makeText(this, "View x = " + x + " View y = " + y, Toast.LENGTH_SHORT).show();
            x2 = mMapVw.getLeft() + x;
            y2 = mMapVw.getBottom() + y;
            Toast.makeText(this, "Screen x = " + x2 + " Screen y = " + y2, Toast.LENGTH_SHORT).show();
            GeoPoint gPt = mMapVw.getProjection().fromPixels((int) x,   (int)y);
            Toast.makeText(this, "Lat = " + gPt.getLatitudeE6() + " Lon = " + gPt.getLongitudeE6(), Toast.LENGTH_SHORT).show();

        }
        return false;
    }
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // Only fires if screen touched outside a view
        float x = e.getX();
        float y = e.getY();
        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            Toast.makeText(this, "Got touch EVENT x = " + x + " y = " + y, Toast.LENGTH_SHORT).show();
        }
        return super.onTouchEvent(e);
    }
    @Override
    protected boolean isRouteDisplayed() {return false;}
}

If you click on the view and on the area outside the mapview, the Toast messages should make it all clear to you.

like image 88
NickT Avatar answered Nov 15 '22 06:11

NickT


I've found a solution, I don't know if it's the best way to get it, but it works!

I've found thank to your help @nickt, the method getScreenRect() which return the current bounds of the screen in screen coordinates.

Here the code :

float pisteX;
float pisteY;
Projection projection = this.mapView.getProjection(); 
Point pt = new Point();
GeoPoint gie = new GeoPoint(latitude,longitude);
Rect rec = mapView.getScreenRect(new Rect());
projection.toPixels(gie, pt);
pisteX = pt.x-rec.left; // car X screen coord
pisteY = pt.y-rec.top; // car Y screen coord
like image 22
Bibu Avatar answered Nov 15 '22 04:11

Bibu