GeoJson builders
This commit is contained in:
parent
0f00abb1b2
commit
b6a3ce0fe7
@ -8,11 +8,7 @@ plugins {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "center.sciprog"
|
group = "center.sciprog"
|
||||||
version = "0.2.1-dev-2"
|
version = "0.2.1-dev-3"
|
||||||
}
|
|
||||||
|
|
||||||
apiValidation{
|
|
||||||
validationDisabled = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ksciencePublish{
|
ksciencePublish{
|
||||||
|
@ -23,7 +23,7 @@ internal data class GmcRectangle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val Rectangle<Gmc>.center: GeodeticMapCoordinates
|
public val Rectangle<Gmc>.center: GeodeticMapCoordinates
|
||||||
get() = GeodeticMapCoordinates(
|
get() = GeodeticMapCoordinates.normalized(
|
||||||
(a.latitude + b.latitude) / 2,
|
(a.latitude + b.latitude) / 2,
|
||||||
(a.longitude + b.longitude) / 2
|
(a.longitude + b.longitude) / 2
|
||||||
)
|
)
|
||||||
@ -51,8 +51,8 @@ public val Rectangle<Gmc>.bottom: Angle get() = minOf(a.latitude, b.latitude)
|
|||||||
public val Rectangle<Gmc>.longitudeDelta: Angle get() = abs(a.longitude - b.longitude)
|
public val Rectangle<Gmc>.longitudeDelta: Angle get() = abs(a.longitude - b.longitude)
|
||||||
public val Rectangle<Gmc>.latitudeDelta: Angle get() = abs(a.latitude - b.latitude)
|
public val Rectangle<Gmc>.latitudeDelta: Angle get() = abs(a.latitude - b.latitude)
|
||||||
|
|
||||||
public val Rectangle<Gmc>.topLeft: GeodeticMapCoordinates get() = GeodeticMapCoordinates(top, left)
|
public val Rectangle<Gmc>.topLeft: Gmc get() = Gmc.normalized(top, left)
|
||||||
public val Rectangle<Gmc>.bottomRight: GeodeticMapCoordinates get() = GeodeticMapCoordinates(bottom, right)
|
public val Rectangle<Gmc>.bottomRight: Gmc get() = Gmc.normalized(bottom, right)
|
||||||
|
|
||||||
//public fun GmcRectangle.enlarge(
|
//public fun GmcRectangle.enlarge(
|
||||||
// top: Distance,
|
// top: Distance,
|
||||||
|
@ -3,7 +3,6 @@ package center.sciprog.maps.compose
|
|||||||
import center.sciprog.maps.coordinates.GeodeticMapCoordinates
|
import center.sciprog.maps.coordinates.GeodeticMapCoordinates
|
||||||
import center.sciprog.maps.coordinates.Gmc
|
import center.sciprog.maps.coordinates.Gmc
|
||||||
import center.sciprog.maps.coordinates.WebMercatorProjection
|
import center.sciprog.maps.coordinates.WebMercatorProjection
|
||||||
import center.sciprog.maps.coordinates.radians
|
|
||||||
import center.sciprog.maps.features.ViewPoint
|
import center.sciprog.maps.features.ViewPoint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,6 +15,6 @@ internal data class MapViewPoint(
|
|||||||
val scaleFactor: Float by lazy { WebMercatorProjection.scaleFactor(zoom) }
|
val scaleFactor: Float by lazy { WebMercatorProjection.scaleFactor(zoom) }
|
||||||
|
|
||||||
public companion object{
|
public companion object{
|
||||||
public val globe: MapViewPoint = MapViewPoint(GeodeticMapCoordinates(0.0.radians, 0.0.radians), 1f)
|
public val globe: MapViewPoint = MapViewPoint(Gmc.ofRadians(0.0, 0.0), 1f)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -66,7 +66,7 @@ public class MapViewScope internal constructor(
|
|||||||
override fun ViewPoint<Gmc>.moveBy(x: Dp, y: Dp): ViewPoint<Gmc> {
|
override fun ViewPoint<Gmc>.moveBy(x: Dp, y: Dp): ViewPoint<Gmc> {
|
||||||
val deltaX = x.value / tileScale
|
val deltaX = x.value / tileScale
|
||||||
val deltaY = y.value / tileScale
|
val deltaY = y.value / tileScale
|
||||||
val newCoordinates = GeodeticMapCoordinates(
|
val newCoordinates = Gmc.normalized(
|
||||||
(focus.latitude + (deltaY / scaleFactor).radians).coerceIn(
|
(focus.latitude + (deltaY / scaleFactor).radians).coerceIn(
|
||||||
-MercatorProjection.MAXIMUM_LATITUDE,
|
-MercatorProjection.MAXIMUM_LATITUDE,
|
||||||
MercatorProjection.MAXIMUM_LATITUDE
|
MercatorProjection.MAXIMUM_LATITUDE
|
||||||
|
@ -29,7 +29,7 @@ public object WebMercatorSpace : CoordinateSpace<Gmc> {
|
|||||||
override fun ViewPoint(center: Gmc, zoom: Float): ViewPoint<Gmc> = MapViewPoint(center, zoom)
|
override fun ViewPoint(center: Gmc, zoom: Float): ViewPoint<Gmc> = MapViewPoint(center, zoom)
|
||||||
|
|
||||||
override fun ViewPoint<Gmc>.moveBy(delta: Gmc): ViewPoint<Gmc> {
|
override fun ViewPoint<Gmc>.moveBy(delta: Gmc): ViewPoint<Gmc> {
|
||||||
val newCoordinates = GeodeticMapCoordinates(
|
val newCoordinates = Gmc.normalized(
|
||||||
(focus.latitude + delta.latitude).coerceIn(
|
(focus.latitude + delta.latitude).coerceIn(
|
||||||
-MercatorProjection.MAXIMUM_LATITUDE,
|
-MercatorProjection.MAXIMUM_LATITUDE,
|
||||||
MercatorProjection.MAXIMUM_LATITUDE
|
MercatorProjection.MAXIMUM_LATITUDE
|
||||||
@ -43,7 +43,7 @@ public object WebMercatorSpace : CoordinateSpace<Gmc> {
|
|||||||
ViewPoint(focus, (zoom + zoomDelta).coerceIn(2f, 18f))
|
ViewPoint(focus, (zoom + zoomDelta).coerceIn(2f, 18f))
|
||||||
} else {
|
} else {
|
||||||
val difScale = (1 - 2f.pow(-zoomDelta))
|
val difScale = (1 - 2f.pow(-zoomDelta))
|
||||||
val newCenter = GeodeticMapCoordinates(
|
val newCenter = Gmc.normalized(
|
||||||
focus.latitude + (invariant.latitude - focus.latitude) * difScale,
|
focus.latitude + (invariant.latitude - focus.latitude) * difScale,
|
||||||
focus.longitude + (invariant.longitude - focus.longitude) * difScale
|
focus.longitude + (invariant.longitude - focus.longitude) * difScale
|
||||||
)
|
)
|
||||||
@ -60,7 +60,7 @@ public object WebMercatorSpace : CoordinateSpace<Gmc> {
|
|||||||
val maxLat = maxOf { it.top }
|
val maxLat = maxOf { it.top }
|
||||||
val minLong = minOf { it.left }
|
val minLong = minOf { it.left }
|
||||||
val maxLong = maxOf { it.right }
|
val maxLong = maxOf { it.right }
|
||||||
return GmcRectangle(GeodeticMapCoordinates(minLat, minLong), GeodeticMapCoordinates(maxLat, maxLong))
|
return GmcRectangle(Gmc.normalized(minLat, minLong), Gmc.normalized(maxLat, maxLong))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Collection<Gmc>.wrapPoints(): Rectangle<Gmc>? {
|
override fun Collection<Gmc>.wrapPoints(): Rectangle<Gmc>? {
|
||||||
@ -70,7 +70,7 @@ public object WebMercatorSpace : CoordinateSpace<Gmc> {
|
|||||||
val maxLat = maxOf { it.latitude }
|
val maxLat = maxOf { it.latitude }
|
||||||
val minLong = minOf { it.longitude }
|
val minLong = minOf { it.longitude }
|
||||||
val maxLong = maxOf { it.longitude }
|
val maxLong = maxOf { it.longitude }
|
||||||
return GmcRectangle(GeodeticMapCoordinates(minLat, minLong), GeodeticMapCoordinates(maxLat, maxLong))
|
return GmcRectangle(Gmc.normalized(minLat, minLong), Gmc.normalized(maxLat, maxLong))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Gmc.offsetTo(b: Gmc, zoom: Float): DpOffset {
|
override fun Gmc.offsetTo(b: Gmc, zoom: Float): DpOffset {
|
||||||
@ -122,11 +122,11 @@ public fun CoordinateSpace<Gmc>.Rectangle(
|
|||||||
height: Angle,
|
height: Angle,
|
||||||
width: Angle,
|
width: Angle,
|
||||||
): Rectangle<Gmc> {
|
): Rectangle<Gmc> {
|
||||||
val a = GeodeticMapCoordinates(
|
val a = Gmc.normalized(
|
||||||
center.latitude - (height / 2),
|
center.latitude - (height / 2),
|
||||||
center.longitude - (width / 2)
|
center.longitude - (width / 2)
|
||||||
)
|
)
|
||||||
val b = GeodeticMapCoordinates(
|
val b = Gmc.normalized(
|
||||||
center.latitude + (height / 2),
|
center.latitude + (height / 2),
|
||||||
center.longitude + (width / 2)
|
center.longitude + (width / 2)
|
||||||
)
|
)
|
||||||
|
@ -5,13 +5,12 @@ package center.sciprog.maps.coordinates
|
|||||||
*/
|
*/
|
||||||
public class GeodeticMapCoordinates(
|
public class GeodeticMapCoordinates(
|
||||||
public val latitude: Angle,
|
public val latitude: Angle,
|
||||||
longitude: Angle,
|
public val longitude: Angle,
|
||||||
public val elevation: Distance = 0.kilometers
|
public val elevation: Distance = 0.kilometers,
|
||||||
) {
|
) {
|
||||||
public val longitude: Angle = longitude.normalized(Angle.zero)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(latitude in (-Angle.piDiv2)..(Angle.piDiv2)) { "Latitude $latitude is not in (-PI/2)..(PI/2)" }
|
require(latitude in (-Angle.piDiv2)..(Angle.piDiv2)) { "Latitude $latitude is not in (-PI/2)..(PI/2)" }
|
||||||
|
require(longitude in (-Angle.pi..Angle.pi)) { "Longitude $longitude is not in (-PI..PI) range" }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -38,14 +37,29 @@ public class GeodeticMapCoordinates(
|
|||||||
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public fun ofRadians(latitude: Double, longitude: Double): GeodeticMapCoordinates =
|
public fun normalized(
|
||||||
GeodeticMapCoordinates(latitude.radians, longitude.radians)
|
latitude: Angle,
|
||||||
|
longitude: Angle,
|
||||||
|
elevation: Distance = 0.kilometers,
|
||||||
|
): GeodeticMapCoordinates = GeodeticMapCoordinates(
|
||||||
|
latitude, longitude.normalized(Angle.zero), elevation
|
||||||
|
)
|
||||||
|
|
||||||
public fun ofDegrees(latitude: Double, longitude: Double): GeodeticMapCoordinates =
|
public fun ofRadians(
|
||||||
GeodeticMapCoordinates(latitude.degrees.radians, longitude.degrees.radians)
|
latitude: Double,
|
||||||
|
longitude: Double,
|
||||||
|
elevation: Distance = 0.kilometers,
|
||||||
|
): GeodeticMapCoordinates = normalized(latitude.radians, longitude.radians, elevation)
|
||||||
|
|
||||||
|
public fun ofDegrees(
|
||||||
|
latitude: Double,
|
||||||
|
longitude: Double,
|
||||||
|
elevation: Distance = 0.kilometers,
|
||||||
|
): GeodeticMapCoordinates = normalized(latitude.degrees.radians, longitude.degrees.radians, elevation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Short name for GeodeticMapCoordinates
|
* Short name for GeodeticMapCoordinates
|
||||||
*/
|
*/
|
||||||
|
@ -64,8 +64,8 @@ public fun GeoEllipsoid.meridianCurve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return GmcCurve(
|
return GmcCurve(
|
||||||
forward = GmcPose(Gmc(fromLatitude, longitude), if (up) zero else pi),
|
forward = GmcPose(Gmc.normalized(fromLatitude, longitude), if (up) zero else pi),
|
||||||
backward = GmcPose(Gmc(toLatitude, longitude), if (up) pi else zero),
|
backward = GmcPose(Gmc.normalized(toLatitude, longitude), if (up) pi else zero),
|
||||||
distance = s
|
distance = s
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -77,8 +77,8 @@ public fun GeoEllipsoid.parallelCurve(latitude: Angle, fromLongitude: Angle, toL
|
|||||||
require(latitude in (-piDiv2)..(piDiv2)) { "Latitude must be in (-90, 90) degrees range" }
|
require(latitude in (-piDiv2)..(piDiv2)) { "Latitude must be in (-90, 90) degrees range" }
|
||||||
val right = toLongitude > fromLongitude
|
val right = toLongitude > fromLongitude
|
||||||
return GmcCurve(
|
return GmcCurve(
|
||||||
forward = GmcPose(Gmc(latitude, fromLongitude), if (right) piDiv2.radians else -piDiv2.radians),
|
forward = GmcPose(Gmc.normalized(latitude, fromLongitude), if (right) piDiv2.radians else -piDiv2.radians),
|
||||||
backward = GmcPose(Gmc(latitude, toLongitude), if (right) -piDiv2.radians else piDiv2.radians),
|
backward = GmcPose(Gmc.normalized(latitude, toLongitude), if (right) -piDiv2.radians else piDiv2.radians),
|
||||||
distance = reducedRadius(latitude) * abs((fromLongitude - toLongitude).radians.value)
|
distance = reducedRadius(latitude) * abs((fromLongitude - toLongitude).radians.value)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ public fun GeoEllipsoid.curveInDirection(
|
|||||||
val L = lambda - (1 - C) * f * sinAlpha *
|
val L = lambda - (1 - C) * f * sinAlpha *
|
||||||
(sigma.value + C * sinSigma * (cosSigmaM2 + C * cosSigma * (-1 + 2 * cos2SigmaM2)))
|
(sigma.value + C * sinSigma * (cosSigmaM2 + C * cosSigma * (-1 + 2 * cos2SigmaM2)))
|
||||||
|
|
||||||
val endPoint = Gmc(phi2, start.longitude + L.radians)
|
val endPoint = Gmc.normalized(phi2, start.longitude + L.radians)
|
||||||
|
|
||||||
// eq. 12
|
// eq. 12
|
||||||
|
|
||||||
|
@ -14,3 +14,9 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kscience{
|
||||||
|
useSerialization {
|
||||||
|
json()
|
||||||
|
}
|
||||||
|
}
|
@ -3,12 +3,14 @@ package center.sciprog.maps.geojson
|
|||||||
import center.sciprog.maps.geojson.GeoJson.Companion.PROPERTIES_KEY
|
import center.sciprog.maps.geojson.GeoJson.Companion.PROPERTIES_KEY
|
||||||
import center.sciprog.maps.geojson.GeoJson.Companion.TYPE_KEY
|
import center.sciprog.maps.geojson.GeoJson.Companion.TYPE_KEY
|
||||||
import center.sciprog.maps.geojson.GeoJsonFeatureCollection.Companion.FEATURES_KEY
|
import center.sciprog.maps.geojson.GeoJsonFeatureCollection.Companion.FEATURES_KEY
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class to work with GeoJson (https://geojson.org/)
|
* A utility class to work with GeoJson (https://geojson.org/)
|
||||||
*/
|
*/
|
||||||
|
@Serializable(GeoJsonSerializer::class)
|
||||||
public sealed interface GeoJson {
|
public sealed interface GeoJson {
|
||||||
public val json: JsonObject
|
public val json: JsonObject
|
||||||
public val type: String get() = json[TYPE_KEY]?.jsonPrimitive?.content ?: error("Not a GeoJson")
|
public val type: String get() = json[TYPE_KEY]?.jsonPrimitive?.content ?: error("Not a GeoJson")
|
||||||
@ -34,6 +36,23 @@ public value class GeoJsonFeature(override val json: JsonObject) : GeoJson {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
public fun GeoJsonFeature.getProperty(key: String): JsonElement? = json[key] ?: properties?.get(key)
|
public fun GeoJsonFeature.getProperty(key: String): JsonElement? = json[key] ?: properties?.get(key)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
@ -60,20 +79,33 @@ public value class GeoJsonFeatureCollection(override val json: JsonObject) : Geo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
public fun GeoJson(json: JsonObject): GeoJson =
|
public fun GeoJson(json: JsonObject): GeoJson =
|
||||||
when (json[TYPE_KEY]?.jsonPrimitive?.contentOrNull ?: error("Not a GeoJson")) {
|
when (json[TYPE_KEY]?.jsonPrimitive?.contentOrNull ?: error("Not a GeoJson")) {
|
||||||
"Feature" -> GeoJsonFeature(json)
|
"Feature" -> GeoJsonFeature(json)
|
||||||
"FeatureCollection" -> GeoJsonFeatureCollection(json)
|
"FeatureCollection" -> GeoJsonFeatureCollection(json)
|
||||||
else -> GeoJsonGeometry(json)
|
else -> GeoJsonGeometry(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine a collection of features to a new [GeoJsonFeatureCollection]
|
|
||||||
*/
|
|
||||||
public fun GeoJsonFeatureCollection(features: Collection<GeoJsonFeature>): GeoJsonFeatureCollection =
|
|
||||||
GeoJsonFeatureCollection(
|
|
||||||
buildJsonObject {
|
|
||||||
put(TYPE_KEY, "FeatureCollection")
|
|
||||||
put(FEATURES_KEY, JsonArray(features.map { it.json }))
|
|
||||||
}
|
|
||||||
)
|
|
@ -1,6 +1,8 @@
|
|||||||
package center.sciprog.maps.geojson
|
package center.sciprog.maps.geojson
|
||||||
|
|
||||||
import center.sciprog.maps.coordinates.Gmc
|
import center.sciprog.maps.coordinates.Gmc
|
||||||
|
import center.sciprog.maps.coordinates.kilometers
|
||||||
|
import center.sciprog.maps.coordinates.meters
|
||||||
import center.sciprog.maps.geojson.GeoJsonGeometry.Companion.COORDINATES_KEY
|
import center.sciprog.maps.geojson.GeoJsonGeometry.Companion.COORDINATES_KEY
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
@ -25,7 +27,31 @@ public fun GeoJsonGeometry(json: JsonObject): GeoJsonGeometry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun JsonElement.toGmc() = jsonArray.run {
|
internal fun JsonElement.toGmc() = jsonArray.run {
|
||||||
Gmc.ofDegrees(get(1).jsonPrimitive.double, get(0).jsonPrimitive.double)
|
Gmc.ofDegrees(
|
||||||
|
get(1).jsonPrimitive.double,
|
||||||
|
get(0).jsonPrimitive.double,
|
||||||
|
get(2).jsonPrimitive.doubleOrNull?.meters ?: 0.kilometers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Gmc.toJsonArray(): JsonArray = buildJsonArray {
|
||||||
|
add(longitude.degrees.value)
|
||||||
|
add(latitude.degrees.value)
|
||||||
|
if (elevation.kilometers != 0.0) {
|
||||||
|
add(elevation.meters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<Gmc>.listToJsonArray(): JsonArray = buildJsonArray {
|
||||||
|
forEach {
|
||||||
|
add(it.toJsonArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<List<Gmc>>.listOfListsToJsonArray(): JsonArray = buildJsonArray {
|
||||||
|
forEach {
|
||||||
|
add(it.listToJsonArray())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
@ -39,6 +65,13 @@ public value class GeoJsonPoint(override val json: JsonObject) : GeoJsonGeometry
|
|||||||
?: error("Coordinates are not provided")
|
?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonPoint(coordinates: Gmc): GeoJsonPoint = GeoJsonPoint(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "Point")
|
||||||
|
put(COORDINATES_KEY, coordinates.toJsonArray())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonMultiPoint(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonMultiPoint(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
@ -51,6 +84,13 @@ public value class GeoJsonMultiPoint(override val json: JsonObject) : GeoJsonGeo
|
|||||||
?: error("Coordinates are not provided")
|
?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonMultiPoint(coordinates: List<Gmc>): GeoJsonMultiPoint = GeoJsonMultiPoint(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "MultiPoint")
|
||||||
|
put(COORDINATES_KEY, coordinates.listToJsonArray())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonLineString(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonLineString(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
@ -63,6 +103,13 @@ public value class GeoJsonLineString(override val json: JsonObject) : GeoJsonGeo
|
|||||||
?: error("Coordinates are not provided")
|
?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonLineString(coordinates: List<Gmc>): GeoJsonLineString = GeoJsonLineString(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "LineString")
|
||||||
|
put(COORDINATES_KEY, coordinates.listToJsonArray())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonMultiLineString(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonMultiLineString(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
@ -77,6 +124,13 @@ public value class GeoJsonMultiLineString(override val json: JsonObject) : GeoJs
|
|||||||
} ?: error("Coordinates are not provided")
|
} ?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonMultiLineString(coordinates: List<List<Gmc>>): GeoJsonMultiLineString = GeoJsonMultiLineString(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "MultiLineString")
|
||||||
|
put(COORDINATES_KEY, coordinates.listOfListsToJsonArray())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonPolygon(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonPolygon(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
@ -91,6 +145,13 @@ public value class GeoJsonPolygon(override val json: JsonObject) : GeoJsonGeomet
|
|||||||
} ?: error("Coordinates are not provided")
|
} ?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonPolygon(coordinates: List<List<Gmc>>): GeoJsonPolygon = GeoJsonPolygon(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "Polygon")
|
||||||
|
put(COORDINATES_KEY, coordinates.listOfListsToJsonArray())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonMultiPolygon(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonMultiPolygon(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
@ -107,11 +168,31 @@ public value class GeoJsonMultiPolygon(override val json: JsonObject) : GeoJsonG
|
|||||||
} ?: error("Coordinates are not provided")
|
} ?: error("Coordinates are not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonMultiPolygon(coordinates: List<List<List<Gmc>>>): GeoJsonMultiPolygon = GeoJsonMultiPolygon(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "MultiPolygon")
|
||||||
|
put(COORDINATES_KEY, buildJsonArray { coordinates.forEach { add(it.listOfListsToJsonArray()) } })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class GeoJsonGeometryCollection(override val json: JsonObject) : GeoJsonGeometry {
|
public value class GeoJsonGeometryCollection(override val json: JsonObject) : GeoJsonGeometry {
|
||||||
init {
|
init {
|
||||||
require(type == "GeometryCollection") { "Not a GeoJson GeometryCollection geometry" }
|
require(type == "GeometryCollection") { "Not a GeoJson GeometryCollection geometry" }
|
||||||
}
|
}
|
||||||
|
|
||||||
public val geometries: List<GeoJsonGeometry> get() = json.jsonArray.map { GeoJsonGeometry(it.jsonObject) }
|
public val geometries: List<GeoJsonGeometry>
|
||||||
|
get() = json["geometries"]?.jsonArray?.map { GeoJsonGeometry(it.jsonObject) } ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun GeoJsonGeometryCollection(geometries: List<GeoJsonGeometry>): GeoJsonGeometryCollection =
|
||||||
|
GeoJsonGeometryCollection(
|
||||||
|
buildJsonObject {
|
||||||
|
put(GeoJson.TYPE_KEY, "GeometryCollection")
|
||||||
|
put("geometries", buildJsonArray {
|
||||||
|
geometries.forEach {
|
||||||
|
add(it.json)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
@ -1,6 +0,0 @@
|
|||||||
package center.sciprog.maps.geojson
|
|
||||||
|
|
||||||
import center.sciprog.attributes.Attribute
|
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
|
|
||||||
public object GeoJsonPropertiesAttribute : Attribute<JsonObject>
|
|
@ -0,0 +1,7 @@
|
|||||||
|
package center.sciprog.maps.geojson
|
||||||
|
|
||||||
|
import center.sciprog.attributes.SerializableAttribute
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
|
||||||
|
public object GeoJsonPropertiesAttribute : SerializableAttribute<JsonObject>("properties", serializer())
|
@ -0,0 +1,21 @@
|
|||||||
|
package center.sciprog.maps.geojson
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
|
||||||
|
|
||||||
|
public object GeoJsonSerializer : KSerializer<GeoJson> {
|
||||||
|
|
||||||
|
private val serializer = JsonObject.serializer()
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = serializer.descriptor
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): GeoJson = GeoJson(serializer.deserialize(decoder))
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: GeoJson) {
|
||||||
|
serializer.serialize(encoder, value.json)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user