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.
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<MapFeature> {
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"))
}

View File

@ -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<Double>)
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(
val center: GeodeticMapCoordinates,
@ -48,11 +54,30 @@ class MapTextFeature(
val text: String,
zoomRange: ClosedFloatingPointRange<Double> = 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<Double> = defaultZoomRange,
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.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()
)
}
}