diff --git a/library/src/main/java/com/google/maps/android/clustering/algo/ContinuousZoomEuclideanCentroidAlgorithm.java b/library/src/main/java/com/google/maps/android/clustering/algo/ContinuousZoomEuclideanCentroidAlgorithm.java
index c49dcb634..b42a65599 100644
--- a/library/src/main/java/com/google/maps/android/clustering/algo/ContinuousZoomEuclideanCentroidAlgorithm.java
+++ b/library/src/main/java/com/google/maps/android/clustering/algo/ContinuousZoomEuclideanCentroidAlgorithm.java
@@ -16,20 +16,23 @@
package com.google.maps.android.clustering.algo;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.geometry.Bounds;
-import com.google.maps.android.quadtree.PointQuadTree;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
* A variant of {@link CentroidNonHierarchicalDistanceBasedAlgorithm} that uses
* continuous zoom scaling and Euclidean distance for clustering.
*
- *
This class overrides {@link #getClusteringItems(PointQuadTree, float)} to compute
+ *
This class overrides {@link #getClusters(float)} to compute
* clusters with a zoom-dependent radius, while keeping the centroid-based cluster positions.
*
* @param the type of cluster item
@@ -38,15 +41,21 @@ public class ContinuousZoomEuclideanCentroidAlgorithm
extends CentroidNonHierarchicalDistanceBasedAlgorithm {
@Override
- protected Collection> getClusteringItems(PointQuadTree> quadTree, float zoom) {
+ public Set extends Cluster> getClusters(float zoom) {
// Continuous zoom — no casting to int
final double zoomSpecificSpan = getMaxDistanceBetweenClusteredItems() / Math.pow(2, zoom) / 256;
final Set> visitedCandidates = new HashSet<>();
- final Collection> result = new ArrayList<>();
+ final Set> results = new HashSet<>();
+ final Map, Double> distanceToCluster = new HashMap<>();
+ final Map, StaticCluster> itemToCluster = new HashMap<>();
+
synchronized (mQuadTree) {
- for (QuadItem candidate : mItems) {
- if (visitedCandidates.contains(candidate)) continue;
+ for (QuadItem candidate : getClusteringItems(mQuadTree, zoom)) {
+ if (visitedCandidates.contains(candidate)) {
+ // Candidate is already part of another cluster.
+ continue;
+ }
Bounds searchBounds = createBoundsFromSpan(candidate.getPoint(), zoomSpecificSpan);
Collection> clusterItems = new ArrayList<>();
@@ -58,11 +67,46 @@ protected Collection> getClusteringItems(PointQuadTree>
}
}
+ if (clusterItems.size() == 1) {
+ // Only the current marker is in range. Just add the single item to the results.
+ results.add(candidate);
+ visitedCandidates.add(candidate);
+ distanceToCluster.put(candidate, 0d);
+ continue;
+ }
+ StaticCluster cluster = new StaticCluster<>(candidate.mClusterItem.getPosition());
+ results.add(cluster);
+
+ for (QuadItem clusterItem : clusterItems) {
+ Double existingDistance = distanceToCluster.get(clusterItem);
+ double distance = distanceSquared(clusterItem.getPoint(), candidate.getPoint());
+ if (existingDistance != null) {
+ // Item already belongs to another cluster. Check if it's closer to this cluster.
+ if (existingDistance < distance) {
+ continue;
+ }
+ // Move item to the closer cluster.
+ itemToCluster.get(clusterItem).remove(clusterItem.mClusterItem);
+ }
+ distanceToCluster.put(clusterItem, distance);
+ cluster.add(clusterItem.mClusterItem);
+ itemToCluster.put(clusterItem, cluster);
+ }
visitedCandidates.addAll(clusterItems);
- result.add(candidate);
}
}
- return result;
- }
-}
+ // Now, apply the centroid logic from CentroidNonHierarchicalDistanceBasedAlgorithm
+ Set> newClusters = new HashSet<>();
+ for (Cluster cluster : results) {
+ LatLng centroid = computeCentroid(cluster.getItems());
+ StaticCluster newCluster = new StaticCluster<>(centroid);
+ for (T item : cluster.getItems()) {
+ newCluster.add(item);
+ }
+ newClusters.add(newCluster);
+ }
+
+ return newClusters;
+ }
+}
\ No newline at end of file