+ /*
+ * GEOMETRY
+ */
+ /**
+ * Ensure that a {@link Polygon} is valid and simple by removing artefacts
+ * (typically coming from GPS).
+ *
+ * @return a simple and valid polygon, or null if the ignoredArea ratio is above
+ * the provided threshold.
+ */
+ public static Polygon cleanPolygon(Polygon polygon, double ignoredAreaRatio) {
+ Polygonizer polygonizer = new Polygonizer(true);
+ Geometry fixed = GeometryFixer.fix(polygon, false);
+ polygonizer.add(fixed);
+ @SuppressWarnings("unchecked")
+ List<Polygon> polygons = new ArrayList<>(polygonizer.getPolygons());
+
+ if (polygons.size() == 0) {
+ throw new IllegalStateException("Polygonizer failed to extract any polygon");
+ }
+
+ Polygon best;
+ if (polygons.size() == 1) {
+ best = polygons.get(0);
+ } else {
+ double totalArea = fixed.getArea();
+ best = polygons.get(0);
+ double bestArea = best.getArea();
+ for (int i = 1; i < polygons.size(); i++) {
+ Polygon p = polygons.get(i);
+ double a = p.getArea();
+ if (a > bestArea) {
+ best = p;
+ bestArea = a;
+ } else {
+ // double ratio = a / totalArea;
+ }
+ }
+ double ignoredRatio = (totalArea - bestArea) / totalArea;
+ if (ignoredRatio > ignoredAreaRatio)
+ return null;
+
+ if (!best.isValid() || !best.isSimple()) {
+ throw new IllegalStateException("The polygon is not simple and/or valid after cleaning");
+ }
+ }
+ // while we are here, we make sure that the geometry will be normalised
+ best.normalize();
+ return best;
+ }
+
+ /**
+ * The smallest polygon without holes containing all the points in this
+ * geometry.
+ */
+ public static Polygon concaveHull(Geometry geom, double lengthRatio) {
+ Objects.requireNonNull(geom);
+ if (geom.getNumPoints() < 3)
+ throw new IllegalArgumentException("At least 3 points are reuired to compute the concave hull and geometry "
+ + geom.getClass() + " contains only " + geom.getNumPoints());
+ Geometry hull = ConcaveHull.concaveHullByLengthRatio(geom, lengthRatio, false);
+ if (hull instanceof Polygon polygon)
+ return polygon;
+ else
+ throw new IllegalStateException("Hull is not a polygon but a " + hull.getClass());
+ }
+