Y a-t-il un moyen de convertir un polygone se croisant en un polygone multipolytique dans JTS?
prendre le polygone invalide POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))
- une forme de minuterie à l'oeuf avec un point d'intersection non déclaré
de nombreuses instructions disent que JTS peut créer une version valide de ceci en utilisant le buffer
méthode:
Geometry input = new WKTReader().read("POLYGON((0 100, 100 100, 0 0, 100 0, 0 100))");
Geometry output = geom.buffer(0);
return output;
Toutefois, ce produit de la sortie POLYGON ((0 100, 100 100, 50 50, 0 100))
où une partie du polygone est perdu:
Est-il possible d'obtenir le STC pour valider les polygones tels que la sortie MULTIPOLYGON(((0 100, 100 100, 50 50, 0 100)), ((0 0, 100 0, 50 50, 0 0)))
pour les entrées données?
cela ressemble à quelque chose qui devrait être intégré à L'API (peut - être que ce comportement est un bogue) - ai-je manqué quelque chose?
je vous Remercie.
1 réponses
JTS semble offrir le comportement dont j'ai besoin, bien que j'ai dû faire un peu de travail dans mon propre code. validate
la fonction que j'ai écrite décompose un polygone / multipolygon en un ensemble de lignes non auto-croisées, et puis utilise le Polygonizer
classe pour construire des polygones à partir du résultat. Je l'ai testé sur le suivant (limitée) de l'ensemble des entrées, et il semble se comporter de la façon dont j'ai besoin:
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:
/**
* 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;
}
}