You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中平移GeoJSON FeatureCollection的所有坐标

GeoJSON FeatureCollection坐标平移的最优实现方案(Kotlin + Jackson)

问题描述

我用Kotlin开发,通过Jackson的jacksonObjectMapper解析GeoJSON的FeatureCollection数据,需要平移所有要素内所有几何图形的所有坐标。目前能想到的是针对每种几何类型循环修改每个坐标,想知道有没有更优的实现方法。

示例输入

FeatureCollection数据

{
    "type":"FeatureCollection",
    "features": [
        {
            "type":"Feature",
            "properties": {
                "background": "WALLS_LOAD_BEARING"
            },
            "geometry": {
                "type":"MultiPolygon",
                "coordinates":[
                    [[[10.0, 20.0], [15.0, 20.0], [10.0, 25.0]]]
                ]
            }
        },
        {
            "type":"Feature",
            "properties": {
                "background":"PARTITIONS"
            },
            "geometry": {
                "type":"MultiPolygon",
                "coordinates": []
            }
        },
        {
            "type":"Feature",
            "properties": {
                "background":"WALLS_LOAD_BEARING"
            },
            "geometry": {
                "type":"LineString",
                "coordinates": [[10.0, 20.0]]
            }
        }
    ]
}

平移参数

val moveX = 10.0
val moveY = 5.0

预期输出

{
    "type":"FeatureCollection",
    "features": [
        {
            "type":"Feature",
            "properties": {
                "background": "WALLS_LOAD_BEARING"
            },
            "geometry": {
                "type":"MultiPolygon",
                "coordinates":[
                    [[[20.0, 25.0], [25.0, 25.0], [20.0, 30.0]]]
                ]
            }
        },
        {
            "type":"Feature",
            "properties": {
                "background":"PARTITIONS"
            },
            "geometry": {
                "type":"MultiPolygon",
                "coordinates": []
            }
        },
        {
            "type":"Feature",
            "properties": {
                "background":"WALLS_LOAD_BEARING"
            },
            "geometry": {
                "type":"LineString",
                "coordinates": [[20.0, 25.0]]
            }
        }
    ]
}

最优解决方案

方案1:递归遍历JsonNode(无额外依赖)

利用GeoJSON坐标的嵌套数组特性,写一个递归函数统一处理所有几何类型的坐标,无需针对每种几何类型单独编码,代码简洁且扩展性强。

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ArrayNode

fun translateGeoJsonCoordinates(rootNode: JsonNode, moveX: Double, moveY: Double) {
    // 遍历所有Feature节点
    val features = rootNode.get("features") as? ArrayNode ?: return
    features.forEach { featureNode ->
        val geometryNode = featureNode.get("geometry") ?: return@forEach
        val coordinatesNode = geometryNode.get("coordinates") as? ArrayNode ?: return@forEach
        // 递归处理所有嵌套坐标
        processCoordinates(coordinatesNode, moveX, moveY)
    }
}

private fun processCoordinates(node: ArrayNode, moveX: Double, moveY: Double) {
    node.forEachIndexed { index, element ->
        when {
            // 识别最内层的坐标点(长度为2的数组),执行平移
            element.isArray && element.size() == 2 -> {
                val newX = element.get(0).asDouble() + moveX
                val newY = element.get(1).asDouble() + moveY
                (element as ArrayNode).set(0, node.objectNodeFactory.numberNode(newX))
                (element as ArrayNode).set(1, node.objectNodeFactory.numberNode(newY))
            }
            // 嵌套数组则递归深入处理
            element.isArray -> processCoordinates(element as ArrayNode, moveX, moveY)
        }
    }
}

// 使用示例
fun main() {
    val mapper = ObjectMapper()
    val geoJsonStr = """你的FeatureCollection JSON字符串"""
    val rootNode = mapper.readTree(geoJsonStr)
    
    // 执行平移
    translateGeoJsonCoordinates(rootNode, 10.0, 5.0)
    
    // 输出格式化后的结果
    println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode))
}

优势:无需额外依赖,代码量少,自动适配所有GeoJSON几何类型(Point、LineString、Polygon、MultiXXX等),新增几何类型时无需修改代码。

方案2:使用专业Geo处理库(适合复杂场景)

如果需要处理更多空间操作(旋转、缩放等),推荐使用专业Geo库(如GeoTools),库会自动处理所有GeoJSON细节,代码更简洁可靠。

依赖配置(build.gradle.kts)

implementation("org.geotools:gt-geojson:28.2")

实现代码

import org.geotools.geojson.feature.FeatureJSON
import org.locationtech.jts.geom.Geometry
import org.locationtech.jts.geom.util.AffineTransformation
import java.io.StringReader
import java.io.StringWriter

fun translateGeoJsonWithGeoTools(geoJsonStr: String, moveX: Double, moveY: Double): String {
    val featureJSON = FeatureJSON()
    // 解析FeatureCollection
    val reader = StringReader(geoJsonStr)
    val featureCollection = featureJSON.readFeatureCollection(reader)
    
    // 创建平移变换
    val affineTransform = AffineTransformation.translationInstance(moveX, moveY)
    
    // 遍历所有Feature并平移几何
    featureCollection.features().forEach { feature ->
        val geometry = feature.defaultGeometry as Geometry
        val translatedGeometry = affineTransform.transform(geometry)
        feature.defaultGeometry = translatedGeometry
    }
    
    // 序列化回JSON
    val writer = StringWriter()
    featureJSON.writeFeatureCollection(featureCollection, writer)
    return writer.toString()
}

// 使用示例
fun main() {
    val geoJsonStr = """你的FeatureCollection JSON字符串"""
    val translatedGeoJson = translateGeoJsonWithGeoTools(geoJsonStr, 10.0, 5.0)
    println(translatedGeoJson)
}

优势:专业库封装了所有空间操作逻辑,无需手动处理坐标嵌套,代码可读性高,适合有复杂空间需求的项目。

总结

  • 仅需简单平移且不想加依赖:选方案1,递归处理JsonNode是最优解
  • 有复杂空间操作需求:选方案2,专业Geo库更高效可靠

内容的提问来源于stack exchange,提问作者user2704006

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 08:25:12