阅读完 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/