如何使用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
相关产品推荐
相关产品推荐

