java - Is there a way to convert a self intersecting polygon to a multipolygon in JTS? -


take invalid polygon polygon((0 100, 100 100, 0 0, 100 0, 0 100)) - egg timer shape undeclared point of intersection

invalid polygon

many instructions jts can create valid version of using buffer method:

geometry input = new wktreader().read("polygon((0 100, 100 100, 0 0, 100 0, 0 100))"); geometry output = geom.buffer(0); return output; 

however, produces output polygon ((0 100, 100 100, 50 50, 0 100)) part of polygon lost:

part of polygon lost

is there way jts validate polygons such produce output multipolygon(((0 100, 100 100, 50 50, 0 100)), ((0 0, 100 0, 50 50, 0 0))) input given?

desired output

this seems should built in api (maybe behaviour bug) - have missed something?

thank you.

jts seems offer behaviour require, though had little legwork in own code. validate function wrote breaks down polygon/multipolygon collection of non self intersecting linestrings, , uses polygonizer class build polygons result. have tested on following (limited) set of inputs, , seems behave way require:

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

code:

/**  * / create valid version of geometry given. if geometry polygon or multi polygon, self intersections /  * inconsistencies fixed. otherwise geometry returned.  *   * @param geom  * @return geometry   */ public static geometry validate(geometry geom){     if(geom instanceof polygon){         if(geom.isvalid()){             geom.normalize(); // validate not pick rings in wrong order - fix             return geom; // if polygon valid return         }         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 not pick rings in wrong order - fix             return geom; // if multipolygon valid return         }         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 case, care polygon / multipolygon geometries     } }  /**  * add line strings polygon given polygonizer given  *   * @param polygon polygon 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 linestring given polygonizer  *   * @param linestring line string  * @param polygonizer polygonizer  */ static void addlinestring(linestring linestring, polygonizer polygonizer){      if(linestring instanceof linearring){ // linearrings treated differently line strings : need linestring not linearring         linestring = linestring.getfactory().createlinestring(linestring.getcoordinatesequence());     }      // unioning linestring point makes self intersections explicit.     point point = linestring.getfactory().createpoint(linestring.getcoordinaten(0));     geometry toadd = linestring.union(point);       //add result polygonizer     polygonizer.add(toadd); }  /**  * geometry collection of polygons.  *   * @param polygons collection  * @param factory factory generate multipolygon if required  * @return null if there no polygons, polygon if there one, or multipolygon containing 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 wrap         default:             //polygons may still overlap! need sym difference them             iterator<polygon> iter = polygons.iterator();             geometry ret = iter.next();             while(iter.hasnext()){                 ret = ret.symdifference(iter.next());             }             return ret;     } } 

Comments