将(旋转的)ImageOverlay 内的 X 和 Y 坐标转换为纬度和经度

Cpt*_*ric 2 javascript leaflet typescript angular-leaflet-directive angular

在阅读了 Projection 的文档和一些尝试失败的测试后,我发现自己无法找到解决此问题的方法。

我发现的所有解决方案都与 x 和 y 坐标参考墨卡托地图投影这一事实有关,但在这种情况下,我将它们来自放置在地图图层上的本地图像。

假设我有一个 400px * 200px 的灰色图像,使用 ImageOverlay.Rotated 放置在传单地图上,位置如下:

var topleft = L.latLng(41.604766, 0.606402);
var topRight = L.latLng(41.605107, 0.606858);
var bottomleft = L.latLng(41.604610, 0.606613);
Run Code Online (Sandbox Code Playgroud)

此图像使用左上角、右上角和左下角坐标作为参考放置在地图上。

结果是一个稍微向北旋转的矩形。

如果我知道我将手机留在像素 100,50(原始图像的左角)处,我如何将这个笛卡尔坐标转换为我的地图的纬度和经度以显示它?

如果它是一个与北方完美对齐的矩形,我想我可以得到左上角和左下角之间的 º 差异,将其除以像素数,然后将结果与手机的 Y 相乘以获得纬度。使用先验值,我将它乘以我手机的 X 以获得我手机的经度。

但鉴于形状是旋转的,世界并不平坦,而且我在地理和三角学方面非常糟糕,我不确定它是否足够精确。

最后,我们说的是电话,而不是建筑物。几米外(2-4 米)是可以的,一个建筑街区之外就不行。

Iva*_*hez 5

哦,你说的是我自己的Leaflet.ImageOverlay.Rotated。我很乐意效劳。

你应该看看它的源代码。所有的数学都在那里。让我们回顾一下这段代码:

    var pxTopLeft    = this._map.latLngToLayerPoint(this._topLeft);
    var pxTopRight   = this._map.latLngToLayerPoint(this._topRight);
    var pxBottomLeft = this._map.latLngToLayerPoint(this._bottomLeft);
Run Code Online (Sandbox Code Playgroud)

这是将三个经纬度坐标转换为屏幕相对像素坐标关于创建子类L.Layer传单教程对“层点”的含义有很好的解释。

您可以将这些计算替换为您想要的任何其他重新投影,假设您在平面上而不是在大地水准面上工作。换句话说:您可能希望将您的经纬度坐标转换为 EPSG:3857 球面墨卡托坐标(这是 Leaflet 使用的显示投影)。如果这样做,您可以稍后将内插的 EPSG:3857 坐标转换为 EPSG:4326“普通纬度-经度”坐标。

    // Calculate the skew angles, both in X and Y
    var vectorX = pxTopRight.subtract(pxTopLeft);
    var vectorY = pxBottomLeft.subtract(pxTopLeft);
Run Code Online (Sandbox Code Playgroud)

CSS 转换需要倾斜角度来正确扭曲图像。这可能违反直觉,但ImageOverlay.Rotated使用CSSskew()而不是rotate. 但是你不需要倾斜角度,你只需要那些微分向量。

如果您想将其可视化,vectorX则是沿着图像顶部(从左到右)vectorY的 2D 矢量,以及沿着左侧(从上到下)的 2D 矢量。

这些向量允许您获取图像中任何点的屏幕坐标,假设输入范围为 ([0..1], [0..1])(0 是图像的顶部或左侧, 1 是底部或右侧)。但是您可能不想使用相对于图像高度/宽度的数字,因为在您的问题中您提到了像素。所以让我们抓住像素。

    var imgW = this._rawImage.width;
    var imgH = this._rawImage.height;
Run Code Online (Sandbox Code Playgroud)

好的。我们已经从ImageOverlay.Rotated所需的所有数学知识中提取出来。


现在,如果您将先前的向量除以以像素为单位的图像尺寸......

    var vectorXperPx = vectorX.divideBy(imgW);
    var vectorYperPx = vectorY.divideBy(imgW);
Run Code Online (Sandbox Code Playgroud)

这些向量从原始图像的一个像素到其左侧 (x) 或下方 (y) 的像素。因此,给定原始图像的像素 (x,y),相对于图像角点的投影向量将为:

    var deltaVector = 
               xPixelCoordinate.scaleBy(vectorXPerPx)
          .add(yPixelCoordinate.scaleBy(vectorYPerPx))
Run Code Online (Sandbox Code Playgroud)

这是屏幕坐标中的向量,从图像的左上角到图像的 (xPixelCoordinate, yPixelCoordinate) 像素。

现在添加图像左上角的屏幕坐标,并设置:

    var finalCoordinateForImagePixel = pxTopLeft.add(deltaVector);
Run Code Online (Sandbox Code Playgroud)

正如我们使用的那样latLngToLayerPoint,结果将相对于该参考系。想拿回来吗?简单:

    var finalCoordinateForImagePixelInLatLong = 
           map.layerPointToLatLng(finalCoordinateForImagePixel);
Run Code Online (Sandbox Code Playgroud)

但鉴于形状是旋转的,世界并不平坦,而且我在地理和三角学方面非常糟糕,我不确定它是否足够精确。

如果您使用 Leaflet 用于显示的坐标参考系统 (EPSG:3857),或任何同态坐标系统(相对于屏幕的像素坐标,相对于图层原点的像素坐标),您将没有问题。