16
16
17
17
package com .google .maps .android .clustering .algo ;
18
18
19
+ import com .google .android .gms .maps .model .LatLng ;
20
+ import com .google .maps .android .clustering .Cluster ;
19
21
import com .google .maps .android .clustering .ClusterItem ;
20
22
import com .google .maps .android .geometry .Bounds ;
21
- import com .google .maps .android .quadtree .PointQuadTree ;
22
23
23
24
import java .util .ArrayList ;
24
25
import java .util .Collection ;
26
+ import java .util .HashMap ;
25
27
import java .util .HashSet ;
28
+ import java .util .Map ;
26
29
import java .util .Set ;
27
30
28
31
/**
29
32
* A variant of {@link CentroidNonHierarchicalDistanceBasedAlgorithm} that uses
30
33
* continuous zoom scaling and Euclidean distance for clustering.
31
34
*
32
- * <p>This class overrides {@link #getClusteringItems(PointQuadTree, float)} to compute
35
+ * <p>This class overrides {@link #getClusters( float)} to compute
33
36
* clusters with a zoom-dependent radius, while keeping the centroid-based cluster positions.</p>
34
37
*
35
38
* @param <T> the type of cluster item
@@ -38,15 +41,21 @@ public class ContinuousZoomEuclideanCentroidAlgorithm<T extends ClusterItem>
38
41
extends CentroidNonHierarchicalDistanceBasedAlgorithm <T > {
39
42
40
43
@ Override
41
- protected Collection < QuadItem < T >> getClusteringItems ( PointQuadTree < QuadItem < T >> quadTree , float zoom ) {
44
+ public Set <? extends Cluster < T >> getClusters ( float zoom ) {
42
45
// Continuous zoom — no casting to int
43
46
final double zoomSpecificSpan = getMaxDistanceBetweenClusteredItems () / Math .pow (2 , zoom ) / 256 ;
44
47
45
48
final Set <QuadItem <T >> visitedCandidates = new HashSet <>();
46
- final Collection <QuadItem <T >> result = new ArrayList <>();
49
+ final Set <Cluster <T >> results = new HashSet <>();
50
+ final Map <QuadItem <T >, Double > distanceToCluster = new HashMap <>();
51
+ final Map <QuadItem <T >, StaticCluster <T >> itemToCluster = new HashMap <>();
52
+
47
53
synchronized (mQuadTree ) {
48
- for (QuadItem <T > candidate : mItems ) {
49
- if (visitedCandidates .contains (candidate )) continue ;
54
+ for (QuadItem <T > candidate : getClusteringItems (mQuadTree , zoom )) {
55
+ if (visitedCandidates .contains (candidate )) {
56
+ // Candidate is already part of another cluster.
57
+ continue ;
58
+ }
50
59
51
60
Bounds searchBounds = createBoundsFromSpan (candidate .getPoint (), zoomSpecificSpan );
52
61
Collection <QuadItem <T >> clusterItems = new ArrayList <>();
@@ -58,11 +67,46 @@ protected Collection<QuadItem<T>> getClusteringItems(PointQuadTree<QuadItem<T>>
58
67
}
59
68
}
60
69
70
+ if (clusterItems .size () == 1 ) {
71
+ // Only the current marker is in range. Just add the single item to the results.
72
+ results .add (candidate );
73
+ visitedCandidates .add (candidate );
74
+ distanceToCluster .put (candidate , 0d );
75
+ continue ;
76
+ }
77
+ StaticCluster <T > cluster = new StaticCluster <>(candidate .mClusterItem .getPosition ());
78
+ results .add (cluster );
79
+
80
+ for (QuadItem <T > clusterItem : clusterItems ) {
81
+ Double existingDistance = distanceToCluster .get (clusterItem );
82
+ double distance = distanceSquared (clusterItem .getPoint (), candidate .getPoint ());
83
+ if (existingDistance != null ) {
84
+ // Item already belongs to another cluster. Check if it's closer to this cluster.
85
+ if (existingDistance < distance ) {
86
+ continue ;
87
+ }
88
+ // Move item to the closer cluster.
89
+ itemToCluster .get (clusterItem ).remove (clusterItem .mClusterItem );
90
+ }
91
+ distanceToCluster .put (clusterItem , distance );
92
+ cluster .add (clusterItem .mClusterItem );
93
+ itemToCluster .put (clusterItem , cluster );
94
+ }
61
95
visitedCandidates .addAll (clusterItems );
62
- result .add (candidate );
63
96
}
64
97
}
65
- return result ;
66
- }
67
98
68
- }
99
+ // Now, apply the centroid logic from CentroidNonHierarchicalDistanceBasedAlgorithm
100
+ Set <StaticCluster <T >> newClusters = new HashSet <>();
101
+ for (Cluster <T > cluster : results ) {
102
+ LatLng centroid = computeCentroid (cluster .getItems ());
103
+ StaticCluster <T > newCluster = new StaticCluster <>(centroid );
104
+ for (T item : cluster .getItems ()) {
105
+ newCluster .add (item );
106
+ }
107
+ newClusters .add (newCluster );
108
+ }
109
+
110
+ return newClusters ;
111
+ }
112
+ }
0 commit comments