Доброго времени суток. В нашем проекте так сложилось, что мы для нашей гео-вики стали использовать OSM а не GM. В ходе написания мобильного клиента под андроид был использован стандартный компонент MapView. Но, в ходе тестирования выявились расхождения в координатах OSM и GM, которые, в некоторых случаях, достигали 30 метров. Таким образом было решено переходить с карт гугла на OSM для чего и была найдена соответствующая библиотека osmdroid. О том, как переехать на эту библиотеку, расскажу под катом.
- 1. Изменяем в layout файле класс com.google.android.maps.MapView на org.osmdroid.views.MapView
- 2. В проекте для кластеризации меток на карте использовалась библиотека MarkerClusterer, все классы com.google.android.maps.* были заменены на org.osmdroid.*
Например com.google.android.maps.GeoPoint на org.osmdroid.util.GeoPoint.
Изза ошибки в коде osmdroid, в результате которой вызов mapView.getProjection().toPixels(...) иногда выдаёт координаты не экранные, а координаты тайла, в результате чего не работал метод hitTest класса ClusterMarker и не отрабатывала обработка клика по кластеру, былнаписаннайден на stack overflow код, который преобразовывает координаты тайла в координаты экрана
/** * * @param x view coord relative to left * @param y view coord relative to top * @param vw MapView * @return GeoPoint */ public static GeoPoint geoPointFromScreenCoords(int x, int y, MapView vw){ if (x < 0 || y < 0 || x > vw.getWidth() || y > vw.getHeight()){ return null; // coord out of bounds } // Get the top left GeoPoint Projection projection = vw.getProjection(); GeoPoint geoPointTopLeft = (GeoPoint) projection.fromPixels(0, 0); Point topLeftPoint = new Point(); // Get the top left Point (includes osmdroid offsets) projection.toPixels(geoPointTopLeft, topLeftPoint); // get the GeoPoint of any point on screen GeoPoint rtnGeoPoint = (GeoPoint) projection.fromPixels(x, y); return rtnGeoPoint; } /** * * @param gp GeoPoint * @param vw Mapview * @return a 'Point' in screen coords relative to top left */ public static Point pointFromGeoPoint(GeoPoint gp, MapView vw){ Point rtnPoint = new Point(); Projection projection = vw.getProjection(); projection.toPixels(gp, rtnPoint); // Get the top left GeoPoint GeoPoint geoPointTopLeft = (GeoPoint) projection.fromPixels(0, 0); Point topLeftPoint = new Point(); // Get the top left Point (includes osmdroid offsets) projection.toPixels(geoPointTopLeft, topLeftPoint); rtnPoint.x-= topLeftPoint.x; // remove offsets rtnPoint.y-= topLeftPoint.y; if (rtnPoint.x > vw.getWidth() || rtnPoint.y > vw.getHeight() || rtnPoint.x < 0 || rtnPoint.y < 0){ return null; // gp must be off the screen } return rtnPoint; }
- 3. В своё время был написан класс-обёртка вокруг стандартного MyLocationOverlay, был выброшен в результате перехода, т.к. в osm есть свой класс для этого.
- 4. Не работал зум «щипком», для включения надо добавить вызов mapView.setMultiTouchControls(true);
- 5. В качестве подложки была выбрана подложка «Mapnik» вызовом mapView.setTileSource(TileSourceFactory.MAPNIK);
В данный момент приложение проходит тестирование, в результате которого могут быть выявлены какие-то новые проблемы с этой библиотекой.
upd:
В ходе тестирования выяснилось, что если сначала выставлять координаты через setCenter(..), а потом приближать зум — попадали не в нужную точку (похоже на проблемы с точностью). В обратном случае всё работает отлично
Автор: Terranz