package org.osm2world.core.math.algorithms; import static org.osm2world.core.math.JTSConversionUtil.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.osm2world.core.math.PolygonWithHolesXZ; import org.osm2world.core.math.SimplePolygonXZ; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.Polygon; /** * utility class for Constructive Area Geometry (CAG), * boolean operations on areas */ public final class CAGUtil { private CAGUtil() { } /** * takes a polygon outline, "subtracts" a collection of other polygon outlines, * and returns a collection of polygons that covers the difference area. * * The result polygons should cover the area that was * within the original polygon (excluding its holes), * but not within a subtracted polygon. * * @return * polygons without self-intersections, but maybe with holes */ public static final Collection<PolygonWithHolesXZ> subtractPolygons( SimplePolygonXZ basePolygon, List<? extends SimplePolygonXZ> subtractPolygons) { List<Geometry> remainingGeometry = Collections.singletonList( (Geometry)polygonXZToJTSPolygon(basePolygon)); for (SimplePolygonXZ subtractPolygon : subtractPolygons) { Polygon jtsSubtractPolygon = polygonXZToJTSPolygon(subtractPolygon); if (!jtsSubtractPolygon.isValid()) continue; List<Geometry> newRemainingGeometry = new ArrayList<Geometry>(1); for (Geometry g : remainingGeometry) { Geometry newG = g.difference(jtsSubtractPolygon); if (newG instanceof GeometryCollection) { for (int i = 0; i < ((GeometryCollection)newG).getNumGeometries(); i++) { newRemainingGeometry.add(((GeometryCollection)newG).getGeometryN(i)); } } else { newRemainingGeometry.add(newG); } } remainingGeometry = newRemainingGeometry; } Collection<PolygonWithHolesXZ> result = new ArrayList<PolygonWithHolesXZ>(); for (Geometry g : remainingGeometry) { result.addAll(polygonsXZFromJTSGeometry(g)); } return result; } /** * calculates the intersection area of a collection of polygons. * * The result polygons should cover the area that was * within all of the polygons. */ public static final Collection<PolygonWithHolesXZ> intersectPolygons( List<? extends SimplePolygonXZ> intersectPolygons) { if (intersectPolygons.isEmpty()) { throw new IllegalArgumentException(); } Geometry remainingGeometry = null; for (SimplePolygonXZ poly : intersectPolygons) { Polygon jtsPoly = polygonXZToJTSPolygon(poly); if (remainingGeometry == null) { remainingGeometry = jtsPoly; } else { remainingGeometry = remainingGeometry.intersection(jtsPoly); } } return polygonsXZFromJTSGeometry(remainingGeometry); } }