Polygon editor demo

This commit is contained in:
Alexander Nozik 2023-01-06 14:15:06 +03:00
parent 5a3a4b059e
commit 6278235b51
7 changed files with 146 additions and 16 deletions

View File

@ -0,0 +1,38 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
val ktorVersion: String by rootProject.extra
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
withJava()
}
sourceSets {
val jvmMain by getting {
dependencies {
implementation(projects.mapsKtScheme)
implementation(compose.desktop.currentOs)
implementation("ch.qos.logback:logback-classic:1.2.11")
}
}
val jvmTest by getting
}
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "polygon-editor-demo"
packageVersion = "1.0.0"
}
}
}

View File

@ -0,0 +1,86 @@
// 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.Button
import androidx.compose.material.CursorDropdownMenu
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.PointMode
import androidx.compose.ui.input.pointer.isSecondaryPressed
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
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
@Composable
@Preview
fun App() {
MaterialTheme {
var clickPoint by remember { mutableStateOf<XY?>(null) }
val myPolygon: SnapshotStateList<XY> = remember { mutableStateListOf<XY>() }
val featureState: FeatureGroup<XY> = FeatureGroup.remember(XYCoordinateSpace) {
points(
listOf(XY(0f, 0f), XY(0f, 1f), XY(1f, 1f), XY(1f, 0f), XY(0f, 0f)),
pointMode = PointMode.Polygon,
id = "frame"
)
}
if(myPolygon.isNotEmpty()) {
featureState.group("polygon") {
points(
myPolygon + myPolygon.first(),
pointMode = PointMode.Polygon,
)
myPolygon.forEachIndexed { index, xy ->
circle(xy, id = "point[$index]").draggable { _, to ->
myPolygon[index] = to.focus
}
}
}
}
val mapState: XYViewScope = XYViewScope.remember(
config = ViewConfig<XY>(
onClick = { event, point ->
if (event.buttons.isSecondaryPressed) {
clickPoint = point.focus
}
}
),
initialRectangle = featureState.getBoundingBox(1f),
)
CursorDropdownMenu(clickPoint != null, { clickPoint = null }) {
clickPoint?.let { point ->
Button({
myPolygon.add(point)
clickPoint = null
}) {
Text("Create node")
}
}
}
SchemeView(
mapState,
featureState,
)
}
}
fun main() = application {
Window(title = "Polygon editor demo", onCloseRequest = ::exitApplication) {
App()
}
}

View File

@ -11,7 +11,6 @@ import androidx.compose.ui.window.application
import center.sciprog.maps.features.FeatureGroup
import center.sciprog.maps.features.ViewConfig
import center.sciprog.maps.features.ViewPoint
import center.sciprog.maps.features.computeBoundingBox
import center.sciprog.maps.scheme.*
import center.sciprog.maps.svg.FeatureStateSnapshot
import center.sciprog.maps.svg.exportToSvg
@ -29,7 +28,7 @@ fun App() {
MaterialTheme {
val scope = rememberCoroutineScope()
val schemeFeaturesState = FeatureGroup.remember(XYCoordinateSpace) {
val schemeFeaturesState: FeatureGroup<XY> = 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,8 +52,7 @@ fun App() {
}
val initialViewPoint: ViewPoint<XY> = remember {
schemeFeaturesState.features.computeBoundingBox(XYCoordinateSpace, 1f)?.computeViewPoint()
?: XYViewPoint(XY(0f, 0f))
schemeFeaturesState.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f))
}
var viewPoint: ViewPoint<XY> by remember { mutableStateOf(initialViewPoint) }

View File

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 469 KiB

View File

@ -47,7 +47,7 @@ class XYViewScope(
companion object{
@Composable
public fun remember(
config: ViewConfig<XY>,
config: ViewConfig<XY> = ViewConfig(),
initialViewPoint: ViewPoint<XY>? = null,
initialRectangle: Rectangle<XY>? = null,
): XYViewScope = remember {

View File

@ -24,12 +24,12 @@ private val logger = KotlinLogging.logger("SchemeView")
public fun SchemeView(
state: XYViewScope,
featuresState: FeatureGroup<XY>,
modifier: Modifier = Modifier.fillMaxSize(),
) {
modifier: Modifier = Modifier,
) = key(state, featuresState) {
with(state) {
val painterCache: Map<PainterFeature<XY>, Painter> = key(featuresState) {
//Can't do that inside canvas
val painterCache: Map<PainterFeature<XY>, Painter> =
featuresState.features.filterIsInstance<PainterFeature<XY>>().associateWith { it.getPainter() }
}
Canvas(modifier = modifier.mapControls(state, featuresState).fillMaxSize()) {
@ -41,10 +41,11 @@ public fun SchemeView(
clipRect {
featuresState.featureMap.values.sortedBy { it.z }
.filter { viewPoint.zoom in it.zoomRange }
.forEach { background ->
drawFeature(state, painterCache, background)
.forEach { feature ->
drawFeature(state, painterCache, feature)
}
}
selectRect?.let { dpRect ->
val rect = dpRect.toRect()
drawRect(
@ -96,7 +97,10 @@ public fun SchemeView(
val state = XYViewScope.remember(
config,
initialViewPoint = initialViewPoint,
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(XYCoordinateSpace, Float.MAX_VALUE),
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(
XYCoordinateSpace,
Float.MAX_VALUE
),
)
SchemeView(state, featureState, modifier)
@ -121,7 +125,10 @@ public fun SchemeView(
val mapState: XYViewScope = XYViewScope.remember(
config,
initialViewPoint = initialViewPoint,
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(XYCoordinateSpace, Float.MAX_VALUE),
initialRectangle = initialRectangle ?: featureState.features.computeBoundingBox(
XYCoordinateSpace,
Float.MAX_VALUE
),
)
SchemeView(mapState, featureState, modifier)

View File

@ -49,8 +49,9 @@ include(
":maps-kt-geojson",
":maps-kt-features",
":maps-kt-compose",
":demo:maps",
":maps-kt-scheme",
":demo:scheme"
":demo:maps",
":demo:scheme",
":demo:polygon-editor"
)