Working box by features
This commit is contained in:
parent
9392c0f991
commit
d3809aca8d
@ -1,8 +1,8 @@
|
|||||||
package centre.sciprog.maps
|
package centre.sciprog.maps
|
||||||
|
|
||||||
import kotlin.math.abs
|
import androidx.compose.ui.unit.DpSize
|
||||||
import kotlin.math.max
|
import centre.sciprog.maps.compose.MapFeature
|
||||||
import kotlin.math.min
|
import kotlin.math.*
|
||||||
|
|
||||||
class GmcBox(val a: GeodeticMapCoordinates, val b: GeodeticMapCoordinates)
|
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)
|
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
|
//TODO optimize computation
|
||||||
val minLat = minOf { it.bottom }
|
val minLat = minOf { it.bottom }
|
||||||
val maxLat = maxOf { it.top }
|
val maxLat = maxOf { it.top }
|
||||||
|
@ -17,7 +17,7 @@ sealed class MapFeature(val zoomRange: IntRange) {
|
|||||||
abstract fun getBoundingBox(zoom: Int): GmcBox
|
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)
|
internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import kotlin.math.min
|
|||||||
|
|
||||||
data class MapViewConfig(
|
data class MapViewConfig(
|
||||||
val zoomSpeed: Double = 1.0 / 3.0,
|
val zoomSpeed: Double = 1.0 / 3.0,
|
||||||
|
val inferViewBoxFromFeatures: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -62,27 +63,4 @@ fun MapView(
|
|||||||
MapViewPoint(box.center, zoom)
|
MapViewPoint(box.center, zoom)
|
||||||
}
|
}
|
||||||
MapView(mapTileProvider, computeViewPoint, featuresBuilder.build(), onClick, config, modifier)
|
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.Window
|
||||||
import androidx.compose.ui.window.application
|
import androidx.compose.ui.window.application
|
||||||
import centre.sciprog.maps.GeodeticMapCoordinates
|
import centre.sciprog.maps.GeodeticMapCoordinates
|
||||||
import centre.sciprog.maps.GmcBox
|
|
||||||
import centre.sciprog.maps.MapViewPoint
|
import centre.sciprog.maps.MapViewPoint
|
||||||
import centre.sciprog.maps.compose.*
|
import centre.sciprog.maps.compose.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
@ -41,7 +40,12 @@ fun App() {
|
|||||||
Column {
|
Column {
|
||||||
//display click coordinates
|
//display click coordinates
|
||||||
Text(coordinates?.toString() ?: "")
|
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 pointOne = 55.568548 to 37.568604
|
||||||
val pointTwo = 55.929444 to 37.518434
|
val pointTwo = 55.929444 to 37.518434
|
||||||
|
|
||||||
|
@ -20,10 +20,7 @@ import centre.sciprog.maps.*
|
|||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.skia.Font
|
import org.jetbrains.skia.Font
|
||||||
import org.jetbrains.skia.Paint
|
import org.jetbrains.skia.Paint
|
||||||
import kotlin.math.ceil
|
import kotlin.math.*
|
||||||
import kotlin.math.floor
|
|
||||||
import kotlin.math.log2
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
|
|
||||||
private fun Color.toPaint(): Paint = Paint().apply {
|
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 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) }
|
val viewPoint by derivedStateOf { viewPointOverride ?: computeViewPoint(canvasSize) }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user