From 7771a9b7b9653b9c497b1d17ab911c2e7b6a58a5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 10 Jul 2022 18:32:37 +0300 Subject: [PATCH] Add vector rendering --- src/jvmMain/kotlin/Main.kt | 6 ++- .../centre/sciprog/maps/compose/MapFeature.kt | 33 +++++++++++++-- .../centre/sciprog/maps/compose/MapView.kt | 41 ++++++++++++------- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/jvmMain/kotlin/Main.kt b/src/jvmMain/kotlin/Main.kt index 4ea671e..68ce992 100644 --- a/src/jvmMain/kotlin/Main.kt +++ b/src/jvmMain/kotlin/Main.kt @@ -1,6 +1,8 @@ // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home import androidx.compose.runtime.Composable import androidx.compose.ui.window.Window import androidx.compose.ui.window.application @@ -18,9 +20,11 @@ fun App() { val pointOne = 55.568548 to 37.568604 val pointTwo = 55.929444 to 37.518434 val features = buildList { - add(MapCircleFeature(pointOne)) +// add(MapCircleFeature(pointOne)) add(MapCircleFeature(pointTwo)) add(MapLineFeature(pointOne, pointTwo)) + add(MapTextFeature(pointOne.toCoordinates(), "Home")) + add(MapVectorImageFeature(pointOne.toCoordinates(), Icons.Filled.Home)) } MapView(viewPoint, features = features, cacheDirectory = Path.of("mapCache")) } diff --git a/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapFeature.kt b/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapFeature.kt index 8ba5b7b..e96e156 100644 --- a/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapFeature.kt +++ b/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapFeature.kt @@ -1,14 +1,20 @@ package centre.sciprog.maps.compose +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.VectorPainter +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.unit.IntSize //TODO replace zoom range with zoom-based representation change sealed class MapFeature(val zoomRange: ClosedFloatingPointRange) private val defaultZoomRange = 1.0..18.0 -private fun Pair.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second) +internal fun Pair.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second) class MapCircleFeature( val center: GeodeticMapCoordinates, @@ -48,11 +54,30 @@ class MapTextFeature( val text: String, zoomRange: ClosedFloatingPointRange = defaultZoomRange, val color: Color = Color.Red, -): MapFeature(zoomRange) +) : MapFeature(zoomRange) -class MapImageFeature( +class MapBitmapImageFeature( val position: GeodeticMapCoordinates, val image: ImageBitmap, + val size: IntSize = IntSize(15, 15), zoomRange: ClosedFloatingPointRange = defaultZoomRange, val color: Color = Color.Red, -): MapFeature(zoomRange) \ No newline at end of file +) : MapFeature(zoomRange) + + +class MapVectorImageFeature internal constructor( + val position: GeodeticMapCoordinates, + val painter: VectorPainter, + val size: Size, + zoomRange: ClosedFloatingPointRange = defaultZoomRange, + val color: Color = Color.Red, +) : MapFeature(zoomRange) + +@Composable +fun MapVectorImageFeature( + position: GeodeticMapCoordinates, + image: ImageVector, + size: Size = Size(20f,20f), + zoomRange: ClosedFloatingPointRange = defaultZoomRange, + color: Color = Color.Red, +): MapVectorImageFeature = MapVectorImageFeature(position, rememberVectorPainter(image), size, zoomRange, color) \ No newline at end of file diff --git a/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapView.kt b/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapView.kt index 42c0ad5..3606180 100644 --- a/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapView.kt +++ b/src/jvmMain/kotlin/centre/sciprog/maps/compose/MapView.kt @@ -9,12 +9,10 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.drawscope.drawIntoCanvas -import androidx.compose.ui.graphics.nativeCanvas -import androidx.compose.ui.graphics.toComposeImageBitmap +import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.onPointerEvent @@ -28,7 +26,9 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import mu.KotlinLogging +import org.jetbrains.skia.Font import org.jetbrains.skia.Image +import org.jetbrains.skia.Paint import java.net.URL import java.nio.file.Path import kotlin.io.path.* @@ -93,13 +93,10 @@ private class OsMapCache(val scope: CoroutineScope, val client: HttpClient, priv } } -private fun Color.toPaint(): org.jetbrains.skia.Paint = org.jetbrains.skia.Paint().setARGB( - (alpha * 256).toInt(), - (red * 256).toInt(), - (green * 256).toInt(), - (blue * 256).toInt() -) - +private fun Color.toPaint(): Paint = Paint().apply { + isAntiAlias = true + color = toArgb() +} private fun Double.toIndex(): Int = floor(this / TILE_SIZE).toInt() private fun Int.toCoordinate(): Double = (this * TILE_SIZE).toDouble() @@ -142,7 +139,7 @@ fun MapView( for (j in verticalIndices) { for (i in horizontalIndices) { - if(z == viewPoint.zoom.toInt() && i in indexRange && j in indexRange) { + if (z == viewPoint.zoom.toInt() && i in indexRange && j in indexRange) { val tileId = OsMapTileId(z, i, j) val tile = mapCache.loadTile(tileId) mapTiles.add(tile) @@ -211,10 +208,24 @@ fun MapView( center = feature.center.toOffset() ) is MapLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset()) - is MapImageFeature -> drawImage(feature.image, feature.position.toOffset()) - is MapTextFeature -> drawIntoCanvas { + is MapBitmapImageFeature -> drawImage(feature.image, feature.position.toOffset()) + is MapVectorImageFeature -> { val offset = feature.position.toOffset() - it.nativeCanvas.drawString(feature.text, offset.x, offset.y, null, feature.color.toPaint()) + translate(offset.x - feature.size.width/2, offset.y - feature.size.height/2) { + with(feature.painter) { + draw(feature.size) + } + } + } + is MapTextFeature -> drawIntoCanvas { canvas -> + val offset = feature.position.toOffset() + canvas.nativeCanvas.drawString( + feature.text, + offset.x + 5, + offset.y - 5, + Font().apply { size = 16f }, + feature.color.toPaint() + ) } }