1+ /*
2+ * Copyright 2025 Google LLC
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com.google.maps.android.utils.demo
18+
19+ import android.view.View
20+ import android.widget.AdapterView
21+ import android.widget.ArrayAdapter
22+ import android.widget.Spinner
23+ import com.google.android.gms.maps.CameraUpdateFactory
24+ import com.google.android.gms.maps.MapView
25+ import com.google.android.gms.maps.model.LatLng
26+ import com.google.maps.android.clustering.ClusterManager
27+ import com.google.maps.android.clustering.algo.CentroidNonHierarchicalDistanceBasedAlgorithm
28+ import com.google.maps.android.clustering.algo.ContinuousZoomEuclideanCentroidAlgorithm
29+ import com.google.maps.android.clustering.algo.GridBasedAlgorithm
30+ import com.google.maps.android.clustering.algo.NonHierarchicalDistanceBasedAlgorithm
31+ import com.google.maps.android.clustering.algo.NonHierarchicalViewBasedAlgorithm
32+ import com.google.maps.android.utils.demo.model.MyItem
33+ import kotlin.random.Random
34+
35+ /* *
36+ * A demo activity that showcases the various clustering algorithms
37+ * available in the library.
38+ */
39+ class ClusterAlgorithmsDemoActivity : BaseDemoActivity () {
40+
41+ private var clusterManager: ClusterManager <MyItem >? = null
42+ private lateinit var mapView: MapView
43+
44+ override fun getLayoutId (): Int {
45+ return R .layout.activity_cluster_algorithms_demo
46+ }
47+
48+ override fun startDemo (isRestore : Boolean ) {
49+ // The MapView is needed for the NonHierarchicalViewBasedAlgorithm.
50+ mapView = findViewById(R .id.map)
51+
52+ if (! isRestore) {
53+ map.moveCamera(
54+ CameraUpdateFactory .newLatLngZoom(
55+ LatLng (51.503186 , - 0.126446 ),
56+ 10f
57+ )
58+ )
59+ }
60+
61+ setupSpinner()
62+
63+ setupClusterer(0 )
64+ }
65+
66+ private fun setupSpinner () {
67+ val spinner: Spinner = findViewById(R .id.algorithm_spinner)
68+ val adapter = ArrayAdapter .createFromResource(
69+ this ,
70+ R .array.clustering_algorithms,
71+ android.R .layout.simple_spinner_item
72+ )
73+ adapter.setDropDownViewResource(android.R .layout.simple_spinner_dropdown_item)
74+ spinner.adapter = adapter
75+ spinner.onItemSelectedListener = object : AdapterView .OnItemSelectedListener {
76+ override fun onItemSelected (
77+ parent : AdapterView <* >? ,
78+ view : View ? ,
79+ position : Int ,
80+ id : Long
81+ ) {
82+ setupClusterer(position)
83+ }
84+
85+ override fun onNothingSelected (parent : AdapterView <* >? ) {
86+ // Do nothing
87+ }
88+ }
89+ }
90+
91+ /* *
92+ * Sets up the ClusterManager with the chosen algorithm and populates it with items.
93+ */
94+ private fun setupClusterer (algorithmPosition : Int ) {
95+ // 1. Clear the map and previous cluster manager
96+ map.clear()
97+ clusterManager = null
98+
99+ // 2. Initialize a new ClusterManager, using getMap() from BaseDemoActivity
100+ clusterManager = ClusterManager (this , map)
101+
102+ // 3. Set the desired algorithm based on the spinner position
103+ when (algorithmPosition) {
104+ 1 -> {
105+ clusterManager?.algorithm = GridBasedAlgorithm ()
106+ }
107+
108+ 2 -> {
109+ clusterManager?.algorithm = NonHierarchicalDistanceBasedAlgorithm ()
110+ }
111+
112+ 3 -> {
113+ clusterManager?.algorithm = CentroidNonHierarchicalDistanceBasedAlgorithm ()
114+ }
115+
116+ 4 -> {
117+ clusterManager?.algorithm = NonHierarchicalViewBasedAlgorithm (
118+ mapView.width, mapView.height
119+ )
120+ }
121+
122+ 5 -> {
123+ clusterManager?.algorithm = ContinuousZoomEuclideanCentroidAlgorithm ()
124+ }
125+
126+ else -> { // Default
127+
128+ }
129+ }
130+
131+ // 4. Point the map's listeners to the ClusterManager
132+ map.setOnCameraIdleListener(clusterManager)
133+ map.setOnMarkerClickListener(clusterManager)
134+
135+ // 5. Add cluster items to the manager
136+ addItems()
137+
138+ // 6. Trigger the initial clustering
139+ clusterManager?.cluster()
140+ }
141+
142+ private fun addItems () {
143+ val items = mutableListOf<MyItem >()
144+ // Add 100 random items in the map region
145+ for (i in 0 .. 99 ) {
146+ val lat = 51.5145 + (Random .nextDouble() - 0.5 ) / 2.0
147+ val lng = - 0.1245 + (Random .nextDouble() - 0.5 ) / 2.0
148+ items.add(MyItem (lat, lng, " Marker #$i " , " Snippet for marker #$i " ))
149+ }
150+ clusterManager?.addItems(items)
151+ }
152+ }
0 commit comments