如果未提供,如何连接椭圆投影中的卡?

或者如何将Yandex地图图块拟合到OpenStreetMaps投影?

参赛作品


每次打开某种在线地图时,都不会完整下载它。 为了加快地图的加载速度,将地图分成小块(平铺),以便仅下载所需区域。 问题是您可以通过几种方式切入这些正方形。



大多数在线卡片都“认为”地球呈球形。 其中,例如Google地图和OpenStreetMaps。 有些人更加细致地考虑到了行星不是正确的球这一事实:至少,它在两极是扁平的。 例如,在Yandex地图中使用了这样的椭圆投影。



结果,在不同投影中具有相同编号的单元将显示完全不同的位置。 例如,这是一个图块,其X轴编号为10427,Y轴编号为5119。比例级别14。左侧-OSM,右侧Yandex。 而不是城市-某种森林。



尽管大多数地图引擎可以自动将图块调整为所需的投影,但有时您可能需要手动执行此操作。 但是如何? 最简单的方法是将图块简单地移动一定数量的像素。 结果,我们将在地图上看到所需的区域。 当然,如果仔细观察,会发现一些变形。 但我认为,同样的准确性,日常工作将绰绰有余。 因此,是时候完成介绍并开始制造转换器了。



方法论


要工作,我们需要一个转换公式。 据我了解,在当时仍然有可能这样做的时候,它是直接从Yandex Maps页面代码中提取的。 我现在找不到指向源的链接,但是此公式在中心上发布 。 我几乎没有碰过它:我只是在Swift上重写了它,并给难以理解的单字母变量赋予了更多“说话”名称。 至少那些能够识别的人。 (感谢Erelen的帮助)

好吧,任务如下。 我们需要做一个转换器,将标准投影中的图块编号作为输入,并将椭圆投影中的图块编号以及需要将其移位到输出的像素数。

这样啊 例如,以编号X 10427,Y 5119,Z 14的瓷砖为例。

我们将采取两个步骤。 首先,您需要找到此图块的坐标(纬度和经度)。 例如,其左上角的坐标。

func tileNumberToCoordinates(tileX: Int, tileY: Int, mapZoom: Int) -> (lat_deg: Double, lon_deg: Double) { let n : Double = pow(2.0, Double(mapZoom)) let lon = (Double(tileX) / n) * 360.0 - 180.0 let lat = atan( sinh (.pi - (Double(tileY) / n) * 2 * Double.pi)) * (180.0 / .pi) return (lat, lon) } 

我们得到输出(55.7889 49.1088)。 现在,将获得的值替换为公式。 缩放级别仍然相同:第14。

 func getWGS84Position(latitude: Double, longitude: Double, zoom: Int) -> (x:Int, y:Int, offsetX:Int, offsetY:Int) { // Earth vertical and horisontal radiuses let radiusA = 6378137.0 let radiusB = 6356752.0 let latitudeInRadians = latitude * Double.pi / 180 let yCompressionOfEllipsoid = sqrt( pow(radiusA, 2.0) - pow(radiusB, 2.0)) / radiusA // I really don't know what the name of this variable mean =( let m2 = log((1 + sin(latitudeInRadians)) / (1 - sin(latitudeInRadians))) / 2 - yCompressionOfEllipsoid * log((1 + yCompressionOfEllipsoid * sin(latitudeInRadians)) / (1 - yCompressionOfEllipsoid * sin(latitudeInRadians))) / 2 // x count = y count let xTilesCountForThisZoom = Double(1 << zoom) //Tile numbers in WGS-84 proection let xTileNumber = floor((longitude + 180) / 360 * xTilesCountForThisZoom) let yTileNumber = floor(xTilesCountForThisZoom / 2 - m2 * xTilesCountForThisZoom / 2 / Double.pi) //Offset in pixels of the coordinate of the //left-top corner of the OSM tile //from the left-top corner of the WGS-84 tile let offsetX = floor(((longitude + 180) / 360 * xTilesCountForThisZoom - xTileNumber) * 256) let offsetY = floor(((xTilesCountForThisZoom / 2 - m2 * xTilesCountForThisZoom / 2 / Double.pi) - yTileNumber) * 256) return (Int(xTileNumber), Int(yTileNumber), Int(offsetX), Int(offsetY)) } 

我们得到(10427,5133,0,117)。 这意味着我们需要一个Yandex贴图,其编号为X 10427,Y 5133,Z14。如果将其向左移动0像素,向上移动117像素,则它将占据正确的位置。



怎么办呢?


如果您编写了导航器,并且有机会影响地图的显示,那么一切都会相对简单。 计算屏幕上任何图块的偏移量。 并以任何方便的方式将带有地图的元素移动此像素数。

但是,如果您无权访问该代码,则必须在地图服务器和导航器之间输入一个中间链接。 例如,为此我制作了一个简单的服务器。 它输入所需的图块编号,然后计算椭圆投影中的图块编号。 它还下载了三个相邻的磁贴。 将这四个图块粘合成一个大的图块,然后从中切出所需的片段,并将其返回给用户导航器。



结果和原始:



当然,所有这些操作都需要额外的时间成本。 使用这些链接,您可以实时评估服务器“ photoshop”卡的速度:

https://anygis.ru/api/v1/Yandex_map/{xasket/{y}/{z}

https://anygis.ru/api/v1/Yandex_sat_clean/{xasket/{y}/{z}

好吧,我希望这里提供的信息对某人有用。 祝您实验顺利。

Source: https://habr.com/ru/post/zh-CN483120/


All Articles