Векторные плитки из mapbox-vector-tile-java приводят к отображению объектов в mapbox-gl в аномально высоких широтах
Мы пытаемся внедрить конечные точки векторных плиток в базовую среду, используя https://github.com/wdtinc/mapbox-vector-tile-java для кодирования географических объектов в векторные плитки. У нас все это в основном работает, за исключением некоторого странного поведения, когда визуализируемые объекты размещаются на широтах намного выше, чем они должны быть. При увеличении масштаба функции будут переходить на более низкие широты, пока, наконец, не получится довольно хорошая точность при действительно низких уровнях масштабирования. Например, мои данные относятся к округам Нью-Мексико. На начальной странице загрузите все графства в Канаде. Когда я увеличу масштаб до уровня 2, они спрыгнут на юг Канады. Чем больше я увеличиваю, тем ближе они оказываются к тому месту, где на самом деле находится Нью-Мексико. Кто-нибудь знает, почему я вижу это поведение?
Некоторые детали высокого уровня:
- Географические объекты из базы данных находятся в EPSG: 4326.
- JTS используется вместе с mapbox-vector-tile-java для обработки кодирования данных.
- Преобразование позиций плиток xyz на основе URL-адресов в границы листов использует точное уравнение, которое Mapbox использует для таких преобразований, как указано в TileBelt MapBox.
Пример URL
https://localhost:8443/app/location/data?x=0&y=0&z=0&config= {some: json}
Внутренний Java-код для построения векторных плиток
Envelope tileEnvelope = this.getTileBounds(x, y, zoom);
GeometryFactory geomFactory = new GeometryFactory();
IGeometryFilter acceptAllGeomFilter = geometry -> true;
MvtLayerParams layerParams = new MvtLayerParams();
TileGeomResult tileGeom = JtsAdapter.createTileGeom(geometries, tileEnvelope, geomFactory, layerParams, acceptAllGeomFilter);
final VectorTile.Tile.Builder tileBuilder = VectorTile.Tile.newBuilder();
// Create MVT layer
final MvtLayerProps layerProps = new MvtLayerProps();
final IUserDataConverter ignoreUserData = new UserDataConverter();
// MVT tile geometry to MVT features
final List<VectorTile.Tile.Feature> features = JtsAdapter.toFeatures(tileGeom.mvtGeoms, layerProps, ignoreUserData);
final VectorTile.Tile.Layer.Builder layerBuilder = MvtLayerBuild.newLayerBuilder(layerName, layerParams);
layerBuilder.addAllFeatures(features);
MvtLayerBuild.writeProps(layerBuilder, layerProps);
// Build MVT layer
final VectorTile.Tile.Layer layer = layerBuilder.build();
// Add built layer to MVT
tileBuilder.addLayers(layer);
/// Build MVT
Tile mvt = tileBuilder.build();
return mvt.toByteArray();
Код, преобразующий положение сетки тайлов в границы тайлов
public Envelope getTileBounds(int x, int y, int zoom)
{
return new Envelope(this.getLong(x, zoom), this.getLong(x + 1, zoom), this.getLat(y, zoom), this.getLat(y + 1, zoom));
}
public double getLong(int x, int zoom)
{
return ( x / Math.pow(2, zoom) * 360 - 180 );
}
public double getLat(int y, int zoom)
{
double r2d = 180 / Math.PI;
double n = Math.PI - 2 * Math.PI * y / Math.pow(2, zoom);
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
}
Результаты преобразования плитки
URL с x=0,y=0,z=1 приводит к Env[-180.0: 0.0, 0.0: 85.0511287798066], который является плиткой, которая, как и ожидалось, покрывает Северную Америку (Мы определили действительность на этом сайте: www.maptiler.org/google-maps-координаты-плитка-границы-проекция).
Пара догадок у нас есть (только догадка)
- Преобразование между положением сетки тайлов в векторную сетку мозаики mapbox-gl отличается от приведенного выше уравнения, несмотря на то, что мы используем уравнение, которое они также используют в TileBelt.
- mapbox-vector-tile-java предоставляет плитки, которые закодированы неправильно.
- Мы устанавливаем границы геометрии JTS неправильно.
1 ответ
Конечно, это оказалось очевидным решением, которое мы почему-то раньше не ловили. Нам просто нужно было спроецировать функции JTS на EPSG 3857 перед кодированием векторных плиток.