有没有办法在JTS中将自相交多边形转换为多面?

取无效多边形POLYGON((0 100, 100 100, 0 0, 100 0, 0 100)) – 一个带有未声明交点的蛋计时器形状

无效的多边形

许多指令说JTS可以使用buffer方法创建一个有效版本:

 Geometry input = new WKTReader().read("POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))"); Geometry output = geom.buffer(0); return output; 

但是,这会产生输出POLYGON ((0 100, 100 100, 50 50, 0 100)) ,其中部分多边形丢失:

部分多边形丢失了

有没有办法让JTSvalidation多边形,使其产生输出MULTIPOLYGON(((0 100, 100 100, 50 50, 0 100)), ((0 0, 100 0, 50 50, 0 0)))给出的输入?

期望的输出

这似乎应该内置到API(可能这种行为是一个错误) – 我错过了什么?

谢谢。

JTS似乎提供了我需要的行为,尽管我必须在自己的代码中做一些小工作。 我写的validate函数将多边形/多面体分解为非自相交线串的集合,然后使用Polygonizer类从结果中构建多边形。 我已经在以下(有限的)输入集上测试了它,它看起来像我需要的那样:

  POLYGON((0 100, 100 100, 0 0, 100 0, 0 100)) POLYGON((0 0, 0 100, 100 100, 100 0, 0 0)) MULTIPOLYGON(((0 0, 0 100, 100 100, 100 0, 0 0)),((50 50, 50 150, 150 150, 150 50, 50 50))) POLYGON((0 0, 50 50, 100 0, 150 0, 200 50, 250 0, 0 0)) 

码:

 /** * Get / create a valid version of the geometry given. If the geometry is a polygon or multi polygon, self intersections / * inconsistencies are fixed. Otherwise the geometry is returned. * * @param geom * @return a geometry */ public static Geometry validate(Geometry geom){ if(geom instanceof Polygon){ if(geom.isValid()){ geom.normalize(); // validate does not pick up rings in the wrong order - this will fix that return geom; // If the polygon is valid just return it } Polygonizer polygonizer = new Polygonizer(); addPolygon((Polygon)geom, polygonizer); return toPolygonGeometry(polygonizer.getPolygons(), geom.getFactory()); }else if(geom instanceof MultiPolygon){ if(geom.isValid()){ geom.normalize(); // validate does not pick up rings in the wrong order - this will fix that return geom; // If the multipolygon is valid just return it } Polygonizer polygonizer = new Polygonizer(); for(int n = geom.getNumGeometries(); n-- > 0;){ addPolygon((Polygon)geom.getGeometryN(n), polygonizer); } return toPolygonGeometry(polygonizer.getPolygons(), geom.getFactory()); }else{ return geom; // In my case, I only care about polygon / multipolygon geometries } } /** * Add all line strings from the polygon given to the polygonizer given * * @param polygon polygon from which to extract line strings * @param polygonizer polygonizer */ static void addPolygon(Polygon polygon, Polygonizer polygonizer){ addLineString(polygon.getExteriorRing(), polygonizer); for(int n = polygon.getNumInteriorRing(); n-- > 0;){ addLineString(polygon.getInteriorRingN(n), polygonizer); } } /** * Add the linestring given to the polygonizer * * @param linestring line string * @param polygonizer polygonizer */ static void addLineString(LineString lineString, Polygonizer polygonizer){ if(lineString instanceof LinearRing){ // LinearRings are treated differently to line strings : we need a LineString NOT a LinearRing lineString = lineString.getFactory().createLineString(lineString.getCoordinateSequence()); } // unioning the linestring with the point makes any self intersections explicit. Point point = lineString.getFactory().createPoint(lineString.getCoordinateN(0)); Geometry toAdd = lineString.union(point); //Add result to polygonizer polygonizer.add(toAdd); } /** * Get a geometry from a collection of polygons. * * @param polygons collection * @param factory factory to generate MultiPolygon if required * @return null if there were no polygons, the polygon if there was only one, or a MultiPolygon containing all polygons otherwise */ static Geometry toPolygonGeometry(Collection polygons, GeometryFactory factory){ switch(polygons.size()){ case 0: return null; // No valid polygons! case 1: return polygons.iterator().next(); // single polygon - no need to wrap default: //polygons may still overlap! Need to sym difference them Iterator iter = polygons.iterator(); Geometry ret = iter.next(); while(iter.hasNext()){ ret = ret.symDifference(iter.next()); } return ret; } }