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

如何使用JTS从坐标列表中提取多边形?

如何使用JTS从坐标列表中提取多边形?

嘿,这个问题我之前也碰到过!其实不用手动挨个检查闭合环,JTS里有更优雅的解决方案,我给你分享两种实用的思路:

方法一:借助WKTReader快速转换

如果你的坐标列表是按完整闭合环顺序排列的(就像你给的例子那样),可以先把整个列表转换成标准WKT格式的MULTIPOLYGON字符串,然后用JTS的WKTReader直接解析出MultiPolygon对象,之后就能轻松提取每个单独的多边形了,省得自己写复杂的判断逻辑。

举个例子,你给出的坐标对应的WKT字符串长这样:

MULTIPOLYGON (((0 0, 0 5, 5 5, 5 0, 0 0)), ((12 12, 12 17, 17 17, 17 12, 12 12)))

对应的Java实现代码大概是这样:

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.io.WKTReader;
import java.util.List;
import java.util.ArrayList;

// 假设你的坐标列表已经准备好
List<Coordinate> coordinateList = ...;

// 第一步:把坐标列表拼接成WKT格式的字符串
StringBuilder wktBuilder = new StringBuilder("MULTIPOLYGON (");
List<Coordinate> currentRing = new ArrayList<>();

for (Coordinate coord : coordinateList) {
    currentRing.add(coord);
    // 检查当前环是否闭合:当前点等于环的第一个点,且环至少有4个点(3个顶点+闭合点)
    if (currentRing.size() >= 4 && coord.equals(currentRing.get(0))) {
        // 拼接当前环的WKT片段
        wktBuilder.append("(");
        for (int i = 0; i < currentRing.size(); i++) {
            Coordinate c = currentRing.get(i);
            wktBuilder.append(c.x).append(" ").append(c.y);
            if (i != currentRing.size() - 1) {
                wktBuilder.append(", ");
            }
        }
        wktBuilder.append("),");
        currentRing.clear();
    }
}

// 移除最后一个多余的逗号,闭合WKT字符串
if (wktBuilder.charAt(wktBuilder.length() - 1) == ',') {
    wktBuilder.deleteCharAt(wktBuilder.length() - 1);
}
wktBuilder.append(")");

// 第二步:用WKTReader解析成MultiPolygon
WKTReader reader = new WKTReader();
Geometry geometry = reader.read(wktBuilder.toString());
if (geometry instanceof MultiPolygon) {
    MultiPolygon multiPolygon = (MultiPolygon) geometry;
    // 遍历提取每个多边形
    for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
        Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
        // 这里处理每个提取到的多边形
        System.out.println("提取到的多边形:" + polygon);
    }
}

方法二:手动分割坐标环(更轻量)

如果你不想依赖WKT解析,其实手动分割也没那么繁琐,而且更轻量。核心思路就是识别闭合环的结束点(也就是和环的起始点相同的点),然后用GeometryFactory直接创建多边形:

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import java.util.List;
import java.util.ArrayList;

GeometryFactory geometryFactory = new GeometryFactory();
List<Coordinate> coordinateList = ...;
List<Polygon> polygons = new ArrayList<>();

if (coordinateList.isEmpty()) {
    return polygons;
}

List<Coordinate> currentRing = new ArrayList<>();
currentRing.add(coordinateList.get(0));

for (int i = 1; i < coordinateList.size(); i++) {
    Coordinate coord = coordinateList.get(i);
    currentRing.add(coord);
    
    // 检查当前环是否闭合
    if (coord.equals(currentRing.get(0)) && currentRing.size() >= 4) {
        // 创建LinearRing和对应的Polygon
        LinearRing linearRing = geometryFactory.createLinearRing(currentRing.toArray(new Coordinate[0]));
        Polygon polygon = geometryFactory.createPolygon(linearRing);
        polygons.add(polygon);
        
        // 重置当前环,准备收集下一个多边形的坐标
        currentRing.clear();
        if (i + 1 < coordinateList.size()) {
            currentRing.add(coordinateList.get(i + 1));
            i++; // 跳过已经加入的下一个环的起始点
        }
    }
}

// 处理最后一个可能遗留的闭合环(根据你的备注,输入是合法的,这一步可能用不上)
if (!currentRing.isEmpty() && currentRing.size() >= 4 && currentRing.get(currentRing.size() - 1).equals(currentRing.get(0))) {
    LinearRing linearRing = geometryFactory.createLinearRing(currentRing.toArray(new Coordinate[0]));
    Polygon polygon = geometryFactory.createPolygon(linearRing);
    polygons.add(polygon);
}

补充说明

为什么GeometryFactory没有直接处理这种连续坐标的方法呢?因为JTS需要明确知道每个环的起始和结束位置,它没法自动判断坐标序列里的分界点。所以上面两种方法本质上都是先识别环的分界,再创建多边形,只是第一种借助了WKT的格式来简化解析过程。

另外,根据你备注里说的输入都是无洞的多边形序列,这两种方法都完全适用,不用考虑内部环的情况~

备注:内容来源于stack exchange,提问作者MC Emperor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 20:23:02