转换经度和纬度坐标以正确的方式映射像素(X和Y)

时间:2016-08-11 18:19:09

标签: java math maps geography

请查看我的另一个问题:这是错误的here

我需要做什么

我有一张我国家地图的图片,我从Google地图中获取了地图,这意味着我知道了经度和纬度的所有角落坐标。我的程序需要显示地图,并在其上绘制目标,其中每个目标都有唯一的经度和纬度,类似于雷达显示目标的方式

问题

我的解决方案的问题在于它并没有真正使用真正的数学公式来获得X,Y位置。它使用简单除法和倍数比率,最小值和最大值,如我在其他问题中所见。

这是方法:

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);
} 

我尝试了什么

所以我对自己有点试图想一些符合逻辑的东西,我怎么能这样做呢。我想出了一些并不完全正常工作的东西:

如果我们有左上角例如坐标(经度和纬度),并且我们有我们想要显示的目标的坐标,这意味着我们可以distanceToPoint知道距离多少公里从一开始就是。

在那之后,我们需要知道到那一点的标题,所以我们calculateHeading给出了目标点的角度。

所以我们称A为起点(左上角)

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

我们的目标点我们称之为b:

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

然后我们可以用千米来计算从 A B 的距离:

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

然后我们计算到该点的角度:

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

如果我们有km距离和角度,我们可以知道经度和纬度的公里距离:

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

所以现在我可能有经度到目标经度的距离,纬度相同。但是我能用这些信息做些什么呢?

我再次尝试思考,并且我发现我可以知道从左上角到右上角距离的距离(以km为单位),左上角到左上角的距离相同。然后我可以width / km来获得每像素的公里数。

但我真的不确定,我确定我做错了什么。 有什么想法吗?

1 个答案:

答案 0 :(得分:1)

墨卡托投影是圆柱投影,即广义坐标可以计算为:

a = longitude
b = tan(latitude)

这些是未缩放的坐标,即它们与像素位置不对应。

假设您有w x h像素的图像,表示(min_long, min_lat) - (max_long, max_lat)之间的区域。可以使用上述公式将这些坐标转换为广义投影坐标,从而得到(min_a, min_b) - (max_a, max_b)

现在您需要将广义坐标线性映射到像素位置。该线性映射可以用四个参数(两个缩放参数和两个偏移参数)表示:

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

因此,您需要找到四个参数。您知道左上角有像素坐标(0, 0)和广义坐标(min_a, max_b)。同样适用于右下角。这为您提供了四个约束和一个线性方程组:

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

该系统的解决方案是:

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)

就是这样。如果你想要某个任意点`(long,lat)的像素坐标,那么执行以下操作:

  1. 计算广义坐标ab(计算tangens时要小心使用弧度)。
  2. 使用线性地图将ab转换为带有预先计算参数的像素坐标xy
  3. 反演

    要从像素坐标获取纬度和经度,请执行以下操作:

    计算广义坐标:

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

    计算地理坐标:

    longitude = a
    latitude = arc tan (b)
    

    再次注意弧度/度数。