use of org.locationtech.jts.operation.valid.TopologyValidationError in project presto by prestodb.
the class GeometryUtils method getGeometryInvalidReason.
public static Optional<String> getGeometryInvalidReason(org.locationtech.jts.geom.Geometry geometry) {
IsValidOp validOp = new IsValidOp(geometry);
IsSimpleOp simpleOp = new IsSimpleOp(geometry);
try {
TopologyValidationError err = validOp.getValidationError();
if (err != null) {
return Optional.of(err.getMessage());
}
} catch (UnsupportedOperationException e) {
// It should not happen in practice.
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "Geometry type not valid", e);
}
if (!simpleOp.isSimple()) {
String errorDescription;
String geometryType = geometry.getGeometryType();
switch(GeometryType.getForJtsGeometryType(geometryType)) {
case POINT:
errorDescription = "Invalid point";
break;
case MULTI_POINT:
errorDescription = "Repeated point";
break;
case LINE_STRING:
case MULTI_LINE_STRING:
errorDescription = "Self-intersection at or near";
break;
case POLYGON:
case MULTI_POLYGON:
case GEOMETRY_COLLECTION:
// In OGC (which JTS follows): Polygons, MultiPolygons, Geometry Collections are simple.
// This shouldn't happen, but in case it does, return a reasonable generic message.
errorDescription = "Topology exception at or near";
break;
default:
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Unknown geometry type: %s", geometryType));
}
org.locationtech.jts.geom.Coordinate nonSimpleLocation = simpleOp.getNonSimpleLocation();
return Optional.of(format("[%s] %s: (%s %s)", geometryType, errorDescription, nonSimpleLocation.getX(), nonSimpleLocation.getY()));
}
return Optional.empty();
}
use of org.locationtech.jts.operation.valid.TopologyValidationError in project vertexium by visallo.
the class GeoUtils method toJtsPolygon.
public static Geometry toJtsPolygon(List<GeoPoint> outerBoundary, List<List<GeoPoint>> holeBoundaries, boolean lenient) {
LinearRing shell = toJtsLinearRing(outerBoundary, true, lenient);
LinearRing[] holes = holeBoundaries == null ? new LinearRing[0] : holeBoundaries.stream().map(holeBoundary -> toJtsLinearRing(holeBoundary, false, lenient)).toArray(LinearRing[]::new);
Geometry polygon = GEOMETRY_FACTORY.createPolygon(shell, holes);
TopologyValidationError validationError = new IsValidOp(polygon).getValidationError();
if (validationError != null) {
if (lenient) {
LOGGER.info("Attempting to repair and normalize an invalid polygon.");
// NOTE: there seems to be a bug in JTS where normalizing puts the paths backwards. Reverse as a hack for now.
polygon = polygon.buffer(0).norm().reverse();
} else {
throw new VertexiumInvalidShapeException(validationError.toString());
}
}
return polygon;
}
use of org.locationtech.jts.operation.valid.TopologyValidationError in project qupath by qupath.
the class GeometryTools method tryToFixPolygon.
/**
* Test a polygon for validity, attempting to fix TopologyValidationErrors if possible.
* This attempts a range of tricks (starting with Geometry.buffer(0)), although none
* are guaranteed to work. The first that largely preserves the polygon's area is returned.
* <p>
* The result is guaranteed to be valid, but not necessarily to be a close match to the
* original polygon; in particular, if everything failed the result will be empty.
* <p>
* Code that calls this method can test if the output is equal to the input to determine
* if any changes were made.
*
* @param polygon input (possibly-invalid) polygon
* @return the input polygon (if valid), an adjusted polygon (if attempted fixes helped),
* or an empty polygon if the situation could not be resolved
*/
public static Geometry tryToFixPolygon(Polygon polygon) {
TopologyValidationError error = new IsValidOp(polygon).getValidationError();
if (error == null)
return polygon;
logger.debug("Invalid polygon detected! Attempting to correct {}", error.toString());
// Area calculations seem to be reliable... even if the topology is invalid
double areaBefore = polygon.getArea();
double tol = 0.0001;
// Try fast buffer trick to make valid (but sometimes this can 'break', e.g. with bow-tie shapes)
Geometry geomBuffered = polygon.buffer(0);
double areaBuffered = geomBuffered.getArea();
if (geomBuffered.isValid() && GeneralTools.almostTheSame(areaBefore, areaBuffered, tol))
return geomBuffered;
// If the buffer trick gave us an exceedingly small area, try removing this and see if that resolves things
if (!geomBuffered.isEmpty() && areaBuffered < areaBefore * 0.001) {
try {
Geometry geomDifference = polygon.difference(geomBuffered);
if (geomDifference.isValid())
return geomDifference;
} catch (Exception e) {
logger.debug("Attempting to fix by difference failed: " + e.getLocalizedMessage(), e);
}
}
// Resort to the slow method of fixing polygons if we have to
logger.debug("Unable to fix Geometry with buffer(0) - will try snapToSelf instead");
double distance = GeometrySnapper.computeOverlaySnapTolerance(polygon);
Geometry geomSnapped = GeometrySnapper.snapToSelf(polygon, distance, true);
if (geomSnapped.isValid())
return geomSnapped;
// If everything failed, return an empty polygon (which will at least be valid...)
return polygon.getFactory().createPolygon();
}
use of org.locationtech.jts.operation.valid.TopologyValidationError in project urban-eureka by errir503.
the class GeometryUtils method getGeometryInvalidReason.
public static Optional<String> getGeometryInvalidReason(org.locationtech.jts.geom.Geometry geometry) {
IsValidOp validOp = new IsValidOp(geometry);
IsSimpleOp simpleOp = new IsSimpleOp(geometry);
try {
TopologyValidationError err = validOp.getValidationError();
if (err != null) {
return Optional.of(err.getMessage());
}
} catch (UnsupportedOperationException e) {
// It should not happen in practice.
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, "Geometry type not valid", e);
}
if (!simpleOp.isSimple()) {
String errorDescription;
String geometryType = geometry.getGeometryType();
switch(GeometryType.getForJtsGeometryType(geometryType)) {
case POINT:
errorDescription = "Invalid point";
break;
case MULTI_POINT:
errorDescription = "Repeated point";
break;
case LINE_STRING:
case MULTI_LINE_STRING:
errorDescription = "Self-intersection at or near";
break;
case POLYGON:
case MULTI_POLYGON:
case GEOMETRY_COLLECTION:
// In OGC (which JTS follows): Polygons, MultiPolygons, Geometry Collections are simple.
// This shouldn't happen, but in case it does, return a reasonable generic message.
errorDescription = "Topology exception at or near";
break;
default:
throw new PrestoException(INVALID_FUNCTION_ARGUMENT, format("Unknown geometry type: %s", geometryType));
}
org.locationtech.jts.geom.Coordinate nonSimpleLocation = simpleOp.getNonSimpleLocation();
return Optional.of(format("[%s] %s: (%s %s)", geometryType, errorDescription, nonSimpleLocation.getX(), nonSimpleLocation.getY()));
}
return Optional.empty();
}
Aggregations