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é

Invalid polygon

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:

Part of the polygon was lost

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?

Desired output

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.

20
demandé sur tofarr 2015-07-17 13:17:51

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;
    }
}
30
répondu tofarr 2016-05-19 12:33:57