Add vector rendering

This commit is contained in:
Alexander Nozik 2022-07-10 18:32:37 +03:00
parent 6258e25669
commit 7771a9b7b9
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
3 changed files with 60 additions and 20 deletions

View File

@ -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. // 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.desktop.ui.tooling.preview.Preview
import androidx.compose.material.MaterialTheme 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.runtime.Composable
import androidx.compose.ui.window.Window import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application import androidx.compose.ui.window.application
@ -18,9 +20,11 @@ fun App() {
val pointOne = 55.568548 to 37.568604 val pointOne = 55.568548 to 37.568604
val pointTwo = 55.929444 to 37.518434 val pointTwo = 55.929444 to 37.518434
val features = buildList<MapFeature> { val features = buildList<MapFeature> {
add(MapCircleFeature(pointOne)) // add(MapCircleFeature(pointOne))
add(MapCircleFeature(pointTwo)) add(MapCircleFeature(pointTwo))
add(MapLineFeature(pointOne, 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")) MapView(viewPoint, features = features, cacheDirectory = Path.of("mapCache"))
} }

View File

@ -1,14 +1,20 @@
package centre.sciprog.maps.compose 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.Color
import androidx.compose.ui.graphics.ImageBitmap 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 //TODO replace zoom range with zoom-based representation change
sealed class MapFeature(val zoomRange: ClosedFloatingPointRange<Double>) sealed class MapFeature(val zoomRange: ClosedFloatingPointRange<Double>)
private val defaultZoomRange = 1.0..18.0 private val defaultZoomRange = 1.0..18.0
private fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second) internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
class MapCircleFeature( class MapCircleFeature(
val center: GeodeticMapCoordinates, val center: GeodeticMapCoordinates,
@ -50,9 +56,28 @@ class MapTextFeature(
val color: Color = Color.Red, val color: Color = Color.Red,
) : MapFeature(zoomRange) ) : MapFeature(zoomRange)
class MapImageFeature( class MapBitmapImageFeature(
val position: GeodeticMapCoordinates, val position: GeodeticMapCoordinates,
val image: ImageBitmap, val image: ImageBitmap,
val size: IntSize = IntSize(15, 15),
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange, zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
val color: Color = Color.Red, val color: Color = Color.Red,
) : MapFeature(zoomRange) ) : MapFeature(zoomRange)
class MapVectorImageFeature internal constructor(
val position: GeodeticMapCoordinates,
val painter: VectorPainter,
val size: Size,
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
val color: Color = Color.Red,
) : MapFeature(zoomRange)
@Composable
fun MapVectorImageFeature(
position: GeodeticMapCoordinates,
image: ImageVector,
size: Size = Size(20f,20f),
zoomRange: ClosedFloatingPointRange<Double> = defaultZoomRange,
color: Color = Color.Red,
): MapVectorImageFeature = MapVectorImageFeature(position, rememberVectorPainter(image), size, zoomRange, color)

View File

@ -9,12 +9,10 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.input.pointer.onPointerEvent
@ -28,7 +26,9 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import mu.KotlinLogging import mu.KotlinLogging
import org.jetbrains.skia.Font
import org.jetbrains.skia.Image import org.jetbrains.skia.Image
import org.jetbrains.skia.Paint
import java.net.URL import java.net.URL
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.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( private fun Color.toPaint(): Paint = Paint().apply {
(alpha * 256).toInt(), isAntiAlias = true
(red * 256).toInt(), color = toArgb()
(green * 256).toInt(), }
(blue * 256).toInt()
)
private fun Double.toIndex(): Int = floor(this / TILE_SIZE).toInt() private fun Double.toIndex(): Int = floor(this / TILE_SIZE).toInt()
private fun Int.toCoordinate(): Double = (this * TILE_SIZE).toDouble() private fun Int.toCoordinate(): Double = (this * TILE_SIZE).toDouble()
@ -211,10 +208,24 @@ fun MapView(
center = feature.center.toOffset() center = feature.center.toOffset()
) )
is MapLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset()) is MapLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset())
is MapImageFeature -> drawImage(feature.image, feature.position.toOffset()) is MapBitmapImageFeature -> drawImage(feature.image, feature.position.toOffset())
is MapTextFeature -> drawIntoCanvas { is MapVectorImageFeature -> {
val offset = feature.position.toOffset() 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()
)
} }
} }