Мы пытаемся включить конечные точки векторных листов во внутреннюю структуру, используя 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-карты-координаты-плитки-границы-проекция).
У нас есть пара догадок (просто догадываюсь)
- Преобразование между положением мозаичной сетки в векторную мозаичную сетку mapbox-gl отличается от приведенного выше уравнения, несмотря на то, что мы использовали уравнение, которое они также используют в TileBelt.
- mapbox-vector-tile-java предоставляет некорректно закодированные плитки.
- Мы неправильно устанавливаем границы геометрии JTS.