yandex / mapkit-android-demo

MapKit Android demo
Other
122 stars 61 forks source link

Полигоны GeoJSON произвольно меняют цвет #199

Closed xpathexception closed 4 years ago

xpathexception commented 4 years ago

При перемещении камеры по карте со слоем GeoJSON произвольно меняется цвет заливки полигонов. Воспроизводится на примере из репозитория, как на эмуляторе (x86, API 19), так и на реальных устройствах, в такой конфигурации

Index: src/main/java/com/yandex/mapkitdemo/GeoJsonActivity.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/java/com/yandex/mapkitdemo/GeoJsonActivity.java    (revision e8713c35907889ab1f7c3f2c1e227547d9c8687d)
+++ src/main/java/com/yandex/mapkitdemo/GeoJsonActivity.java    (date 1595433747000)
@@ -40,7 +40,7 @@
      * You can get it at the https://developer.tech.yandex.ru/ website.
      */
     private final String MAPKIT_API_KEY = "your_api_key";
-    private final Point CAMERA_TARGET = new Point(59.952, 30.318);
+    private final Point CAMERA_TARGET = new Point(55.756439, 37.615936);
     private final int MAX_ZOOM = 30;

     private static final String TAG = "GeoJsonActivity";
@@ -58,8 +58,10 @@
         super.onCreate(savedInstanceState);
         mapView = (MapView)findViewById(R.id.mapview);

-        mapView.getMap().move(new CameraPosition(CAMERA_TARGET, 15.f, 0.f, 0.f));
+        mapView.getMap().move(new CameraPosition(CAMERA_TARGET, 10.f, 0.f, 0.f));
         mapView.getMap().setMapType(MapType.VECTOR_MAP);
+        mapView.getMap().setTiltGesturesEnabled(false);
+        mapView.getMap().setRotateGesturesEnabled(false);

         // Client code must retain strong references to providers and projection
         projection = Projections.createWgs84Mercator();
@@ -129,12 +131,12 @@
     }

     private String style() throws IOException {
-        return getJsonResource("geo_json_style_example");
+        return getJsonResource("style");
     }

     private TileProvider createTileProvider() throws IOException
     {
-        final String jsonTemplate = getJsonResource("geo_json_example_template");
+        final String jsonTemplate = getJsonResource("geo_min_2");

         return new TileProvider() {
             @NonNull

geo_min_2.json.txt style.json.txt

eberkovich commented 4 years ago

В Вашем примере все тайлы содержат одни те же географические координаты, то есть по сути не являются тайлами: по этому каждая точка на экране рисуется столько раз, сколько тайлов поместилось на экран, при изменении масштаба число тайлов на экране изменяется => изменяется количество отрисовок точки => изменяется прозрачность.

xpathexception commented 4 years ago

@eberkovich, спасибо за ответ, суть проблемы понятна. В качестве решения проблемы пока только приходит в голову "нарезка" исходного полигона внутри TileProvider#load по границам тайла. Есть ли какой-то другой способ при таких исходных данных?

eberkovich commented 4 years ago

Да, для того, чтобы добавить свой векторный слой нужно разбить данные на тайлы. Либо можно попробовать воспользоваться мап объектами, но тут нужно оценить количество вершин: вариант с мап объектами может работать медленнее.

svsorokina commented 3 years ago

@xpathexception подскажите, удалось как-то решить проблему?

xpathexception commented 3 years ago

@svshishkina в итоге пришлось руками парсить geojson самостоятельно и подсовывать в MapKit полигоны. То есть нужно распарсить geojson, вытащив из него innerRing и outerRings, перепаковать их в com.yandex.mapkit.geometry.LinearRing, собрать в com.yandex.mapkit.geometry.Polygon и уже эти полигоны отдавать карте.

Вот тут есть немного об устройстве формата https://geojson.org/geojson-spec.html

svsorokina commented 3 years ago

@svshishkina в итоге пришлось ~руками~ парсить geojson самостоятельно и подсовывать в MapKit полигоны. То есть нужно распарсить geojson, вытащив из него innerRing и outerRings, перепаковать их в com.yandex.mapkit.geometry.LinearRing, собрать в com.yandex.mapkit.geometry.Polygon и уже эти полигоны отдавать карте.

Вот тут есть немного об устройстве формата https://geojson.org/geojson-spec.html

Мы изначально пошли таким путем, но не устроило по производительности, у нас около 40000 точек. Приложение лагало или вообще вылетало. Поэтому перешли на geoJson, а тут такой подвох оказался.

eberkovich commented 3 years ago

Поэтому перешли на geoJson, а тут такой подвох оказался.

Для того чтобы перейти на geo json нужно разбить данные на тайлы. https://github.com/yandex/mapkit-android-demo/issues/199#issuecomment-663165116

В данном случае смысл перехода на geojson с мап объектов как раз в том, чтобы не грузить все данные на карту сразу.

svsorokina commented 3 years ago

Для того чтобы перейти на geo json нужно разбить данные на тайлы. #199 (comment)

Не подскажите, где об этом можно подробней посмотреть, каким образом это делается? Первый раз пришлось работать с geoJson, много чего непонятно.