5

There are several questions/answers using ERIS,etc. like: Remove holes from polygon

But I am having a challenge applying the solution programmatically using the JTS Topology suite only.

Below is an example of MultiPolygon.. I want to remove/fill the holes.

enter image description here

3 Answers 3

6

OpenJUMP has a "remove holes" tool (and an advanced "remove small holes" tool as well). OpenJUMP often uses JTS rather directly but I am not sure about this case. The source code of the function is at https://sourceforge.net/p/jump-pilot/code/HEAD/tree/core/trunk/src/com/vividsolutions/jump/workbench/ui/plugin/analysis/GeometryFunction.java

The idea seems to be simple: Get the list of polygons, get the exterior rings and create new polygons from those. Inner rings disappear and job is done.

  // added on 2016-11-11 by mmichaud
  private static class RemoveHolesFunction extends GeometryFunction {
    public RemoveHolesFunction() {
      super(I18N.get("ui.plugin.analysis.GeometryFunction.Remove-Holes"), 1, 0);
    }

    public Geometry execute(Geometry[] geom, double[] param)
    {
      AbstractGeometryProcessor removeHoleProcessor = new AbstractGeometryProcessor() {
        public void process(Polygon polygon, List<Geometry> list) {
          list.add(polygon.getFactory().createPolygon((LinearRing)polygon.getExteriorRing()));
        }
      };
      return removeHoleProcessor.process(geom[0]);
    }
  }
5

Basically, you need to create a new Polygon from the ExteriorRing of the input Polygon.

gf.createPolygon(p.getExteriorRing().getCoordinateSequence());

There is a little more work with MultiPolygons as you have to handle each subpolygon in turn. The whole method becomes something like:

  static GeometryFactory gf = new GeometryFactory();
  static public Geometry removeHoles(Geometry g) {

    if (g.getGeometryType().equalsIgnoreCase("Polygon")) {
      Polygon p = (Polygon) g;
      return gf.createPolygon(p.getExteriorRing().getCoordinateSequence());
    } else if (g.getGeometryType().equalsIgnoreCase("MultiPolygon")) {

      MultiPolygon mp = (MultiPolygon) g;
      List<Polygon> polys = new ArrayList<>();
      for (int i = 0; i < mp.getNumGeometries(); i++) {
        Polygon poly = gf.createPolygon(((Polygon) mp.getGeometryN(i)).getExteriorRing().getCoordinateSequence());
        polys.add(poly);
      }
      return gf.createMultiPolygon(polys.toArray(new Polygon[] {}));

    }

    return g;
  }
1
  • 1
    Yup. Thanks I did just that.
    – Jeryl Cook
    Commented Jun 11, 2020 at 14:31
1
/**
 * Remove holes from a Polygonal geometry
 * @param g The geometry to remove holes from
 * @param filter A filter to decide if the holes should be removed. If null removes all
 * @param <T> Geometry type
 * @return A geometry with holes removed
 */
@SuppressWarnings("unchecked")
public static  <T extends Geometry> T removeHoles(T g, Predicate<Polygon> filter) {
    if (!g.isEmpty() && g instanceof Polygon) {
        final Polygon p = (Polygon) g;

        final GeometryFactory factory = p.getFactory();
        final List<LinearRing> interiorRings = new ArrayList<>();
        for(int i = 0 ; i < p.getNumInteriorRing() ; i++){
            final LineString interiorRing = p.getInteriorRingN(i);
            final LinearRing linearRing = factory.createLinearRing(interiorRing.getCoordinates());
            if(filter!=null && filter.test(factory.createPolygon(linearRing,new LinearRing[]{}))){
                interiorRings.add(linearRing);
            }
        }
        return (T) factory.createPolygon(factory.createLinearRing(p.getExteriorRing().getCoordinates()),interiorRings.toArray(new LinearRing[]{}));
    } else if (!g.isEmpty() && g instanceof MultiPolygon) {
        final MultiPolygon mp = (MultiPolygon) g;
        final ArrayList<Polygon> polygons = new ArrayList<>();
        for(int i = 0 ; i < mp.getNumGeometries() ; i++){
            polygons.add(removeHoles((Polygon) mp.getGeometryN(i),filter));
        }
        return (T)mp.getFactory().createMultiPolygon(polygons.toArray(new Polygon[]{}));
    }

    return g;
}

Use it like this:

//removes hole bigger than minAreaFactor
removeHoles(someGeometry, p -> p.getArea() > minAreaFactor)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.