Move cluster experiment in samples (#858)

This commit is contained in:
Emux 2021-06-24 15:07:36 +03:00 committed by GitHub
parent e2c901d1e5
commit 5de7070f15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 92 additions and 158 deletions

View File

@ -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)

View File

@ -19,13 +19,13 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
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,

View File

@ -14,7 +14,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
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);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<MarkerInterface>(),
markerRendererFactory,
this);
mMap.layers().add(mMarkerLayer);
// Create some markers spaced STEP degrees
List<MarkerInterface> 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());
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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.