// Process a Polygonal layer made of simple Polygons, and create holes // in larger polygons using inner Polygons. // The rules used to determine if a Polygon represents a Shell or a Hole are as // follows : // - A Polygon A which is not contained in the Exterior Envelope of any other // Polygon is a Shell // - A Polygon A which is strictly included in a Shell B is a Hole of B, except // if there is another Polygon C included in the Shell B and including A // - A Polygon A included in a "Hole" of Polygon B (A is strictly included in // the Exterior Envelope of Polygon B but not in the Area of Polygon B) is // considered as a Hole of Polygon B if it "fill" the hole (this last test is // just done by comparing lengths of A.intersection(B) and A exterior Ring. // Michael Michaud 2010-03-30 import com.vividsolutions.jump.feature.IndexedFeatureCollection; import com.vividsolutions.jts.index.strtree.STRtree; import com.vividsolutions.jump.workbench.ui.OKCancelDialog; /** * Determine if g1 can be considered as a hole of g2. */ boolean isIn(Geometry g1, Geometry g2) { if (!(g1 instanceof Polygon)) return false; if (!(g2 instanceof Polygon)) return false; if (!g1.envelopeInternal.intersects(g2.envelopeInternal)) return false; if (g1.envelopeInternal.contains(g2.envelopeInternal)) return false; // g2 envelope contains g1 envelope if (g2.envelopeInternal.contains(g1.envelopeInternal) && // g1 "fill" a hole of g2 Math.abs(1.0 - g1.intersection(g2).getLength()/g1.exteriorRing.getLength()) < 0.01 && // g1 is "strictly" contained in g2 g1.relate(g2.factory.createPolygon(g2.exteriorRing, new LinearRing[0]), "TFFTFF***")) { return true; } return false; } /** * Main loop over pairs of Features */ List processFeatures(FeatureCollection fc) { // A map containing all the Polygons "enclosing" a given key-Polygon enclosing = new HashMap(); // A map containing all the Polygons strictly included in a given key-Polygon enclosed = new HashMap(); // For each feature int count = 0; for (f1: fc.features) { // Ajoute une liste des contours circonscrits //enclosing.put(f1, new ArrayList()); if (count++%100==99) print(" phase 1 : " + count + " objets trait�s"); for (f2 : fc.query(f1.geometry.envelopeInternal)) { if (f1!=f2 && isIn(f1.geometry, f2.geometry)) { outers = enclosing.get(f1); outers = outers==null?new ArrayList():outers; outers.add(f2); enclosing.put(f1, outers); inners = enclosed.get(f2); inners = inners==null?new ArrayList():inners; inners.add(f1); enclosed.put(f2, inners); } } } print(" phase 1 : " + count + " objets trait�s"); count = 0; holes = new ArrayList(); for (f1 : fc.features) { count++; inners = enclosed.get(f1); if (inners == null) continue; for (f2 : inners) { enclosingf1 = enclosing.get(f1); nbenclosingf1 = enclosingf1 == null ? 0 : enclosingf1.size(); enclosingf2 = enclosing.get(f2); if (enclosingf2 != null && enclosingf2.size() == nbenclosingf1+1 && nbenclosingf1%2==0) { f1.setGeometry(f1.geometry.difference(f2.geometry)); holes.add(f2); } } } print(" phase 2 : " + count + " objets trait�s"); return holes; } class Main extends Thread { // S�lection des layers layers = wc.layerNamePanel.selectedLayers; public void run() { dialog = new OKCancelDialog(wc.workbench.frame, "Create holes", true, new JLabel("This action will try to create holes
in all the selected layers.
Do you want to continue ?"), null); dialog.show(); if (dialog.wasOKPressed()) { for (layer : layers) { print("Traitement de la couche \"" + layer.name + "\""); holes = processFeatures(new IndexedFeatureCollection(layer.featureCollectionWrapper, new STRtree())); layer.featureCollectionWrapper.removeAll(holes); wc.layerViewPanel.repaint(); } print("Traitement termin�"); } } } new Main().start(); /* Test case POLYGON ((829.7 541.9, 829.7 542.3, 832.5 542.3, 832.5 541.9, 829.7 541.9)) POLYGON ((829.5 542.6, 829.5 542.9, 829.9 542.9, 829.9 542.6, 829.5 542.6)) POLYGON ((831.4 541.3, 831.4 541.6, 832.5 541.6, 832.5 541.3, 831.4 541.3)) POLYGON ((831.7 541.4, 831.7 541.5, 832.2 541.5, 832.2 541.4, 831.7 541.4)) POLYGON ((829 539.5, 829 542.3, 829.7 542.3, 829.7 539.5, 829 539.5), (829.2 539.8, 829.5 539.8, 829.5 542, 829.2 542, 829.2 539.8)) POLYGON ((830.3 541.6, 830.3 541.9, 832.5 541.9, 832.5 541.6, 830.3 541.6)) POLYGON ((830.9 540.5, 830.9 540.6, 831 540.6, 831 540.5, 830.9 540.5)) POLYGON ((829 542.3, 829 543.2, 832.5 543.2, 832.5 542.3, 829 542.3), (829.2 542.4, 830.4 542.4, 830.4 543.1, 829.2 543.1, 829.2 542.4)) POLYGON ((829.9 540.2, 829.9 541.3, 830.2 541.3, 830.2 540.2, 829.9 540.2)) POLYGON ((830.3 541.3, 830.3 541.6, 831.4 541.6, 831.4 541.3, 830.3 541.3)) POLYGON ((829.3 540.1, 829.3 540.7, 829.4 540.7, 829.4 540.1, 829.3 540.1)) POLYGON ((830.6 540.1, 830.6 541, 831.5 541, 831.5 540.1, 830.6 540.1)) POLYGON ((830.8 540.4, 830.8 540.8, 831.2 540.8, 831.2 540.4, 830.8 540.4)) POLYGON ((829.7 539.5, 829.7 541.9, 830.3 541.9, 830.3 539.5, 829.7 539.5)) POLYGON ((829.3 541.1, 829.3 541.8, 829.4 541.8, 829.4 541.1, 829.3 541.1)) POLYGON ((829.2 539.8, 829.2 542, 829.5 542, 829.5 539.8, 829.2 539.8), (829.3 541.1, 829.4 541.1, 829.4 541.8, 829.3 541.8, 829.3 541.1)) POLYGON ((830.3 539.5, 830.3 541.3, 832.5 541.3, 832.5 539.5, 830.3 539.5)) */