Working box by features
This commit is contained in:
parent
9392c0f991
commit
d3809aca8d
@ -1,8 +1,8 @@
|
||||
package centre.sciprog.maps
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import centre.sciprog.maps.compose.MapFeature
|
||||
import kotlin.math.*
|
||||
|
||||
class GmcBox(val a: GeodeticMapCoordinates, val b: GeodeticMapCoordinates)
|
||||
|
||||
@ -28,9 +28,10 @@ val GmcBox.width get() = abs(a.longitude - b.longitude)
|
||||
val GmcBox.height get() = abs(a.latitude - b.latitude)
|
||||
|
||||
/**
|
||||
* Compute a minimal bounding box including all given boxes
|
||||
* Compute a minimal bounding box including all given boxes. Return null if collection is empty
|
||||
*/
|
||||
fun Iterable<GmcBox>.wrapAll(): GmcBox {
|
||||
fun Collection<GmcBox>.wrapAll(): GmcBox? {
|
||||
if (isEmpty()) return null
|
||||
//TODO optimize computation
|
||||
val minLat = minOf { it.bottom }
|
||||
val maxLat = maxOf { it.top }
|
||||
|
@ -17,7 +17,7 @@ sealed class MapFeature(val zoomRange: IntRange) {
|
||||
abstract fun getBoundingBox(zoom: Int): GmcBox
|
||||
}
|
||||
|
||||
fun Iterable<MapFeature>.computeBoundingBox(zoom: Int): GmcBox = map { it.getBoundingBox(zoom) }.wrapAll()
|
||||
fun Iterable<MapFeature>.computeBoundingBox(zoom: Int): GmcBox? = map { it.getBoundingBox(zoom) }.wrapAll()
|
||||
|
||||
internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
|
||||
|
||||
|
@ -12,6 +12,7 @@ import kotlin.math.min
|
||||
|
||||
data class MapViewConfig(
|
||||
val zoomSpeed: Double = 1.0 / 3.0,
|
||||
val inferViewBoxFromFeatures: Boolean = false
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ -62,27 +63,4 @@ fun MapView(
|
||||
MapViewPoint(box.center, zoom)
|
||||
}
|
||||
MapView(mapTileProvider, computeViewPoint, featuresBuilder.build(), onClick, config, modifier)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MapView with initial [MapViewPoint] inferred from features
|
||||
*
|
||||
* @param defaultZoom the zoom, for which the bounding box is computed
|
||||
*/
|
||||
@Composable
|
||||
fun MapViewWithFeatures(
|
||||
mapTileProvider: MapTileProvider,
|
||||
features: Map<FeatureId, MapFeature> = emptyMap(),
|
||||
onClick: (GeodeticMapCoordinates) -> Unit = {},
|
||||
config: MapViewConfig = MapViewConfig(),
|
||||
defaultZoom: Int = 1,
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
buildFeatures: @Composable (FeatureBuilder.() -> Unit),
|
||||
) {
|
||||
val featuresBuilder = MapFeatureBuilder(features)
|
||||
featuresBuilder.buildFeatures()
|
||||
val featureSet = featuresBuilder.build()
|
||||
if(featureSet.isEmpty()) error("Can't create `MapViewWithFeatures` from empty feature set")
|
||||
val box: GmcBox = featureSet.values.map { it.getBoundingBox(defaultZoom) }.wrapAll()
|
||||
MapView(mapTileProvider, box, features, onClick, config, modifier, buildFeatures)
|
||||
}
|
@ -10,7 +10,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import centre.sciprog.maps.GeodeticMapCoordinates
|
||||
import centre.sciprog.maps.GmcBox
|
||||
import centre.sciprog.maps.MapViewPoint
|
||||
import centre.sciprog.maps.compose.*
|
||||
import io.ktor.client.HttpClient
|
||||
@ -41,7 +40,12 @@ fun App() {
|
||||
Column {
|
||||
//display click coordinates
|
||||
Text(coordinates?.toString() ?: "")
|
||||
MapViewWithFeatures(mapTileProvider, onClick = { gmc: GeodeticMapCoordinates -> coordinates = gmc }) {
|
||||
MapView(
|
||||
mapTileProvider,
|
||||
viewPoint,
|
||||
onClick = { gmc -> coordinates = gmc },
|
||||
config = MapViewConfig(inferViewBoxFromFeatures = true)
|
||||
) {
|
||||
val pointOne = 55.568548 to 37.568604
|
||||
val pointTwo = 55.929444 to 37.518434
|
||||
|
||||
|
@ -20,10 +20,7 @@ import centre.sciprog.maps.*
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.skia.Font
|
||||
import org.jetbrains.skia.Paint
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.log2
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
private fun Color.toPaint(): Paint = Paint().apply {
|
||||
@ -48,7 +45,21 @@ actual fun MapView(
|
||||
) {
|
||||
var canvasSize by remember { mutableStateOf(DpSize(512.dp, 512.dp)) }
|
||||
|
||||
var viewPointOverride by remember { mutableStateOf<MapViewPoint?>(null) }
|
||||
var viewPointOverride by remember { mutableStateOf<MapViewPoint?>(
|
||||
if(config.inferViewBoxFromFeatures){
|
||||
features.values.computeBoundingBox(1)?.let { box ->
|
||||
val zoom = log2(
|
||||
min(
|
||||
canvasSize.width.value / box.width,
|
||||
canvasSize.height.value / box.height
|
||||
) * PI / mapTileProvider.tileSize
|
||||
)
|
||||
MapViewPoint(box.center, zoom)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
) }
|
||||
|
||||
val viewPoint by derivedStateOf { viewPointOverride ?: computeViewPoint(canvasSize) }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user