diff --git a/docs/Changelog.md b/docs/Changelog.md index ea3c5f3a..a143367d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -2,6 +2,7 @@ ## New since 0.16.0 +- Move cluster experiment in samples [#858](https://github.com/mapsforge/vtm/pull/858) - Many other minor improvements and bug fixes - [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.17.0) diff --git a/vtm/src/org/oscim/layers/marker/ClusterMarkerRenderer.java b/vtm-android-example/src/org/oscim/android/cluster/ClusterMarkerRenderer.java similarity index 94% rename from vtm/src/org/oscim/layers/marker/ClusterMarkerRenderer.java rename to vtm-android-example/src/org/oscim/android/cluster/ClusterMarkerRenderer.java index c81a6abd..e56fac0f 100644 --- a/vtm/src/org/oscim/layers/marker/ClusterMarkerRenderer.java +++ b/vtm-android-example/src/org/oscim/android/cluster/ClusterMarkerRenderer.java @@ -19,13 +19,13 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.layers.marker; +package org.oscim.android.cluster; import org.oscim.backend.canvas.Bitmap; import org.oscim.core.MercatorProjection; import org.oscim.core.PointF; import org.oscim.core.Tile; -import org.oscim.layers.marker.utils.ScreenUtils; +import org.oscim.layers.marker.*; import org.oscim.layers.marker.utils.SparseIntArray; import org.oscim.renderer.GLViewport; import org.oscim.renderer.bucket.SymbolItem; @@ -45,7 +45,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { /** * default color of number inside the icon. Would be super-cool to cook this into the map theme */ - private static int CLUSTER_COLORTEXT = 0xff8000c0; + private static final int CLUSTER_COLORTEXT = 0xff8000c0; /** * default color of circle background @@ -84,12 +84,12 @@ public class ClusterMarkerRenderer extends MarkerRenderer { * We use a flat Sparse array to calculate the clusters. The sparse array models a 2D map where every (x,y) denotes * a grid slot, ie. 64x64dp. For efficiency I use a linear sparsearray with ARRindex = SLOTypos * max_x + SLOTxpos" */ - private SparseIntArray mGridMap = new SparseIntArray(200); // initial space for 200 markers, that's not a lot of memory, and in most cases will avoid resizing the array + private final SparseIntArray mGridMap = new SparseIntArray(200); // initial space for 200 markers, that's not a lot of memory, and in most cases will avoid resizing the array /** * Whether to enable clustering or disable the functionality */ - private boolean mClusteringEnabled = false; + private final boolean mClusteringEnabled; /** * Constructs a clustered marker renderer @@ -139,18 +139,18 @@ public class ClusterMarkerRenderer extends MarkerRenderer { */ private void repopulateCluster(int size, double scale) { /* the grid slot size in px. increase to group more aggressively. currently set to marker size */ - final int GRIDSIZE = ScreenUtils.getPixels(MAP_GRID_SIZE_DP); + final int GRIDSIZE = ClusterUtils.getPixels(MAP_GRID_SIZE_DP); /* the factor to map into Grid Coordinates (discrete squares of GRIDSIZE x GRIDSIZE) */ final double factor = (scale / GRIDSIZE); - InternalItem.Clustered[] tmp = new InternalItem.Clustered[size]; + Clustered[] tmp = new Clustered[size]; // clear grid map to count items that share the same "grid slot" mGridMap.clear(); for (int i = 0; i < size; i++) { - InternalItem.Clustered it = tmp[i] = new InternalItem.Clustered(); + Clustered it = tmp[i] = new Clustered(); it.item = mMarkerLayer.createItem(i); @@ -160,7 +160,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { it.py = mMapPoint.y; // items can be declared non-clusterable - if (!(it.item instanceof MarkerItem.NonClusterable)) { + if (!(it.item instanceof NonClusterable)) { final int absposx = (int) (it.px * factor), // absolute item X position in the grid @@ -244,7 +244,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { int numVisible = 0; // Increase view to show items that are partially visible - mMarkerLayer.map().viewport().getMapExtents(mBox, Tile.SIZE / 2); + mMarkerLayer.map().viewport().getMapExtents(mBox, Tile.SIZE >> 1); long flip = (long) (Tile.SIZE * v.pos.scale) >> 1; @@ -262,7 +262,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { /* check visibility */ for (InternalItem itm : mItems) { - InternalItem.Clustered it = (InternalItem.Clustered) itm; + Clustered it = (Clustered) itm; it.changes = false; it.x = (float) ((it.px - mx) * scale); @@ -318,7 +318,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { //log.debug(Arrays.toString(mItems)); for (InternalItem itm : mItems) { - InternalItem.Clustered it = (InternalItem.Clustered) itm; + Clustered it = (Clustered) itm; // skip invisible AND clustered-out if ((!it.visible) || (it.clusteredOut)) @@ -387,7 +387,7 @@ public class ClusterMarkerRenderer extends MarkerRenderer { // create and cache bitmap. This is unacceptable inside the GL thread, // so we'll call this routine at the beginning to pre-cache all bitmaps - ScreenUtils.ClusterDrawable drawable = new ScreenUtils.ClusterDrawable( + ClusterUtils.ClusterDrawable drawable = new ClusterUtils.ClusterDrawable( MAP_MARKER_CLUSTER_SIZE_DP - CLUSTER_MAXSIZE + size, // make size dependent on cluster size mStyleForeground, mStyleBackground, diff --git a/vtm/src/org/oscim/layers/marker/utils/ScreenUtils.java b/vtm-android-example/src/org/oscim/android/cluster/ClusterUtils.java similarity index 89% rename from vtm/src/org/oscim/layers/marker/utils/ScreenUtils.java rename to vtm-android-example/src/org/oscim/android/cluster/ClusterUtils.java index b62a0c24..b36ae1bd 100644 --- a/vtm/src/org/oscim/layers/marker/utils/ScreenUtils.java +++ b/vtm-android-example/src/org/oscim/android/cluster/ClusterUtils.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see . */ -package org.oscim.layers.marker.utils; +package org.oscim.android.cluster; import org.oscim.backend.CanvasAdapter; import org.oscim.backend.canvas.Bitmap; @@ -25,7 +25,7 @@ import org.oscim.backend.canvas.Paint; * A simple utility class to make clustered markers functionality self-contained. * Includes a method to translate between DPs and PXs and a circular icon generator. */ -public class ScreenUtils { +public class ClusterUtils { /** * Get pixels from DPs @@ -38,8 +38,9 @@ public class ScreenUtils { } public static class ClusterDrawable { - private Paint mPaintText = CanvasAdapter.newPaint(); - private Paint mPaintCircle = CanvasAdapter.newPaint(), mPaintBorder = CanvasAdapter.newPaint(); + private final Paint mPaintText = CanvasAdapter.newPaint(); + private final Paint mPaintCircle = CanvasAdapter.newPaint(); + private final Paint mPaintBorder = CanvasAdapter.newPaint(); private int mSize; private String mText; @@ -57,8 +58,8 @@ public class ScreenUtils { } private void setup(int sizedp, int foregroundColor, int backgroundColor) { - mSize = ScreenUtils.getPixels(sizedp); - mPaintText.setTextSize(ScreenUtils.getPixels((int) (sizedp * 0.6666666))); + mSize = ClusterUtils.getPixels(sizedp); + mPaintText.setTextSize(ClusterUtils.getPixels((int) (sizedp * 0.6666666))); mPaintText.setColor(foregroundColor); mPaintCircle.setColor(backgroundColor); diff --git a/vtm-android-example/src/org/oscim/android/cluster/Clustered.java b/vtm-android-example/src/org/oscim/android/cluster/Clustered.java new file mode 100644 index 00000000..509dd5f3 --- /dev/null +++ b/vtm-android-example/src/org/oscim/android/cluster/Clustered.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 nebular + * Copyright 2017 devemux86 + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.android.cluster; + +import org.oscim.layers.marker.InternalItem; + +/** + * Extension for clustered items. + */ +public class Clustered extends InternalItem { + /** + * If this is >0, this item will be displayed as a cluster circle, with size clusterSize+1. + */ + public int clusterSize; + + /** + * If this is true, this item is hidden (because it's represented by another InternalItem acting as cluster. + */ + public boolean clusteredOut; +} diff --git a/vtm-android-example/src/org/oscim/android/cluster/NonClusterable.java b/vtm-android-example/src/org/oscim/android/cluster/NonClusterable.java new file mode 100644 index 00000000..9feb8353 --- /dev/null +++ b/vtm-android-example/src/org/oscim/android/cluster/NonClusterable.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 nebular + * Copyright 2017 devemux86 + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program. If not, see . + */ +package org.oscim.android.cluster; + +import org.oscim.core.GeoPoint; +import org.oscim.layers.marker.MarkerItem; + +/** + * If a MarkerItem is created using this convenience class instead of MarkerItem, + * this specific item will not be clusterable. + */ +public class NonClusterable extends MarkerItem { + public NonClusterable(String title, String description, GeoPoint geoPoint) { + super(null, title, description, geoPoint); + } + + public NonClusterable(Object uid, String title, String description, GeoPoint geoPoint) { + super(uid, title, description, geoPoint); + } +} diff --git a/vtm-android-example/src/org/oscim/android/test/ClusterMarkerOverlayActivity.java b/vtm-android-example/src/org/oscim/android/test/ClusterMarkerOverlayActivity.java index 9f89ebda..ba78168a 100644 --- a/vtm-android-example/src/org/oscim/android/test/ClusterMarkerOverlayActivity.java +++ b/vtm-android-example/src/org/oscim/android/test/ClusterMarkerOverlayActivity.java @@ -17,6 +17,7 @@ package org.oscim.android.test; import android.graphics.BitmapFactory; import org.oscim.android.canvas.AndroidBitmap; +import org.oscim.android.cluster.ClusterMarkerRenderer; import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Color; import org.oscim.core.GeoPoint; diff --git a/vtm-playground/src/org/oscim/test/ClusterMarkerLayerTest.java b/vtm-playground/src/org/oscim/test/ClusterMarkerLayerTest.java deleted file mode 100644 index 07988e20..00000000 --- a/vtm-playground/src/org/oscim/test/ClusterMarkerLayerTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2016-2020 devemux86 - * Copyright 2017 nebular - * - * This program is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program. If not, see . - */ -package org.oscim.test; - -import org.oscim.backend.CanvasAdapter; -import org.oscim.backend.canvas.Bitmap; -import org.oscim.backend.canvas.Color; -import org.oscim.core.GeoPoint; -import org.oscim.gdx.GdxMapApp; -import org.oscim.layers.marker.*; -import org.oscim.layers.tile.bitmap.BitmapTileLayer; -import org.oscim.tiling.source.OkHttpEngine; -import org.oscim.tiling.source.UrlTileSource; -import org.oscim.tiling.source.bitmap.DefaultSources; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class ClusterMarkerLayerTest extends MarkerLayerTest { - - private static final int COUNT = 5; - private static final float STEP = 100f / 110000f; // roughly 100 meters - - @Override - public void createLayers() { - try { - // Map events receiver - mMap.layers().add(new MapEventsReceiver(mMap)); - - UrlTileSource tileSource = DefaultSources.OPENSTREETMAP - .httpFactory(new OkHttpEngine.OkHttpFactory()) - .build(); - tileSource.setHttpRequestHeaders(Collections.singletonMap("User-Agent", "vtm-playground")); - mMap.layers().add(new BitmapTileLayer(mMap, tileSource)); - - mMap.setMapPosition(53.08, 8.83, 1 << 15); - - Bitmap bitmapPoi = CanvasAdapter.decodeBitmap(getClass().getResourceAsStream("/res/marker_poi.png")); - final MarkerSymbol symbol; - if (BILLBOARDS) - symbol = new MarkerSymbol(bitmapPoi, MarkerSymbol.HotspotPlace.BOTTOM_CENTER); - else - symbol = new MarkerSymbol(bitmapPoi, MarkerSymbol.HotspotPlace.CENTER, false); - - MarkerRendererFactory markerRendererFactory = new MarkerRendererFactory() { - @Override - public MarkerRenderer create(MarkerLayer markerLayer) { - return new ClusterMarkerRenderer(markerLayer, symbol, new ClusterMarkerRenderer.ClusterStyle(Color.WHITE, Color.BLUE)) { - @Override - protected Bitmap getClusterBitmap(int size) { - // Can customize cluster bitmap here - return super.getClusterBitmap(size); - } - }; - } - }; - mMarkerLayer = new ItemizedLayer( - mMap, - new ArrayList(), - markerRendererFactory, - this); - mMap.layers().add(mMarkerLayer); - - // Create some markers spaced STEP degrees - List pts = new ArrayList<>(); - GeoPoint center = mMap.getMapPosition().getGeoPoint(); - for (int x = -COUNT; x < COUNT; x++) { - for (int y = -COUNT; y < COUNT; y++) { - double random = STEP * Math.random() * 2; - MarkerItem item = new MarkerItem(y + ", " + x, "", - new GeoPoint(center.getLatitude() + y * STEP + random, center.getLongitude() + x * STEP + random) - ); - pts.add(item); - } - } - mMarkerLayer.addItems(pts); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void main(String[] args) { - GdxMapApp.init(); - GdxMapApp.run(new ClusterMarkerLayerTest()); - } -} diff --git a/vtm/src/org/oscim/layers/marker/InternalItem.java b/vtm/src/org/oscim/layers/marker/InternalItem.java index 405166dd..caabb9d6 100644 --- a/vtm/src/org/oscim/layers/marker/InternalItem.java +++ b/vtm/src/org/oscim/layers/marker/InternalItem.java @@ -3,7 +3,6 @@ * Copyright 2016 Izumi Kawashima * Copyright 2017 Longri * Copyright 2017-2020 devemux86 - * Copyright 2017 nebular * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -36,22 +35,4 @@ public class InternalItem { public String toString() { return "\n" + x + ":" + y + " / " + dy + " " + visible; } - - /** - * Extension to the above class for clustered items. This could be a separate 1st level class, - * but it is included here not to pollute the source tree with tiny new files. - * It only adds a couple properties to InternalItem, and the semantics "InternalItem.Clustered" - * are not bad. - */ - public static class Clustered extends InternalItem { - /** - * If this is >0, this item will be displayed as a cluster circle, with size clusterSize+1. - */ - public int clusterSize; - - /** - * If this is true, this item is hidden (because it's represented by another InternalItem acting as cluster. - */ - public boolean clusteredOut; - } } diff --git a/vtm/src/org/oscim/layers/marker/ItemizedLayer.java b/vtm/src/org/oscim/layers/marker/ItemizedLayer.java index 0e65a1f0..d447ad0a 100644 --- a/vtm/src/org/oscim/layers/marker/ItemizedLayer.java +++ b/vtm/src/org/oscim/layers/marker/ItemizedLayer.java @@ -2,7 +2,7 @@ * Copyright 2012 osmdroid authors: Nicolas Gramlich, Theodore Hong, Fred Eisele * * Copyright 2013 Hannes Janetzek - * Copyright 2016-2020 devemux86 + * Copyright 2016-2021 devemux86 * Copyright 2016 Stephan Leuschner * Copyright 2016 Pedinel * Copyright 2019 Carlos Alberto Martínez Gadea @@ -78,7 +78,7 @@ public class ItemizedLayer extends MarkerLayer implements GestureListener { } @Override - protected synchronized MarkerInterface createItem(int index) { + public synchronized MarkerInterface createItem(int index) { return mItemList.get(index); } diff --git a/vtm/src/org/oscim/layers/marker/MarkerItem.java b/vtm/src/org/oscim/layers/marker/MarkerItem.java index c5e88e61..de5380ee 100644 --- a/vtm/src/org/oscim/layers/marker/MarkerItem.java +++ b/vtm/src/org/oscim/layers/marker/MarkerItem.java @@ -8,7 +8,6 @@ * Copyright 2016 devemux86 * Copyright 2016 Erik Duisters * Copyright 2017 Longri - * Copyright 2017 nebular * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -82,18 +81,4 @@ public class MarkerItem implements MarkerInterface { if (mMarker != null) mMarker.setRotation(rotation); } - - /** - * If a MarkerItem is created using this convenience class instead of MarkerItem, - * this specific item will not be clusterable. - */ - public static class NonClusterable extends MarkerItem { - public NonClusterable(String title, String description, GeoPoint geoPoint) { - super(null, title, description, geoPoint); - } - - public NonClusterable(Object uid, String title, String description, GeoPoint geoPoint) { - super(uid, title, description, geoPoint); - } - } } diff --git a/vtm/src/org/oscim/layers/marker/MarkerLayer.java b/vtm/src/org/oscim/layers/marker/MarkerLayer.java index abc5acc6..3dec2801 100644 --- a/vtm/src/org/oscim/layers/marker/MarkerLayer.java +++ b/vtm/src/org/oscim/layers/marker/MarkerLayer.java @@ -6,7 +6,7 @@ * * Copyright 2013 Hannes Janetzek * Copyright 2016 Stephan Leuschner - * Copyright 2016-2020 devemux86 + * Copyright 2016-2021 devemux86 * Copyright 2017 Longri * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). @@ -43,7 +43,7 @@ public abstract class MarkerLayer extends Layer { * Method by which subclasses create the actual Items. This will only be * called from populate() we'll cache them for later use. */ - protected abstract MarkerInterface createItem(int i); + public abstract MarkerInterface createItem(int i); /** * The number of items in this overlay.