1 /*
2  * Copyright (c) 2016 Vivid Solutions.
3  *
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
8  * and the Eclipse Distribution License is available at
9  *
10  * http://www.eclipse.org/org/documents/edl-v10.php.
11  */
12 package org.locationtech.jtslab.clean;
13 
14 import java.util.ArrayList;
15 import java.util.List;
16 
17 import org.locationtech.jts.geom.Geometry;
18 import org.locationtech.jts.geom.GeometryFactory;
19 import org.locationtech.jts.geom.LinearRing;
20 import org.locationtech.jts.geom.Polygon;
21 import org.locationtech.jts.geom.util.GeometryMapper;
22 import org.locationtech.jts.geom.util.GeometryMapper.MapOp;
23 
24 /**
25  * Removes holes which match a given predicate.
26  *
27  * @author Martin Davis
28  *
29  */
30 public class HoleRemover {
31 
32   public interface Predicate {
value(Geometry geom)33     boolean value(Geometry geom);
34   }
35 
36   private Geometry geom;
37   private Predicate isRemoved;
38 
39   /**
40    * Creates a new hole remover instance.
41    *
42    * @param geom the geometry to process
43    */
HoleRemover(Geometry geom, Predicate isRemoved)44   public HoleRemover(Geometry geom, Predicate isRemoved) {
45     this.geom = geom;
46     this.isRemoved = isRemoved;
47   }
48 
49   /**
50    * Gets the cleaned geometry.
51    *
52    * @return the geometry with matched holes removed.
53    */
getResult()54   public Geometry getResult()
55   {
56     return GeometryMapper.map(geom, new HoleRemoverMapOp());
57   }
58 
59   private class HoleRemoverMapOp implements MapOp {
map(Geometry geom)60     public Geometry map(Geometry geom) {
61       if (geom instanceof Polygon)
62         return  PolygonHoleRemover.clean((Polygon) geom, isRemoved);
63       return geom;
64     }
65   }
66 
67   private static class PolygonHoleRemover {
68 
clean(Polygon poly, Predicate isRemoved)69     public static Polygon clean(Polygon poly, Predicate isRemoved) {
70       PolygonHoleRemover pihr = new PolygonHoleRemover(poly, isRemoved);
71       return pihr.getResult();
72     }
73 
74     private Polygon poly;
75     private Predicate isRemoved;
76 
PolygonHoleRemover(Polygon poly, Predicate isRemoved)77     public PolygonHoleRemover(Polygon poly, Predicate isRemoved) {
78       this.poly = poly;
79       this.isRemoved = isRemoved;
80     }
81 
getResult()82     public Polygon getResult()
83     {
84       GeometryFactory gf = poly.getFactory();
85       Polygon shell = gf.createPolygon(poly.getExteriorRing());
86 
87       List holes = new ArrayList();
88       for (int i = 0; i < poly.getNumInteriorRing(); i++) {
89         LinearRing hole = poly.getInteriorRingN(i);
90         if (! isRemoved.value(hole)) {
91           holes.add(hole);
92         }
93       }
94       // all holes valid, so return original
95       if (holes.size() == poly.getNumInteriorRing())
96         return poly;
97 
98       // return new polygon with covered holes only
99       Polygon result = gf.createPolygon(poly.getExteriorRing(),
100           GeometryFactory.toLinearRingArray(holes));
101       return result;
102     }
103 
104   }
105 }
106