diff --git a/README.md b/README.md index 9ae1731..bcbf181 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,63 @@ +# Maps-kt + This repository is a work-in-progress implementation of Map-with-markers component for Compose-Multiplatform -## [maps-kt-core](maps-kt-core) -A multiplatform coordinates representation and conversion. +![](docs/images/Screenshot%202023-01-12%20110429.png) -## [maps-kt-compose](maps-kt-compose) -A compose multiplatform (currently desktop only, contributions of android target are welcome) implementation of a map component, features and builder. +## Modules -## [maps-kt-scheme](maps-kt-scheme) -An alternative component used for the same functionality on 2D schemes. Not all features from maps could be ported because it requires some code duplication (ideas for common API are welcome). -## [demo](demo) -Demonstration projects for different features \ No newline at end of file +### [demo](demo) +> +> +> **Maturity**: EXPERIMENTAL + +### [maps-kt-compose](maps-kt-compose) +> Compose-multiplaform implementation for web-mercator tiled maps +> +> **Maturity**: DEVELOPMENT +> +> **Features:** +> - [osm](maps-kt-compose/#) : OpenStreetMap tile provider. + + +### [maps-kt-core](maps-kt-core) +> Core cartography, UI-agnostic +> +> **Maturity**: DEVELOPMENT +> +> **Features:** +> - [angles and distances](maps-kt-core/#) : Type-safe angle and distance measurements. +> - [ellipsoid](maps-kt-core/#) : Ellipsoid geometry and distances +> - [mercator](maps-kt-core/#) : Mercator and web-mercator projections + + +### [maps-kt-features](maps-kt-features) +> +> +> **Maturity**: EXPERIMENTAL + +### [maps-kt-geojson](maps-kt-geojson) +> +> +> **Maturity**: EXPERIMENTAL + +### [maps-kt-scheme](maps-kt-scheme) +> +> +> **Maturity**: EXPERIMENTAL + +### [maps](demo/maps) +> +> +> **Maturity**: EXPERIMENTAL + +### [polygon-editor](demo/polygon-editor) +> +> +> **Maturity**: EXPERIMENTAL + +### [scheme](demo/scheme) +> +> +> **Maturity**: EXPERIMENTAL diff --git a/build.gradle.kts b/build.gradle.kts index abaaad7..710a4e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { allprojects { group = "center.sciprog" - version = "0.2.1-dev-1" + version = "0.2.1-dev-2" } apiValidation{ @@ -41,5 +41,7 @@ subprojects { } } +readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") + diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 0000000..e2a13c4 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,4 @@ +# Module demo + + + diff --git a/demo/maps/README.md b/demo/maps/README.md new file mode 100644 index 0000000..27897a7 --- /dev/null +++ b/demo/maps/README.md @@ -0,0 +1,4 @@ +# Module maps + + + diff --git a/demo/polygon-editor/README.md b/demo/polygon-editor/README.md new file mode 100644 index 0000000..e045dec --- /dev/null +++ b/demo/polygon-editor/README.md @@ -0,0 +1,4 @@ +# Module polygon-editor + + + diff --git a/demo/scheme/README.md b/demo/scheme/README.md new file mode 100644 index 0000000..bee64dc --- /dev/null +++ b/demo/scheme/README.md @@ -0,0 +1,4 @@ +# Module scheme + + + diff --git a/docs/images/Screenshot 2023-01-12 110429.png b/docs/images/Screenshot 2023-01-12 110429.png new file mode 100644 index 0000000..5121fab Binary files /dev/null and b/docs/images/Screenshot 2023-01-12 110429.png differ diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md new file mode 100644 index 0000000..8045ec7 --- /dev/null +++ b/docs/templates/ARTIFACT-TEMPLATE.md @@ -0,0 +1,17 @@ +## Artifact: + +The Maven coordinates of this project are `${group}:${name}:${version}`. + +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() + // development and snapshot versions + maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev") +} + +dependencies { + implementation("${group}:${name}:${version}") +} +``` \ No newline at end of file diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md new file mode 100644 index 0000000..9bf53a9 --- /dev/null +++ b/docs/templates/README-TEMPLATE.md @@ -0,0 +1,9 @@ +# Maps-kt + +This repository is a work-in-progress implementation of Map-with-markers component for Compose-Multiplatform + +![](docs/images/Screenshot%202023-01-12%20110429.png) + +## Modules + +${modules} \ No newline at end of file diff --git a/maps-kt-compose/README.md b/maps-kt-compose/README.md new file mode 100644 index 0000000..a838973 --- /dev/null +++ b/maps-kt-compose/README.md @@ -0,0 +1,33 @@ +# Module kmath-core + +The core interfaces of KMath. + + - [osm](#) : OpenStreetMap tile provider. + + +## Artifact: + +The Maven coordinates of this project are `center.sciprog:maps-kt-compose:0.2.1-dev-2`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'center.sciprog:maps-kt-compose:0.2.1-dev-2' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("center.sciprog:maps-kt-compose:0.2.1-dev-2") +} +``` diff --git a/maps-kt-compose/build.gradle.kts b/maps-kt-compose/build.gradle.kts index ecec062..8b50a14 100644 --- a/maps-kt-compose/build.gradle.kts +++ b/maps-kt-compose/build.gradle.kts @@ -46,4 +46,14 @@ java { tasks.withType { useJUnitPlatform() +} + +readme { + description = "Compose-multiplaform implementation for web-mercator tiled maps" + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature( + id = "osm", + ) { "OpenStreetMap tile provider." } } \ No newline at end of file diff --git a/maps-kt-compose/docs/README-TEMPLATE.md b/maps-kt-compose/docs/README-TEMPLATE.md new file mode 100644 index 0000000..41cfe1c --- /dev/null +++ b/maps-kt-compose/docs/README-TEMPLATE.md @@ -0,0 +1,7 @@ +# Module kmath-core + +The core interfaces of KMath. + +${features} + +${artifact} diff --git a/maps-kt-core/README.md b/maps-kt-core/README.md new file mode 100644 index 0000000..a8e8b7a --- /dev/null +++ b/maps-kt-core/README.md @@ -0,0 +1,35 @@ +# Module kmath-core + +The core interfaces of KMath. + + - [angles and distances](#) : Type-safe angle and distance measurements. + - [ellipsoid](#) : Ellipsoid geometry and distances + - [mercator](#) : Mercator and web-mercator projections + + +## Artifact: + +The Maven coordinates of this project are `center.sciprog:maps-kt-core:0.2.1-dev-2`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'center.sciprog:maps-kt-core:0.2.1-dev-2' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("center.sciprog:maps-kt-core:0.2.1-dev-2") +} +``` diff --git a/maps-kt-core/build.gradle.kts b/maps-kt-core/build.gradle.kts index 1c891d6..408fd0e 100644 --- a/maps-kt-core/build.gradle.kts +++ b/maps-kt-core/build.gradle.kts @@ -1,4 +1,22 @@ plugins { id("space.kscience.gradle.mpp") `maven-publish` +} + +readme { + description = "Core cartography, UI-agnostic" + maturity = space.kscience.gradle.Maturity.DEVELOPMENT + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature( + id = "angles and distances", + ) { "Type-safe angle and distance measurements." } + + feature( + id = "ellipsoid", + ) { "Ellipsoid geometry and distances" } + + feature( + id = "mercator", + ) { "Mercator and web-mercator projections" } } \ No newline at end of file diff --git a/maps-kt-core/docs/README-TEMPLATE.md b/maps-kt-core/docs/README-TEMPLATE.md new file mode 100644 index 0000000..41cfe1c --- /dev/null +++ b/maps-kt-core/docs/README-TEMPLATE.md @@ -0,0 +1,7 @@ +# Module kmath-core + +The core interfaces of KMath. + +${features} + +${artifact} diff --git a/maps-kt-features/README.md b/maps-kt-features/README.md new file mode 100644 index 0000000..afed054 --- /dev/null +++ b/maps-kt-features/README.md @@ -0,0 +1,32 @@ +# Module maps-kt-features + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `center.sciprog:maps-kt-features:0.2.1-dev-2`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'center.sciprog:maps-kt-features:0.2.1-dev-2' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("center.sciprog:maps-kt-features:0.2.1-dev-2") +} +``` diff --git a/maps-kt-features/build.gradle.kts b/maps-kt-features/build.gradle.kts index 19910f4..f5887cd 100644 --- a/maps-kt-features/build.gradle.kts +++ b/maps-kt-features/build.gradle.kts @@ -12,4 +12,10 @@ kotlin { } } } +} + +kscience{ + useSerialization{ + json() + } } \ No newline at end of file diff --git a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attribute.kt b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attribute.kt index 563f1a7..48cce56 100644 --- a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attribute.kt +++ b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attribute.kt @@ -1,8 +1,20 @@ package center.sciprog.attributes +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.serializer + public interface Attribute +public abstract class SerializableAttribute( + public val serialId: String, + public val serializer: KSerializer, +) : Attribute + +public interface AttributeWithDefault : Attribute { + public val default: T +} + public interface SetAttribute : Attribute> -public object NameAttribute : Attribute +public object NameAttribute : SerializableAttribute("name", String.serializer()) diff --git a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt index 3421521..de0660e 100644 --- a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt +++ b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/Attributes.kt @@ -5,27 +5,30 @@ import center.sciprog.maps.features.ZAttribute import kotlin.jvm.JvmInline @JvmInline -public value class Attributes internal constructor(internal val map: Map, Any>) { +public value class Attributes internal constructor(public val content: Map, Any>) { + + public val keys: Set> get() = content.keys + @Suppress("UNCHECKED_CAST") - public operator fun get(attribute: Attribute): T? = map[attribute] as? T + public operator fun get(attribute: Attribute): T? = content[attribute] as? T -// public operator fun Attribute.invoke(value: T?): Attributes = withAttribute(this, value) - - override fun toString(): String = "Attributes(value=${map.entries})" + override fun toString(): String = "Attributes(value=${content.entries})" public companion object { public val EMPTY: Attributes = Attributes(emptyMap()) } } +public fun Attributes.getOrDefault(attribute: AttributeWithDefault): T = get(attribute) ?: attribute.default + public fun > Attributes.withAttribute( attribute: A, attrValue: T?, ): Attributes = Attributes( if (attrValue == null) { - map - attribute + content - attribute } else { - map + (attribute to attrValue) + content + (attribute to attrValue) } ) @@ -38,7 +41,7 @@ public fun > Attributes.withAttributeElement( ): Attributes { val currentSet: Set = get(attribute) ?: emptySet() return Attributes( - map + (attribute to (currentSet + attrValue)) + content + (attribute to (currentSet + attrValue)) ) } @@ -51,7 +54,7 @@ public fun > Attributes.withoutAttributeElement( ): Attributes { val currentSet: Set = get(attribute) ?: emptySet() return Attributes( - map + (attribute to (currentSet - attrValue)) + content + (attribute to (currentSet - attrValue)) ) } @@ -60,7 +63,7 @@ public fun > Attributes( attrValue: T, ): Attributes = Attributes(mapOf(attribute to attrValue)) -public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(map + other.map) +public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(content + other.content) public val Feature<*>.z: Float get() = attributes[ZAttribute] ?: 0f diff --git a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesBuilder.kt b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesBuilder.kt index d8a13c8..c61e20e 100644 --- a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesBuilder.kt +++ b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesBuilder.kt @@ -17,7 +17,7 @@ public class AttributesBuilder internal constructor(private val map: MutableMap< } public fun from(attributes: Attributes) { - map.putAll(attributes.map) + map.putAll(attributes.content) } public fun SetAttribute.add( @@ -42,4 +42,6 @@ public class AttributesBuilder internal constructor(private val map: MutableMap< public fun AttributesBuilder( attributes: Attributes, -): AttributesBuilder = AttributesBuilder(attributes.map.toMutableMap()) \ No newline at end of file +): AttributesBuilder = AttributesBuilder(attributes.content.toMutableMap()) + +public fun Attributes(builder: AttributesBuilder.() -> Unit): Attributes = AttributesBuilder().apply(builder).build() \ No newline at end of file diff --git a/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesSerializer.kt b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesSerializer.kt new file mode 100644 index 0000000..b811f7f --- /dev/null +++ b/maps-kt-features/src/commonMain/kotlin/center.sciprog.attributes/AttributesSerializer.kt @@ -0,0 +1,44 @@ +@file:Suppress("UNCHECKED_CAST") + +package center.sciprog.attributes + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.buildJsonObject + +public class AttributesSerializer( + private val serializableAttributes: Set>, +) : KSerializer { + private val jsonSerializer = JsonObject.serializer() + override val descriptor: SerialDescriptor get() = jsonSerializer.descriptor + + override fun deserialize(decoder: Decoder): Attributes { + val jsonElement = jsonSerializer.deserialize(decoder) + val attributeMap: Map, Any> = jsonElement.entries.associate { (key, element) -> + val attr = serializableAttributes.find { it.serialId == key } + ?: error("Attribute serializer for key $key not found") + val value = Json.decodeFromJsonElement(attr.serializer, element) ?: error("Null values are not allowed") + + attr to value + } + return Attributes(attributeMap) + } + + override fun serialize(encoder: Encoder, value: Attributes) { + val json = buildJsonObject { + value.content.forEach { (key, value) -> + if (key !in serializableAttributes) error("An attribute key $key is not in the list of allowed attributes for this serializer") + val serializableKey = key as SerializableAttribute + put( + serializableKey.serialId, + Json.encodeToJsonElement(serializableKey.serializer as KSerializer, value) + ) + } + } + jsonSerializer.serialize(encoder, json) + } +} \ No newline at end of file diff --git a/maps-kt-features/src/commonTest/kotlin/center/sciprog/attributes/AttributesSerializationTest.kt b/maps-kt-features/src/commonTest/kotlin/center/sciprog/attributes/AttributesSerializationTest.kt new file mode 100644 index 0000000..d26a769 --- /dev/null +++ b/maps-kt-features/src/commonTest/kotlin/center/sciprog/attributes/AttributesSerializationTest.kt @@ -0,0 +1,29 @@ +package center.sciprog.attributes + +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class AttributesSerializationTest { + + internal object TestAttribute : SerializableAttribute>("test", serializer()) + + @Test + fun restore() { + val serializer = AttributesSerializer(setOf(NameAttribute, TestAttribute)) + + + val attributes = Attributes { + NameAttribute("myTest") + TestAttribute(mapOf("a" to "aa", "b" to "bb")) + } + + val serialized = Json.encodeToString(serializer, attributes) + println(serialized) + + val restored = Json.decodeFromString(serializer, serialized) + + assertEquals(attributes, restored) + } +} \ No newline at end of file diff --git a/maps-kt-geojson/README.md b/maps-kt-geojson/README.md new file mode 100644 index 0000000..41c72ba --- /dev/null +++ b/maps-kt-geojson/README.md @@ -0,0 +1,32 @@ +# Module maps-kt-geojson + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `center.sciprog:maps-kt-geojson:0.2.1-dev-2`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'center.sciprog:maps-kt-geojson:0.2.1-dev-2' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("center.sciprog:maps-kt-geojson:0.2.1-dev-2") +} +``` diff --git a/maps-kt-scheme/README.md b/maps-kt-scheme/README.md new file mode 100644 index 0000000..e661110 --- /dev/null +++ b/maps-kt-scheme/README.md @@ -0,0 +1,32 @@ +# Module maps-kt-scheme + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `center.sciprog:maps-kt-scheme:0.2.1-dev-2`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'center.sciprog:maps-kt-scheme:0.2.1-dev-2' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("center.sciprog:maps-kt-scheme:0.2.1-dev-2") +} +```