【问题标题】:Converting longitude and latitude coordinates to map pixels (X and Y) the right way以正确的方式将经度和纬度坐标转换为地图像素(X 和 Y)
【发布时间】:2016-12-18 14:47:27
【问题描述】:

请看看我的另一个问题,这是错误的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 获取每像素的公里数。

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

【问题讨论】:

  • 为什么不使用 Google API 来检索地图数据和转换坐标呢?无论如何,您不能只复制部分 Google 地图并将其与您的应用程序一起分发。
  • @NicoSchertler 好吧,它不是真正的谷歌地图,我只是举了一个例子。它绘制的东西,但完美的坐标。但是如何在没有嵌入的情况下在 Java 上获取谷歌地图?我在一个无法使用互联网的封闭网络上工作
  • 那么您至少需要知道创建地图时使用的投影方法。 Mercator Projection 是被广泛使用的一种。如果你知道投影,应该很容易找到丢失的坐标。
  • @NicoSchertler 这是墨拉克投影,EPSG:4141,这能说明什么吗?

标签: java math maps geography


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

反转

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

计算广义坐标:

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

计算地理坐标:

longitude = a
latitude = arc tan (b)

同样,请注意弧度/度数。

【讨论】:

  • 嘿,谢谢你的回答,你能记录下 s_ 和 o_ 代表什么吗?
  • 缩放和偏移,分别。
  • 这非常有效。但它与我在其他问题中使用的公式有何不同?
  • 我计算 x 和 y 像素的方法很简单: int x = (int) (s_a * a + o_a); int y = (int) (s_b * b + o_b);
  • 广义坐标的中间步骤考虑了投影,而您的其他方法则没有。如果你只有一个很小的窗口(切线可以用一条线很好地近似),你可能不会有很大的变化。
猜你喜欢
  • 2016-12-09
  • 1970-01-01
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-29
  • 1970-01-01
相关资源
最近更新 更多