@@ -4,6 +4,9 @@ import com.mapconductor.core.circle.CircleOverlayManager
44import com.mapconductor.core.circle.CircleRenderer
55import com.mapconductor.core.circle.CircleState
66import com.mapconductor.core.circle.OnCircleEventHandler
7+ import com.mapconductor.core.features.IGeoPoint
8+ import com.mapconductor.core.geocell.HexCell
9+ import com.mapconductor.core.geocell.HexCoord
710import com.mapconductor.core.geocell.HexGeocell
811import com.mapconductor.core.map.MapViewHolder
912import com.mapconductor.core.map.OnCameraMoveHandler
@@ -43,31 +46,27 @@ interface MapViewController<ActualMarker, ActualCircle, ActualPolyline, ActualPo
4346
4447 suspend fun clearOverlays ()
4548
46- fun setCameraMoveListener (listener : OnCameraMoveHandler ? )
47-
48- fun setMapClickListener (listener : OnMapEventHandler ? )
49-
50- fun setMapLongClickListener (listener : OnMapEventHandler ? )
51-
52- fun setMarkerClickListener (listener : OnMarkerEventHandler ? )
53-
54- fun setMarkerDragStartListener (listener : OnMarkerEventHandler ? )
55-
56- fun setMarkerDragListener (listener : OnMarkerEventHandler ? )
57-
58- fun setMarkerDragEndListener (listener : OnMarkerEventHandler ? )
59-
60- fun setCircleClickListener (listener : OnCircleEventHandler ? )
61-
62- fun setPolylineClickListener (listener : OnPolylineEventHandler ? )
63-
6449 fun setOnMarkerAnimationStart (listener : OnMarkerEventHandler ? )
6550
6651 fun setOnMarkerAnimationEnd (listener : OnMarkerEventHandler ? )
6752}
6853typealias MapViewControllerAlias = MapViewController <* , * , * , * >
6954
70- abstract class BaseMapViewController <ActualMarker , ActualCircle , ActualPolyline , ActualPolygon > :
55+ data class SearchRangeAnalysis (
56+ val clickPosition : IGeoPoint ,
57+ val zoom : Double ,
58+ val tolerancePixels : Double ,
59+ val toleranceMeters : Double ,
60+ val clickedCell : HexCell ,
61+ val hexSideLength : Double ,
62+ val hexDistance : Double ,
63+ val searchRadiusHexUnits : Int ,
64+ val searchCells : List <HexCoord >,
65+ val outlineCells : List <HexCoord >,
66+ val markersInRange : List <MarkerState >,
67+ )
68+
69+ abstract class BaseMapViewController <ActualCamera , ActualMarker , ActualCircle , ActualPolyline , ActualPolygon > :
7170 MapViewController <ActualMarker , ActualCircle , ActualPolyline , ActualPolygon > {
7271 abstract val markerRenderer: MarkerRenderer <ActualMarker >
7372
@@ -121,59 +120,201 @@ abstract class BaseMapViewController<ActualMarker, ActualCircle, ActualPolyline,
121120
122121 protected abstract fun createCircleOverlayManager (): CircleOverlayManager <ActualCircle >
123122
124- protected var cameraMoveCallback : OnCameraMoveHandler ? = null
125- protected var mapClickCallback : OnMapEventHandler ? = null
126- protected var mapLongClickCallback : OnMapEventHandler ? = null
127- protected var markerClickCallback : OnMarkerEventHandler ? = null
128- protected var markerDragStartCallback : OnMarkerEventHandler ? = null
129- protected var markerDragCallback : OnMarkerEventHandler ? = null
130- protected var markerDragEndCallback : OnMarkerEventHandler ? = null
131- protected var circleClickCallback : OnCircleEventHandler ? = null
132- protected var polylineClickCallback : OnPolylineEventHandler ? = null
123+ var cameraMoveListener : ( OnCameraMoveHandler < ActualCamera >) ? = null
124+ var mapClickListener : OnMapEventHandler ? = null
125+ var mapLongClickListener : OnMapEventHandler ? = null
126+ var markerClickListener : OnMarkerEventHandler ? = null
127+ var markerDragStartListener : OnMarkerEventHandler ? = null
128+ var markerDragListener : OnMarkerEventHandler ? = null
129+ var markerDragEndListener : OnMarkerEventHandler ? = null
130+ var circleClickListener : OnCircleEventHandler ? = null
131+ var polylineClickListener : OnPolylineEventHandler ? = null
133132
134133 abstract fun setupListeners ()
135134
136- override fun setCameraMoveListener (listener : OnCameraMoveHandler ? ) {
137- this .cameraMoveCallback = listener
138- }
139-
140- override fun setMapClickListener (listener : OnMapEventHandler ? ) {
141- this .mapClickCallback = listener
142- }
143-
144- override fun setMapLongClickListener (listener : OnMapEventHandler ? ) {
145- this .mapClickCallback = listener
146- }
147-
148- override fun setMarkerClickListener (listener : OnMarkerEventHandler ? ) {
149- this .markerClickCallback = listener
150- }
151-
152- override fun setMarkerDragStartListener (listener : OnMarkerEventHandler ? ) {
153- this .markerDragStartCallback = listener
154- }
155-
156- override fun setMarkerDragListener (listener : OnMarkerEventHandler ? ) {
157- this .markerDragCallback = listener
158- }
159-
160- override fun setMarkerDragEndListener (listener : OnMarkerEventHandler ? ) {
161- this .markerDragEndCallback = listener
162- }
163-
164- override fun setCircleClickListener (listener : OnCircleEventHandler ? ) {
165- this .circleClickCallback = listener
166- }
167-
168- override fun setPolylineClickListener (listener : OnPolylineEventHandler ? ) {
169- this .polylineClickCallback = listener
170- }
171-
172135 override fun setOnMarkerAnimationStart (listener : OnMarkerEventHandler ? ) =
173136 markerRenderer
174137 .setOnMarkerAnimationStart(listener)
175138
176139 override fun setOnMarkerAnimationEnd (listener : OnMarkerEventHandler ? ) =
177140 markerRenderer
178141 .setOnMarkerAnimationEnd(listener)
142+
143+ // protected fun analyzeSearchRange(
144+ // position: IGeoPoint,
145+ // zoom: Double,
146+ // tolerancePixels: Double,
147+ // ): SearchRangeAnalysis {
148+ // val toleranceMeters =
149+ // markerOverlayManager.markerManager.metersPerPixel(
150+ // position, zoom, tolerancePixels,
151+ // )
152+ //
153+ // val clickedCell = hexGeocell.latLngToHexCell(position, zoom)
154+ //
155+ // // Hex metrics
156+ // val scale = 1.0 / (2.0.pow(zoom))
157+ // val latScale = kotlin.math.cos(position.latitude * kotlin.math.PI / 180).coerceAtLeast(0.01)
158+ // val hexSideLength = hexGeocell.baseHexSideLength * scale / latScale
159+ // val hexDistance = hexSideLength * kotlin.math.sqrt(3.0)
160+ // val searchRadiusHexUnits = kotlin.math.ceil(toleranceMeters / hexDistance).toInt()
161+ //
162+ // // Search cells
163+ // val searchCells = hexGeocell.hexRange(clickedCell.coord, searchRadiusHexUnits)
164+ // val outlineCells = findOutlineCells(searchCells)
165+ //
166+ // // Find markers in range
167+ // val markersInRange = findMarkersInSearchRange(position, searchCells, toleranceMeters, zoom)
168+ //
169+ // return SearchRangeAnalysis(
170+ // clickPosition = position,
171+ // zoom = zoom,
172+ // tolerancePixels = tolerancePixels,
173+ // toleranceMeters = toleranceMeters,
174+ // clickedCell = clickedCell,
175+ // hexSideLength = hexSideLength,
176+ // hexDistance = hexDistance,
177+ // searchRadiusHexUnits = searchRadiusHexUnits,
178+ // searchCells = searchCells,
179+ // outlineCells = outlineCells,
180+ // markersInRange = markersInRange,
181+ // )
182+ // }
183+ //
184+ // /**
185+ // * 検索範囲内のマーカーを特定
186+ // */
187+ // protected fun findMarkersInSearchRange(
188+ // clickPosition: IGeoPoint,
189+ // searchCells: List<HexCoord>,
190+ // toleranceMeters: Double,
191+ // zoom: Double,
192+ // ): List<MarkerState> {
193+ // val cellSet = searchCells.toSet()
194+ // val markersInRange = mutableListOf<MarkerState>()
195+ //
196+ // markerOverlayManager.markerManager.allEntities().forEach { markerEntity ->
197+ // val markerCell = hexGeocell.latLngToHexCell(markerEntity.state.position, zoom)
198+ //
199+ // if (markerCell.coord in cellSet) {
200+ // val distance = haversineDistance(clickPosition, markerEntity.state.position)
201+ // if (distance <= toleranceMeters) {
202+ // markersInRange.add(markerEntity.state)
203+ // }
204+ // }
205+ // }
206+ //
207+ // return markersInRange
208+ // }
209+
210+ // /**
211+ // * 検索範囲の外郭セルを特定
212+ // */
213+ // protected fun findOutlineCells(searchCells: List<HexCoord>): List<HexCoord> {
214+ // val cellSet = searchCells.toSet()
215+ //
216+ // return searchCells.filter { cell ->
217+ // // 近隣セルのいずれかが検索範囲外なら、これは外郭セル
218+ // cell.neighbors().any { neighbor ->
219+ // neighbor !in cellSet
220+ // }
221+ // }
222+ // }
223+
224+ // /**
225+ // * 円形の近似ポイントを生成
226+ // */
227+ // protected fun createCirclePoints(
228+ // center: IGeoPoint,
229+ // radiusMeters: Double,
230+ // numPoints: Int = 32,
231+ // ): List<IGeoPoint> {
232+ // val points = mutableListOf<IGeoPoint>()
233+ // val earthRadius = 6371000.0 // 地球半径(メートル)
234+ //
235+ // for (i in 0 until numPoints) {
236+ // val angle = 2.0 * kotlin.math.PI * i / numPoints
237+ // val deltaLat = radiusMeters * kotlin.math.cos(angle) / earthRadius * 180.0 / kotlin.math.PI
238+ // val deltaLng =
239+ // radiusMeters * kotlin.math.sin(angle) / earthRadius * 180.0 / kotlin.math.PI /
240+ // kotlin.math.cos(center.latitude * kotlin.math.PI / 180.0)
241+ //
242+ // points.add(
243+ // object : IGeoPoint {
244+ // override val latitude = center.latitude + deltaLat
245+ // override val longitude = center.longitude + deltaLng
246+ // override val altitude = center.altitude
247+ // },
248+ // )
249+ // }
250+ //
251+ // // 円を閉じる
252+ // if (points.isNotEmpty()) {
253+ // points.add(points[0])
254+ // }
255+ //
256+ // return points
257+ // }
258+
259+ // protected fun drawDistanceCircles(analysis: SearchRangeAnalysis) {
260+ // // 距離サークルの近似(正n角形として)
261+ // val circlePoints =
262+ // createCirclePoints(
263+ // center = analysis.clickPosition,
264+ // radiusMeters = analysis.toleranceMeters,
265+ // numPoints = 32,
266+ // )
267+ // drawPolyline(circlePoints)
268+ // }
269+ //
270+ // /**
271+ // * 各種可視化モード
272+ // */
273+ // protected fun drawClickedCell(analysis: SearchRangeAnalysis) {
274+ // val points =
275+ // hexGeocell.hexToPolygonLatLng(
276+ // coord = analysis.clickedCell.coord,
277+ // latHint = analysis.clickPosition.latitude,
278+ // zoom = analysis.zoom,
279+ // )
280+ // drawPolyline(points)
281+ // }
282+
283+ // protected fun drawFullSearchRange(analysis: SearchRangeAnalysis) {
284+ // val allPoints = mutableListOf<IGeoPoint>()
285+ //
286+ // analysis.searchCells.take(50).forEach { coord ->
287+ // // パフォーマンス制限
288+ // val cellPoints =
289+ // hexGeocell.hexToPolygonLatLng(
290+ // coord,
291+ // analysis.clickPosition.latitude,
292+ // analysis.zoom,
293+ // )
294+ // allPoints.addAll(cellPoints)
295+ // allPoints.add(cellPoints[0]) // 閉じる
296+ // }
297+ //
298+ // if (allPoints.isNotEmpty()) {
299+ // drawPolyline(allPoints)
300+ // }
301+ // }
302+ //
303+ // protected fun drawSearchOutline(analysis: SearchRangeAnalysis) {
304+ // val outlinePoints = mutableListOf<IGeoPoint>()
305+ //
306+ // analysis.outlineCells.forEach { coord ->
307+ // val cellPoints =
308+ // hexGeocell.hexToPolygonLatLng(
309+ // coord,
310+ // analysis.clickPosition.latitude,
311+ // analysis.zoom,
312+ // )
313+ // outlinePoints.addAll(cellPoints)
314+ // }
315+ //
316+ // if (outlinePoints.isNotEmpty()) {
317+ // drawPolyline(outlinePoints)
318+ // }
319+ // }
179320}
0 commit comments