diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Feature.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Feature.kt index ea22bdfb..cdbd8d9e 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Feature.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Feature.kt @@ -1,6 +1,8 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.FeatureSerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.idProp import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox @@ -36,7 +38,8 @@ class Feature( val geometry: Geometry?, properties: Map = emptyMap(), val id: String? = null, - override val bbox: BoundingBox? = null + override val bbox: BoundingBox? = null, + override val foreignMembers: Map = emptyMap() ) : GeoJson { private val _properties: MutableMap = properties.toMutableMap() val properties: Map get() = _properties @@ -86,6 +89,7 @@ class Feature( if (id != other.id) return false if (bbox != other.bbox) return false if (_properties != other._properties) return false + if (foreignMembers != other.foreignMembers) return false return true } @@ -95,6 +99,7 @@ class Feature( result = 31 * result + (id?.hashCode() ?: 0) result = 31 * result + (bbox?.hashCode() ?: 0) result = 31 * result + _properties.hashCode() + result = 31 * result + foreignMembers.hashCode() return result } @@ -102,6 +107,7 @@ class Feature( operator fun component2() = properties operator fun component3() = id operator fun component4() = bbox + operator fun component5() = foreignMembers override fun toString(): String = json() @@ -113,16 +119,18 @@ class Feature( JsonElement.serializer() ), properties ) - }}""" + }${foreignMembersJsonProps()}}""" fun copy( geometry: Geometry? = this.geometry, properties: Map = this.properties, id: String? = this.id, - bbox: BoundingBox? = this.bbox - ): Feature = Feature(geometry, properties, id, bbox) + bbox: BoundingBox? = this.bbox, + foreignMembers: Map = this.foreignMembers + ): Feature = Feature(geometry, properties, id, bbox, foreignMembers) companion object { + @JvmStatic fun fromJson(json: String): Feature = fromJson(Json.decodeFromString(JsonObject.serializer(), json)) @@ -145,7 +153,10 @@ class Feature( val geom = json["geometry"]?.jsonObject val geometry: Geometry? = if (geom != null) Geometry.fromJson(geom) else null - return Feature(geometry, json["properties"]?.jsonObject ?: emptyMap(), id, bbox) + val properties = json["properties"]?.jsonObject ?: emptyMap() + val foreignMembers = json.foreignMembers() + + return Feature(geometry, properties, id, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/FeatureCollection.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/FeatureCollection.kt index 6fb43fa3..a1b5cdb4 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/FeatureCollection.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/FeatureCollection.kt @@ -1,11 +1,14 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.FeatureCollectionSerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -24,10 +27,15 @@ import kotlin.jvm.JvmStatic @Serializable(with = FeatureCollectionSerializer::class) class FeatureCollection( val features: List = emptyList(), - override val bbox: BoundingBox? = null + override val bbox: BoundingBox? = null, + override val foreignMembers: Map = emptyMap() ) : Collection by features, GeoJson { - constructor(vararg features: Feature, bbox: BoundingBox? = null) : this(features.toMutableList(), bbox) + constructor( + vararg features: Feature, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(features.toMutableList(), bbox, foreignMembers) override fun equals(other: Any?): Boolean { if (this === other) return true @@ -37,6 +45,7 @@ class FeatureCollection( if (features != other.features) return false if (bbox != other.bbox) return false + if (foreignMembers != other.foreignMembers) return false return true } @@ -44,18 +53,22 @@ class FeatureCollection( override fun hashCode(): Int { var result = features.hashCode() result = 31 * result + (bbox?.hashCode() ?: 0) + result = 31 * result + foreignMembers.hashCode() return result } override fun toString(): String = json() + @Suppress("MaxLineLength") override fun json(): String = - """{"type":"FeatureCollection",${bbox.jsonProp()}"features":${features.jsonJoin { it.json() }}}""" + """{"type":"FeatureCollection",${bbox.jsonProp()}"features":${features.jsonJoin { it.json() }}${foreignMembersJsonProps()}}""" operator fun component1(): List = features operator fun component2(): BoundingBox? = bbox + operator fun component3(): Map = foreignMembers companion object { + @JvmStatic public fun fromJson(json: String): FeatureCollection = fromJson(Json.decodeFromString(JsonObject.serializer(), json)) @@ -75,8 +88,9 @@ class FeatureCollection( val bbox = json["bbox"]?.jsonArray?.toBbox() val features = json.getValue("features").jsonArray.map { Feature.fromJson(it.jsonObject) } + val foreignMembers = json.foreignMembers() - return FeatureCollection(features, bbox) + return FeatureCollection(features, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeoJson.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeoJson.kt index cb1acb43..73cd41b5 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeoJson.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeoJson.kt @@ -1,5 +1,7 @@ package io.github.dellisd.spatialk.geojson +import kotlinx.serialization.json.JsonElement + /** * A GeoJSON object represents a [Geometry], [Feature], or [collection of Features][FeatureCollection]. * @@ -7,6 +9,7 @@ package io.github.dellisd.spatialk.geojson */ interface GeoJson { val bbox: BoundingBox? + val foreignMembers: Map /** * Gets a JSON representation of this object. diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Geometry.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Geometry.kt index d6ce39b7..68e1fad1 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Geometry.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Geometry.kt @@ -3,13 +3,38 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonPrimitive import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) -sealed class Geometry protected constructor() : GeoJson { - abstract override val bbox: BoundingBox? +sealed class Geometry protected constructor( + override val bbox: BoundingBox? = null, + override val foreignMembers: Map = emptyMap() +) : GeoJson { + + protected abstract val coordinatesOrGeometries: Any + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as Geometry + + if (coordinatesOrGeometries != other.coordinatesOrGeometries) return false + if (bbox != other.bbox) return false + if (foreignMembers != other.foreignMembers) return false + + return true + } + + override fun hashCode(): Int { + var result = coordinatesOrGeometries.hashCode() + result = 31 * result + (bbox?.hashCode() ?: 0) + result = 31 * result + foreignMembers.hashCode() + return result + } override fun toString(): String = json() diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeometryCollection.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeometryCollection.kt index 4af24319..29b58e25 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeometryCollection.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/GeometryCollection.kt @@ -1,11 +1,14 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -17,31 +20,21 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class GeometryCollection @JvmOverloads constructor( val geometries: List, - override val bbox: BoundingBox? = null -) : Geometry(), Collection by geometries { - @JvmOverloads - constructor(vararg geometries: Geometry, bbox: BoundingBox? = null) : this(geometries.toList(), bbox) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as GeometryCollection - - if (geometries != other.geometries) return false - if (bbox != other.bbox) return false + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers), Collection by geometries { + override val coordinatesOrGeometries get() = geometries - return true - } - - override fun hashCode(): Int { - var result = geometries.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } + @JvmOverloads + constructor( + vararg geometries: Geometry, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(geometries.toList(), bbox, foreignMembers) + @Suppress("MaxLineLength") override fun json(): String = - """{"type":"GeometryCollection",${bbox.jsonProp()}"geometries":${geometries.jsonJoin { it.json() }}}""" + """{"type":"GeometryCollection",${bbox.jsonProp()}"geometries":${geometries.jsonJoin { it.json() }}${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -66,8 +59,9 @@ class GeometryCollection @JvmOverloads constructor( } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return GeometryCollection(geometries, bbox) + return GeometryCollection(geometries, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/LineString.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/LineString.kt index a4380119..b3f96aac 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/LineString.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/LineString.kt @@ -1,12 +1,15 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -17,41 +20,32 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class LineString @JvmOverloads constructor( val coordinates: List, - override val bbox: BoundingBox? = null -) : Geometry() { + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates + @JvmOverloads - constructor(vararg coordinates: Position, bbox: BoundingBox? = null) : this(coordinates.toList(), bbox) + constructor( + vararg coordinates: Position, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.toList(), bbox, foreignMembers) @JvmOverloads constructor( coordinates: Array, - bbox: BoundingBox? = null - ) : this(coordinates.map(::Position), bbox) + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.map(::Position), bbox, foreignMembers) init { require(coordinates.size >= 2) { "LineString must have at least two positions" } } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as LineString - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false - - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } - + @Suppress("MaxLineLength") override fun json(): String = - """{"type":"LineString",${bbox.jsonProp()}"coordinates":${coordinates.jsonJoin(transform = Position::json)}}""" + """{"type":"LineString",${bbox.jsonProp()}"coordinates":${coordinates.jsonJoin(transform = Position::json)}${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -72,8 +66,9 @@ class LineString @JvmOverloads constructor( val coords = json.getValue("coordinates").jsonArray.map { it.jsonArray.toPosition() } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return LineString(coords, bbox) + return LineString(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiLineString.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiLineString.kt index e88ce4f0..9f3628a7 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiLineString.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiLineString.kt @@ -1,12 +1,15 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -17,16 +20,24 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class MultiLineString @JvmOverloads constructor( val coordinates: List>, - override val bbox: BoundingBox? = null -) : Geometry() { + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates + @JvmOverloads - constructor(vararg coordinates: List, bbox: BoundingBox? = null) : this(coordinates.toList(), bbox) + constructor( + vararg coordinates: List, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.toList(), bbox, foreignMembers) @JvmOverloads constructor( coordinates: Array>, - bbox: BoundingBox? = null - ) : this(coordinates.map { it.map(::Position) }, bbox) + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.map { it.map(::Position) }, bbox, foreignMembers) init { coordinates.forEach { line -> @@ -34,30 +45,12 @@ class MultiLineString @JvmOverloads constructor( } } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as MultiLineString - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false - - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } - override fun json(): String = """{"type":"MultiLineString",${bbox.jsonProp()}"coordinates":${ coordinates.jsonJoin { it.jsonJoin(transform = Position::json) } - }}""" + }${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -80,8 +73,9 @@ class MultiLineString @JvmOverloads constructor( val coords = json.getValue("coordinates").jsonArray.map { line -> line.jsonArray.map { it.jsonArray.toPosition() } } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return MultiLineString(coords, bbox) + return MultiLineString(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPoint.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPoint.kt index e02e6305..5895d77f 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPoint.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPoint.kt @@ -1,12 +1,15 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -17,37 +20,28 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class MultiPoint @JvmOverloads constructor( val coordinates: List, - override val bbox: BoundingBox? = null -) : Geometry() { + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates + @JvmOverloads - constructor(vararg coordinates: Position, bbox: BoundingBox? = null) : this(coordinates.toList(), bbox) + constructor( + vararg coordinates: Position, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.toList(), bbox, foreignMembers) @JvmOverloads constructor( coordinates: Array, - bbox: BoundingBox? = null - ) : this(coordinates.map(::Position), bbox) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as MultiPoint - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false - - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.map(::Position), bbox, foreignMembers) + @Suppress("MaxLineLength") override fun json(): String = - """{"type":"MultiPoint",${bbox.jsonProp()}"coordinates":${coordinates.jsonJoin(transform = Position::json)}}""" + """{"type":"MultiPoint",${bbox.jsonProp()}"coordinates":${coordinates.jsonJoin(transform = Position::json)}${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -68,8 +62,9 @@ class MultiPoint @JvmOverloads constructor( val coords = json.getValue("coordinates").jsonArray.map { it.jsonArray.toPosition() } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return MultiPoint(coords, bbox) + return MultiPoint(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPolygon.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPolygon.kt index 957dc5b6..84affd24 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPolygon.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/MultiPolygon.kt @@ -1,12 +1,15 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -17,34 +20,24 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class MultiPolygon @JvmOverloads constructor( val coordinates: List>>, - override val bbox: BoundingBox? = null -) : Geometry() { + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates + @JvmOverloads - constructor(vararg coordinates: List>, bbox: BoundingBox? = null) : this(coordinates.toList(), bbox) + constructor( + vararg coordinates: List>, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.toList(), bbox, foreignMembers) @JvmOverloads constructor( coordinates: Array>>, - bbox: BoundingBox? = null - ) : this(coordinates.map { ring -> ring.map { it.map(::Position) } }, bbox) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as MultiPolygon - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false - - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.map { ring -> ring.map { it.map(::Position) } }, bbox, foreignMembers) override fun json(): String = """{"type":"MultiPolygon",${bbox.jsonProp()}"coordinates":${ @@ -53,7 +46,7 @@ class MultiPolygon @JvmOverloads constructor( it.jsonJoin(transform = Position::json) } } - }}""" + }${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -78,8 +71,9 @@ class MultiPolygon @JvmOverloads constructor( polygon.jsonArray.map { ring -> ring.jsonArray.map { it.jsonArray.toPosition() } } } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return MultiPolygon(coords, bbox) + return MultiPolygon(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Point.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Point.kt index ad86d22e..5bba25a1 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Point.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Point.kt @@ -1,11 +1,14 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -14,29 +17,22 @@ import kotlin.jvm.JvmStatic @Suppress("SERIALIZER_TYPE_INCOMPATIBLE") @Serializable(with = GeometrySerializer::class) -class Point @JvmOverloads constructor(val coordinates: Position, override val bbox: BoundingBox? = null) : Geometry() { - @JvmOverloads - constructor(coordinates: DoubleArray, bbox: BoundingBox? = null) : this(Position(coordinates), bbox) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as Point - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false +class Point @JvmOverloads constructor( + val coordinates: Position, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } + @JvmOverloads + constructor( + coordinates: DoubleArray, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(Position(coordinates), bbox, foreignMembers) - override fun json(): String = """{"type":"Point",${bbox.jsonProp()}"coordinates":${coordinates.json()}}""" + @Suppress("MaxLineLength") + override fun json(): String = """{"type":"Point",${bbox.jsonProp()}"coordinates":${coordinates.json()}${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -57,8 +53,9 @@ class Point @JvmOverloads constructor(val coordinates: Position, override val bb val coords = json.getValue("coordinates").jsonArray.toPosition() val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return Point(coords, bbox) + return Point(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Polygon.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Polygon.kt index 1cb50819..54408e87 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Polygon.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/Polygon.kt @@ -1,12 +1,15 @@ package io.github.dellisd.spatialk.geojson import io.github.dellisd.spatialk.geojson.serialization.GeometrySerializer +import io.github.dellisd.spatialk.geojson.serialization.foreignMembers +import io.github.dellisd.spatialk.geojson.serialization.foreignMembersJsonProps import io.github.dellisd.spatialk.geojson.serialization.jsonJoin import io.github.dellisd.spatialk.geojson.serialization.jsonProp import io.github.dellisd.spatialk.geojson.serialization.toBbox import io.github.dellisd.spatialk.geojson.serialization.toPosition import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive @@ -17,39 +20,29 @@ import kotlin.jvm.JvmStatic @Serializable(with = GeometrySerializer::class) class Polygon @JvmOverloads constructor( val coordinates: List>, - override val bbox: BoundingBox? = null -) : Geometry() { + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() +) : Geometry(bbox, foreignMembers) { + override val coordinatesOrGeometries get() = coordinates + @JvmOverloads - constructor(vararg coordinates: List, bbox: BoundingBox? = null) : this(coordinates.toList(), bbox) + constructor( + vararg coordinates: List, + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.toList(), bbox, foreignMembers) @JvmOverloads constructor( coordinates: Array>, - bbox: BoundingBox? = null - ) : this(coordinates.map { it.map(::Position) }, bbox) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as Polygon - - if (coordinates != other.coordinates) return false - if (bbox != other.bbox) return false - - return true - } - - override fun hashCode(): Int { - var result = coordinates.hashCode() - result = 31 * result + (bbox?.hashCode() ?: 0) - return result - } + bbox: BoundingBox? = null, + foreignMembers: Map = emptyMap() + ) : this(coordinates.map { it.map(::Position) }, bbox, foreignMembers) override fun json(): String = """{"type":"Polygon",${bbox.jsonProp()}"coordinates":${ coordinates.jsonJoin { it.jsonJoin(transform = Position::json) } - }}""" + }${foreignMembersJsonProps()}}""" companion object { @JvmStatic @@ -71,8 +64,9 @@ class Polygon @JvmOverloads constructor( val coords = json.getValue("coordinates").jsonArray.map { line -> line.jsonArray.map { it.jsonArray.toPosition() } } val bbox = json["bbox"]?.jsonArray?.toBbox() + val foreignMembers = json.foreignMembers() - return Polygon(coords, bbox) + return Polygon(coords, bbox, foreignMembers) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureCollectionDsl.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureCollectionDsl.kt index 970f0e65..fb3a9783 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureCollectionDsl.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureCollectionDsl.kt @@ -6,27 +6,38 @@ import io.github.dellisd.spatialk.geojson.BoundingBox import io.github.dellisd.spatialk.geojson.Feature import io.github.dellisd.spatialk.geojson.FeatureCollection import io.github.dellisd.spatialk.geojson.Geometry +import kotlinx.serialization.json.JsonElement import kotlin.jvm.JvmName @GeoJsonDsl class FeatureCollectionDsl( private val features: MutableList = mutableListOf(), - var bbox: BoundingBox? = null + var bbox: BoundingBox? = null, + val foreignMembers: MutableMap = mutableMapOf() ) { operator fun Feature.unaryPlus() { features.add(this) } fun create(): FeatureCollection = - FeatureCollection(features, bbox) + FeatureCollection(features, bbox, foreignMembers) fun feature( geometry: Geometry? = null, id: String? = null, bbox: BoundingBox? = null, + foreignMembers: ForeignMembersBuilder.() -> Unit = {}, properties: PropertiesBuilder.() -> Unit = {} ) { - +Feature(geometry, PropertiesBuilder().apply(properties).build(), id, bbox) + +io.github.dellisd.spatialk.geojson.dsl.feature(geometry = geometry, + id = id, + bbox = bbox, + foreignMembers = foreignMembers, + properties = properties) + } + + fun foreignMembers(foreignMembers: ForeignMembersBuilder.() -> Unit = {}) { + this.foreignMembers.putAll(ForeignMembersBuilder().apply(foreignMembers).build()) } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureDsl.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureDsl.kt index a4af667e..1c7732c6 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureDsl.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/FeatureDsl.kt @@ -38,5 +38,11 @@ inline fun feature( geometry: Geometry? = null, id: String? = null, bbox: BoundingBox? = null, + foreignMembers: ForeignMembersBuilder.() -> Unit = {}, properties: PropertiesBuilder.() -> Unit = {} -) = Feature(geometry, PropertiesBuilder().apply(properties).build(), id, bbox) +) = Feature( + geometry = geometry, + properties = PropertiesBuilder().apply(properties).build(), + id = id, + bbox = bbox, + foreignMembers = ForeignMembersBuilder().apply(foreignMembers).build()) diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/ForeignMembersBuilder.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/ForeignMembersBuilder.kt new file mode 100644 index 00000000..102c4288 --- /dev/null +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/ForeignMembersBuilder.kt @@ -0,0 +1,27 @@ +package io.github.dellisd.spatialk.geojson.dsl + +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive + +@GeoJsonDsl +class ForeignMembersBuilder { + private val foreignMembers = mutableMapOf() + + fun put(key: String, value: String?) { + foreignMembers[key] = JsonPrimitive(value) + } + + fun put(key: String, value: Number?) { + foreignMembers[key] = JsonPrimitive(value) + } + + fun put(key: String, value: Boolean?) { + foreignMembers[key] = JsonPrimitive(value) + } + + fun put(key: String, value: JsonElement) { + foreignMembers[key] = value + } + + fun build(): Map = foreignMembers +} diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeometryDsl.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeometryDsl.kt index 9fc9fad9..6159ae56 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeometryDsl.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeometryDsl.kt @@ -12,17 +12,25 @@ import io.github.dellisd.spatialk.geojson.MultiPoint import io.github.dellisd.spatialk.geojson.MultiPolygon import io.github.dellisd.spatialk.geojson.Point import io.github.dellisd.spatialk.geojson.Polygon +import kotlinx.serialization.json.JsonElement import kotlin.jvm.JvmName @GeoJsonDsl -abstract class GeometryDsl protected constructor(var bbox: BoundingBox? = null) { +abstract class GeometryDsl protected constructor( + var bbox: BoundingBox? = null, + val foreignMembers: MutableMap = mutableMapOf() +) { abstract fun create(): T + + fun foreignMembers(foreignMembers: ForeignMembersBuilder.() -> Unit = {}) { + this.foreignMembers.putAll(ForeignMembersBuilder().apply(foreignMembers).build()) + } } @GeoJsonDsl class PointDsl(private var coordinates: Position) : GeometryDsl() { override fun create(): Point = - Point(coordinates, bbox) + Point(coordinates, bbox, foreignMembers) } @GeoJsonDsl @@ -43,7 +51,7 @@ inline fun point( @GeoJsonDsl class MultiPointDsl(private val points: MutableList = mutableListOf()) : GeometryDsl() { override fun create(): MultiPoint = - MultiPoint(points, bbox) + MultiPoint(points, bbox, foreignMembers) operator fun Position.unaryPlus() { points.add(this) @@ -63,9 +71,9 @@ inline fun multiPoint(block: MultiPointDsl.() -> Unit): MultiPoint = MultiPointD .apply(block).create() @GeoJsonDsl -class LineStringDsl(internal val points: MutableList = mutableListOf()) : GeometryDsl() { +class LineStringDsl(private val points: MutableList = mutableListOf()) : GeometryDsl() { override fun create(): LineString = - LineString(points, bbox) + LineString(points, bbox, foreignMembers) operator fun Position.unaryPlus() { points.add(this) @@ -88,7 +96,7 @@ inline fun lineString(block: LineStringDsl.() -> Unit) = LineStringDsl() class MultiLineStringDsl(private val coordinates: MutableList> = mutableListOf()) : GeometryDsl() { override fun create(): MultiLineString = - MultiLineString(coordinates) + MultiLineString(coordinates, bbox, foreignMembers) inline fun lineString(block: LineStringDsl.() -> Unit) { +LineStringDsl().apply(block).create() @@ -106,7 +114,7 @@ inline fun multiLineString(block: MultiLineStringDsl.() -> Unit) = MultiLineStri @GeoJsonDsl class PolygonDsl(internal val coordinates: MutableList> = mutableListOf()) : GeometryDsl() { override fun create(): Polygon = - Polygon(coordinates, bbox) + Polygon(coordinates, bbox, foreignMembers) inner class RingDsl(internal val points: MutableList = mutableListOf()) { operator fun Position.unaryPlus() { @@ -147,7 +155,7 @@ inline fun polygon(block: PolygonDsl.() -> Unit) = PolygonDsl() class MultiPolygonDsl(private val coordinates: MutableList>> = mutableListOf()) : GeometryDsl() { override fun create(): MultiPolygon = - MultiPolygon(coordinates, bbox) + MultiPolygon(coordinates, bbox, foreignMembers) inline fun polygon(block: PolygonDsl.() -> Unit) { +PolygonDsl().apply(block).create() @@ -167,7 +175,7 @@ inline fun multiPolygon(block: MultiPolygonDsl.() -> Unit) = MultiPolygonDsl() class GeometryCollectionDsl(private val geometries: MutableList = mutableListOf()) : GeometryDsl() { override fun create(): GeometryCollection = - GeometryCollection(geometries) + GeometryCollection(geometries, bbox, foreignMembers) operator fun Geometry.unaryPlus() { geometries.add(this) diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializer.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializer.kt index ed7bb5d9..b56d7329 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializer.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializer.kt @@ -29,6 +29,7 @@ object FeatureCollectionSerializer : JsonSerializer { value.features.forEach { add(it.toJsonObject()) } } ) + value.foreignMembers.forEach { (key, value) -> put(key, value) } } output.encodeJsonElement(data) } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializer.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializer.kt index 8c3a5ba1..b3ba1a10 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializer.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializer.kt @@ -28,5 +28,7 @@ object FeatureSerializer : JsonSerializer { id?.let { put("id", it) } put("properties", JsonObject(properties)) + + foreignMembers.forEach { (key, value) -> put(key, value) } } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/GeometrySerializer.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/GeometrySerializer.kt index ea86c351..81c1d66c 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/GeometrySerializer.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/GeometrySerializer.kt @@ -125,6 +125,7 @@ object GeometrySerializer : KSerializer { } bbox?.let { put("bbox", it.toJsonArray()) } + foreignMembers.forEach { (key, value) -> put(key, value) } } diff --git a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/Utils.kt b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/Utils.kt index 51218f0f..032c46f2 100644 --- a/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/Utils.kt +++ b/geojson/src/commonMain/kotlin/io/github/dellisd/spatialk/geojson/serialization/Utils.kt @@ -2,8 +2,12 @@ package io.github.dellisd.spatialk.geojson.serialization import io.github.dellisd.spatialk.geojson.BoundingBox import io.github.dellisd.spatialk.geojson.Feature +import io.github.dellisd.spatialk.geojson.GeoJson import io.github.dellisd.spatialk.geojson.Position +import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.double import kotlinx.serialization.json.jsonArray @@ -19,8 +23,31 @@ internal fun BoundingBox?.jsonProp(): String = if (this == null) "" else """"bbo internal fun Feature.idProp(): String = if (this.id == null) "" else """"id":"${this.id}",""" +internal fun GeoJson.foreignMembersJsonProps(): String { + if (this.foreignMembers.isEmpty()) return "" + return this.foreignMembers.entries.joinToString(prefix = ",", separator = ",") { + """"${it.key}":${Json.encodeToString(JsonElement.serializer(), it.value)}""" + } +} + internal fun JsonArray.toPosition(): Position = Position(this[0].jsonPrimitive.double, this[1].jsonPrimitive.double, this.getOrNull(2)?.jsonPrimitive?.double) internal fun JsonArray.toBbox(): BoundingBox = BoundingBox(this.map { it.jsonPrimitive.double }.toDoubleArray()) + +private val FEATURE_MEMBERS = listOf("type", "geometry", "properties", "id", "bbox") +private val FEATURE_COLLECTION_MEMBERS = listOf("type", "features", "bbox") +private val GEOMETRY_COLLECTION_MEMBERS = listOf("type", "geometries", "bbox") +private val GEOMETRY_ELEMENT_MEMBERS = listOf("type", "coordinates", "bbox") + +internal fun JsonObject.foreignMembers(): Map { + val knownMembers = when(this.getValue("type").jsonPrimitive.content) { + "Feature" -> FEATURE_MEMBERS + "FeatureCollection" -> FEATURE_COLLECTION_MEMBERS + "GeometryCollection" -> GEOMETRY_COLLECTION_MEMBERS + else -> GEOMETRY_ELEMENT_MEMBERS + } + return this.filterKeys { !knownMembers.contains(it) } +} + diff --git a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeoJsonDslTests.kt b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeoJsonDslTests.kt index 4a2164f2..aacce879 100644 --- a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeoJsonDslTests.kt +++ b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/dsl/GeoJsonDslTests.kt @@ -5,6 +5,9 @@ import io.github.dellisd.spatialk.geojson.LineString import io.github.dellisd.spatialk.geojson.MultiPoint import io.github.dellisd.spatialk.geojson.Polygon import io.github.dellisd.spatialk.geojson.Position +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFails @@ -77,7 +80,22 @@ class GeoJsonDslTests { +simplePoint +simpleLine +simplePolygon + +point(-70.0, 40.0) { + foreignMembers { + put("geometry extension", "value") + } + } + }, foreignMembers = { + put("fm string", "str") + put("fm number", 5) + put("fm array", JsonArray(listOf(JsonPrimitive("elem1"), JsonPrimitive("elem2")))) + put("fm bool", true) + put("fm object", JsonObject(mapOf("prop1" to JsonPrimitive("value1"), "prop2" to JsonPrimitive("value2")))) }) + + foreignMembers { + put("feature collection extension", "value") + } } private val collectionJson = @@ -92,7 +110,10 @@ class GeoJsonDslTests { |[3.0,3.0],[4.0,4.0]]],[[[12.0,0.0],[0.0,12.0],[-12.0,0.0],[5.0,5.0],[12.0,0.0]]]]},"properties":{}},{"type":"Feature", |"geometry":{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[-75.0,45.0,100.0]}, |{"type":"LineString","coordinates":[[45.0,45.0],[0.0,0.0]]},{"type":"Polygon","coordinates":[[[45.0,45.0],[0.0,0.0], -|[12.0,12.0],[45.0,45.0]],[[4.0,4.0],[2.0,2.0],[3.0,3.0],[4.0,4.0]]]}]},"properties":{}}]}""".trimMargin() +|[12.0,12.0],[45.0,45.0]],[[4.0,4.0],[2.0,2.0],[3.0,3.0],[4.0,4.0]]]},{"type":"Point","coordinates":[-70.0,40.0],"geometry extension":"value"}]}, +|"properties":{},"fm string":"str","fm number":5,"fm array":["elem1","elem2"],"fm bool":true,"fm object":{"prop1":"value1","prop2":"value2"}}], +|"feature collection extension":"value"} +|""".trimMargin() @Test fun testDslConstruction() { diff --git a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializationTests.kt b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializationTests.kt index a2624ca4..131844a6 100644 --- a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializationTests.kt +++ b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureCollectionSerializationTests.kt @@ -22,12 +22,15 @@ class FeatureCollectionSerializationTests { "name" to JsonPrimitive("Nowhere") ) ) - val collection = FeatureCollection(feature, feature) + val collection = FeatureCollection(features = listOf(feature, feature), foreignMembers = mapOf( + "ext" to JsonPrimitive("extension value") + )) val json = - """{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates": - |[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}},{"type":"Feature","geometry":{"type":"Point", - |"coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}]}""" + """{"type":"FeatureCollection","features":[ + |{"type":"Feature","geometry":{"type":"Point","coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}, + |{"type":"Feature","geometry":{"type":"Point","coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}], + |"ext":"extension value"}""" .trimMargin() .replace("\n", "") @@ -44,14 +47,17 @@ class FeatureCollectionSerializationTests { "name" to JsonPrimitive("Nowhere") ) ) - val collection = FeatureCollection(feature, feature) + val collection = FeatureCollection(features = listOf(feature, feature), foreignMembers = mapOf( + "ext" to JsonPrimitive("extension value") + )) assertEquals( collection, FeatureCollection.fromJson( - """{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates": - |[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}},{"type":"Feature","geometry":{"type":"Point", - |"coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}]}""" + """{"type":"FeatureCollection","features":[ + |{"type":"Feature","geometry":{"type":"Point","coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}, + |{"type":"Feature","geometry":{"type":"Point","coordinates":[12.3,45.6]},"properties":{"size":45.1,"name":"Nowhere"}}], + |"ext":"extension value"}""" .trimMargin() .replace("\n", "") ) diff --git a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializationTests.kt b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializationTests.kt index e302f6ca..a58f0401 100644 --- a/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializationTests.kt +++ b/geojson/src/commonTest/kotlin/io/github/dellisd/spatialk/geojson/serialization/FeatureSerializationTests.kt @@ -15,7 +15,9 @@ class FeatureSerializationTests { @Test fun testSerializeFeature() { - val geometry = Point(Position(12.3, 45.6)) + val geometry = Point(Position(12.3, 45.6), foreignMembers = mapOf( + "geom ext" to JsonPrimitive("extension value") + )) val feature = Feature( geometry, mapOf( @@ -23,12 +25,19 @@ class FeatureSerializationTests { "name" to JsonPrimitive("Nowhere") ), "001", - BoundingBox(11.6, 45.1, 12.7, 45.7) + BoundingBox(11.6, 45.1, 12.7, 45.7), + foreignMembers = mapOf( + "ext" to JsonPrimitive("extension value") + ) ) val json = - """{"type":"Feature","bbox":[11.6,45.1,12.7,45.7],"geometry":{"type":"Point","coordinates":[12.3,45.6]}, - |"id":"001","properties":{"size":45.1,"name":"Nowhere"}} + """{"type":"Feature", + |"bbox":[11.6,45.1,12.7,45.7], + |"geometry":{"type":"Point","coordinates":[12.3,45.6],"geom ext":"extension value"}, + |"id":"001", + |"properties":{"size":45.1,"name":"Nowhere"}, + |"ext":"extension value"} """.trimMargin().replace("\n", "") assertEquals(json, feature.json(), "Feature (fast)") @@ -37,7 +46,9 @@ class FeatureSerializationTests { @Test fun testDeserializeFeature() { - val geometry = Point(Position(12.3, 45.6)) + val geometry = Point(Position(12.3, 45.6), foreignMembers = mapOf( + "geom ext" to JsonPrimitive("extension value") + )) val feature = Feature( geometry, properties = mapOf( @@ -45,7 +56,10 @@ class FeatureSerializationTests { "name" to JsonPrimitive("Nowhere") ), id = "001", - bbox = BoundingBox(11.6, 45.1, 12.7, 45.7) + bbox = BoundingBox(11.6, 45.1, 12.7, 45.7), + foreignMembers = mapOf( + "ext" to JsonPrimitive("extension value") + ) ) assertEquals( @@ -55,12 +69,14 @@ class FeatureSerializationTests { |"bbox":[11.6,45.1,12.7,45.7], |"geometry":{ |"type":"Point", - |"coordinates":[12.3,45.6]}, + |"coordinates":[12.3,45.6], + |"geom ext":"extension value"}, |"id":"001", |"properties":{ |"size":45.1, |"name":"Nowhere" - |}} + |}, + |"ext":"extension value"} """.trimMargin().replace("\n", "") ) )