All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.jetbrains.datalore.base.spatial.GeoJson.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * Copyright (c) 2020. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.base.spatial

import jetbrains.datalore.base.json.FluentArray
import jetbrains.datalore.base.json.FluentObject
import jetbrains.datalore.base.json.JsonSupport
import jetbrains.datalore.base.typedGeometry.*

object GeoJson {
    private const val LON_INDEX = 0
    private const val LAT_INDEX = 1

    fun  parse(geoJson: String, handler: SimpleFeature.Consumer.() -> Unit) {
        val geoObj = FluentObject(JsonSupport.parseJson(geoJson))
        val geometryConsumer = SimpleFeature.Consumer().apply(handler)
        Parser().parse(geoObj, geometryConsumer)
    }

    fun  parse(geoJson: String, consumer: SimpleFeature.GeometryConsumer) {
        val geoObj = FluentObject(JsonSupport.parseJson(geoJson))
        Parser().parse(geoObj, consumer)
    }

    private class Parser {

        internal fun parse(obj: FluentObject, handler: SimpleFeature.GeometryConsumer) {
            when (val type = obj.getString("type")) {
                "FeatureCollection" -> {
                    require(obj.contains("features")) { "GeoJson: Missing 'features' in 'FeatureCollection'" }

                    obj.getArray("features").fluentObjectStream()
                        .filter { it.getString("type") == "Feature" }
                        .map { it.getObject("geometry") }
                        .forEach { parse(it, handler) }
                }

                "GeometryCollection" -> {
                    require(obj.contains("geometries")) { "GeoJson: Missing 'geometries' in 'GeometryCollection'" }

                    obj.getArray("geometries").fluentObjectStream()
                        .forEach { parse(it, handler) }
                }

                else -> {
                    require(obj.contains("coordinates")) { "GeoJson: Missing 'coordinates' in $type" }

                    val coordinates = obj.getArray("coordinates")
                    when (type) {
                        "Point" -> parsePoint(coordinates).let(handler::onPoint)
                        "LineString" -> parseLineString(coordinates).let(handler::onLineString)
                        "Polygon" -> parsePolygon(coordinates).let(handler::onPolygon)
                        "MultiPoint" -> parseMultiPoint(coordinates).let(handler::onMultiPoint)
                        "MultiLineString" -> parseMultiLineString(coordinates).let(handler::onMultiLineString)
                        "MultiPolygon" -> parseMultiPolygon(coordinates).let(handler::onMultiPolygon)
                        else -> error("Not support GeoJson type: $type")
                    }
                }
            }
        }

        private fun parsePoint(jsonPoint: FluentArray): Vec {
            return explicitVec(
                jsonPoint.getDouble(LON_INDEX),
                jsonPoint.getDouble(LAT_INDEX)
            )
        }

        private fun parseLineString(jsonLineString: FluentArray): LineString {
            return jsonLineString.mapArray(this::parsePoint).let(::LineString)
        }

        private fun parseRing(jsonRing: FluentArray): Ring {
            return jsonRing.mapArray(this::parsePoint).let(::Ring)
        }

        private fun parseMultiPoint(jsonMultiPoint: FluentArray): MultiPoint {
            return jsonMultiPoint.mapArray(this::parsePoint).let(::MultiPoint)
        }

        private fun parsePolygon(jsonPolygon: FluentArray): Polygon {
            return jsonPolygon.mapArray(this::parseRing).let(::Polygon)
        }

        private fun parseMultiLineString(jsonLineStrings: FluentArray): MultiLineString {
            return jsonLineStrings.mapArray(this::parseLineString).let(::MultiLineString)
        }

        private fun parseMultiPolygon(jsonMultiPolygon: FluentArray): MultiPolygon {
            return jsonMultiPolygon.mapArray(this::parsePolygon).let(::MultiPolygon)
        }

        private fun  FluentArray.mapArray(f: (FluentArray) -> T): List {
            return this.stream().map { f(FluentArray(it as List)) }.toList()
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy