以正确的方式将经度和纬度坐标转换为地图像素(X 和 Y)

Converting longitude and latitude coordinates to map pixels (X and Y) the right way

请看看我的另一个问题,这个问题做错了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;

然后我们可以计算出从AB的距离,单位公里:

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

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

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

如果我们有公里距离和角度,我们就可以知道经度和纬度的距​​离(以公里为单位):

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

所以现在我大概知道经度到目标经度的距离,纬度也一样。但是我能用这些信息做什么呢?

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

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

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

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(计算切线时注意使用弧度)。
  2. 使用线性映射将ab转换为像素坐标xy并使用预先计算的参数。

反转

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

计算广义坐标:

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

计算地理坐标:

longitude = a
latitude = arc tan (b)

再次提醒,注意radians/degrees。