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

标签 javascript angular typescript leaflet angular-leaflet-directive

阅读完 Projection 的 documentation 后以及一些尝试失败的测试,我发现自己无法找到解决此问题的方法。

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

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

var topleft = L.latLng(41.604766, 0.606402);
var topRight = L.latLng(41.605107, 0.606858);
var bottomleft = L.latLng(41.604610, 0.606613);

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

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

如果我知道我 Handlebars 机落在像素 100,50(屏幕的左上角) 原始图像),我如何将这个笛卡尔坐标转换为纬度和经度以便我的 map 显示它?

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

但是考虑到形状是旋转的,世界并不平坦,而且我的地理和三 Angular 学真的很糟糕,我不确定它是否足够精确。

最终我们谈论的是电话,而不是建筑物。离几米(2-4)还可以,离一个街区就不行了。

最佳答案

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

你应该看看它的 source code 。所有的数学都在那里。让我们看一下该代码的一些部分:

    var pxTopLeft    = this._map.latLngToLayerPoint(this._topLeft);
    var pxTopRight   = this._map.latLngToLayerPoint(this._topRight);
    var pxBottomLeft = this._map.latLngToLayerPoint(this._bottomLeft);

这会将三个经纬度坐标转换为屏幕相对像素坐标Leaflet tutorial about creating subclasses of 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);

CSS 变换需要倾斜 Angular 才能正确扭曲图像。这也许是违反直觉的,但 ImageOverlay.Rotated 使用 CSS's skew()而不是rotate 。但你不需要倾斜 Angular ,你只需要那些微分向量。

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

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

    var imgW = this._rawImage.width;
    var imgH = this._rawImage.height;

好。我们已经从 ImageOverlay.Rotated 中提取了所需的所有数学运算。

<小时/>

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

    var vectorXperPx = vectorX.divideBy(imgW);
    var vectorYperPx = vectorY.divideBy(imgW);

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

    var deltaVector = 
               xPixelCoordinate.scaleBy(vectorXPerPx)
          .add(yPixelCoordinate.scaleBy(vectorYPerPx))

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

现在添加图像左上角的屏幕坐标,然后就完成了:

    var finalCoordinateForImagePixel = pxTopLeft.add(deltaVector);

由于我们使用了latLngToLayerPoint,结果将相对于该引用系。想拿回来吗?简单:

    var finalCoordinateForImagePixelInLatLong = 
           map.layerPointToLatLng(finalCoordinateForImagePixel);
<小时/>

but given the shape is rotated, the world is not flat, and i was really bad at geography and trigonometry, i'm not sure about it being precise enough.

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

关于javascript - 将(旋转的)ImageOverlay 内的 X 和 Y 坐标转换为纬度和经度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49152005/

相关文章:

javascript - div下无法添加按钮

javascript - Chrome 扩展访问唯一的 client_id (UUID)

javascript - oninput 事件触发一次。也可能存在范围问题

angular - Angular 4 中的动画路线

javascript - Typescript 中的类型保护正在缩小到从不键入

javascript - 原型(prototype)序列化函数无法识别

angular - 首次单击 Rxjs 时未将值发送到 Angular 中的其他组件

angular - 有没有办法在 Angular 中延迟加载组件而不是模块?

javascript - typescript 限制解决方法

javascript - Angular:找不到 Promise、Map、Set 和 Iterator