2

Please take a look at my other question which this was done incorrectly here.

What I need to do

I have an image of a map of my country, I took the piece of the map from Google Maps, so that means I know all of the corner's coordinates in longitude and latitude. My program needs to show up the map, and paint targets on it where each target has its only longitude and latitude, similar to how radar displays targets.

The problem

The problem with my solution is that it's not really using real mathematical formulas to get the X, Y position. It uses simple division and multiple by ratio with minimum and maximum as you can see in my other question.

this is the method:

protected Location getCoordinatesByGlobe(float latitude, float longitude) {

    /**
     * Work out minimum and maximums, clamp inside map bounds
     */
    latitude = Math.max(mapLatitudeMin, Math.min(mapLatitudeMax, latitude));
    longitude = Math.max(mapLongitudeMin, Math.min(mapLongitudeMax, longitude));

    /**
     * We need the distance from 0 or minimum long/lat
     */
    float adjLon = longitude - mapLongitudeMin;
    float adjLat = latitude - mapLatitudeMin;

    float mapLongWidth = mapLongitudeMax - mapLongitudeMin;
    float mapLatHeight = mapLatitudeMax - mapLatitudeMin;

    float mapWidth = mapImage.getWidth();
    float mapHeight = mapImage.getHeight();

    float longPixelRatio = mapWidth / mapLongWidth;
    float latPixelRatio = mapHeight / mapLatHeight;

    int x = Math.round(adjLon * longPixelRatio) - 3;// these are offsets for the target icon that shows.. eedit laterrr @oz
    int y = Math.round(adjLat * latPixelRatio) + 3; //

    // turn it up
    y = (int) (mapHeight - y);

    return new Location(x, y);
} 

What I have tried

So I was a bit with myself tried to think of something logical, on how can I do this. And I came up with something that doesn't really work exactly:

If we have the corner top-left for example coordinates (Longitude and latitude), and we have the coordinates of the target that we want to display, that means we can do distanceToPoint to know how many kilometers far from the start it is.

After that, we need to know the heading to that point, so we do calculateHeading which gives us the angle to the target point.

So lets call A the starting point (top-left corner)

float aLat = 33.49f;
float aLong = 33.69f;

And our target point we call it b:

float bLat = 32f;
float bLong = 35f;

And then we can calculate the distance from A to B in kilometers:

double km = distanceTopPoint(aLat, aLong, bLat, bLong);

And then we calculate the angle to the point:

double angle = calculateHeading(aLat, aLong, bLat, bLong);

And if we have the km distance and angle, we can know the distance in km for longitude and latitude:

int latDistance = (int) Math.round(km * Math.cos(angle));
int lonDistance = (int) Math.round(km * Math.sin(angle));

So now I probably have the distance from the longitude to the target's longitude and same for latitude. But what can I do with this information?

I tried thinking again, and I figured out that I can know the distance from the left top corner to the right top corner distance in km and same for top left corner to top left bottom corner. And then I can do width / km to get the km per pixel.

But I am really unsure, im sure that I am doing something wrong. Any ideas?

Community
  • 1
  • 1
Artemkller545
  • 979
  • 3
  • 21
  • 55
  • Why don't you use the Google API to both retrieve the map data and convert the coordinates? You are not allowed to just copy part of the Google maps and distribute it with your application, anyway. – Nico Schertler Aug 11 '16 at 19:32
  • @NicoSchertler Well its not really google maps, I just gave an example. Its something drawn but to the perfect coordinates. But how can I get google map on Java without embeded? I work on a closed network it cannot use internet – Artemkller545 Aug 11 '16 at 20:10
  • Then you need to know at least the projection method the map was created with. The [Mercator Projection](https://en.wikipedia.org/wiki/Mercator_projection) is one of the widely used ones. If you know the projection, it should be easy to find the missing coordinates. – Nico Schertler Aug 11 '16 at 21:38
  • @NicoSchertler It's Meractor Projection, EPSG:4141, does that tell something ? – Artemkller545 Aug 11 '16 at 21:39

1 Answers1

3

The Mercator projection is a cylindrical projection, i.e. the generalized coordinates can be calculated as:

a = longitude
b = tan(latitude)

These are unscaled coordinates, i.e. they do not correspond to pixel positions.

Let's say you have an image of w x h pixels that represents the area between (min_long, min_lat) - (max_long, max_lat). These coordinates can be converted to generalized projected coordinates with the above formulas, which yields (min_a, min_b) - (max_a, max_b).

Now you need a linear mapping of the generalized coordinates to pixel positions. This linear mapping can be expressed with four parameters (two scaling parameters and two offset parameters):

x = s_a * a + o_a
y = s_b * b = o_a

Therefore, you need to find the four parameters. You know that the top left corner has pixel coordinates (0, 0) and generalized coordinates (min_a, max_b). Similarly for the bottom right corner. This gives you four constraints and a linear system of equations:

0 = s_a * min_a + o_a
0 = s_b * max_b + o_b
w = s_a * max_a + o_a
h = s_b * min_b + o_b

The solution of this system is:

s_a =  w / (max_a - min_a)
o_a = -w * min_a / (max_a - min_a)
s_b = -h / (max_b - min_b)
o_b =  h * max_b / (max_b - min_b)

And this is it. If you want the pixel coordinates for some arbitrary point `(long, lat), then do the following:

  1. Calculate the generalized coordinates a and b (be careful to use radians when calculating the tangens).
  2. Use the linear map to convert a and b to pixel coordinates x and y with the pre-calculated parameters.

Inversion

To get latitude and longitude from pixel coordinates, do the following:

Calculate the generalized coordinates:

a = (x - o_a) / s_a
b = (x - o_b) / s_b

Calculate the geo-coordinates:

longitude = a
latitude = arc tan (b)

Again, be careful about radians/degrees.

Nico Schertler
  • 32,049
  • 4
  • 39
  • 70