From 6278235b5137752cf0e3123add5f0e274302f31a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 6 Jan 2023 14:15:06 +0300 Subject: [PATCH] Polygon editor demo --- demo/polygon-editor/build.gradle.kts | 38 ++++++++ .../polygon-editor/src/jvmMain/kotlin/Main.kt | 86 ++++++++++++++++++ demo/scheme/src/jvmMain/kotlin/Main.kt | 8 +- .../src/jvmMain/resources/middle-earth.jpg | Bin .../center/sciprog/maps/scheme/XYViewScope.kt | 2 +- .../center/sciprog/maps/scheme/SchemeView.kt | 23 +++-- settings.gradle.kts | 5 +- 7 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 demo/polygon-editor/build.gradle.kts create mode 100644 demo/polygon-editor/src/jvmMain/kotlin/Main.kt rename {maps-kt-scheme => demo/scheme}/src/jvmMain/resources/middle-earth.jpg (100%) diff --git a/demo/polygon-editor/build.gradle.kts b/demo/polygon-editor/build.gradle.kts new file mode 100644 index 0000000..f140cf5 --- /dev/null +++ b/demo/polygon-editor/build.gradle.kts @@ -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" + } + } +} diff --git a/demo/polygon-editor/src/jvmMain/kotlin/Main.kt b/demo/polygon-editor/src/jvmMain/kotlin/Main.kt new file mode 100644 index 0000000..0adbc58 --- /dev/null +++ b/demo/polygon-editor/src/jvmMain/kotlin/Main.kt @@ -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(null) } + + val myPolygon: SnapshotStateList = remember { mutableStateListOf() } + + val featureState: FeatureGroup = 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( + 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() + } +} diff --git a/demo/scheme/src/jvmMain/kotlin/Main.kt b/demo/scheme/src/jvmMain/kotlin/Main.kt index 9296e0e..9e1e847 100644 --- a/demo/scheme/src/jvmMain/kotlin/Main.kt +++ b/demo/scheme/src/jvmMain/kotlin/Main.kt @@ -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 = 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 = remember { - schemeFeaturesState.features.computeBoundingBox(XYCoordinateSpace, 1f)?.computeViewPoint() - ?: XYViewPoint(XY(0f, 0f)) + schemeFeaturesState.getBoundingBox(1f)?.computeViewPoint() ?: XYViewPoint(XY(0f, 0f)) } var viewPoint: ViewPoint by remember { mutableStateOf(initialViewPoint) } @@ -81,7 +79,7 @@ fun App() { ) { val mapState: XYViewScope = XYViewScope.remember( ViewConfig( - onClick = {_, click -> + onClick = { _, click -> println("${click.focus.x}, ${click.focus.y}") }, onViewChange = { viewPoint = this } diff --git a/maps-kt-scheme/src/jvmMain/resources/middle-earth.jpg b/demo/scheme/src/jvmMain/resources/middle-earth.jpg similarity index 100% rename from maps-kt-scheme/src/jvmMain/resources/middle-earth.jpg rename to demo/scheme/src/jvmMain/resources/middle-earth.jpg 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 84c54cd..a1b0071 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 @@ -47,7 +47,7 @@ class XYViewScope( companion object{ @Composable public fun remember( - config: ViewConfig, + config: ViewConfig = ViewConfig(), initialViewPoint: ViewPoint? = null, initialRectangle: Rectangle? = null, ): XYViewScope = remember { diff --git a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt index de89384..1aad880 100644 --- a/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt +++ b/maps-kt-scheme/src/jvmMain/kotlin/center/sciprog/maps/scheme/SchemeView.kt @@ -24,12 +24,12 @@ private val logger = KotlinLogging.logger("SchemeView") public fun SchemeView( state: XYViewScope, featuresState: FeatureGroup, - modifier: Modifier = Modifier.fillMaxSize(), -) { + modifier: Modifier = Modifier, +) = key(state, featuresState) { with(state) { - val painterCache: Map, Painter> = key(featuresState) { + //Can't do that inside canvas + val painterCache: Map, Painter> = featuresState.features.filterIsInstance>().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) diff --git a/settings.gradle.kts b/settings.gradle.kts index 6892f42..8014588 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -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" )