2022-12-26 23:22:21 +03:00
|
|
|
package center.sciprog.maps.geojson
|
|
|
|
|
|
|
|
import center.sciprog.maps.geojson.GeoJson.Companion.PROPERTIES_KEY
|
|
|
|
import center.sciprog.maps.geojson.GeoJson.Companion.TYPE_KEY
|
|
|
|
import center.sciprog.maps.geojson.GeoJsonFeatureCollection.Companion.FEATURES_KEY
|
2023-01-12 14:50:10 +03:00
|
|
|
import kotlinx.serialization.Serializable
|
2022-12-26 23:22:21 +03:00
|
|
|
import kotlinx.serialization.json.*
|
|
|
|
import kotlin.jvm.JvmInline
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A utility class to work with GeoJson (https://geojson.org/)
|
|
|
|
*/
|
2023-01-12 14:50:10 +03:00
|
|
|
@Serializable(GeoJsonSerializer::class)
|
2022-12-26 23:22:21 +03:00
|
|
|
public sealed interface GeoJson {
|
|
|
|
public val json: JsonObject
|
|
|
|
public val type: String get() = json[TYPE_KEY]?.jsonPrimitive?.content ?: error("Not a GeoJson")
|
|
|
|
|
|
|
|
public companion object {
|
|
|
|
public const val TYPE_KEY: String = "type"
|
|
|
|
public const val PROPERTIES_KEY: String = "properties"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@JvmInline
|
|
|
|
public value class GeoJsonFeature(override val json: JsonObject) : GeoJson {
|
|
|
|
init {
|
|
|
|
require(type == "Feature") { "Not a GeoJson Feature" }
|
|
|
|
}
|
|
|
|
|
|
|
|
public val properties: JsonObject? get() = json[PROPERTIES_KEY]?.jsonObject
|
|
|
|
|
|
|
|
public val geometry: GeoJsonGeometry? get() = json[GEOMETRY_KEY]?.jsonObject?.let { GeoJsonGeometry(it) }
|
|
|
|
|
2022-12-27 11:51:14 +03:00
|
|
|
public companion object {
|
2022-12-26 23:22:21 +03:00
|
|
|
public const val GEOMETRY_KEY: String = "geometry"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 14:50:10 +03:00
|
|
|
/**
|
|
|
|
* A builder function for [GeoJsonFeature]
|
|
|
|
*/
|
|
|
|
public fun GeoJsonFeature(
|
|
|
|
geometry: GeoJsonGeometry?,
|
|
|
|
properties: JsonObject? = null,
|
|
|
|
builder: JsonObjectBuilder.() -> Unit = {},
|
|
|
|
): GeoJsonFeature = GeoJsonFeature(
|
|
|
|
buildJsonObject {
|
|
|
|
put(TYPE_KEY, "Feature")
|
|
|
|
geometry?.json?.let { put(GeoJsonFeature.GEOMETRY_KEY, it) }
|
|
|
|
properties?.let { put(PROPERTIES_KEY, it) }
|
|
|
|
|
|
|
|
builder()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-01-06 10:40:21 +03:00
|
|
|
public fun GeoJsonFeature.getProperty(key: String): JsonElement? = json[key] ?: properties?.get(key)
|
|
|
|
|
2022-12-26 23:22:21 +03:00
|
|
|
@JvmInline
|
|
|
|
public value class GeoJsonFeatureCollection(override val json: JsonObject) : GeoJson, Iterable<GeoJsonFeature> {
|
|
|
|
init {
|
|
|
|
require(type == "FeatureCollection") { "Not a GeoJson FeatureCollection" }
|
|
|
|
}
|
|
|
|
|
|
|
|
public val properties: JsonObject? get() = json[PROPERTIES_KEY]?.jsonObject
|
|
|
|
|
|
|
|
public val features: List<GeoJsonFeature>
|
|
|
|
get() = json[FEATURES_KEY]?.jsonArray?.map {
|
|
|
|
GeoJsonFeature(it.jsonObject)
|
|
|
|
} ?: error("Features not defined in GeoJson features collection")
|
|
|
|
|
|
|
|
override fun iterator(): Iterator<GeoJsonFeature> = features.iterator()
|
|
|
|
|
|
|
|
public companion object {
|
|
|
|
|
|
|
|
public const val FEATURES_KEY: String = "features"
|
|
|
|
public fun parse(string: String): GeoJsonFeatureCollection = GeoJsonFeatureCollection(
|
|
|
|
Json.parseToJsonElement(string).jsonObject
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 14:50:10 +03:00
|
|
|
/**
|
|
|
|
* A builder for [GeoJsonFeatureCollection]
|
|
|
|
*/
|
|
|
|
public fun GeoJsonFeatureCollection(
|
|
|
|
features: List<GeoJsonFeature>,
|
|
|
|
properties: JsonObject? = null,
|
|
|
|
builder: JsonObjectBuilder.() -> Unit = {},
|
|
|
|
): GeoJsonFeatureCollection = GeoJsonFeatureCollection(
|
|
|
|
buildJsonObject {
|
|
|
|
put(TYPE_KEY, "FeatureCollection")
|
|
|
|
putJsonArray(FEATURES_KEY) {
|
|
|
|
features.forEach {
|
|
|
|
add(it.json)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
properties?.let { put(PROPERTIES_KEY, it) }
|
|
|
|
builder()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generic Json to GeoJson converter
|
|
|
|
*/
|
2022-12-27 11:51:14 +03:00
|
|
|
public fun GeoJson(json: JsonObject): GeoJson =
|
|
|
|
when (json[TYPE_KEY]?.jsonPrimitive?.contentOrNull ?: error("Not a GeoJson")) {
|
|
|
|
"Feature" -> GeoJsonFeature(json)
|
|
|
|
"FeatureCollection" -> GeoJsonFeatureCollection(json)
|
|
|
|
else -> GeoJsonGeometry(json)
|
2023-01-12 14:50:10 +03:00
|
|
|
}
|