From 2bc595d97d7777150a3ba4318398d52a63e9a239 Mon Sep 17 00:00:00 2001 From: darksnake Date: Thu, 11 May 2023 09:39:08 +0300 Subject: [PATCH 01/14] Fix for #20 - auto-scale for single point --- demo/trajectory-playground/src/jvmMain/kotlin/Main.kt | 10 ++++++++++ .../kotlin/center/sciprog/maps/compose/MapViewScope.kt | 2 +- .../kotlin/center/sciprog/maps/scheme/XYViewScope.kt | 9 ++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/demo/trajectory-playground/src/jvmMain/kotlin/Main.kt b/demo/trajectory-playground/src/jvmMain/kotlin/Main.kt index 41550cf..fde1f7e 100644 --- a/demo/trajectory-playground/src/jvmMain/kotlin/Main.kt +++ b/demo/trajectory-playground/src/jvmMain/kotlin/Main.kt @@ -157,6 +157,14 @@ fun doubleObstacle() { } } +@Composable +@Preview +fun singleElement() { + SchemeView { + points(listOf(XY(1f,1f))) + } +} + @Composable @Preview @@ -165,6 +173,7 @@ fun playground() { "Close starting points", "Single obstacle", "Two obstacles", + "Single element" ) var currentExample by remember { mutableStateOf(examples.first()) } @@ -182,6 +191,7 @@ fun playground() { examples[0] -> closePoints() examples[1] -> singleObstacle() examples[2] -> doubleObstacle() + examples[3] -> singleElement() } } } diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapViewScope.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapViewScope.kt index 38783d6..afdd0fa 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapViewScope.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapViewScope.kt @@ -63,7 +63,7 @@ public class MapViewScope internal constructor( canvasSize.width.value / rectangle.longitudeDelta.radians, canvasSize.height.value / rectangle.latitudeDelta.radians ) * 2 * PI / mapTileProvider.tileSize - ) + ).coerceIn(0.0..22.0) return space.ViewPoint(rectangle.center, zoom.toFloat()) } diff --git a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt index 550a66a..48a2673 100644 --- a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt +++ b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt @@ -26,12 +26,15 @@ public class XYViewScope( ) override fun computeViewPoint(rectangle: Rectangle): ViewPoint { - val scale = min( + val scale: Float = min( canvasSize.width.value / rectangle.width, canvasSize.height.value / rectangle.height ) - - return XYViewPoint(rectangle.center, scale) + return if(scale.isInfinite()){ + XYViewPoint(rectangle.center, 1f) + } else { + XYViewPoint(rectangle.center, scale) + } } override fun ViewPoint.moveBy(x: Dp, y: Dp): ViewPoint { From 1caf141d27181bc60945953fbe1db1efa10395a0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 26 May 2023 15:49:14 +0300 Subject: [PATCH 02/14] Fix for #22 (default hairline size for points) --- .space.kts | 10 +++++----- build.gradle.kts | 4 ++-- demo/maps/src/jvmMain/kotlin/Main.kt | 17 ++++++++++++++--- .../maps/features/mapFeatureAttributes.kt | 3 +++ .../center/sciprog/maps/features/drawFeature.kt | 7 +++++-- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/.space.kts b/.space.kts index bd47550..c5dd962 100644 --- a/.space.kts +++ b/.space.kts @@ -9,17 +9,17 @@ job("Publish") { gitPush { enabled = false } } container("spc.registry.jetbrains.space/p/sci/containers/kotlin-ci:1.0.3") { - env["SPACE_USER"] = Secrets("space_user") - env["SPACE_TOKEN"] = Secrets("space_token") + env["SPACE_USER"] = "{{ project:space_user }}" + env["SPACE_TOKEN"] = "{{ project:space_token }}" kotlinScript { api -> val spaceUser = System.getenv("SPACE_USER") val spaceToken = System.getenv("SPACE_TOKEN") - // write version to the build directory + // write the version to the build directory api.gradlew("version") - //read version from build file + //read the version from build file val version = java.nio.file.Path.of("build/project-version.txt").readText() val revisionSuffix = if (version.endsWith("SNAPSHOT")) { @@ -32,7 +32,7 @@ job("Publish") { project = api.projectIdentifier(), targetIdentifier = TargetIdentifier.Key("maps-kt"), version = version+revisionSuffix, - // automatically update deployment status based on a status of a job + // automatically update deployment status based on the status of a job syncWithAutomationJob = true ) api.gradlew( diff --git a/build.gradle.kts b/build.gradle.kts index 2ee9a4d..6507ca2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,11 +6,11 @@ plugins { id("space.kscience.gradle.project") } -val kmathVersion: String by extra("0.3.1-dev-RC") +val kmathVersion: String by extra("0.3.1") allprojects { group = "center.sciprog" - version = "0.2.2" + version = "0.2.3-dev-1" repositories { mavenLocal() diff --git a/demo/maps/src/jvmMain/kotlin/Main.kt b/demo/maps/src/jvmMain/kotlin/Main.kt index 235bcac..14d5a67 100644 --- a/demo/maps/src/jvmMain/kotlin/Main.kt +++ b/demo/maps/src/jvmMain/kotlin/Main.kt @@ -55,7 +55,6 @@ fun App() { val centerCoordinates = MutableStateFlow(null) - val pointOne = 55.568548 to 37.568604 val pointTwo = 55.929444 to 37.518434 // val pointThree = 60.929444 to 37.518434 @@ -90,6 +89,7 @@ fun App() { println("line 3 clicked") } + multiLine( points = listOf( 55.742465 to 37.615812, @@ -101,6 +101,15 @@ fun App() { ), ) + points( + points = listOf( + 55.744 to 38.614, + 55.8 to 38.5, + 56.0 to 38.5, + ) + ).pointSize(5f) + + //remember feature ID val circleId = circle( centerCoordinates = pointTwo, @@ -120,9 +129,11 @@ fun App() { arc(pointOne, 10.0.kilometers, (PI / 4).radians, -Angle.pi / 2) + line(pointOne, pointTwo, id = "line") text(pointOne, "Home", font = { size = 32f }) + pixelMap( space.Rectangle( Gmc(latitude = 55.58461879539754.degrees, longitude = 37.8746197303493.degrees), @@ -132,8 +143,8 @@ fun App() { 0.005.degrees ) { gmc -> Color( - red = ((gmc.latitude + Angle.piDiv2).degrees*10 % 1f).toFloat(), - green = ((gmc.longitude + Angle.pi).degrees*10 % 1f).toFloat(), + red = ((gmc.latitude + Angle.piDiv2).degrees * 10 % 1f).toFloat(), + green = ((gmc.longitude + Angle.pi).degrees * 10 % 1f).toFloat(), blue = 0f ).copy(alpha = 0.3f) } diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt index 9b85e82..a824a50 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt @@ -169,4 +169,7 @@ public fun FeatureRef>.pathEffect(effect: Pat public object StrokeAttribute : Attribute public fun > FeatureRef.stroke(width: Float): FeatureRef = + modifyAttribute(StrokeAttribute, width) + +public fun > FeatureRef.pointSize(width: Float): FeatureRef = modifyAttribute(StrokeAttribute, width) \ No newline at end of file diff --git a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt b/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt index 8948f79..f9c9d73 100644 --- a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt +++ b/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt @@ -3,7 +3,10 @@ package center.sciprog.maps.features import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.* -import androidx.compose.ui.graphics.drawscope.* +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.graphics.painter.Painter import center.sciprog.attributes.plus import org.jetbrains.skia.Font @@ -121,7 +124,7 @@ public fun DrawScope.drawFeature( drawPoints( points = points, color = color, - strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth, + strokeWidth = feature.attributes[StrokeAttribute] ?: 5f, pointMode = PointMode.Points, pathEffect = feature.attributes[PathEffectAttribute], alpha = alpha From 75b5a69a27993e7ee4f8522c706612c83e0c9c31 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 10 Sep 2023 13:12:45 +0300 Subject: [PATCH 03/14] Full refactor of map state --- build.gradle.kts | 2 +- demo/maps/build.gradle.kts | 2 +- demo/maps/src/jvmMain/kotlin/Main.kt | 10 +- .../polygon-editor/src/jvmMain/kotlin/Main.kt | 4 +- demo/scheme/build.gradle.kts | 1 + demo/scheme/src/jvmMain/kotlin/Main.kt | 2 +- demo/scheme/src/jvmMain/kotlin/joker2023.kt | 76 +++++ .../scheme/src/jvmMain/resources/SPC-logo.png | Bin 0 -> 5166 bytes gradle.properties | 8 +- maps-kt-compose/build.gradle.kts | 1 - .../{MapViewScope.kt => MapCanvasState.kt} | 15 +- .../center/sciprog/maps/compose/MapView.kt | 147 +++++++--- .../sciprog/maps/compose/mapFeatures.kt | 39 ++- .../maps/compose/OpenStreetMapTileProvider.kt | 11 +- .../center/sciprog/maps/compose/mapViewJvm.kt | 146 ---------- .../sciprog/maps/coordinates/GeoEllipsoid.kt | 64 +++-- .../sciprog/maps/coordinates/GmcCurve.kt | 6 +- maps-kt-features/build.gradle.kts | 1 + .../center.sciprog.attributes/Attributes.kt | 6 - ...{CoordinateViewScope.kt => CanvasState.kt} | 50 ++-- .../sciprog/maps/features/FeatureDrawScope.kt | 108 +++++++ .../sciprog/maps/features/FeatureGroup.kt | 112 +++++--- .../sciprog/maps/features/drawFeature.kt | 49 ++-- .../maps/features/mapFeatureAttributes.kt | 9 +- .../{mapControls.kt => canvasControls.kt} | 32 +-- .../center/sciprog/maps/scheme/SchemeView.kt | 52 +--- .../kotlin/center/sciprog/maps/scheme/XY.kt | 2 + .../{XYViewScope.kt => XYCanvasState.kt} | 12 +- .../sciprog/maps/scheme/schemeFeatures.kt | 33 ++- .../center/sciprog/maps/svg/SvgDrawScope.kt | 33 ++- .../center/sciprog/maps/svg/exportToSvg.kt | 269 +++++++++--------- settings.gradle.kts | 4 +- trajectory-kt/build.gradle.kts | 2 +- 33 files changed, 738 insertions(+), 570 deletions(-) create mode 100644 demo/scheme/src/jvmMain/kotlin/joker2023.kt create mode 100644 demo/scheme/src/jvmMain/resources/SPC-logo.png rename maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/{MapViewScope.kt => MapCanvasState.kt} (91%) delete mode 100644 maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/mapViewJvm.kt rename maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/{CoordinateViewScope.kt => CanvasState.kt} (65%) create mode 100644 maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt rename maps-kt-features/src/{jvmMain => commonMain}/kotlin/center/sciprog/maps/features/drawFeature.kt (80%) rename maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/{mapControls.kt => canvasControls.kt} (86%) rename maps-kt-scheme/src/{jvmMain => commonMain}/kotlin/center/sciprog/maps/scheme/SchemeView.kt (60%) rename maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/{XYViewScope.kt => XYCanvasState.kt} (87%) diff --git a/build.gradle.kts b/build.gradle.kts index 6507ca2..a461ddb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ val kmathVersion: String by extra("0.3.1") allprojects { group = "center.sciprog" - version = "0.2.3-dev-1" + version = "0.3.0-dev-1" repositories { mavenLocal() diff --git a/demo/maps/build.gradle.kts b/demo/maps/build.gradle.kts index c9a83f8..443f3f5 100644 --- a/demo/maps/build.gradle.kts +++ b/demo/maps/build.gradle.kts @@ -17,7 +17,7 @@ kotlin { implementation(projects.mapsKtGeojson) implementation(compose.desktop.currentOs) implementation("io.ktor:ktor-client-cio") - implementation("ch.qos.logback:logback-classic:1.2.11") + implementation(spclibs.logback.classic) } } val jvmTest by getting diff --git a/demo/maps/src/jvmMain/kotlin/Main.kt b/demo/maps/src/jvmMain/kotlin/Main.kt index 14d5a67..f7986a6 100644 --- a/demo/maps/src/jvmMain/kotlin/Main.kt +++ b/demo/maps/src/jvmMain/kotlin/Main.kt @@ -15,7 +15,9 @@ import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import center.sciprog.attributes.Attributes import center.sciprog.maps.compose.* -import center.sciprog.maps.coordinates.* +import center.sciprog.maps.coordinates.GeodeticMapCoordinates +import center.sciprog.maps.coordinates.Gmc +import center.sciprog.maps.coordinates.kilometers import center.sciprog.maps.features.* import center.sciprog.maps.geojson.geoJson import io.ktor.client.HttpClient @@ -109,8 +111,11 @@ fun App() { ) ).pointSize(5f) +// geodeticLine(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)).color(Color.Blue) +// line(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)) - //remember feature ID + + //remember feature ref val circleId = circle( centerCoordinates = pointTwo, ) @@ -170,6 +175,7 @@ fun App() { } } } +// println(toPrettyString()) } } } diff --git a/demo/polygon-editor/src/jvmMain/kotlin/Main.kt b/demo/polygon-editor/src/jvmMain/kotlin/Main.kt index c6746aa..2e0a346 100644 --- a/demo/polygon-editor/src/jvmMain/kotlin/Main.kt +++ b/demo/polygon-editor/src/jvmMain/kotlin/Main.kt @@ -13,7 +13,7 @@ import center.sciprog.maps.features.* import center.sciprog.maps.scheme.SchemeView import center.sciprog.maps.scheme.XY import center.sciprog.maps.scheme.XYCoordinateSpace -import center.sciprog.maps.scheme.XYViewScope +import center.sciprog.maps.scheme.XYCanvasState @Composable @Preview @@ -31,7 +31,7 @@ fun App() { ) } - val mapState: XYViewScope = XYViewScope.remember( + val mapState: XYCanvasState = XYCanvasState.remember( config = ViewConfig( onClick = { event, point -> if (event.buttons.isSecondaryPressed) { diff --git a/demo/scheme/build.gradle.kts b/demo/scheme/build.gradle.kts index 845f9bd..e1f558d 100644 --- a/demo/scheme/build.gradle.kts +++ b/demo/scheme/build.gradle.kts @@ -26,6 +26,7 @@ compose{ desktop { application { mainClass = "MainKt" + //mainClass = "Joker2023Kt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "scheme-compose-demo" diff --git a/demo/scheme/src/jvmMain/kotlin/Main.kt b/demo/scheme/src/jvmMain/kotlin/Main.kt index 991d6e5..9aeefae 100644 --- a/demo/scheme/src/jvmMain/kotlin/Main.kt +++ b/demo/scheme/src/jvmMain/kotlin/Main.kt @@ -78,7 +78,7 @@ fun App() { ) } ) { - val mapState: XYViewScope = XYViewScope.remember( + val mapState: XYCanvasState = XYCanvasState.remember( ViewConfig( onClick = { _, click -> println("${click.focus.x}, ${click.focus.y}") diff --git a/demo/scheme/src/jvmMain/kotlin/joker2023.kt b/demo/scheme/src/jvmMain/kotlin/joker2023.kt new file mode 100644 index 0000000..7e09487 --- /dev/null +++ b/demo/scheme/src/jvmMain/kotlin/joker2023.kt @@ -0,0 +1,76 @@ +import androidx.compose.material.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Face +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import center.sciprog.maps.features.* +import center.sciprog.maps.scheme.* +import center.sciprog.maps.scheme.XYCoordinateSpace.Rectangle + + +fun main() = application { + Window(onCloseRequest = ::exitApplication, title = "Joker2023 demo", icon = painterResource("SPC-logo.png")) { + MaterialTheme { + + SchemeView( + initialRectangle = Rectangle(XY(0f, 0f), XY(1734f, 724f)), + config = ViewConfig( + onClick = { _, pointer -> + println("(${pointer.focus.x}, ${pointer.focus.y})") + } + ) + ) { + background(1734f, 724f, id = "background") { painterResource("joker2023.png") } + group(id = "hall_1") { + polygon( + listOf( + XY(1582.0042, 210.29636), + XY(1433.7021, 127.79796), + XY(1370.7639, 127.79796), + XY(1315.293, 222.73865), + XY(1314.2262, 476.625), + XY(1364.3635, 570.4984), + XY(1434.7689, 570.4984), + XY(1579.8469, 493.69244), + ) + ).modifyAttributes { + ColorAttribute(Color.Blue) + AlphaAttribute(0.4f) + }.onClick { + println("hall_1") + } + } + + group(id = "hall_2") { + rectanglePolygon( + left = 893, right = 1103, + bottom = 223, top = 406, + ).modifyAttributes { + ColorAttribute(Color.Blue) + AlphaAttribute(0.4f) + } + } + + group(id = "hall_3") { + rectanglePolygon( + Rectangle(XY(460f, 374f), width = 140f, height = 122f), + ).modifyAttributes { + ColorAttribute(Color.Blue) + AlphaAttribute(0.4f) + } + } + + group(id = "people") { + icon(XY(815.60535, 342.71313), Icons.Default.Face).color(Color.Red) + icon(XY(743.751, 381.09064), Icons.Default.Face).color(Color.Red) + icon(XY(1349.6648, 417.36014), Icons.Default.Face).color(Color.Red) + icon(XY (1362.4658, 287.21667), Icons.Default.Face).color(Color.Red) + icon(XY(208.24274, 317.08566), Icons.Default.Face).color(Color.Red) + icon(XY (293.5827, 319.21915), Icons.Default.Face).color(Color.Red) + } + } + } + } +} diff --git a/demo/scheme/src/jvmMain/resources/SPC-logo.png b/demo/scheme/src/jvmMain/resources/SPC-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..953de16d4876765010935ffc20cbd1d37351dbb6 GIT binary patch literal 5166 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 dG+}ahdgIi>+tx>p41sTb1Y0Y6EEhcx^&il, -) : CoordinateViewScope(config) { +) : CanvasState(config) { override val space: CoordinateSpace get() = WebMercatorSpace private val scaleFactor: Float @@ -87,14 +88,14 @@ public class MapViewScope internal constructor( config: ViewConfig = ViewConfig(), initialViewPoint: ViewPoint? = null, initialRectangle: Rectangle? = null, - ): MapViewScope = remember { - MapViewScope(mapTileProvider, config).also { mapState -> + ): MapCanvasState = remember { + MapCanvasState(mapTileProvider, config).apply { if (initialViewPoint != null) { - mapState.viewPoint = initialViewPoint + viewPoint = initialViewPoint } else if (initialRectangle != null) { - mapState.viewPoint = mapState.computeViewPoint(initialRectangle) + viewPoint = computeViewPoint(initialRectangle) } } } } -} \ No newline at end of file +} diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt index 08b64b7..0a6c18b 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt @@ -2,44 +2,137 @@ package center.sciprog.maps.compose import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateMapOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathEffect +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.graphics.toComposeImageBitmap +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp import center.sciprog.maps.coordinates.Gmc import center.sciprog.maps.features.* +import io.github.oshai.kotlinlogging.KotlinLogging +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope +import org.jetbrains.skia.Image +import kotlin.math.ceil +import kotlin.math.pow -@Composable -public expect fun MapView( - viewScope: MapViewScope, - features: FeatureGroup, - modifier: Modifier = Modifier.fillMaxSize(), -) +private fun IntRange.intersect(other: IntRange) = kotlin.math.max(first, other.first)..kotlin.math.min(last, other.last) + +private val logger = KotlinLogging.logger("MapView") /** - * A builder for a Map with static features. + * A component that renders map and provides basic map manipulation capabilities + */ +@Composable +public fun MapView( + mapState: MapCanvasState, + mapTileProvider: MapTileProvider, + features: FeatureGroup, + modifier: Modifier, +) { + val mapTiles = remember(mapTileProvider) { + mutableStateMapOf() + } + + with(mapState) { + + // Load tiles asynchronously + LaunchedEffect(viewPoint, canvasSize) { + with(mapTileProvider) { + val indexRange = 0 until 2.0.pow(intZoom).toInt() + + val left = centerCoordinates.x - canvasSize.width.value / 2 / tileScale + val right = centerCoordinates.x + canvasSize.width.value / 2 / tileScale + val horizontalIndices: IntRange = (toIndex(left)..toIndex(right)).intersect(indexRange) + + val top = (centerCoordinates.y + canvasSize.height.value / 2 / tileScale) + val bottom = (centerCoordinates.y - canvasSize.height.value / 2 / tileScale) + val verticalIndices: IntRange = (toIndex(bottom)..toIndex(top)).intersect(indexRange) + + for (j in verticalIndices) { + for (i in horizontalIndices) { + val id = TileId(intZoom, i, j) + //ensure that failed tiles do not fail the application + supervisorScope { + //start all + val deferred = loadTileAsync(id) + //wait asynchronously for it to finish + launch { + try { + val tile = deferred.await() + mapTiles[tile.id] = tile.image + } catch (ex: Exception) { + //displaying the error is maps responsibility + if(ex !is CancellationException) { + logger.error(ex) { "Failed to load tile with id=$id" } + } + } + } + } + mapTiles.keys.filter { + it.zoom != intZoom || it.j !in verticalIndices || it.i !in horizontalIndices + }.forEach { + mapTiles.remove(it) + } + } + } + } + } + } + + + FeatureCanvas(mapState, features, modifier = modifier.canvasControls(mapState, features)) { + val tileScale = mapState.tileScale + + clipRect { + val tileSize = IntSize( + ceil((mapTileProvider.tileSize.dp * tileScale).toPx()).toInt(), + ceil((mapTileProvider.tileSize.dp * tileScale).toPx()).toInt() + ) + mapTiles.forEach { (id, image) -> + //converting back from tile index to screen offset + val offset = IntOffset( + (mapState.canvasSize.width / 2 + (mapTileProvider.toCoordinate(id.i).dp - mapState.centerCoordinates.x.dp) * tileScale).roundToPx(), + (mapState.canvasSize.height / 2 + (mapTileProvider.toCoordinate(id.j).dp - mapState.centerCoordinates.y.dp) * tileScale).roundToPx() + ) + drawImage( + image = image.toComposeImageBitmap(), + dstOffset = offset, + dstSize = tileSize + ) + } + } + } +} + +/** + * Create a [MapView] with given [features] group. */ @Composable public fun MapView( mapTileProvider: MapTileProvider, + config: ViewConfig, features: FeatureGroup, initialViewPoint: ViewPoint? = null, initialRectangle: Rectangle? = null, - config: ViewConfig = ViewConfig(), - modifier: Modifier = Modifier.fillMaxSize(), + modifier: Modifier, ) { - - val mapState: MapViewScope = MapViewScope.remember( - mapTileProvider, - config, - initialViewPoint = initialViewPoint, - initialRectangle = initialRectangle ?: features.getBoundingBox(Float.MAX_VALUE), - ) - - MapView(mapState, features, modifier) + val mapState = MapCanvasState.remember(mapTileProvider, config, initialViewPoint, initialRectangle) + MapView(mapState, mapTileProvider, features, modifier) } /** * Draw a map using convenient parameters. If neither [initialViewPoint], noe [initialRectangle] is defined, - * use map features to infer view region. + * use map features to infer the view region. * @param initialViewPoint The view point of the map using center and zoom. Is used if provided * @param initialRectangle The rectangle to be used for view point computation. Used if [initialViewPoint] is not defined. * @param buildFeatures - a builder for features @@ -47,24 +140,12 @@ public fun MapView( @Composable public fun MapView( mapTileProvider: MapTileProvider, + config: ViewConfig = ViewConfig(), initialViewPoint: ViewPoint? = null, initialRectangle: Rectangle? = null, - config: ViewConfig = ViewConfig(), modifier: Modifier = Modifier.fillMaxSize(), buildFeatures: FeatureGroup.() -> Unit = {}, ) { - val featureState = FeatureGroup.remember(WebMercatorSpace, buildFeatures) - - val mapState: MapViewScope = MapViewScope.remember( - mapTileProvider, - config, - initialViewPoint = initialViewPoint, - initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox( - WebMercatorSpace, - Float.MAX_VALUE - ), - ) - - MapView(mapState, featureState, modifier) + MapView(mapTileProvider, config, featureState, initialViewPoint, initialRectangle, modifier) } \ No newline at end of file diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/mapFeatures.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/mapFeatures.kt index fa17d6c..29fb11a 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/mapFeatures.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/mapFeatures.kt @@ -6,10 +6,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import center.sciprog.maps.coordinates.Distance -import center.sciprog.maps.coordinates.GeodeticMapCoordinates -import center.sciprog.maps.coordinates.Gmc -import center.sciprog.maps.coordinates.GmcCurve +import center.sciprog.maps.coordinates.* import center.sciprog.maps.features.* import space.kscience.kmath.geometry.Angle import kotlin.math.ceil @@ -55,6 +52,39 @@ public fun FeatureGroup.line( LineFeature(space, curve.forward.coordinates, curve.backward.coordinates) ) +/** + * A segmented geodetic curve + */ +public fun FeatureGroup.geodeticLine( + curve: GmcCurve, + ellipsoid: GeoEllipsoid = GeoEllipsoid.WGS84, + maxLineDistance: Distance = 100.kilometers, + id: String? = null, +): FeatureRef> = if (curve.distance < maxLineDistance) { + feature( + id, + LineFeature(space, curve.forward.coordinates, curve.backward.coordinates) + ) +} else { + val segments = ceil(curve.distance / maxLineDistance).toInt() + val segmentSize = curve.distance / segments + val points = buildList { + add(curve.forward) + repeat(segments) { + val segment = ellipsoid.curveInDirection(this.last(), segmentSize, 1e-2) + add(segment.backward) + } + } + multiLine(points.map { it.coordinates }, id = id) +} + +public fun FeatureGroup.geodeticLine( + from: Gmc, + to: Gmc, + ellipsoid: GeoEllipsoid = GeoEllipsoid.WGS84, + maxLineDistance: Distance = 100.kilometers, + id: String? = null, +): FeatureRef> = geodeticLine(ellipsoid.curveBetween(from, to), ellipsoid, maxLineDistance, id) public fun FeatureGroup.line( aCoordinates: Pair, @@ -65,7 +95,6 @@ public fun FeatureGroup.line( LineFeature(space, coordinatesOf(aCoordinates), coordinatesOf(bCoordinates)) ) - public fun FeatureGroup.arc( center: Pair, radius: Distance, diff --git a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/OpenStreetMapTileProvider.kt b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/OpenStreetMapTileProvider.kt index 10581d2..322b07b 100644 --- a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/OpenStreetMapTileProvider.kt +++ b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/OpenStreetMapTileProvider.kt @@ -1,15 +1,12 @@ package center.sciprog.maps.compose +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.HttpClient import io.ktor.client.request.get import io.ktor.client.statement.readBytes -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async +import kotlinx.coroutines.* import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit -import mu.KotlinLogging import org.jetbrains.skia.Image import java.net.URL import java.nio.file.Path @@ -76,7 +73,9 @@ public class OpenStreetMapTileProvider( //collect the result asynchronously return async { val image: Image = runCatching { imageDeferred.await() }.onFailure { - logger.error(it) { "Failed to load tile image with id=$tileId" } + if(it !is CancellationException) { + logger.error(it) { "Failed to load tile image with id=$tileId" } + } cache.remove(tileId) }.getOrThrow() diff --git a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/mapViewJvm.kt b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/mapViewJvm.kt deleted file mode 100644 index 82dda16..0000000 --- a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/mapViewJvm.kt +++ /dev/null @@ -1,146 +0,0 @@ -package center.sciprog.maps.compose - -import androidx.compose.foundation.Canvas -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathEffect -import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.graphics.toComposeImageBitmap -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import center.sciprog.attributes.z -import center.sciprog.maps.coordinates.Gmc -import center.sciprog.maps.features.FeatureGroup -import center.sciprog.maps.features.PainterFeature -import center.sciprog.maps.features.drawFeature -import center.sciprog.maps.features.zoomRange -import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope -import mu.KotlinLogging -import org.jetbrains.skia.Image -import org.jetbrains.skia.Paint -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min -import kotlin.math.pow - - -private fun Color.toPaint(): Paint = Paint().apply { - isAntiAlias = true - color = toArgb() -} - -private fun IntRange.intersect(other: IntRange) = max(first, other.first)..min(last, other.last) - -private val logger = KotlinLogging.logger("MapView") - -/** - * A component that renders map and provides basic map manipulation capabilities - */ -@Composable -public actual fun MapView( - viewScope: MapViewScope, - features: FeatureGroup, - modifier: Modifier, -): Unit = with(viewScope) { - val mapTiles = remember(mapTileProvider) { mutableStateMapOf() } - - // Load tiles asynchronously - LaunchedEffect(viewPoint, canvasSize) { - with(mapTileProvider) { - val indexRange = 0 until 2.0.pow(intZoom).toInt() - - val left = centerCoordinates.x - canvasSize.width.value / 2 / tileScale - val right = centerCoordinates.x + canvasSize.width.value / 2 / tileScale - val horizontalIndices: IntRange = (toIndex(left)..toIndex(right)).intersect(indexRange) - - val top = (centerCoordinates.y + canvasSize.height.value / 2 / tileScale) - val bottom = (centerCoordinates.y - canvasSize.height.value / 2 / tileScale) - val verticalIndices: IntRange = (toIndex(bottom)..toIndex(top)).intersect(indexRange) - - for (j in verticalIndices) { - for (i in horizontalIndices) { - val id = TileId(intZoom, i, j) - //ensure that failed tiles do not fail the application - supervisorScope { - //start all - val deferred = loadTileAsync(id) - //wait asynchronously for it to finish - launch { - try { - val tile = deferred.await() - mapTiles[tile.id] = tile.image - } catch (ex: Exception) { - //displaying the error is maps responsibility - logger.error(ex) { "Failed to load tile with id=$id" } - } - } - } - mapTiles.keys.filter { - it.zoom != intZoom || it.j !in verticalIndices || it.i !in horizontalIndices - }.forEach { - mapTiles.remove(it) - } - } - } - } - } - key(viewScope, features) { - val painterCache: Map, Painter> = - features.features.filterIsInstance>().associateWith { it.getPainter() } - - Canvas(modifier = modifier.mapControls(viewScope, features)) { - - if (canvasSize != size.toDpSize()) { - logger.debug { "Recalculate canvas. Size: $size" } - config.onCanvasSizeChange(canvasSize) - canvasSize = size.toDpSize() - } - - clipRect { - val tileSize = IntSize( - ceil((mapTileProvider.tileSize.dp * tileScale).toPx()).toInt(), - ceil((mapTileProvider.tileSize.dp * tileScale).toPx()).toInt() - ) - mapTiles.forEach { (id, image) -> - //converting back from tile index to screen offset - val offset = IntOffset( - (canvasSize.width / 2 + (mapTileProvider.toCoordinate(id.i).dp - centerCoordinates.x.dp) * tileScale).roundToPx(), - (canvasSize.height / 2 + (mapTileProvider.toCoordinate(id.j).dp - centerCoordinates.y.dp) * tileScale).roundToPx() - ) - drawImage( - image = image.toComposeImageBitmap(), - dstOffset = offset, - dstSize = tileSize - ) - } - - features.featureMap.values.sortedBy { it.z } - .filter { viewPoint.zoom in it.zoomRange } - .forEach { feature -> - drawFeature(viewScope, painterCache, feature) - } - } - - selectRect?.let { dpRect -> - val rect = dpRect.toRect() - drawRect( - color = Color.Blue, - topLeft = rect.topLeft, - size = rect.size, - alpha = 0.5f, - style = Stroke( - width = 2f, - pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) - ) - ) - } - } - } -} - diff --git a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GeoEllipsoid.kt b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GeoEllipsoid.kt index 607aeca..b3706f0 100644 --- a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GeoEllipsoid.kt +++ b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GeoEllipsoid.kt @@ -1,10 +1,8 @@ package center.sciprog.maps.coordinates import kotlinx.serialization.Serializable -import space.kscience.kmath.geometry.Angle -import space.kscience.kmath.geometry.tan -import kotlin.math.pow -import kotlin.math.sqrt +import space.kscience.kmath.geometry.* +import kotlin.math.* @Serializable public class GeoEllipsoid(public val equatorRadius: Distance, public val polarRadius: Distance) { @@ -43,12 +41,7 @@ public class GeoEllipsoid(public val equatorRadius: Distance, public val polarRa polarRadius = Distance(6378.137) ) -// /** -// * https://en.wikipedia.org/wiki/Great-circle_distance -// */ -// public fun greatCircleAngleBetween(r1: GMC, r2: GMC): Radians = acos( -// sin(r1.latitude) * sin(r2.latitude) + cos(r1.latitude) * cos(r2.latitude) * cos(r1.longitude - r2.longitude) -// ).radians + } } @@ -59,22 +52,35 @@ public fun GeoEllipsoid.reducedRadius(latitude: Angle): Distance { val reducedLatitudeTan = (1 - f) * tan(latitude) return equatorRadius / sqrt(1.0 + reducedLatitudeTan.pow(2)) } -// -// -///** -// * Compute distance between two map points using giv -// * https://en.wikipedia.org/wiki/Geographical_distance#Lambert's_formula_for_long_lines -// */ -//public fun GeoEllipsoid.lambertDistanceBetween(r1: GMC, r2: GMC): Distance { -// val s = greatCircleAngleBetween(r1, r2) -// -// val b1: Double = (1 - f) * tan(r1.latitude) -// val b2: Double = (1 - f) * tan(r2.latitude) -// val p = (b1 + b2) / 2 -// val q = (b2 - b1) / 2 -// -// val x = (s.value - sin(s)) * sin(p).pow(2) * cos(q).pow(2) / cos(s / 2).pow(2) -// val y = (s.value + sin(s)) * cos(p).pow(2) * sin(q).pow(2) / sin(s / 2).pow(2) -// -// return equatorRadius * (s.value - f / 2 * (x + y)) -//} \ No newline at end of file + + +/** + * Compute distance between two map points using giv + * https://en.wikipedia.org/wiki/Geographical_distance#Lambert's_formula_for_long_lines + */ +public fun GeoEllipsoid.lambertDistanceBetween(r1: Gmc, r2: Gmc): Distance { + + /** + * https://en.wikipedia.org/wiki/Great-circle_distance + */ + fun greatCircleAngleBetween( + r1: Gmc, + r2: Gmc, + ): Radians = acos( + sin(r1.latitude) * sin(r2.latitude) + + cos(r1.latitude) * cos(r2.latitude) * + cos(r1.longitude - r2.longitude) + ).radians + + val s = greatCircleAngleBetween(r1, r2) + + val b1: Double = (1 - f) * tan(r1.latitude) + val b2: Double = (1 - f) * tan(r2.latitude) + val p = (b1 + b2) / 2 + val q = (b2 - b1) / 2 + + val x = (s.value - sin(s)) * sin(p).pow(2) * cos(q).pow(2) / cos(s / 2).pow(2) + val y = (s.value + sin(s)) * cos(p).pow(2) * sin(q).pow(2) / sin(s / 2).pow(2) + + return equatorRadius * (s.value - f / 2 * (x + y)) +} \ No newline at end of file diff --git a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GmcCurve.kt b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GmcCurve.kt index a99c159..3587156 100644 --- a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GmcCurve.kt +++ b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/GmcCurve.kt @@ -5,10 +5,10 @@ import kotlin.math.* /** * A directed straight (geodetic) segment on a spheroid with given start, direction, end point and distance. - * @param forward coordinate of a start point with forward direction - * @param backward coordinate of an end point with backward direction + * @param forward coordinate of a start point with the forward direction + * @param backward coordinate of an end point with the backward direction */ -public class GmcCurve( +public class GmcCurve internal constructor( public val forward: GmcPose, public val backward: GmcPose, public val distance: Distance, diff --git a/maps-kt-features/build.gradle.kts b/maps-kt-features/build.gradle.kts index d761986..e718828 100644 --- a/maps-kt-features/build.gradle.kts +++ b/maps-kt-features/build.gradle.kts @@ -24,6 +24,7 @@ kotlin { dependencies { api(projects.trajectoryKt) api(compose.foundation) + api("io.github.oshai:kotlin-logging:5.1.0") } } } diff --git a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt index 68fb15a..128eab8 100644 --- a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt +++ b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt @@ -66,9 +66,3 @@ public fun > Attributes( ): Attributes = Attributes(mapOf(attribute to attrValue)) public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(content + other.content) - -public val Feature<*>.z: Float - get() = attributes[ZAttribute] ?: 0f -// set(value) { -// attributes[ZAttribute] = value -// } \ No newline at end of file diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CoordinateViewScope.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt similarity index 65% rename from maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CoordinateViewScope.kt rename to maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt index 03631ec..7309bbb 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CoordinateViewScope.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt @@ -1,16 +1,15 @@ package center.sciprog.maps.features -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.* -public abstract class CoordinateViewScope( - public val config: ViewConfig, -) { - +/** + * A state holder for current canvas size and view point. Allows transformation from coordinates to pixels and back + */ +public abstract class CanvasState( + public val viewConfig: ViewConfig +){ public abstract val space: CoordinateSpace private var canvasSizeState: MutableState = mutableStateOf(null) @@ -20,13 +19,14 @@ public abstract class CoordinateViewScope( get() = canvasSizeState.value ?: DpSize(512.dp, 512.dp) set(value) { canvasSizeState.value = value + viewConfig.onCanvasSizeChange(value) } public var viewPoint: ViewPoint get() = viewPointState.value ?: space.defaultViewPoint set(value) { viewPointState.value = value - config.onViewChange(viewPoint) + viewConfig.onViewChange(viewPoint) } public val zoom: Float get() = viewPoint.zoom @@ -35,28 +35,28 @@ public abstract class CoordinateViewScope( // Selection rectangle. If null - no selection public var selectRect: DpRect? by mutableStateOf(null) - public abstract fun DpOffset.toCoordinates(): T - - - public abstract fun T.toDpOffset(): DpOffset - - public fun T.toOffset(density: Density): Offset = with(density) { - val dpOffset = this@toOffset.toDpOffset() - Offset(dpOffset.x.toPx(), dpOffset.y.toPx()) - } - - public fun Offset.toCoordinates(density: Density): T = with(density) { - val dpOffset = DpOffset(x.toDp(), y.toDp()) - dpOffset.toCoordinates() - } - public abstract fun Rectangle.toDpRect(): DpRect public abstract fun ViewPoint.moveBy(x: Dp, y: Dp): ViewPoint public abstract fun computeViewPoint(rectangle: Rectangle): ViewPoint -} + public abstract fun DpOffset.toCoordinates(): T + + + public abstract fun T.toDpOffset(): DpOffset + + public fun toCoordinates(offset: Offset, density: Density): T = with(density){ + val dpOffset = DpOffset(offset.x.toDp(), offset.y.toDp()) + dpOffset.toCoordinates() + } + + public fun toOffset(coordinates: T, density: Density): Offset = with(density){ + val dpOffset = coordinates.toDpOffset() + return Offset(dpOffset.x.toPx(), dpOffset.y.toPx()) + } + +} public val DpRect.topLeft: DpOffset get() = DpOffset(left, top) diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt new file mode 100644 index 0000000..1ac270f --- /dev/null +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt @@ -0,0 +1,108 @@ +package center.sciprog.maps.features + +import androidx.compose.foundation.Canvas +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathEffect +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.DrawScopeMarker +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.text.TextMeasurer +import androidx.compose.ui.text.drawText +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.unit.DpRect +import center.sciprog.attributes.Attributes +import io.github.oshai.kotlinlogging.KotlinLogging + +/** + * An extension of [DrawScope] to include map-specific features + */ +@DrawScopeMarker +public abstract class FeatureDrawScope( + public val state: CanvasState, +) : DrawScope { + public fun Offset.toCoordinates(): T = with(state) { + toCoordinates(this@toCoordinates, this@FeatureDrawScope) + } + + public fun T.toOffset(): Offset = with(state) { + toOffset(this@toOffset, this@FeatureDrawScope) + } + + public fun Rectangle.toDpRect(): DpRect = with(state) { toDpRect() } + + public abstract fun painterFor(feature: PainterFeature): Painter + + public abstract fun drawText(text: String, position: Offset, attributes: Attributes) +} + +/** + * Default implementation of FeatureDrawScope to be used in Compose (both schemes and Maps) + */ +@DrawScopeMarker +public class ComposeFeatureDrawScope( + drawScope: DrawScope, + state: CanvasState, + private val painterCache: Map, Painter>, + private val textMeasurer: TextMeasurer, +) : FeatureDrawScope(state), DrawScope by drawScope { + override fun drawText(text: String, position: Offset, attributes: Attributes) { + try { + drawText(textMeasurer, text, position) + } catch (ex: Exception){ + KotlinLogging.logger("features").error(ex){"Failed to measure text"} + } + } + + override fun painterFor(feature: PainterFeature): Painter = painterCache[feature] ?: error("Can't resolve painter for $feature") +} + + +/** + * Create a canvas with extended functionality (e.g., drawing text) + */ +@Composable +public fun FeatureCanvas( + state: CanvasState, + features: FeatureGroup, + modifier: Modifier = Modifier, + draw: FeatureDrawScope.() -> Unit = {}, +) { + val textMeasurer = rememberTextMeasurer(200) + + val painterCache: Map, Painter> = features.features.flatMap { + if (it is FeatureGroup) it.features else listOf(it) + }.filterIsInstance>().associateWith { it.getPainter() } + + Canvas(modifier) { + if (state.canvasSize != size.toDpSize()) { + state.canvasSize = size.toDpSize() + } + ComposeFeatureDrawScope(this, state, painterCache, textMeasurer).apply(draw).apply{ + clipRect { + features.featureMap.values.sortedBy { it.z } + .filter { state.viewPoint.zoom in it.zoomRange } + .forEach { feature -> + this@apply.drawFeature(feature) + } + } + } + state.selectRect?.let { dpRect -> + val rect = dpRect.toRect() + drawRect( + color = Color.Blue, + topLeft = rect.topLeft, + size = rect.size, + alpha = 0.5f, + style = Stroke( + width = 2f, + pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) + ) + ) + } + } +} diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureGroup.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureGroup.kt index 8cbb6ff..9d4f573 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureGroup.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureGroup.kt @@ -1,8 +1,6 @@ package center.sciprog.maps.features -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateMapOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawScope @@ -11,7 +9,8 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import center.sciprog.attributes.* +import center.sciprog.attributes.Attribute +import center.sciprog.attributes.Attributes import space.kscience.kmath.geometry.Angle import space.kscience.kmath.nd.* import space.kscience.kmath.structures.Buffer @@ -33,8 +32,12 @@ public val > FeatureRef.attributes: Attributes get public data class FeatureGroup( override val space: CoordinateSpace, public val featureMap: SnapshotStateMap> = mutableStateMapOf(), - override val attributes: Attributes = Attributes.EMPTY, ) : CoordinateSpace by space, Feature { + + private val attributesState: MutableState = mutableStateOf(Attributes.EMPTY) + + override val attributes: Attributes get() = attributesState.value + // // @Suppress("UNCHECKED_CAST") // public operator fun > get(id: FeatureId): F = @@ -62,26 +65,8 @@ public data class FeatureGroup( public val features: Collection> get() = featureMap.values.sortedByDescending { it.z } - public fun visit(visitor: FeatureGroup.(id: String, feature: Feature) -> Unit) { - featureMap.entries.sortedByDescending { it.value.z }.forEach { (key, feature) -> - if (feature is FeatureGroup) { - feature.visit(visitor) - } else { - visitor(this, key, feature) - } - } - } - public fun visitUntil(visitor: FeatureGroup.(id: String, feature: Feature) -> Boolean) { - featureMap.entries.sortedByDescending { it.value.z }.forEach { (key, feature) -> - if (feature is FeatureGroup) { - feature.visitUntil(visitor) - } else { - if (!visitor(this, key, feature)) return@visitUntil - } - } - } -// + // // @Suppress("UNCHECKED_CAST") // public fun getAttribute(id: FeatureId>, key: Attribute): A? = // get(id).attributes[key] @@ -91,7 +76,10 @@ public data class FeatureGroup( featureMap.values.mapNotNull { it.getBoundingBox(zoom) }.wrapRectangles() } - override fun withAttributes(modify: Attributes.() -> Attributes): Feature = copy(attributes = modify(attributes)) + override fun withAttributes(modify: Attributes.() -> Attributes): Feature { + attributesState.value = attributes.modify() + return this + } public companion object { @@ -118,6 +106,29 @@ public data class FeatureGroup( } } +/** + * Recursively search for feature until function returns true + */ +public fun FeatureGroup.forEachUntil(visitor: FeatureGroup.(id: String, feature: Feature) -> Boolean) { + featureMap.entries.sortedByDescending { it.value.z }.forEach { (key, feature) -> + if (feature is FeatureGroup) { + feature.forEachUntil(visitor) + } else { + if (!visitor(this, key, feature)) return@forEachUntil + } + } +} + +/** + * Recursively visit all features in this group + */ +public fun FeatureGroup.forEach( + visitor: FeatureGroup.(id: String, feature: Feature) -> Unit, +): Unit = forEachUntil { id, feature -> + visitor(id, feature) + true +} + /** * Process all features with a given attribute from the one with highest [z] to lowest */ @@ -125,7 +136,7 @@ public fun FeatureGroup.forEachWithAttribute( key: Attribute, block: FeatureGroup.(id: String, feature: Feature, attributeValue: A) -> Unit, ) { - visit { id, feature -> + forEach { id, feature -> feature.attributes[key]?.let { block(id, feature, it) } @@ -136,7 +147,7 @@ public fun FeatureGroup.forEachWithAttributeUntil( key: Attribute, block: FeatureGroup.(id: String, feature: Feature, attributeValue: A) -> Boolean, ) { - visitUntil { id, feature -> + forEachUntil { id, feature -> feature.attributes[key]?.let { block(id, feature, it) } ?: true @@ -146,7 +157,7 @@ public fun FeatureGroup.forEachWithAttributeUntil( public inline fun > FeatureGroup.forEachWithType( crossinline block: (FeatureRef) -> Unit, ) { - visit { id, feature -> + forEach { id, feature -> if (feature is F) block(FeatureRef(id, this)) } } @@ -154,7 +165,7 @@ public inline fun > FeatureGroup.forEachWithT public inline fun > FeatureGroup.forEachWithTypeUntil( crossinline block: (FeatureRef) -> Boolean, ) { - visitUntil { id, feature -> + forEachUntil { id, feature -> if (feature is F) block(FeatureRef(id, this)) else true } } @@ -241,25 +252,23 @@ public fun FeatureGroup.icon( size: DpSize = DpSize(image.defaultWidth, image.defaultHeight), attributes: Attributes = Attributes.EMPTY, id: String? = null, -): FeatureRef> = - feature( - id, - VectorIconFeature( - space, - position, - size, - image, - attributes - ) +): FeatureRef> = feature( + id, + VectorIconFeature( + space, + position, + size, + image, + attributes ) +) public fun FeatureGroup.group( - attributes: Attributes = Attributes.EMPTY, id: String? = null, builder: FeatureGroup.() -> Unit, ): FeatureRef> { val collection = FeatureGroup(space).apply(builder) - val feature = FeatureGroup(space, collection.featureMap, attributes) + val feature = FeatureGroup(space, collection.featureMap) return feature(id, feature) } @@ -302,4 +311,23 @@ public fun FeatureGroup.pixelMap( ): FeatureRef> = feature( id, PixelMapFeature(space, rectangle, pixelMap, attributes = attributes) -) \ No newline at end of file +) + +/** + * Create a pretty tree-like representation of this feature group + */ +public fun FeatureGroup<*>.toPrettyString(): String { + fun StringBuilder.printGroup(id: String, group: FeatureGroup<*>, prefix: String) { + appendLine("${prefix}* [group] $id") + group.featureMap.forEach { (id, feature) -> + if (feature is FeatureGroup<*>) { + printGroup(id, feature, " ") + } else { + appendLine("$prefix * [${feature::class.simpleName}] $id ") + } + } + } + return buildString { + printGroup("root", this@toPrettyString, "") + } +} \ No newline at end of file diff --git a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/drawFeature.kt similarity index 80% rename from maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt rename to maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/drawFeature.kt index f9c9d73..1f4ce2e 100644 --- a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/drawFeature.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/drawFeature.kt @@ -2,35 +2,31 @@ package center.sciprog.maps.features import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.* -import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.PointMode import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.drawscope.translate -import androidx.compose.ui.graphics.painter.Painter import center.sciprog.attributes.plus -import org.jetbrains.skia.Font -import org.jetbrains.skia.Paint import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.geometry.degrees -internal fun Color.toPaint(): Paint = Paint().apply { - isAntiAlias = true - color = toArgb() -} +//internal fun Color.toPaint(): Paint = Paint().apply { +// isAntiAlias = true +// color = toArgb() +//} -public fun DrawScope.drawFeature( - state: CoordinateViewScope, - painterCache: Map, Painter>, + +public fun FeatureDrawScope.drawFeature( feature: Feature, -): Unit = with(state) { +): Unit { val color = feature.color ?: Color.Red val alpha = feature.attributes[AlphaAttribute] ?: 1f - fun T.toOffset(): Offset = toOffset(this@drawFeature) when (feature) { - is FeatureSelector -> drawFeature(state, painterCache, feature.selector(state.zoom)) + is FeatureSelector -> drawFeature(feature.selector(state.zoom)) is CircleFeature -> drawCircle( color, feature.radius.toPx(), @@ -78,22 +74,13 @@ public fun DrawScope.drawFeature( val offset = feature.center.toOffset() val size = feature.size.toSize() translate(offset.x - size.width / 2, offset.y - size.height / 2) { - with(painterCache[feature]!!) { - draw(size) + with(this@drawFeature.painterFor(feature)) { + draw(size, colorFilter = feature.color?.let { ColorFilter.tint(it) }) } } } - is TextFeature -> drawIntoCanvas { canvas -> - val offset = feature.position.toOffset() - canvas.nativeCanvas.drawString( - feature.text, - offset.x + 5, - offset.y - 5, - Font().apply(feature.fontConfig), - (feature.color ?: Color.Black).toPaint() - ) - } + is TextFeature -> drawText(feature.text, feature.position.toOffset(), feature.attributes) is DrawFeature -> { val offset = feature.position.toOffset() @@ -104,9 +91,7 @@ public fun DrawScope.drawFeature( is FeatureGroup -> { feature.featureMap.values.forEach { - drawFeature(state, painterCache, it.withAttributes { - feature.attributes + this - }) + drawFeature(it.withAttributes { feature.attributes + this }) } } @@ -163,7 +148,7 @@ public fun DrawScope.drawFeature( val offset = rect.topLeft translate(offset.x, offset.y) { - with(painterCache[feature]!!) { + with(this@drawFeature.painterFor(feature)) { draw(rect.size) } } diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt index a824a50..95c28cf 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/mapFeatureAttributes.kt @@ -13,6 +13,9 @@ import center.sciprog.attributes.withAttribute public object ZAttribute : Attribute +public val Feature<*>.z: Float + get() = attributes[ZAttribute] ?: 0f + public object DraggableAttribute : Attribute> public object DragListenerAttribute : SetAttribute> @@ -46,12 +49,14 @@ public fun > FeatureRef.zoomRange(range: FloatRang public object AlphaAttribute : Attribute -public fun > FeatureRef.modifyAttributes(modify: AttributesBuilder.() -> Unit): FeatureRef { +public fun > FeatureRef.modifyAttributes( + modification: AttributesBuilder.() -> Unit +): FeatureRef { @Suppress("UNCHECKED_CAST") parent.feature( id, resolve().withAttributes { - AttributesBuilder(this).apply(modify).build() + AttributesBuilder(this).apply(modification).build() } as F ) return this diff --git a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/mapControls.kt b/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt similarity index 86% rename from maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/mapControls.kt rename to maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt index 5aec2fa..dddbcb8 100644 --- a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/mapControls.kt +++ b/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt @@ -16,10 +16,10 @@ import kotlin.math.min * Create a modifier for Map/Scheme canvas controls on desktop * @param features a collection of features to be rendered in descending [ZAttribute] order */ -public fun Modifier.mapControls( - state: CoordinateViewScope, +public fun Modifier.canvasControls( + state: CanvasState, features: FeatureGroup, -): Modifier = with(state) { +): Modifier = with(state){ // //selecting all tapabales ahead of time // val allTapable = buildMap { @@ -32,8 +32,8 @@ public fun Modifier.mapControls( awaitPointerEventScope { while (true) { val event = awaitPointerEvent() - val coordinates = event.changes.first().position.toCoordinates(this) - val point = space.ViewPoint(coordinates, zoom) + val coordinates = toCoordinates(event.changes.first().position, this) + val point = state.space.ViewPoint(coordinates, zoom) if (event.type == PointerEventType.Move) { features.forEachWithAttribute(HoverListenerAttribute) { _, feature, listeners -> @@ -47,9 +47,9 @@ public fun Modifier.mapControls( } }.pointerInput(Unit) { detectClicks( - onDoubleClick = if (state.config.zoomOnDoubleClick) { + onDoubleClick = if (viewConfig.zoomOnDoubleClick) { { event -> - val invariant = event.position.toCoordinates(this) + val invariant = toCoordinates(event.position, this) viewPoint = with(space) { viewPoint.zoomBy( if (event.buttons.isPrimaryPressed) 1f else if (event.buttons.isSecondaryPressed) -1f else 0f, @@ -59,10 +59,10 @@ public fun Modifier.mapControls( } } else null, onClick = { event -> - val coordinates = event.position.toCoordinates(this) + val coordinates = toCoordinates(event.position, this) val point = space.ViewPoint(coordinates, zoom) - config.onClick?.handle( + viewConfig.onClick?.handle( event, point ) @@ -88,7 +88,7 @@ public fun Modifier.mapControls( //compute invariant point of translation val invariant = DpOffset(xPos.toDp(), yPos.toDp()).toCoordinates() viewPoint = with(space) { - viewPoint.zoomBy(-change.scrollDelta.y * config.zoomSpeed, invariant) + viewPoint.zoomBy(-change.scrollDelta.y * viewConfig.zoomSpeed, invariant) } change.consume() } @@ -110,14 +110,14 @@ public fun Modifier.mapControls( //apply drag handle and check if it prohibits the drag even propagation if (selectionStart == null) { val dragStart = space.ViewPoint( - dragChange.previousPosition.toCoordinates(this), + toCoordinates(dragChange.previousPosition, this), zoom ) val dragEnd = space.ViewPoint( - dragChange.position.toCoordinates(this), + toCoordinates(dragChange.position, this), zoom ) - val dragResult = config.dragHandle?.handle(event, dragStart, dragEnd) + val dragResult = viewConfig.dragHandle?.handle(event, dragStart, dragEnd) if (dragResult?.handleNext == false) return@drag var continueAfter = true @@ -132,7 +132,7 @@ public fun Modifier.mapControls( } if (event.buttons.isPrimaryPressed) { - //If selection process is started, modify the frame + //If the selection process is started, modify the frame selectionStart?.let { start -> val offset = dragChange.position selectRect = DpRect( @@ -161,8 +161,8 @@ public fun Modifier.mapControls( rect.topLeft.toCoordinates(), rect.bottomRight.toCoordinates() ) - config.onSelect(coordinateRect) - if (config.zoomOnSelect) { + viewConfig.onSelect(coordinateRect) + if (viewConfig.zoomOnSelect) { viewPoint = computeViewPoint(coordinateRect) } selectRect = null diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt similarity index 60% rename from maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt rename to maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt index f482df8..da4eeba 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt +++ b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt @@ -1,18 +1,14 @@ package center.sciprog.maps.scheme -import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable -import androidx.compose.runtime.key import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.DpSize -import center.sciprog.attributes.z -import center.sciprog.maps.compose.mapControls +import center.sciprog.maps.compose.canvasControls import center.sciprog.maps.features.* import mu.KotlinLogging import kotlin.math.min @@ -22,48 +18,14 @@ private val logger = KotlinLogging.logger("SchemeView") @Composable public fun SchemeView( - state: XYViewScope, + state: XYCanvasState, features: FeatureGroup, modifier: Modifier = Modifier.fillMaxSize(), -): Unit = key(state, features) { - with(state) { - //Can't do that inside canvas - val painterCache: Map, Painter> = - features.features.filterIsInstance>().associateWith { it.getPainter() } - - Canvas(modifier = modifier.mapControls(state, features)) { - - if (canvasSize != size.toDpSize()) { - canvasSize = size.toDpSize() - logger.debug { "Recalculate canvas. Size: $size" } - } - - clipRect { - features.featureMap.values.sortedBy { it.z } - .filter { viewPoint.zoom in it.zoomRange } - .forEach { feature -> - drawFeature(state, painterCache, feature) - } - } - - selectRect?.let { dpRect -> - val rect = dpRect.toRect() - drawRect( - color = Color.Blue, - topLeft = rect.topLeft, - size = rect.size, - alpha = 0.5f, - style = Stroke( - width = 2f, - pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) - ) - ) - } - } - } - +): Unit { + FeatureCanvas(state, features, modifier = modifier.canvasControls(state, features)) } + public fun Rectangle.computeViewPoint( canvasSize: DpSize = defaultCanvasSize, ): ViewPoint { @@ -87,7 +49,7 @@ public fun SchemeView( modifier: Modifier = Modifier.fillMaxSize(), ) { - val state = XYViewScope.remember( + val state = XYCanvasState.remember( config, initialViewPoint = initialViewPoint, initialRectangle = initialRectangle ?: features.getBoundingBox(Float.MAX_VALUE), @@ -112,7 +74,7 @@ public fun SchemeView( buildFeatures: FeatureGroup.() -> Unit = {}, ) { val featureState = FeatureGroup.remember(XYCoordinateSpace, buildFeatures) - val mapState: XYViewScope = XYViewScope.remember( + val mapState: XYCanvasState = XYCanvasState.remember( config, initialViewPoint = initialViewPoint, initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox( diff --git a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XY.kt b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XY.kt index 8895cbd..e4bba6f 100644 --- a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XY.kt +++ b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XY.kt @@ -12,6 +12,8 @@ import kotlin.math.min public data class XY(override val x: Float, override val y: Float): Vector2D +public fun XY(x: Number, y: Number): XY = XY(x.toFloat(), y.toFloat()) + internal data class XYRectangle( override val a: XY, override val b: XY, diff --git a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYCanvasState.kt similarity index 87% rename from maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt rename to maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYCanvasState.kt index 48a2673..532cd05 100644 --- a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYViewScope.kt +++ b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/XYCanvasState.kt @@ -9,9 +9,9 @@ import androidx.compose.ui.unit.dp import center.sciprog.maps.features.* import kotlin.math.min -public class XYViewScope( +public class XYCanvasState( config: ViewConfig, -) : CoordinateViewScope(config) { +) : CanvasState(config) { override val space: CoordinateSpace get() = XYCoordinateSpace @@ -54,12 +54,12 @@ public class XYViewScope( config: ViewConfig = ViewConfig(), initialViewPoint: ViewPoint? = null, initialRectangle: Rectangle? = null, - ): XYViewScope = remember { - XYViewScope(config).also { mapState-> + ): XYCanvasState = remember { + XYCanvasState(config).apply { if (initialViewPoint != null) { - mapState.viewPoint = initialViewPoint + viewPoint = initialViewPoint } else if (initialRectangle != null) { - mapState.viewPoint = mapState.computeViewPoint(initialRectangle) + viewPoint = computeViewPoint(initialRectangle) } } } diff --git a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/schemeFeatures.kt b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/schemeFeatures.kt index 1ceaa6d..0a2a3bd 100644 --- a/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/schemeFeatures.kt +++ b/maps-kt-scheme/src/commonMain/kotlin/center/sciprog/maps/scheme/schemeFeatures.kt @@ -41,7 +41,7 @@ public fun FeatureGroup.circle( centerCoordinates: Pair, size: Dp = 5.dp, id: String? = null, -): FeatureRef> = circle(centerCoordinates.toCoordinates(), size, id = id) +): FeatureRef> = circle(centerCoordinates.toCoordinates(), size, id = id) public fun FeatureGroup.draw( position: Pair, @@ -63,7 +63,7 @@ public fun FeatureGroup.arc( arcLength: Angle, id: String? = null, ): FeatureRef> = arc( - oval = XYCoordinateSpace.Rectangle(center.toCoordinates(), 2*radius, 2*radius), + oval = XYCoordinateSpace.Rectangle(center.toCoordinates(), 2 * radius, 2 * radius), startAngle = startAngle, arcLength = arcLength, id = id @@ -108,4 +108,33 @@ public fun FeatureGroup.pixelMap( ) ) +public fun FeatureGroup.rectanglePolygon( + left: Number, right: Number, + bottom: Number, top: Number, + attributes: Attributes = Attributes.EMPTY, + id: String? = null, +): FeatureRef> = polygon( + listOf( + XY(left.toFloat(), top.toFloat()), + XY(right.toFloat(), top.toFloat()), + XY(right.toFloat(), bottom.toFloat()), + XY(left.toFloat(), bottom.toFloat()) + ), + attributes, id +) + +public fun FeatureGroup.rectanglePolygon( + rectangle: Rectangle, + attributes: Attributes = Attributes.EMPTY, + id: String? = null, +): FeatureRef> = polygon( + listOf( + XY(rectangle.left, rectangle.top), + XY(rectangle.right, rectangle.top), + XY(rectangle.right, rectangle.bottom), + XY(rectangle.left, rectangle.bottom) + ), + attributes, id +) + diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt index 024a4ea..448bf2b 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt +++ b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt @@ -5,21 +5,26 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.drawscope.* +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection +import center.sciprog.attributes.Attributes +import center.sciprog.maps.features.* +import center.sciprog.maps.scheme.XY import org.jfree.svg.SVGGraphics2D import java.awt.BasicStroke -import java.awt.Font import java.awt.geom.* import java.awt.image.AffineTransformOp import java.awt.Color as AWTColor public class SvgDrawScope( + state: CanvasState, private val graphics: SVGGraphics2D, size: Size, - private val defaultStrokeWidth: Float = 1f, -) : DrawScope { + private val painterCache: Map, Painter>, + private val defaultStrokeWidth: Float = 1f +) : FeatureDrawScope(state) { override val layoutDirection: LayoutDirection get() = LayoutDirection.Ltr @@ -459,16 +464,20 @@ public class SvgDrawScope( } } - public fun drawText( - text: String, - x: Float, - y: Float, - font: Font, - color: Color, + public fun renderText( + textFeature: TextFeature, ) { - setupColor(color) - graphics.font = font - graphics.drawString(text, x, y) + textFeature.color?.let { setupColor(it)} + graphics.drawString(textFeature.text, textFeature.position.x, textFeature.position.y) + } + + override fun painterFor(feature: PainterFeature): Painter { + return painterCache[feature]!! + } + + override fun drawText(text: String, position: Offset, attributes: Attributes) { + attributes[ColorAttribute]?.let { setupColor(it)} + graphics.drawString(text, position.x, position.y) } override val drawContext: DrawContext = SvgDrawContext(graphics, size) diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt index 0424bbf..6414190 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt +++ b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt @@ -1,21 +1,13 @@ package center.sciprog.maps.svg import androidx.compose.runtime.Composable -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PointMode -import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.graphics.drawscope.drawIntoCanvas -import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.graphics.painter.Painter import center.sciprog.maps.features.* -import center.sciprog.maps.scheme.* +import center.sciprog.maps.scheme.XY +import center.sciprog.maps.scheme.XYCanvasState import org.jfree.svg.SVGGraphics2D import org.jfree.svg.SVGUtils -import space.kscience.kmath.geometry.degrees -import java.awt.Font.PLAIN -import kotlin.math.abs public class FeatureStateSnapshot( @@ -26,9 +18,12 @@ public class FeatureStateSnapshot( @Composable public fun FeatureGroup.snapshot(): FeatureStateSnapshot = FeatureStateSnapshot( featureMap, - features.filterIsInstance>().associateWith { it.getPainter() } + features.flatMap { + if (it is FeatureGroup) it.features else listOf(it) + }.filterIsInstance>().associateWith { it.getPainter() } ) + public fun FeatureStateSnapshot.generateSvg( viewPoint: ViewPoint, width: Double, @@ -36,139 +31,137 @@ public fun FeatureStateSnapshot.generateSvg( id: String? = null, ): String { - fun XY.toOffset(): Offset = Offset( - (width / 2 + (x - viewPoint.focus.x) * viewPoint.zoom).toFloat(), - (height / 2 + (viewPoint.focus.y - y) * viewPoint.zoom).toFloat() - ) - - - fun SvgDrawScope.drawFeature(scale: Float, feature: Feature) { - - val color = feature.color ?: Color.Red - val alpha = feature.attributes[AlphaAttribute] ?: 1f - - when (feature) { - is ScalableImageFeature -> { - val offset = XY(feature.rectangle.left, feature.rectangle.top).toOffset() - val backgroundSize = Size( - (feature.rectangle.width * scale), - (feature.rectangle.height * scale) - ) - - translate(offset.x, offset.y) { - with(painterCache[feature]!!) { - draw(backgroundSize) - } - } - } - - is FeatureSelector -> drawFeature(scale, feature.selector(scale)) - - is CircleFeature -> drawCircle( - color, - feature.radius.toPx(), - center = feature.center.toOffset(), - alpha = alpha - ) - - is LineFeature -> drawLine( - color, - feature.a.toOffset(), - feature.b.toOffset(), - alpha = alpha - ) - - is PointsFeature -> { - val points = feature.points.map { it.toOffset() } - drawPoints( - points = points, - color = color, - strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth, - pointMode = PointMode.Points, - pathEffect = feature.attributes[PathEffectAttribute], - alpha = alpha - ) - } - - is MultiLineFeature -> { - val points = feature.points.map { it.toOffset() } - drawPoints( - points = points, - color = color, - strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth, - pointMode = PointMode.Polygon, - pathEffect = feature.attributes[PathEffectAttribute], - alpha = alpha - ) - } - - is ArcFeature -> { - val topLeft = feature.oval.leftTop.toOffset() - val bottomRight = feature.oval.rightBottom.toOffset() - - val size = Size(abs(topLeft.x - bottomRight.x), abs(topLeft.y - bottomRight.y)) - - drawArc( - color = color, - startAngle = feature.startAngle.degrees.toFloat(), - sweepAngle = feature.arcLength.degrees.toFloat(), - useCenter = false, - topLeft = topLeft, - size = size, - style = Stroke(), - alpha = alpha - ) - } - - is BitmapIconFeature -> drawImage(feature.image, feature.center.toOffset()) - - is VectorIconFeature -> { - val offset = feature.center.toOffset() - val imageSize = feature.size.toSize() - translate(offset.x - imageSize.width / 2, offset.y - imageSize.height / 2) { - with(painterCache[feature]!!) { - draw(imageSize, alpha = alpha) - } - } - } - - is TextFeature -> drawIntoCanvas { _ -> - val offset = feature.position.toOffset() - drawText( - feature.text, - offset.x + 5, - offset.y - 5, - java.awt.Font(null, PLAIN, 16), - color - ) - } - - is DrawFeature -> { - val offset = feature.position.toOffset() - translate(offset.x, offset.y) { - feature.drawFeature(this) - } - } - - is FeatureGroup -> { - feature.featureMap.values.forEach { - drawFeature(scale, it) - } - } - } - } +// fun XY.toOffset(): Offset = Offset( +// (width / 2 + (x - viewPoint.focus.x) * viewPoint.zoom).toFloat(), +// (height / 2 + (viewPoint.focus.y - y) * viewPoint.zoom).toFloat() +// ) +// +// +// fun SvgDrawScope.drawFeature(scale: Float, feature: Feature) { +// +// val color = feature.color ?: Color.Red +// val alpha = feature.attributes[AlphaAttribute] ?: 1f +// +// when (feature) { +// is ScalableImageFeature -> { +// val offset = XY(feature.rectangle.left, feature.rectangle.top).toOffset() +// val backgroundSize = Size( +// (feature.rectangle.width * scale), +// (feature.rectangle.height * scale) +// ) +// +// translate(offset.x, offset.y) { +// with(painterCache[feature]!!) { +// draw(backgroundSize) +// } +// } +// } +// +// is FeatureSelector -> drawFeature(scale, feature.selector(scale)) +// +// is CircleFeature -> drawCircle( +// color, +// feature.radius.toPx(), +// center = feature.center.toOffset(), +// alpha = alpha +// ) +// +// is LineFeature -> drawLine( +// color, +// feature.a.toOffset(), +// feature.b.toOffset(), +// alpha = alpha +// ) +// +// is PointsFeature -> { +// val points = feature.points.map { it.toOffset() } +// drawPoints( +// points = points, +// color = color, +// strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth, +// pointMode = PointMode.Points, +// pathEffect = feature.attributes[PathEffectAttribute], +// alpha = alpha +// ) +// } +// +// is MultiLineFeature -> { +// val points = feature.points.map { it.toOffset() } +// drawPoints( +// points = points, +// color = color, +// strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth, +// pointMode = PointMode.Polygon, +// pathEffect = feature.attributes[PathEffectAttribute], +// alpha = alpha +// ) +// } +// +// is ArcFeature -> { +// val topLeft = feature.oval.leftTop.toOffset() +// val bottomRight = feature.oval.rightBottom.toOffset() +// +// val size = Size(abs(topLeft.x - bottomRight.x), abs(topLeft.y - bottomRight.y)) +// +// drawArc( +// color = color, +// startAngle = feature.startAngle.degrees.toFloat(), +// sweepAngle = feature.arcLength.degrees.toFloat(), +// useCenter = false, +// topLeft = topLeft, +// size = size, +// style = Stroke(), +// alpha = alpha +// ) +// } +// +// is BitmapIconFeature -> drawImage(feature.image, feature.center.toOffset()) +// +// is VectorIconFeature -> { +// val offset = feature.center.toOffset() +// val imageSize = feature.size.toSize() +// translate(offset.x - imageSize.width / 2, offset.y - imageSize.height / 2) { +// with(painterCache[feature]!!) { +// draw(imageSize, alpha = alpha) +// } +// } +// } +// +// is TextFeature -> drawIntoCanvas { _ -> +// val offset = feature.position.toOffset() +// drawText( +// feature.text, +// offset.x + 5, +// offset.y - 5, +// java.awt.Font(null, PLAIN, 16), +// color +// ) +// } +// +// is DrawFeature -> { +// val offset = feature.position.toOffset() +// translate(offset.x, offset.y) { +// feature.drawFeature(this) +// } +// } +// +// is FeatureGroup -> { +// feature.featureMap.values.forEach { +// drawFeature(scale, it) +// } +// } +// } +// } val svgGraphics2D: SVGGraphics2D = SVGGraphics2D(width, height) - val svgScope = SvgDrawScope(svgGraphics2D, Size(width.toFloat(), height.toFloat())) + val svgCanvasState: XYCanvasState = XYCanvasState(ViewConfig()) + val svgScope = SvgDrawScope(svgCanvasState, svgGraphics2D, Size(width.toFloat(), height.toFloat()), painterCache) svgScope.apply { - features.values.filterIsInstance>().forEach { background -> - drawFeature(viewPoint.zoom, background) - } features.values.filter { - it !is ScalableImageFeature && viewPoint.zoom in it.zoomRange + viewPoint.zoom in it.zoomRange }.forEach { feature -> - drawFeature(viewPoint.zoom, feature) + drawFeature(feature) } } return svgGraphics2D.getSVGElement(id) diff --git a/settings.gradle.kts b/settings.gradle.kts index 172c19b..afa549e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,8 +16,8 @@ pluginManagement { } plugins { - id("com.android.application").version(extra["agp.version"] as String) - id("com.android.library").version(extra["agp.version"] as String) +// id("com.android.application").version(extra["agp.version"] as String) +// id("com.android.library").version(extra["agp.version"] as String) id("org.jetbrains.compose").version(extra["compose.version"] as String) id("space.kscience.gradle.project") version toolsVersion id("space.kscience.gradle.mpp") version toolsVersion diff --git a/trajectory-kt/build.gradle.kts b/trajectory-kt/build.gradle.kts index 45512f0..0783429 100644 --- a/trajectory-kt/build.gradle.kts +++ b/trajectory-kt/build.gradle.kts @@ -10,7 +10,7 @@ val kmathVersion: String by rootProject.extra kscience{ jvm() js() - native() +// native() useContextReceivers() useSerialization() From aebf4af24fe31b8ccf4eb124be061cfe73f7f5e5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 10 Sep 2023 21:13:54 +0300 Subject: [PATCH 04/14] Fix svg export --- demo/maps/src/jvmMain/kotlin/Main.kt | 23 +++++++++++-------- .../center/sciprog/maps/compose/MapView.kt | 8 +++---- .../sciprog/maps/features/FeatureDrawScope.kt | 15 ++++++++---- .../center/sciprog/maps/svg/SvgDrawScope.kt | 9 ++++---- .../center/sciprog/maps/svg/exportToSvg.kt | 23 +++++++++++-------- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/demo/maps/src/jvmMain/kotlin/Main.kt b/demo/maps/src/jvmMain/kotlin/Main.kt index f7986a6..3bea047 100644 --- a/demo/maps/src/jvmMain/kotlin/Main.kt +++ b/demo/maps/src/jvmMain/kotlin/Main.kt @@ -77,9 +77,12 @@ fun App() { icon(pointOne, Icons.Filled.Home) - val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) - val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) - val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) + val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) + val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) + val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) draggableLine(marker1, marker2, id = "line 1").color(Color.Red).onClick { println("line 1 clicked") @@ -103,13 +106,13 @@ fun App() { ), ) - points( - points = listOf( - 55.744 to 38.614, - 55.8 to 38.5, - 56.0 to 38.5, - ) - ).pointSize(5f) +// points( +// points = listOf( +// 55.744 to 38.614, +// 55.8 to 38.5, +// 56.0 to 38.5, +// ) +// ).pointSize(5f) // geodeticLine(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)).color(Color.Blue) // line(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)) diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt index 0a6c18b..e6148b3 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt @@ -6,9 +6,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathEffect -import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.toComposeImageBitmap import androidx.compose.ui.unit.IntOffset @@ -72,7 +69,7 @@ public fun MapView( mapTiles[tile.id] = tile.image } catch (ex: Exception) { //displaying the error is maps responsibility - if(ex !is CancellationException) { + if (ex !is CancellationException) { logger.error(ex) { "Failed to load tile with id=$id" } } } @@ -147,5 +144,6 @@ public fun MapView( buildFeatures: FeatureGroup.() -> Unit = {}, ) { val featureState = FeatureGroup.remember(WebMercatorSpace, buildFeatures) - MapView(mapTileProvider, config, featureState, initialViewPoint, initialRectangle, modifier) + val computedRectangle = initialRectangle ?: featureState.getBoundingBox() + MapView(mapTileProvider, config, featureState, initialViewPoint, computedRectangle, modifier) } \ No newline at end of file diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt index 1ac270f..e5998c3 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt @@ -29,7 +29,7 @@ public abstract class FeatureDrawScope( toCoordinates(this@toCoordinates, this@FeatureDrawScope) } - public fun T.toOffset(): Offset = with(state) { + public open fun T.toOffset(): Offset = with(state) { toOffset(this@toOffset, this@FeatureDrawScope) } @@ -53,12 +53,17 @@ public class ComposeFeatureDrawScope( override fun drawText(text: String, position: Offset, attributes: Attributes) { try { drawText(textMeasurer, text, position) - } catch (ex: Exception){ - KotlinLogging.logger("features").error(ex){"Failed to measure text"} + } catch (ex: Exception) { + logger.error(ex) { "Failed to measure text" } } } - override fun painterFor(feature: PainterFeature): Painter = painterCache[feature] ?: error("Can't resolve painter for $feature") + override fun painterFor(feature: PainterFeature): Painter = + painterCache[feature] ?: error("Can't resolve painter for $feature") + + public companion object{ + private val logger = KotlinLogging.logger("ComposeFeatureDrawScope") + } } @@ -82,7 +87,7 @@ public fun FeatureCanvas( if (state.canvasSize != size.toDpSize()) { state.canvasSize = size.toDpSize() } - ComposeFeatureDrawScope(this, state, painterCache, textMeasurer).apply(draw).apply{ + ComposeFeatureDrawScope(this, state, painterCache, textMeasurer).apply(draw).apply { clipRect { features.featureMap.values.sortedBy { it.z } .filter { state.viewPoint.zoom in it.zoomRange } diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt index 448bf2b..2da269a 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt +++ b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/SvgDrawScope.kt @@ -21,9 +21,8 @@ import java.awt.Color as AWTColor public class SvgDrawScope( state: CanvasState, private val graphics: SVGGraphics2D, - size: Size, private val painterCache: Map, Painter>, - private val defaultStrokeWidth: Float = 1f + private val defaultStrokeWidth: Float = 1f, ) : FeatureDrawScope(state) { override val layoutDirection: LayoutDirection @@ -467,7 +466,7 @@ public class SvgDrawScope( public fun renderText( textFeature: TextFeature, ) { - textFeature.color?.let { setupColor(it)} + textFeature.color?.let { setupColor(it) } graphics.drawString(textFeature.text, textFeature.position.x, textFeature.position.y) } @@ -476,10 +475,10 @@ public class SvgDrawScope( } override fun drawText(text: String, position: Offset, attributes: Attributes) { - attributes[ColorAttribute]?.let { setupColor(it)} + attributes[ColorAttribute]?.let { setupColor(it) } graphics.drawString(text, position.x, position.y) } - override val drawContext: DrawContext = SvgDrawContext(graphics, size) + override val drawContext: DrawContext = SvgDrawContext(graphics, state.canvasSize.toSize()) } \ No newline at end of file diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt index 6414190..a5073c9 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt +++ b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/svg/exportToSvg.kt @@ -3,6 +3,8 @@ package center.sciprog.maps.svg import androidx.compose.runtime.Composable import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp import center.sciprog.maps.features.* import center.sciprog.maps.scheme.XY import center.sciprog.maps.scheme.XYCanvasState @@ -154,15 +156,18 @@ public fun FeatureStateSnapshot.generateSvg( // } val svgGraphics2D: SVGGraphics2D = SVGGraphics2D(width, height) - val svgCanvasState: XYCanvasState = XYCanvasState(ViewConfig()) - val svgScope = SvgDrawScope(svgCanvasState, svgGraphics2D, Size(width.toFloat(), height.toFloat()), painterCache) + val svgCanvasState: XYCanvasState = XYCanvasState(ViewConfig()).apply { + this.viewPoint = viewPoint + this.canvasSize = DpSize(width.dp, height.dp) + } + val svgScope = SvgDrawScope(svgCanvasState, svgGraphics2D, painterCache) svgScope.apply { - features.values.filter { - viewPoint.zoom in it.zoomRange - }.forEach { feature -> - drawFeature(feature) - } + features.values.sortedBy { it.z } + .filter { state.viewPoint.zoom in it.zoomRange } + .forEach { feature -> + this@apply.drawFeature(feature) + } } return svgGraphics2D.getSVGElement(id) } @@ -173,8 +178,6 @@ public fun FeatureStateSnapshot.exportToSvg( height: Double, path: java.nio.file.Path, ) { - - val svgString = generateSvg(viewPoint, width, height) - + val svgString: String = generateSvg(viewPoint, width, height) SVGUtils.writeToSVG(path.toFile(), svgString) } \ No newline at end of file From 7d3b219d706232a6f4d05dedc83277278e46e63a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 1 Oct 2023 11:12:15 +0300 Subject: [PATCH 05/14] Move files around --- demo/maps/src/jvmMain/kotlin/Main.kt | 7 ++--- demo/scheme/src/jvmMain/kotlin/Main.kt | 8 +++--- gradle.properties | 6 +++-- maps-kt-compose/build.gradle.kts | 3 ++- .../maps/compose/OsmTileProviderTest.kt | 1 - .../sciprog/maps/compose/canvasControls.kt | 1 + .../sciprog/maps/compose/clickGestures.kt | 27 ++----------------- settings.gradle.kts | 6 ++++- 8 files changed, 22 insertions(+), 37 deletions(-) rename maps-kt-features/src/{jvmMain => commonMain}/kotlin/center/sciprog/maps/compose/canvasControls.kt (99%) rename maps-kt-features/src/{jvmMain => commonMain}/kotlin/center/sciprog/maps/compose/clickGestures.kt (85%) diff --git a/demo/maps/src/jvmMain/kotlin/Main.kt b/demo/maps/src/jvmMain/kotlin/Main.kt index 3bea047..1081d2b 100644 --- a/demo/maps/src/jvmMain/kotlin/Main.kt +++ b/demo/maps/src/jvmMain/kotlin/Main.kt @@ -72,7 +72,7 @@ fun App() { ) { geoJson(javaClass.getResource("/moscow.geo.json")!!) - .modifyAttribute(ColorAttribute, Color.Blue) + .color(Color.Blue) .modifyAttribute(AlphaAttribute, 0.4f) icon(pointOne, Icons.Filled.Home) @@ -153,8 +153,9 @@ fun App() { Color( red = ((gmc.latitude + Angle.piDiv2).degrees * 10 % 1f).toFloat(), green = ((gmc.longitude + Angle.pi).degrees * 10 % 1f).toFloat(), - blue = 0f - ).copy(alpha = 0.3f) + blue = 0f, + alpha = 0.3f + ) } centerCoordinates.filterNotNull().onEach { diff --git a/demo/scheme/src/jvmMain/kotlin/Main.kt b/demo/scheme/src/jvmMain/kotlin/Main.kt index 9aeefae..a74f42d 100644 --- a/demo/scheme/src/jvmMain/kotlin/Main.kt +++ b/demo/scheme/src/jvmMain/kotlin/Main.kt @@ -29,7 +29,7 @@ fun App() { MaterialTheme { val scope = rememberCoroutineScope() - val schemeFeaturesState: FeatureGroup = FeatureGroup.remember(XYCoordinateSpace) { + val features: FeatureGroup = FeatureGroup.remember(XYCoordinateSpace) { background(1600f, 1200f) { painterResource("middle-earth.jpg") } circle(410.52737 to 868.7676).color(Color.Blue) text(410.52737 to 868.7676, "Shire").color(Color.Blue) @@ -53,7 +53,7 @@ fun App() { } val initialViewPoint: ViewPoint = remember { - schemeFeaturesState.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f)) + features.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f)) } var viewPoint: ViewPoint by remember { mutableStateOf(initialViewPoint) } @@ -61,7 +61,7 @@ fun App() { var snapshot: FeatureStateSnapshot? by remember { mutableStateOf(null) } if (snapshot == null) { - snapshot = schemeFeaturesState.snapshot() + snapshot = features.snapshot() } ContextMenuArea( @@ -90,7 +90,7 @@ fun App() { SchemeView( mapState, - schemeFeaturesState, + features, ) } diff --git a/gradle.properties b/gradle.properties index c574f8a..5b599e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,12 @@ kotlin.code.style=official compose.version=1.5.1 -#agp.version=7.4.2 -#android.useAndroidX=true org.jetbrains.compose.experimental.jscanvas.enabled=true +agp.version=8.1.0 +android.useAndroidX=true +android.enableJetifier=true + org.gradle.jvmargs=-Xmx4096m toolsVersion=0.14.9-kotlin-1.9.0 \ No newline at end of file diff --git a/maps-kt-compose/build.gradle.kts b/maps-kt-compose/build.gradle.kts index e6c658d..819ae81 100644 --- a/maps-kt-compose/build.gradle.kts +++ b/maps-kt-compose/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("space.kscience.gradle.mpp") id("org.jetbrains.compose") +// id("com.android.library") `maven-publish` } @@ -39,4 +40,4 @@ readme { feature( id = "osm", ) { "OpenStreetMap tile provider." } -} \ No newline at end of file +} diff --git a/maps-kt-compose/src/jvmTest/kotlin/center/sciprog/maps/compose/OsmTileProviderTest.kt b/maps-kt-compose/src/jvmTest/kotlin/center/sciprog/maps/compose/OsmTileProviderTest.kt index 4c9049c..1e5a367 100644 --- a/maps-kt-compose/src/jvmTest/kotlin/center/sciprog/maps/compose/OsmTileProviderTest.kt +++ b/maps-kt-compose/src/jvmTest/kotlin/center/sciprog/maps/compose/OsmTileProviderTest.kt @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test import java.nio.file.Files import kotlin.test.assertFails -@OptIn(ExperimentalCoroutinesApi::class) class OsmTileProviderTest { // @get:Rule // val rule = createComposeRule() diff --git a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/canvasControls.kt similarity index 99% rename from maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt rename to maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/canvasControls.kt index dddbcb8..747abee 100644 --- a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/canvasControls.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/canvasControls.kt @@ -1,5 +1,6 @@ package center.sciprog.maps.compose +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.drag import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset diff --git a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/clickGestures.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/clickGestures.kt similarity index 85% rename from maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/clickGestures.kt rename to maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/clickGestures.kt index 2939a0d..9f9ada5 100644 --- a/maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/compose/clickGestures.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/compose/clickGestures.kt @@ -26,32 +26,9 @@ public val PointerEvent.position: Offset get() = firstChange.position /** - * Detects tap, double-tap, and long press gestures and calls [onClick], [onDoubleClick], and - * [onLongClick], respectively, when detected. [onPress] is called when the press is detected - * and the [PressGestureScope.tryAwaitRelease] and [PressGestureScope.awaitRelease] can be - * used to detect when pointers have released or the gesture was canceled. - * The first pointer down and final pointer up are consumed, and in the - * case of long press, all changes after the long press is detected are consumed. - * - * Each function parameter receives an [Offset] representing the position relative to the containing - * element. The [Offset] can be outside the actual bounds of the element itself meaning the numbers - * can be negative or larger than the element bounds if the touch target is smaller than the - * [ViewConfiguration.minimumTouchTargetSize]. - * - * When [onDoubleClick] is provided, the tap gesture is detected only after - * the [ViewConfiguration.doubleTapMinTimeMillis] has passed and [onDoubleClick] is called if the - * second tap is started before [ViewConfiguration.doubleTapTimeoutMillis]. If [onDoubleClick] is not - * provided, then [onClick] is called when the pointer up has been received. - * - * After the initial [onPress], if the pointer moves out of the input area, the position change - * is consumed, or another gesture consumes the down or up events, the gestures are considered - * canceled. That means [onDoubleClick], [onLongClick], and [onClick] will not be called after a - * gesture has been canceled. - * - * If the first down event is consumed somewhere else, the entire gesture will be skipped, - * including [onPress]. + * An alternative to [detectTapGestures] with reimplementation of internal logic */ -public suspend fun PointerInputScope.detectClicks( +internal suspend fun PointerInputScope.detectClicks( onDoubleClick: (Density.(PointerEvent) -> Unit)? = null, onLongClick: (Density.(PointerEvent) -> Unit)? = null, onPress: suspend PressGestureScope.(event: PointerEvent) -> Unit = NoPressGesture, diff --git a/settings.gradle.kts b/settings.gradle.kts index afa549e..29d9fec 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,8 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { val toolsVersion: String by extra + val composeVersion = extra["compose.version"] as String + val agpVersion = extra["agp.version"] as String repositories { mavenLocal() @@ -18,11 +20,13 @@ pluginManagement { plugins { // id("com.android.application").version(extra["agp.version"] as String) // id("com.android.library").version(extra["agp.version"] as String) - id("org.jetbrains.compose").version(extra["compose.version"] as String) + id("org.jetbrains.compose") version composeVersion id("space.kscience.gradle.project") version toolsVersion id("space.kscience.gradle.mpp") version toolsVersion id("space.kscience.gradle.jvm") version toolsVersion id("space.kscience.gradle.js") version toolsVersion + id("com.android.application") version agpVersion + id("com.android.library") version agpVersion } } From f05f6e137c3274d4a32bd6395e575e6a8f78c795 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 1 Oct 2023 11:22:02 +0300 Subject: [PATCH 06/14] Add Js targets --- maps-kt-compose/build.gradle.kts | 6 ++++-- .../kotlin/center/sciprog/maps/compose/LruCache.kt | 2 ++ maps-kt-scheme/build.gradle.kts | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/maps-kt-compose/build.gradle.kts b/maps-kt-compose/build.gradle.kts index 819ae81..7731254 100644 --- a/maps-kt-compose/build.gradle.kts +++ b/maps-kt-compose/build.gradle.kts @@ -5,8 +5,10 @@ plugins { `maven-publish` } -kscience{ +kscience { jvm() + js() + useCoroutines() } kotlin { @@ -20,7 +22,7 @@ kotlin { api("io.ktor:ktor-client-core") } } - val jvmTest by getting { + getByName("jvmTest") { dependencies { implementation("io.ktor:ktor-client-cio") implementation(compose.desktop.currentOs) diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/LruCache.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/LruCache.kt index 4a776ee..d599ba5 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/LruCache.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/LruCache.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package center.sciprog.maps.compose import kotlin.jvm.Synchronized diff --git a/maps-kt-scheme/build.gradle.kts b/maps-kt-scheme/build.gradle.kts index 48c27b8..6264557 100644 --- a/maps-kt-scheme/build.gradle.kts +++ b/maps-kt-scheme/build.gradle.kts @@ -6,6 +6,7 @@ plugins { kscience{ jvm() + js() } kotlin { @@ -17,7 +18,7 @@ kotlin { api(compose.foundation) } } - val jvmMain by getting { + getByName("jvmMain"){ dependencies { implementation("org.jfree:org.jfree.svg:5.0.4") api(compose.desktop.currentOs) From d21d6ebb2a5fecbfdf472e5b1d6956162fb0b9d3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 1 Oct 2023 14:05:03 +0300 Subject: [PATCH 07/14] Add (not working yet) JS implementation --- build.gradle.kts | 1 - demo/maps-js/build.gradle.kts | 26 +++ demo/maps-js/src/jsMain/kotlin/Main.kt | 172 ++++++++++++++++++ demo/maps-js/src/jsMain/resources/index.html | 13 ++ gradle.properties | 2 +- maps-kt-compose/build.gradle.kts | 14 +- .../compose/OpenStreetMapTileProvider.kt | 91 +++++++++ maps-kt-core/build.gradle.kts | 1 + .../sciprog/maps/features/CanvasState.kt | 5 +- .../sciprog/maps/features/FeatureDrawScope.kt | 6 +- settings.gradle.kts | 3 +- trajectory-kt/build.gradle.kts | 2 +- 12 files changed, 327 insertions(+), 9 deletions(-) create mode 100644 demo/maps-js/build.gradle.kts create mode 100644 demo/maps-js/src/jsMain/kotlin/Main.kt create mode 100644 demo/maps-js/src/jsMain/resources/index.html create mode 100644 maps-kt-compose/src/jsMain/kotlin/compose/OpenStreetMapTileProvider.kt diff --git a/build.gradle.kts b/build.gradle.kts index a461ddb..11adfc1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,6 @@ ksciencePublish { subprojects { repositories { - maven("https://maven.pkg.jetbrains.space/mipt-npm/p/sci/dev") google() mavenCentral() maven("https://repo.kotlin.link") diff --git a/demo/maps-js/build.gradle.kts b/demo/maps-js/build.gradle.kts new file mode 100644 index 0000000..3f46b2c --- /dev/null +++ b/demo/maps-js/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +val ktorVersion: String by rootProject.extra + +kotlin { + js { + browser() + binaries.executable() + } + sourceSets { + val jsMain by getting { + dependencies { + implementation(projects.mapsKtCompose) + implementation(compose.runtime) + implementation(compose.html.core) + } + } + } +} + +compose { + web {} +} \ No newline at end of file diff --git a/demo/maps-js/src/jsMain/kotlin/Main.kt b/demo/maps-js/src/jsMain/kotlin/Main.kt new file mode 100644 index 0000000..f67c8df --- /dev/null +++ b/demo/maps-js/src/jsMain/kotlin/Main.kt @@ -0,0 +1,172 @@ +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.PointerMatcher +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFontFamilyResolver +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.font.createFontFamilyResolver +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import center.sciprog.attributes.Attributes +import center.sciprog.maps.compose.* +import center.sciprog.maps.coordinates.GeodeticMapCoordinates +import center.sciprog.maps.coordinates.Gmc +import center.sciprog.maps.coordinates.kilometers +import center.sciprog.maps.features.* +import io.ktor.client.HttpClient +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import org.jetbrains.compose.web.renderComposable +import space.kscience.kmath.geometry.Angle +import space.kscience.kmath.geometry.degrees +import space.kscience.kmath.geometry.radians +import kotlin.math.PI +import kotlin.random.Random + +public fun GeodeticMapCoordinates.toShortString(): String = + "${(latitude.degrees).toString().take(6)}:${(longitude.degrees).toString().take(6)}" + + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun App() { + + val scope = rememberCoroutineScope() + + val mapTileProvider = remember { + OpenStreetMapTileProvider( + client = HttpClient(), + ) + } + + val centerCoordinates = MutableStateFlow(null) + + val pointOne = 55.568548 to 37.568604 + val pointTwo = 55.929444 to 37.518434 +// val pointThree = 60.929444 to 37.518434 + + MapView( + mapTileProvider = mapTileProvider, + config = ViewConfig( + onViewChange = { centerCoordinates.value = focus }, + onClick = { _, viewPoint -> + println(viewPoint) + } + ) + ) { + +// icon(pointOne, Icons.Filled.Home) + + val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) + val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) + val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp)) + .color(Color.Magenta) + + draggableLine(marker1, marker2, id = "line 1").color(Color.Red).onClick { + println("line 1 clicked") + } + draggableLine(marker2, marker3, id = "line 2").color(Color.DarkGray).onClick { + println("line 2 clicked") + } + draggableLine(marker3, marker1, id = "line 3").color(Color.Blue).onClick { + println("line 3 clicked") + } + + + multiLine( + points = listOf( + 55.742465 to 37.615812, + 55.742713 to 37.616370, + 55.742815 to 37.616659, + 55.742320 to 37.617132, + 55.742086 to 37.616566, + 55.741715 to 37.616716 + ), + ) + + //remember feature ref + val circleId = circle( + centerCoordinates = pointTwo, + ) + scope.launch { + while (isActive) { + delay(200) + circleId.color(Color(Random.nextFloat(), Random.nextFloat(), Random.nextFloat())) + } + } + + arc(pointOne, 10.0.kilometers, (PI / 4).radians, -Angle.pi / 2) + + + line(pointOne, pointTwo, id = "line") + text(pointOne, "Home", font = { size = 32f }) + + + pixelMap( + space.Rectangle( + Gmc(latitude = 55.58461879539754.degrees, longitude = 37.8746197303493.degrees), + Gmc(latitude = 55.442792937592415.degrees, longitude = 38.132240805463844.degrees) + ), + 0.005.degrees, + 0.005.degrees + ) { gmc -> + Color( + red = ((gmc.latitude + Angle.piDiv2).degrees * 10 % 1f).toFloat(), + green = ((gmc.longitude + Angle.pi).degrees * 10 % 1f).toFloat(), + blue = 0f, + alpha = 0.3f + ) + } + + centerCoordinates.filterNotNull().onEach { + group(id = "center") { + circle(center = it, id = "circle", size = 1.dp).color(Color.Blue) + text(position = it, it.toShortString(), id = "text").color(Color.Blue) + } + }.launchIn(scope) + + //Add click listeners for all polygons + forEachWithType> { ref -> + ref.onClick(PointerMatcher.Primary) { + println("Click on ${ref.id}") + //draw in top-level scope + with(this@MapView) { + multiLine( + ref.resolve().points, + attributes = Attributes(ZAttribute, 10f), + id = "selected", + ).modifyAttribute(StrokeAttribute, 4f).color(Color.Magenta) + } + } + } + } + +} + + +fun main() { + renderComposable(rootElementId = "root") { + CompositionLocalProvider( + LocalDensity provides Density(1.0f), + LocalLayoutDirection provides LayoutDirection.Ltr, +// LocalViewConfiguration provides DefaultViewConfiguration(Density(1.0f)), +// LocalInputModeManager provides InputModeManagerObject, + LocalFontFamilyResolver provides createFontFamilyResolver() + ) { + App() + } + } +} diff --git a/demo/maps-js/src/jsMain/resources/index.html b/demo/maps-js/src/jsMain/resources/index.html new file mode 100644 index 0000000..225341b --- /dev/null +++ b/demo/maps-js/src/jsMain/resources/index.html @@ -0,0 +1,13 @@ + + + + + Maps-kt demo + + + + +
+ + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5b599e7..043026b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ kotlin.code.style=official -compose.version=1.5.1 +compose.version=1.5.2 org.jetbrains.compose.experimental.jscanvas.enabled=true agp.version=8.1.0 diff --git a/maps-kt-compose/build.gradle.kts b/maps-kt-compose/build.gradle.kts index 7731254..e266367 100644 --- a/maps-kt-compose/build.gradle.kts +++ b/maps-kt-compose/build.gradle.kts @@ -19,9 +19,21 @@ kotlin { api(projects.mapsKtFeatures) api(compose.foundation) api(project.dependencies.platform(spclibs.ktor.bom)) - api("io.ktor:ktor-client-core") } } + + getByName("jvmMain"){ + dependencies { + api("io.ktor:ktor-client-cio") + } + } + + getByName("jsMain"){ + dependencies { + api("io.ktor:ktor-client-js") + } + } + getByName("jvmTest") { dependencies { implementation("io.ktor:ktor-client-cio") diff --git a/maps-kt-compose/src/jsMain/kotlin/compose/OpenStreetMapTileProvider.kt b/maps-kt-compose/src/jsMain/kotlin/compose/OpenStreetMapTileProvider.kt new file mode 100644 index 0000000..f6a6941 --- /dev/null +++ b/maps-kt-compose/src/jsMain/kotlin/compose/OpenStreetMapTileProvider.kt @@ -0,0 +1,91 @@ +package center.sciprog.maps.compose + +import io.github.oshai.kotlinlogging.KotlinLogging +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.client.statement.readBytes +import io.ktor.http.Url +import io.ktor.util.decodeBase64Bytes +import io.ktor.util.encodeBase64 +import kotlinx.browser.window +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit +import org.jetbrains.skia.Image +import org.w3c.dom.Storage + +/** + * A [MapTileProvider] based on Open Street Map API. With in-memory and file cache + */ +public class OpenStreetMapTileProvider( + private val client: HttpClient, + private val storage: Storage = window.localStorage, + parallelism: Int = 4, + cacheCapacity: Int = 200, + private val osmBaseUrl: String = "https://tile.openstreetmap.org", +) : MapTileProvider { + private val semaphore = Semaphore(parallelism) + private val cache = LruCache>(cacheCapacity) + + private fun TileId.osmUrl() = Url("$osmBaseUrl/${zoom}/${i}/${j}.png") + + private fun TileId.imageName() = "${zoom}/${i}/${j}.png" + + private fun TileId.readImage() = storage.getItem(imageName()) + + /** + * Download and cache the tile image + */ + private fun CoroutineScope.downloadImageAsync(id: TileId): Deferred = async { + + id.readImage()?.let { imageString -> + try { + return@async Image.makeFromEncoded(imageString.decodeBase64Bytes()) + } catch (ex: Exception) { + logger.debug { "Failed to load image from $imageString" } + storage.removeItem(id.imageName()) + } + } + + //semaphore works only for actual download + semaphore.withPermit { + val url = id.osmUrl() + val byteArray = client.get(url).readBytes() + logger.debug { "Finished downloading map tile with id $id from $url" } + val imageName = id.imageName() + logger.debug { "Caching map tile $id to $imageName" } + storage.setItem(imageName, byteArray.encodeBase64()) + Image.makeFromEncoded(byteArray) + } + } + + override fun CoroutineScope.loadTileAsync( + tileId: TileId, + ): Deferred { + + //start image download + val imageDeferred: Deferred = cache.getOrPut(tileId) { + downloadImageAsync(tileId) + } + + //collect the result asynchronously + return async { + val image: Image = runCatching { imageDeferred.await() }.onFailure { + if (it !is CancellationException) { + logger.error(it) { "Failed to load tile image with id=$tileId" } + } + cache.remove(tileId) + }.getOrThrow() + + MapTile(tileId, image) + } + } + + + public companion object { + private val logger = KotlinLogging.logger("OpenStreetMapCache") + } +} \ No newline at end of file diff --git a/maps-kt-core/build.gradle.kts b/maps-kt-core/build.gradle.kts index a7f9a0e..b5ecff3 100644 --- a/maps-kt-core/build.gradle.kts +++ b/maps-kt-core/build.gradle.kts @@ -8,6 +8,7 @@ val kmathVersion: String by rootProject.extra kscience{ jvm() js() + native() useSerialization() dependencies{ diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt index 7309bbb..1572b3c 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/CanvasState.kt @@ -1,6 +1,9 @@ package center.sciprog.maps.features -import androidx.compose.runtime.* +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.* diff --git a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt index e5998c3..b2f8d79 100644 --- a/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt +++ b/maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureDrawScope.kt @@ -48,11 +48,11 @@ public class ComposeFeatureDrawScope( drawScope: DrawScope, state: CanvasState, private val painterCache: Map, Painter>, - private val textMeasurer: TextMeasurer, + private val textMeasurer: TextMeasurer?, ) : FeatureDrawScope(state), DrawScope by drawScope { override fun drawText(text: String, position: Offset, attributes: Attributes) { try { - drawText(textMeasurer, text, position) + drawText(textMeasurer?: error("Text measurer not defined"), text, position) } catch (ex: Exception) { logger.error(ex) { "Failed to measure text" } } @@ -77,7 +77,7 @@ public fun FeatureCanvas( modifier: Modifier = Modifier, draw: FeatureDrawScope.() -> Unit = {}, ) { - val textMeasurer = rememberTextMeasurer(200) + val textMeasurer = rememberTextMeasurer(0) val painterCache: Map, Painter> = features.features.flatMap { if (it is FeatureGroup) it.features else listOf(it) diff --git a/settings.gradle.kts b/settings.gradle.kts index 29d9fec..8307daa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -59,6 +59,7 @@ include( ":demo:maps", ":demo:scheme", ":demo:polygon-editor", - ":demo:trajectory-playground" + ":demo:trajectory-playground", + ":demo:maps-js" ) diff --git a/trajectory-kt/build.gradle.kts b/trajectory-kt/build.gradle.kts index 0783429..45512f0 100644 --- a/trajectory-kt/build.gradle.kts +++ b/trajectory-kt/build.gradle.kts @@ -10,7 +10,7 @@ val kmathVersion: String by rootProject.extra kscience{ jvm() js() -// native() + native() useContextReceivers() useSerialization() From ea7869e39d6cc690f0808f933b432a75c07cd2d5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 15 Nov 2023 16:43:13 +0300 Subject: [PATCH 08/14] First preview of 0.3.0 --- build.gradle.kts | 13 ++-------- gradle.properties | 4 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- maps-kt-compose/build.gradle.kts | 4 +++ maps-kt-leaflet/build.gradle.kts | 31 +++++++++++++++++++++++ maps-kt-leaflet/src/jsMain/kotlin/main.kt | 7 +++++ settings.gradle.kts | 1 + 7 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 maps-kt-leaflet/build.gradle.kts create mode 100644 maps-kt-leaflet/src/jsMain/kotlin/main.kt diff --git a/build.gradle.kts b/build.gradle.kts index 11adfc1..abaa2d7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import space.kscience.gradle.isInDevelopment import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useSPCTeam @@ -24,15 +23,8 @@ ksciencePublish { useApache2Licence() useSPCTeam() } - github("SciProgCentre", "maps-kt") - space( - if (isInDevelopment) { - "https://maven.pkg.jetbrains.space/spc/p/sci/dev" - } else { - "https://maven.pkg.jetbrains.space/spc/p/sci/maven" - } - ) - sonatype() + repository("spc","https://maven.sciprog.center/kscience") + sonatype("https://oss.sonatype.org") } subprojects { @@ -47,4 +39,3 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") - diff --git a/gradle.properties b/gradle.properties index 043026b..fe14959 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ kotlin.code.style=official -compose.version=1.5.2 +compose.version=1.5.10 org.jetbrains.compose.experimental.jscanvas.enabled=true agp.version=8.1.0 @@ -9,4 +9,4 @@ android.enableJetifier=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.9-kotlin-1.9.0 \ No newline at end of file +toolsVersion=0.15.0-kotlin-1.9.20 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fae0804..e411586 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/maps-kt-compose/build.gradle.kts b/maps-kt-compose/build.gradle.kts index e266367..c7a0359 100644 --- a/maps-kt-compose/build.gradle.kts +++ b/maps-kt-compose/build.gradle.kts @@ -55,3 +55,7 @@ readme { id = "osm", ) { "OpenStreetMap tile provider." } } + +//tasks.getByName("downloadWix"){ +// duplicatesStrategy = DuplicatesStrategy.WARN +//} diff --git a/maps-kt-leaflet/build.gradle.kts b/maps-kt-leaflet/build.gradle.kts new file mode 100644 index 0000000..6644712 --- /dev/null +++ b/maps-kt-leaflet/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + id("space.kscience.gradle.mpp") + id("org.jetbrains.compose") + `maven-publish` +} + +kscience{ + js { + binaries.executable() + } +} + +kotlin { + sourceSets { + val jsMain by getting { + dependencies { + implementation(projects.mapsKtCompose) + implementation(compose.runtime) + implementation(compose.html.core) + implementation(npm("@types/leaflet", "1.9.6")) + } + } + } +} + +compose { + experimental.web{ + application{} + } +// web{} +} \ No newline at end of file diff --git a/maps-kt-leaflet/src/jsMain/kotlin/main.kt b/maps-kt-leaflet/src/jsMain/kotlin/main.kt new file mode 100644 index 0000000..e6d832d --- /dev/null +++ b/maps-kt-leaflet/src/jsMain/kotlin/main.kt @@ -0,0 +1,7 @@ +import org.jetbrains.skiko.wasm.onWasmReady + +fun main() { + onWasmReady { + + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 8307daa..4254c8c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -56,6 +56,7 @@ include( ":maps-kt-features", ":maps-kt-compose", ":maps-kt-scheme", +// ":maps-kt-leaflet", ":demo:maps", ":demo:scheme", ":demo:polygon-editor", From 327cef9ea9b5738f9bc036e96ea7ad4b7ed78fe0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 23 Feb 2024 12:11:43 +0300 Subject: [PATCH 09/14] Update dependencies. Add wasm demo --- build.gradle.kts | 5 +- demo/maps-js/build.gradle.kts | 26 --- demo/maps-js/src/jsMain/kotlin/Main.kt | 172 ------------------ demo/maps-js/src/jsMain/resources/index.html | 13 -- demo/maps-wasm/build.gradle.kts | 30 +++ demo/maps-wasm/src/wasmJsMain/kotlin/Main.kt | 79 ++++++++ .../src/wasmJsMain/resources/index.html | 12 ++ .../src/wasmJsMain/resources/middle-earth.jpg | Bin 0 -> 480042 bytes demo/maps/src/jvmMain/kotlin/Main.kt | 8 +- .../src/jvmMain/resources/joker2023.png | Bin 0 -> 991405 bytes .../src/jvmMain/kotlin/Main.kt | 42 ++--- gradle.properties | 5 +- gradle/wrapper/gradle-wrapper.properties | 2 +- maps-kt-compose/build.gradle.kts | 15 +- .../sciprog/maps/compose/MapCanvasState.kt | 4 +- .../sciprog/maps/compose/mapFeatures.kt | 3 +- maps-kt-core/build.gradle.kts | 2 + .../coordinates/GeodeticMapCoordinates.kt | 3 +- .../sciprog/maps/coordinates/GmcCurve.kt | 2 +- .../maps/coordinates/MercatorProjection.kt | 8 +- .../maps/coordinates/WebMercatorProjection.kt | 5 +- .../sciprog/maps/coordinates/DistanceTest.kt | 6 +- .../sciprog/maps/coordinates/MercatorTest.kt | 9 +- maps-kt-features/build.gradle.kts | 23 ++- .../center.sciprog.attributes/Attribute.kt | 22 --- .../center.sciprog.attributes/Attributes.kt | 68 ------- .../AttributesBuilder.kt | 47 ----- .../center/sciprog/maps/features/Feature.kt | 7 +- .../sciprog/maps/features/FeatureDrawScope.kt | 6 +- .../sciprog/maps/features/FeatureFont.kt | 5 - .../sciprog/maps/features/FeatureGroup.kt | 19 +- .../maps/features/compositeFeatures.kt | 6 +- .../sciprog/maps/features/drawFeature.kt | 13 +- .../maps/features/mapFeatureAttributes.kt | 13 +- .../attributes/AttributesSerializationTest.kt | 37 ++-- .../sciprog/maps/features/FeatureFont.kt | 5 - .../sciprog/maps/features/FeatureFont.kt | 5 - maps-kt-geojson/build.gradle.kts | 4 +- .../sciprog/maps/geojson/GeoJsonGeometry.kt | 5 +- .../geojson/GeoJsonPropertiesAttribute.kt | 2 +- .../sciprog/maps/geojson/geoJsonToMap.kt | 2 +- maps-kt-scheme/build.gradle.kts | 5 +- .../center/sciprog/maps/scheme/SchemeView.kt | 6 +- .../kotlin/center/sciprog/maps/scheme/XY.kt | 2 +- .../sciprog/maps/scheme/schemeFeatures.kt | 2 +- .../center/sciprog/maps/svg/SvgCanvas.kt | 2 +- .../center/sciprog/maps/svg/SvgDrawScope.kt | 7 +- settings.gradle.kts | 2 +- trajectory-kt/build.gradle.kts | 5 +- .../space/kscience}/AttributesSerializer.kt | 29 ++- .../geometry => }/geometryExtensions.kt | 32 ++-- .../kmath/geometry/polygonExtensions.kt | 21 --- .../space/kscience/polygonExtensions.kt | 28 +++ .../space/kscience/trajectory/DubinsPath.kt | 105 ++++++----- .../space/kscience/trajectory/Obstacle.kt | 27 ++- .../space/kscience/trajectory/Obstacles.kt | 28 ++- .../space/kscience/trajectory/Pose2D.kt | 31 ++-- .../space/kscience/trajectory/Trajectory2D.kt | 45 +++-- .../kscience/trajectory/circumvention.kt | 10 +- .../space/kscience/kmath/geometry/ArcTests.kt | 17 +- .../kscience/kmath/geometry/CircleTests.kt | 18 +- .../kscience/kmath/geometry/LineTests.kt | 15 +- .../space/kscience/trajectory/DubinsTests.kt | 6 +- .../space/kscience/trajectory/ObstacleTest.kt | 16 +- .../space/kscience/trajectory/TangentTest.kt | 11 +- .../space/kscience/trajectory/testutils.kt | 9 +- 66 files changed, 541 insertions(+), 678 deletions(-) delete mode 100644 demo/maps-js/build.gradle.kts delete mode 100644 demo/maps-js/src/jsMain/kotlin/Main.kt delete mode 100644 demo/maps-js/src/jsMain/resources/index.html create mode 100644 demo/maps-wasm/build.gradle.kts create mode 100644 demo/maps-wasm/src/wasmJsMain/kotlin/Main.kt create mode 100644 demo/maps-wasm/src/wasmJsMain/resources/index.html create mode 100644 demo/maps-wasm/src/wasmJsMain/resources/middle-earth.jpg create mode 100644 demo/scheme/src/jvmMain/resources/joker2023.png delete mode 100644 maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attribute.kt delete mode 100644 maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt delete mode 100644 maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesBuilder.kt delete mode 100644 maps-kt-features/src/commonMain/kotlin/center/sciprog/maps/features/FeatureFont.kt delete mode 100644 maps-kt-features/src/jsMain/kotlin/center/sciprog/maps/features/FeatureFont.kt delete mode 100644 maps-kt-features/src/jvmMain/kotlin/center/sciprog/maps/features/FeatureFont.kt rename {maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes => trajectory-kt/src/commonMain/kotlin/space/kscience}/AttributesSerializer.kt (68%) rename trajectory-kt/src/commonMain/kotlin/space/kscience/{kmath/geometry => }/geometryExtensions.kt (64%) delete mode 100644 trajectory-kt/src/commonMain/kotlin/space/kscience/kmath/geometry/polygonExtensions.kt create mode 100644 trajectory-kt/src/commonMain/kotlin/space/kscience/polygonExtensions.kt diff --git a/build.gradle.kts b/build.gradle.kts index abaa2d7..a624464 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,16 +5,15 @@ plugins { id("space.kscience.gradle.project") } -val kmathVersion: String by extra("0.3.1") +val kmathVersion: String by extra("0.4.0-RC2") allprojects { group = "center.sciprog" - version = "0.3.0-dev-1" + version = "0.3.0-dev-2" repositories { mavenLocal() maven("https://repo.kotlin.link") - maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev") } } diff --git a/demo/maps-js/build.gradle.kts b/demo/maps-js/build.gradle.kts deleted file mode 100644 index 3f46b2c..0000000 --- a/demo/maps-js/build.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -val ktorVersion: String by rootProject.extra - -kotlin { - js { - browser() - binaries.executable() - } - sourceSets { - val jsMain by getting { - dependencies { - implementation(projects.mapsKtCompose) - implementation(compose.runtime) - implementation(compose.html.core) - } - } - } -} - -compose { - web {} -} \ No newline at end of file diff --git a/demo/maps-js/src/jsMain/kotlin/Main.kt b/demo/maps-js/src/jsMain/kotlin/Main.kt deleted file mode 100644 index f67c8df..0000000 --- a/demo/maps-js/src/jsMain/kotlin/Main.kt +++ /dev/null @@ -1,172 +0,0 @@ -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.PointerMatcher -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalFontFamilyResolver -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.text.font.createFontFamilyResolver -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp -import center.sciprog.attributes.Attributes -import center.sciprog.maps.compose.* -import center.sciprog.maps.coordinates.GeodeticMapCoordinates -import center.sciprog.maps.coordinates.Gmc -import center.sciprog.maps.coordinates.kilometers -import center.sciprog.maps.features.* -import io.ktor.client.HttpClient -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import org.jetbrains.compose.web.renderComposable -import space.kscience.kmath.geometry.Angle -import space.kscience.kmath.geometry.degrees -import space.kscience.kmath.geometry.radians -import kotlin.math.PI -import kotlin.random.Random - -public fun GeodeticMapCoordinates.toShortString(): String = - "${(latitude.degrees).toString().take(6)}:${(longitude.degrees).toString().take(6)}" - - -@OptIn(ExperimentalFoundationApi::class) -@Composable -fun App() { - - val scope = rememberCoroutineScope() - - val mapTileProvider = remember { - OpenStreetMapTileProvider( - client = HttpClient(), - ) - } - - val centerCoordinates = MutableStateFlow(null) - - val pointOne = 55.568548 to 37.568604 - val pointTwo = 55.929444 to 37.518434 -// val pointThree = 60.929444 to 37.518434 - - MapView( - mapTileProvider = mapTileProvider, - config = ViewConfig( - onViewChange = { centerCoordinates.value = focus }, - onClick = { _, viewPoint -> - println(viewPoint) - } - ) - ) { - -// icon(pointOne, Icons.Filled.Home) - - val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp)) - .color(Color.Magenta) - val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp)) - .color(Color.Magenta) - val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp)) - .color(Color.Magenta) - - draggableLine(marker1, marker2, id = "line 1").color(Color.Red).onClick { - println("line 1 clicked") - } - draggableLine(marker2, marker3, id = "line 2").color(Color.DarkGray).onClick { - println("line 2 clicked") - } - draggableLine(marker3, marker1, id = "line 3").color(Color.Blue).onClick { - println("line 3 clicked") - } - - - multiLine( - points = listOf( - 55.742465 to 37.615812, - 55.742713 to 37.616370, - 55.742815 to 37.616659, - 55.742320 to 37.617132, - 55.742086 to 37.616566, - 55.741715 to 37.616716 - ), - ) - - //remember feature ref - val circleId = circle( - centerCoordinates = pointTwo, - ) - scope.launch { - while (isActive) { - delay(200) - circleId.color(Color(Random.nextFloat(), Random.nextFloat(), Random.nextFloat())) - } - } - - arc(pointOne, 10.0.kilometers, (PI / 4).radians, -Angle.pi / 2) - - - line(pointOne, pointTwo, id = "line") - text(pointOne, "Home", font = { size = 32f }) - - - pixelMap( - space.Rectangle( - Gmc(latitude = 55.58461879539754.degrees, longitude = 37.8746197303493.degrees), - Gmc(latitude = 55.442792937592415.degrees, longitude = 38.132240805463844.degrees) - ), - 0.005.degrees, - 0.005.degrees - ) { gmc -> - Color( - red = ((gmc.latitude + Angle.piDiv2).degrees * 10 % 1f).toFloat(), - green = ((gmc.longitude + Angle.pi).degrees * 10 % 1f).toFloat(), - blue = 0f, - alpha = 0.3f - ) - } - - centerCoordinates.filterNotNull().onEach { - group(id = "center") { - circle(center = it, id = "circle", size = 1.dp).color(Color.Blue) - text(position = it, it.toShortString(), id = "text").color(Color.Blue) - } - }.launchIn(scope) - - //Add click listeners for all polygons - forEachWithType> { ref -> - ref.onClick(PointerMatcher.Primary) { - println("Click on ${ref.id}") - //draw in top-level scope - with(this@MapView) { - multiLine( - ref.resolve().points, - attributes = Attributes(ZAttribute, 10f), - id = "selected", - ).modifyAttribute(StrokeAttribute, 4f).color(Color.Magenta) - } - } - } - } - -} - - -fun main() { - renderComposable(rootElementId = "root") { - CompositionLocalProvider( - LocalDensity provides Density(1.0f), - LocalLayoutDirection provides LayoutDirection.Ltr, -// LocalViewConfiguration provides DefaultViewConfiguration(Density(1.0f)), -// LocalInputModeManager provides InputModeManagerObject, - LocalFontFamilyResolver provides createFontFamilyResolver() - ) { - App() - } - } -} diff --git a/demo/maps-js/src/jsMain/resources/index.html b/demo/maps-js/src/jsMain/resources/index.html deleted file mode 100644 index 225341b..0000000 --- a/demo/maps-js/src/jsMain/resources/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Maps-kt demo - - - - -
- - - \ No newline at end of file diff --git a/demo/maps-wasm/build.gradle.kts b/demo/maps-wasm/build.gradle.kts new file mode 100644 index 0000000..58aa306 --- /dev/null +++ b/demo/maps-wasm/build.gradle.kts @@ -0,0 +1,30 @@ +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl + +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +//val ktorVersion: String by rootProject.extra + +kotlin { + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + browser() + binaries.executable() + } + sourceSets { + val wasmJsMain by getting { + dependencies { + implementation(projects.mapsKtScheme) + @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) api(compose.components.resources) + } + } + } +} + +compose { + experimental.web{ + application{} + } +} \ No newline at end of file diff --git a/demo/maps-wasm/src/wasmJsMain/kotlin/Main.kt b/demo/maps-wasm/src/wasmJsMain/kotlin/Main.kt new file mode 100644 index 0000000..8c655aa --- /dev/null +++ b/demo/maps-wasm/src/wasmJsMain/kotlin/Main.kt @@ -0,0 +1,79 @@ +@file:OptIn(ExperimentalComposeUiApi::class, ExperimentalResourceApi::class) + +import androidx.compose.runtime.* +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.window.CanvasBasedWindow +import center.sciprog.maps.features.FeatureGroup +import center.sciprog.maps.features.ViewConfig +import center.sciprog.maps.features.ViewPoint +import center.sciprog.maps.features.color +import center.sciprog.maps.scheme.* +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.painterResource +import space.kscience.kmath.geometry.Angle + + +@Composable +fun App() { + + val scope = rememberCoroutineScope() + + + val features: FeatureGroup = FeatureGroup.remember(XYCoordinateSpace) { + background(1600f, 1200f) { painterResource(DrawableResource("middle-earth.jpg")) } + circle(410.52737 to 868.7676).color(Color.Blue) + text(410.52737 to 868.7676, "Shire").color(Color.Blue) + circle(1132.0881 to 394.99127).color(Color.Red) + text(1132.0881 to 394.99127, "Ordruin").color(Color.Red) + arc(center = 1132.0881 to 394.99127, radius = 20f, startAngle = Angle.zero, Angle.piTimes2) + + //circle(410.52737 to 868.7676, id = "hobbit") + + scope.launch { + var t = 0.0 + while (isActive) { + val x = 410.52737 + t * (1132.0881 - 410.52737) + val y = 868.7676 + t * (394.99127 - 868.7676) + circle(x to y, id = "hobbit").color(Color.Green) + delay(100) + t += 0.005 + if (t >= 1.0) t = 0.0 + } + } + } + + val initialViewPoint: ViewPoint = remember { + features.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f)) + } + + var viewPoint: ViewPoint by remember { mutableStateOf(initialViewPoint) } + + val mapState: XYCanvasState = XYCanvasState.remember( + ViewConfig( + onClick = { _, click -> + println("${click.focus.x}, ${click.focus.y}") + }, + onViewChange = { viewPoint = this } + ), + initialViewPoint = initialViewPoint, + ) + + SchemeView( + mapState, + features, + ) + +} + + +fun main() { +// renderComposable(rootElementId = "root") { + CanvasBasedWindow("Maps demo", canvasElementId = "ComposeTarget") { + App() + } +} diff --git a/demo/maps-wasm/src/wasmJsMain/resources/index.html b/demo/maps-wasm/src/wasmJsMain/resources/index.html new file mode 100644 index 0000000..5b0eca0 --- /dev/null +++ b/demo/maps-wasm/src/wasmJsMain/resources/index.html @@ -0,0 +1,12 @@ + + + + + Compose App + + + + + + + \ No newline at end of file diff --git a/demo/maps-wasm/src/wasmJsMain/resources/middle-earth.jpg b/demo/maps-wasm/src/wasmJsMain/resources/middle-earth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ed4735ce783b82ceb168eaa8378314ba8b5b72c GIT binary patch literal 480042 zcmb5URZtuZ6D*3mI|O%kx8T0`;_l1h?t$R$?(U1byD#n%LU0c(BtVk?e&^vR8$l+3_J`B zbaV_N99%3sQX(=kQX&!(3MwWVicbubBqX$)v<%EFZ0v00G+ew~th`LDY^?C8sHhld z7=#!Ygsc=K6s-Tx@xO66d^Dt16d6Q#dN>4pctm{o|4qUPz`-FP!vCLD|NlTlLO@1= zheL&j`#<&ns{sd(fcW1L|J#GZLWGAyz(d6QZ)9<ZqAd>`axxQ!o5N z$4NPZ5tF)Qmh5^Jbl-?naQ*1o8)X%Sg4OZWPBn8Y8!M2teYUGrZPND%G^babgRkfS z*)~ya-=s7#J=mN(mqoH6P zm&E9RX5vvODh-JKMWXTJHe5d6B(}IOe5T57%ul10&Uq`L`plgWjQyLj&P=&ECZgJ z05P|3RVIV%#Phd$R-&+W((Nrkkm<+I-sci@_8mFIt3pEOY(k?oxZgJ^)Jb{pMSuj3 zy#bqsqilzXA{#GQjWNm3JiJK*ZPt!mf}0A*zIDcWyHSJu_Bc2{G!@ctd-vwAYr}$w zF*;*R)7M<0<;KpfsfvBfbbYu=khkD&RxtshT-A1y8?#O;ZCfdVLfU$GDnO)*yE-AB zrX0IEijIMK{jdmyd;WoA%_MWFi0%-$J^>{I8C@|x{k~005XlGUH{u$l+|R){?>6+8 z@G3fSncC<&wg$Z^UOz813Uh)3$Fe4~V}^4Fw9Etd62X<0DkTJfFP!;iJ{jLAsyQ07 zHyLSUg{oJ3D_Rw;4`)0A(fruF75wi%u3>z9hQ(0kx+Xcy&D zmct-iMFXTDJUZDLx%~|Pr6%;-8q0zw9Kk*EB7Q~3ALyIgrh1=rST|CW4_c-6auc|B z#;1$MC5$slMUpLYIB?u$g3c?XjwVvlYcS75>7)CQY`IFP&r<_mqf0vdAZaAluHJsb z$n`~=y+Gx@R@>4bev@D+Hm}c$Z@J1+(cwExEVtfITfRYnj@DL%X5Im}Dc}&3!rse? zwd&NBr~o$ci0<1<=T#$YU~Y3Y%}PuF?v@MznfxUqQd*|^1hsq|&C{9TqDBWpAZ_AA z0d;(mG*KPP>q4d^3LZLH71^iUndnw&O@iM=ELU2!F~nMdAU<*XTPeUcO*Ia{HW!Gt zN}G=E1(-<_Wz|zbP$5I!nPg&G#Q!OY@K6&zmBx=Csk{^L{hN23Zs-rsXHPr{?i6s2 z9MbMrlApBSBzDUz1jn2xG$`jbaJad-$-|P`vZ83a=~55UHX<{~n2yjq+{X+iKq<0U zaC{C72ClLZHhp3QWb8l30OLM^5o3Msk#EAaFj88 zSF-UdwV5o_6h@w?Bl2FtZVV}P4ZN~BMGt+q|kUDc(CFx zP~OddGdN;@B!UsloVotGfNau2fZl~+oDG{l{8Q>RFySYI2yG!QL3xQ3XJPwh<C% zr14C>g7c9c23{Kun8sI3lyI@*Fq@=Pyxb7hMM?6&)rdYG%(d9aYJ52UhsaFIuZ%2+ zqqn0T{A2iiV_&Ic^M<-5+*hNWVFUTTIlcP|u%fY}+F+baE(8HA&j&KNX>*)no3imM z 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

Ud@``2lpk~!DnXUp*3`r?Tii4Qv}Sj|Z>B;J0j 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 (ux0=wwKahvYw8??VMe2sj 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¬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 )ws8v7 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