Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import com.mapconductor.core.circle.CircleOverlayManager
import com.mapconductor.core.circle.CircleRenderer
import com.mapconductor.core.circle.CircleState
import com.mapconductor.core.circle.OnCircleEventHandler
import com.mapconductor.core.features.IGeoPoint
import com.mapconductor.core.geocell.HexCell
import com.mapconductor.core.geocell.HexCoord
import com.mapconductor.core.geocell.HexGeocell
import com.mapconductor.core.map.MapViewHolder
import com.mapconductor.core.map.OnCameraMoveHandler
Expand Down Expand Up @@ -46,27 +43,31 @@ interface MapViewController<ActualMarker, ActualCircle, ActualPolyline, ActualPo

suspend fun clearOverlays()

fun setCameraMoveListener(listener: OnCameraMoveHandler?)

fun setMapClickListener(listener: OnMapEventHandler?)

fun setMapLongClickListener(listener: OnMapEventHandler?)

fun setMarkerClickListener(listener: OnMarkerEventHandler?)

fun setMarkerDragStartListener(listener: OnMarkerEventHandler?)

fun setMarkerDragListener(listener: OnMarkerEventHandler?)

fun setMarkerDragEndListener(listener: OnMarkerEventHandler?)

fun setCircleClickListener(listener: OnCircleEventHandler?)

fun setPolylineClickListener(listener: OnPolylineEventHandler?)

fun setOnMarkerAnimationStart(listener: OnMarkerEventHandler?)

fun setOnMarkerAnimationEnd(listener: OnMarkerEventHandler?)
}
typealias MapViewControllerAlias = MapViewController<*, *, *, *>

data class SearchRangeAnalysis(
val clickPosition: IGeoPoint,
val zoom: Double,
val tolerancePixels: Double,
val toleranceMeters: Double,
val clickedCell: HexCell,
val hexSideLength: Double,
val hexDistance: Double,
val searchRadiusHexUnits: Int,
val searchCells: List<HexCoord>,
val outlineCells: List<HexCoord>,
val markersInRange: List<MarkerState>,
)

abstract class BaseMapViewController<ActualCamera, ActualMarker, ActualCircle, ActualPolyline, ActualPolygon> :
abstract class BaseMapViewController<ActualMarker, ActualCircle, ActualPolyline, ActualPolygon> :
MapViewController<ActualMarker, ActualCircle, ActualPolyline, ActualPolygon> {
abstract val markerRenderer: MarkerRenderer<ActualMarker>

Expand Down Expand Up @@ -120,201 +121,59 @@ abstract class BaseMapViewController<ActualCamera, ActualMarker, ActualCircle, A

protected abstract fun createCircleOverlayManager(): CircleOverlayManager<ActualCircle>

var cameraMoveListener: (OnCameraMoveHandler<ActualCamera>)? = null
var mapClickListener: OnMapEventHandler? = null
var mapLongClickListener: OnMapEventHandler? = null
var markerClickListener: OnMarkerEventHandler? = null
var markerDragStartListener: OnMarkerEventHandler? = null
var markerDragListener: OnMarkerEventHandler? = null
var markerDragEndListener: OnMarkerEventHandler? = null
var circleClickListener: OnCircleEventHandler? = null
var polylineClickListener: OnPolylineEventHandler? = null
protected var cameraMoveCallback: OnCameraMoveHandler? = null
protected var mapClickCallback: OnMapEventHandler? = null
protected var mapLongClickCallback: OnMapEventHandler? = null
protected var markerClickCallback: OnMarkerEventHandler? = null
protected var markerDragStartCallback: OnMarkerEventHandler? = null
protected var markerDragCallback: OnMarkerEventHandler? = null
protected var markerDragEndCallback: OnMarkerEventHandler? = null
protected var circleClickCallback: OnCircleEventHandler? = null
protected var polylineClickCallback: OnPolylineEventHandler? = null

abstract fun setupListeners()

override fun setCameraMoveListener(listener: OnCameraMoveHandler?) {
this.cameraMoveCallback = listener
}

override fun setMapClickListener(listener: OnMapEventHandler?) {
this.mapClickCallback = listener
}

override fun setMapLongClickListener(listener: OnMapEventHandler?) {
this.mapClickCallback = listener
}

override fun setMarkerClickListener(listener: OnMarkerEventHandler?) {
this.markerClickCallback = listener
}

override fun setMarkerDragStartListener(listener: OnMarkerEventHandler?) {
this.markerDragStartCallback = listener
}

override fun setMarkerDragListener(listener: OnMarkerEventHandler?) {
this.markerDragCallback = listener
}

override fun setMarkerDragEndListener(listener: OnMarkerEventHandler?) {
this.markerDragEndCallback = listener
}

override fun setCircleClickListener(listener: OnCircleEventHandler?) {
this.circleClickCallback = listener
}

override fun setPolylineClickListener(listener: OnPolylineEventHandler?) {
this.polylineClickCallback = listener
}

override fun setOnMarkerAnimationStart(listener: OnMarkerEventHandler?) =
markerRenderer
.setOnMarkerAnimationStart(listener)

override fun setOnMarkerAnimationEnd(listener: OnMarkerEventHandler?) =
markerRenderer
.setOnMarkerAnimationEnd(listener)

// protected fun analyzeSearchRange(
// position: IGeoPoint,
// zoom: Double,
// tolerancePixels: Double,
// ): SearchRangeAnalysis {
// val toleranceMeters =
// markerOverlayManager.markerManager.metersPerPixel(
// position, zoom, tolerancePixels,
// )
//
// val clickedCell = hexGeocell.latLngToHexCell(position, zoom)
//
// // Hex metrics
// val scale = 1.0 / (2.0.pow(zoom))
// val latScale = kotlin.math.cos(position.latitude * kotlin.math.PI / 180).coerceAtLeast(0.01)
// val hexSideLength = hexGeocell.baseHexSideLength * scale / latScale
// val hexDistance = hexSideLength * kotlin.math.sqrt(3.0)
// val searchRadiusHexUnits = kotlin.math.ceil(toleranceMeters / hexDistance).toInt()
//
// // Search cells
// val searchCells = hexGeocell.hexRange(clickedCell.coord, searchRadiusHexUnits)
// val outlineCells = findOutlineCells(searchCells)
//
// // Find markers in range
// val markersInRange = findMarkersInSearchRange(position, searchCells, toleranceMeters, zoom)
//
// return SearchRangeAnalysis(
// clickPosition = position,
// zoom = zoom,
// tolerancePixels = tolerancePixels,
// toleranceMeters = toleranceMeters,
// clickedCell = clickedCell,
// hexSideLength = hexSideLength,
// hexDistance = hexDistance,
// searchRadiusHexUnits = searchRadiusHexUnits,
// searchCells = searchCells,
// outlineCells = outlineCells,
// markersInRange = markersInRange,
// )
// }
//
// /**
// * 検索範囲内のマーカーを特定
// */
// protected fun findMarkersInSearchRange(
// clickPosition: IGeoPoint,
// searchCells: List<HexCoord>,
// toleranceMeters: Double,
// zoom: Double,
// ): List<MarkerState> {
// val cellSet = searchCells.toSet()
// val markersInRange = mutableListOf<MarkerState>()
//
// markerOverlayManager.markerManager.allEntities().forEach { markerEntity ->
// val markerCell = hexGeocell.latLngToHexCell(markerEntity.state.position, zoom)
//
// if (markerCell.coord in cellSet) {
// val distance = haversineDistance(clickPosition, markerEntity.state.position)
// if (distance <= toleranceMeters) {
// markersInRange.add(markerEntity.state)
// }
// }
// }
//
// return markersInRange
// }

// /**
// * 検索範囲の外郭セルを特定
// */
// protected fun findOutlineCells(searchCells: List<HexCoord>): List<HexCoord> {
// val cellSet = searchCells.toSet()
//
// return searchCells.filter { cell ->
// // 近隣セルのいずれかが検索範囲外なら、これは外郭セル
// cell.neighbors().any { neighbor ->
// neighbor !in cellSet
// }
// }
// }

// /**
// * 円形の近似ポイントを生成
// */
// protected fun createCirclePoints(
// center: IGeoPoint,
// radiusMeters: Double,
// numPoints: Int = 32,
// ): List<IGeoPoint> {
// val points = mutableListOf<IGeoPoint>()
// val earthRadius = 6371000.0 // 地球半径(メートル)
//
// for (i in 0 until numPoints) {
// val angle = 2.0 * kotlin.math.PI * i / numPoints
// val deltaLat = radiusMeters * kotlin.math.cos(angle) / earthRadius * 180.0 / kotlin.math.PI
// val deltaLng =
// radiusMeters * kotlin.math.sin(angle) / earthRadius * 180.0 / kotlin.math.PI /
// kotlin.math.cos(center.latitude * kotlin.math.PI / 180.0)
//
// points.add(
// object : IGeoPoint {
// override val latitude = center.latitude + deltaLat
// override val longitude = center.longitude + deltaLng
// override val altitude = center.altitude
// },
// )
// }
//
// // 円を閉じる
// if (points.isNotEmpty()) {
// points.add(points[0])
// }
//
// return points
// }

// protected fun drawDistanceCircles(analysis: SearchRangeAnalysis) {
// // 距離サークルの近似(正n角形として)
// val circlePoints =
// createCirclePoints(
// center = analysis.clickPosition,
// radiusMeters = analysis.toleranceMeters,
// numPoints = 32,
// )
// drawPolyline(circlePoints)
// }
//
// /**
// * 各種可視化モード
// */
// protected fun drawClickedCell(analysis: SearchRangeAnalysis) {
// val points =
// hexGeocell.hexToPolygonLatLng(
// coord = analysis.clickedCell.coord,
// latHint = analysis.clickPosition.latitude,
// zoom = analysis.zoom,
// )
// drawPolyline(points)
// }

// protected fun drawFullSearchRange(analysis: SearchRangeAnalysis) {
// val allPoints = mutableListOf<IGeoPoint>()
//
// analysis.searchCells.take(50).forEach { coord ->
// // パフォーマンス制限
// val cellPoints =
// hexGeocell.hexToPolygonLatLng(
// coord,
// analysis.clickPosition.latitude,
// analysis.zoom,
// )
// allPoints.addAll(cellPoints)
// allPoints.add(cellPoints[0]) // 閉じる
// }
//
// if (allPoints.isNotEmpty()) {
// drawPolyline(allPoints)
// }
// }
//
// protected fun drawSearchOutline(analysis: SearchRangeAnalysis) {
// val outlinePoints = mutableListOf<IGeoPoint>()
//
// analysis.outlineCells.forEach { coord ->
// val cellPoints =
// hexGeocell.hexToPolygonLatLng(
// coord,
// analysis.clickPosition.latitude,
// analysis.zoom,
// )
// outlinePoints.addAll(cellPoints)
// }
//
// if (outlinePoints.isNotEmpty()) {
// drawPolyline(outlinePoints)
// }
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce

typealias OnMapEventHandler = (GeoPoint) -> Unit
typealias OnCameraMoveHandler<CameraPosition> = (CameraPosition) -> Unit
typealias OnCameraMoveHandler = (MapCameraPosition) -> Unit

@OptIn(FlowPreview::class)
@Composable
Expand Down Expand Up @@ -70,7 +70,7 @@ fun <
) {
val isResourceProviderReady by ResourceProvider.initialized.collectAsState()
val initState by state.isInitialized.collectAsState()
val cameraPosition by state.mapCameraPosition.collectAsState()
val cameraPosition by state.cameraPosition.collectAsState()
val bubbles by scope.bubbleFlow.collectAsState()
val controller = controllerRef.value

Expand Down Expand Up @@ -172,7 +172,7 @@ fun <
}
}

if (controller != null && cameraPosition != null && bubbles.isNotEmpty()) {
if (controller != null && bubbles.isNotEmpty()) {
Box(
modifier =
Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface MapViewState<T> {
val id: String
val initCameraPosition: MapCameraPosition
val isInitialized: StateFlow<InitState>
val mapCameraPosition: StateFlow<MapCameraPosition?>
val cameraPosition: StateFlow<MapCameraPosition>
val mapDesignType: MapDesignType<T>

fun initAsync(init: suspend () -> Boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,21 @@ fun ArcGISMapView(
state.controller = controller
controller.holder.mapView.onCreate(owner)
controller.holder.mapView.onResume(owner)
controller.cameraMoveListener = state::OnCameraChange
controller.mapClickListener = onMapClick
controller.markerClickListener = onMarkerClick
controller.markerDragStartListener = onMarkerDragStart
controller.markerDragListener = onMarkerDrag
controller.markerDragEndListener = onMarkerDragEnd
controller.circleClickListener = onCircleClick
controller.polylineClickListener = onPolylineClick
controller.setCameraMoveListener(state::onCameraChange)
controller.setMapClickListener(onMapClick)
controller.setMarkerClickListener(onMarkerClick)
controller.setMarkerDragStartListener(onMarkerDragStart)
controller.setMarkerDragListener(onMarkerDrag)
controller.setMarkerDragEndListener(onMarkerDragEnd)
controller.setCircleClickListener(onCircleClick)
controller.setPolylineClickListener(onPolylineClick)
controller.setOnMarkerAnimationStart(onMarkerAnimateStart)
controller.setOnMarkerAnimationEnd(onMarkerAnimateEnd)

state.controller = controller

val restoreCameraPosition =
state.mapCameraPosition.value
state.cameraPosition.value
?: MapCameraPosition.from(state.initCameraPosition)
controller.moveCamera(restoreCameraPosition)

Expand Down
Loading
Loading