7

I have an activity in my app where there are images I use as maps. If the image is "grid aligned" to google maps then when I use the top left and bottom right corners of the map I get from googlemaps online then I can turn the users gps into an x and y on screen. However if the map is not "grid aligned" and is at an angle than the values my math returns draws the users position off screen. Obviously I am missing the part on how to handle the angle of the map so if anyone could shed some light on how to do that it would be super helpfull.

I know I would have to figure out the angle in radians and do some conversion but I have no idea where to start. This is what I use to get an x and y to plot on a canvas so far.

public double[] getPositionGPS(Location upperLeft, Location lowerRight, Location current){

    try{

        double hypotenuse = upperLeft.distanceTo(current);
        double bearing = upperLeft.bearingTo(current);
        double currentDistanceY = Math.cos(bearing * Math.PI / OneEightyDeg) * hypotenuse;
        //                           "percentage to mark the position"
        double totalHypotenuse = upperLeft.distanceTo(lowerRight);
        double totalDistanceY = totalHypotenuse * Math.cos(upperLeft.bearingTo(lowerRight) * Math.PI / OneEightyDeg);
        double currentPixelY = currentDistanceY / totalDistanceY * ImageSizeH;

        double hypotenuse2 = upperLeft.distanceTo(current);
        double bearing2 = upperLeft.bearingTo(current);
        double currentDistanceX = Math.sin(bearing2 * Math.PI / OneEightyDeg) * hypotenuse2;
        //                           "percentage to mark the position"
        double totalHypotenuse2 = upperLeft.distanceTo(lowerRight);
        double totalDistanceX = totalHypotenuse2 * Math.sin(upperLeft.bearingTo(lowerRight) * Math.PI / OneEightyDeg);
        double currentPixelX = currentDistanceX / totalDistanceX * ImageSizeW;

        return new double[]{currentPixelX, currentPixelY};

    }catch(Exception e){

        e.printStackTrace();
        return new double[]{0,0};

    }
James andresakis
  • 5,335
  • 9
  • 53
  • 88

5 Answers5

2

First, map your google map coord to your custom image as if the image is NOT at an angle. Here you are basically dealing with scaling and offsets. Assume the coord you get is (x, y).

Then, rotate your coord according to this matrix: Rotate a point around origin. Since you already know the angle, you know / can calculate that center point coord that your custom map is rotating around. Assume it's (a, b). Specifically:

1) turn your map coord (x, y) to a (0,0) based coord, (x-a, y-b),

2) rotate using that matrix and you have a new coord (x', y'),

3) turn it back to (a, b) based coord, (x'+a, y'+b).

Community
  • 1
  • 1
StoneBird
  • 1,900
  • 13
  • 12
  • I have a few questions regarding your suggestion. First, Im not using google maps so I dont have a google map coordinate. I do have the location of the device though. Second, how am I to turn the map coordinate into a 0,0 based coord? In what way? Its already basically an x,y when I decide where to draw it. Are you saying to do the math I put in my question, take the x,y and then transform it? Also a,b.....are those the center of my image I use as a map? – James andresakis Nov 04 '13 at 20:08
  • @Jamesandresakis The thing is that you need to figure out how your custom map is rotated. So if it's just rotate in the screen then (a,b) would be the center point of your image, since your image is rotating with (a, b) being the pivot. In this case (0,0) would be upperleft corner of the screen. So you have your grid aligned coord, and map that to your canvas as if it's too grid aligned, and then transform that coord by rotation, draw the final result. – StoneBird Nov 04 '13 at 23:01
  • @Jamesandresakis you don't have to convert to (0,0) though. It's just a breakdown of the math. There are one-liners that summarize it I think, but I can't remember. But the idea is there. You rotate your coord around the point which your image is rotating around. – StoneBird Nov 04 '13 at 23:05
  • How do I get the angle and then what do I do with it? – James andresakis Nov 12 '13 at 17:20
  • @Jamesandresakis I thought you already have the angle? It could either be in radian or degree. Doesn't matter as long as you can calculate Sin and Cos. – StoneBird Nov 15 '13 at 02:05
1

I might be completely wrong but I think this is a way to get the angle of rotation (or maybe the 4 corners):

  1. Get the angle alpha between lowerRight and upperLeft. I guess this is equal 180 - lowerRight.bearingTo(upperLeft) EDIT (This equation should be dependent on the quadrant of the screen)
  2. Use your X,Y (screen) coordinates to get the angle theta between the hypotenuse and the lower edge. I guess (again) the sine of this angle is equal to: (height) / ((height^2) + (width^2))^1/2
  3. Now the angle of rotation is equal to theta - alpha

If you want to visualize this:

bla

Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
  • Ok but what do I do with the angle once I have it. I had this in code before and I dont think I was using the angle correctly because where I ended up drawing the circle representing the user position it would be off but it looked like the orientation was shifted like 45 degrees – James andresakis Nov 08 '13 at 18:04
0

I'm not sure if I understood your question, but can't you get the (X, Y) location from the API like this?

// myMap is a GoogleMap instance and location is a Location instance
Projection projection = myMap.getProjection();
LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
Point pointInTheScreen = projection.toScreenLocation(latlng);

See the GoogleMap API for further info.

Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • Im not using the google map api. Im drawing all this inside of a custom imageview that scales with pinch and zoom where I can draw on the image using a canvas. – James andresakis Nov 04 '13 at 20:01
0

Yes you can draw points that aren't on the visible map. Get around this by setting up a LatLngBounds. Then display the map for the LatLngBounds. You can also move the map to display the LatLngBounds. There's nothing tricky here no tangents or slopes or hyperbolic curvature of the earth. All that's taken care of by the point which is in degrees so don't over think your solution. If you turn the map the points will turn with it. So add your points to the map find the bounds and tilt the camera. Tilt the camera back and all the points will still be on screen! This will get you started with the all the points on the screen.

Same as the samples get a reference to a google map.

private void setUpMapIfNeeded() {
    // Do a null check to confirm that we have not already instantiated the
    // map.

    if (mMap == null) {
        // Try to obtain the map from the SupportMapFragment.
        // mMap = mMapFragment.getMap();
        // // Check if we were successful in obtaining the map.

        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map)).getMap();
        // use the settings maptype

        // Check if we were successful in obtaining the map.
        if (mMap != null) {
            setUpMap();
        }
    }
}

Let's get started finding the boundry of the map.

import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;

A field for LatLngBounds and a LatLngBounds.Builder

private LatLngBounds bounds;
private LatLngBounds.Builder myLatLngBuilder;

initialize the LatLngBounds.Builder

myLatLngBuilder = new LatLngBounds.Builder();

for each point on your map.

LatLng myLatLng = new LatLng(latitude, longitude);
myLatLngBuilder.include(myLatLng);

Then when your finished adding points build your boundary.

bounds = myLatLngBuilder.build();

Now I have the bounds of all the points on my map and I can display just that area of the map. This code I lifted from the map samples.

final View mapView = getSupportFragmentManager().findFragmentById(
            R.id.map).getView();
    if (mapView.getViewTreeObserver().isAlive()) {
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(
                new OnGlobalLayoutListener() {
                    @SuppressWarnings("deprecation")
                    // We use the new method when supported
                    @SuppressLint("NewApi")
                    // We check which build version we are using.
                    @Override
                    public void onGlobalLayout() {
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                            mapView.getViewTreeObserver()
                                    .removeGlobalOnLayoutListener(this);
                        } else {
                            mapView.getViewTreeObserver()
                                    .removeOnGlobalLayoutListener(this);
                        }
                        mMap.moveCamera(CameraUpdateFactory
                                .newLatLngBounds(bounds, 50));
                    }
                });
    }

This is essentially how my app Bestrides KML Reader displays maps so no points are off screen.

Good Luck Danny117

danny117
  • 5,581
  • 1
  • 26
  • 35
  • @James I just saw your not using google maps so you should take android off the title it led me to believe something different. – danny117 Nov 08 '13 at 02:57
-1

You could use a Magnetic Field sensor (aka Compass) to get the device's orientation and with that, 'grid-align' your custom view to your map.

Beowulf Bjornson
  • 1,626
  • 1
  • 14
  • 24