java geometry jts

java - ¿Hay una manera de convertir un polígono que se intersecta a sí mismo en un multipolígono en JTS?



jts github (1)

Tome el polígono no válido POLYGON((0 100, 100 100, 0 0, 100 0, 0 100)) - una forma de temporizador de huevo con un punto de intersección no declarado

Muchas instrucciones dicen que JTS puede crear una versión válida de esto usando el método de buffer :

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

Sin embargo, esto produce la salida POLYGON ((0 100, 100 100, 50 50, 0 100)) donde se pierde parte del polígono:

¿Hay alguna forma de que JTS valide polígonos de modo que produzca la salida MULTIPOLYGON(((0 100, 100 100, 50 50, 0 100)), ((0 0, 100 0, 50 50, 0 0))) para la entrada dada?

Esto parece algo que debería estar integrado en la API (tal vez este comportamiento es un error). ¿Me he perdido algo?

Gracias.


JTS parece ofrecer el comportamiento que necesito, aunque tuve que hacer un poco de trabajo de piernas en mi propio código. La función de validate que escribí descompone un polígono / multipolígono en una colección de cadenas de líneas que no se intersectan a sí mismas, y luego usa la clase Polygonizer para construir polígonos a partir del resultado. Lo he probado en el siguiente conjunto (limitado) de entradas y parece que se comporta de la manera que necesito:

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))

Código:

/** * 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<Polygon> 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<Polygon> iter = polygons.iterator(); Geometry ret = iter.next(); while(iter.hasNext()){ ret = ret.symDifference(iter.next()); } return ret; } }