com.hazelcast.shaded.org.locationtech.jts.geom.GeometryOverlay Maven / Gradle / Ivy
/*
* Copyright (c) 2020 Martin Davis.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package com.hazelcast.shaded.org.locationtech.jts.geom;
import com.hazelcast.shaded.org.locationtech.jts.geom.util.GeometryCollectionMapper;
import com.hazelcast.shaded.org.locationtech.jts.geom.util.GeometryMapper;
import com.hazelcast.shaded.org.locationtech.jts.operation.overlay.OverlayOp;
import com.hazelcast.shaded.org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
import com.hazelcast.shaded.org.locationtech.jts.operation.overlayng.OverlayNGRobust;
import com.hazelcast.shaded.org.locationtech.jts.operation.union.UnaryUnionOp;
/**
* Internal class which encapsulates the runtime switch to use OverlayNG,
* and some additional extensions for optimization and GeometryCollection handling.
*
* This class allows the {@link Geometry} overlay methods to be
* switched between the original algorithm and the modern OverlayNG codebase
* via a system property jts.overlay
.
*
* jts.overlay=old
- (default) use original overlay algorithm
* jts.overlay=ng
- use OverlayNG
*
*
* @author mdavis
*
*/
class GeometryOverlay
{
public static String OVERLAY_PROPERTY_NAME = "jts.overlay";
public static String OVERLAY_PROPERTY_VALUE_NG = "ng";
public static String OVERLAY_PROPERTY_VALUE_OLD = "old";
/**
* Currently the original JTS overlay implementation is the default
*/
public static boolean OVERLAY_NG_DEFAULT = false;
private static boolean isOverlayNG = OVERLAY_NG_DEFAULT;
static {
setOverlayImpl(System.getProperty(OVERLAY_PROPERTY_NAME));
}
/**
* This function is provided primarily for unit testing.
* It is not recommended to use it dynamically, since
* that may result in inconsistent overlay behaviour.
*
* @param overlayImplCode the code for the overlay method (may be null)
*/
static void setOverlayImpl(String overlayImplCode) {
if (overlayImplCode == null)
return;
// set flag explicitly since current value may not be default
isOverlayNG = OVERLAY_NG_DEFAULT;
if (OVERLAY_PROPERTY_VALUE_NG.equalsIgnoreCase(overlayImplCode) )
isOverlayNG = true;
}
private static Geometry overlay(Geometry a, Geometry b, int opCode) {
if (isOverlayNG) {
return OverlayNGRobust.overlay(a, b, opCode);
}
else {
return SnapIfNeededOverlayOp.overlayOp(a, b, opCode);
}
}
static Geometry difference(Geometry a, Geometry b)
{
// special case: if A.isEmpty ==> empty; if B.isEmpty ==> A
if (a.isEmpty()) return OverlayOp.createEmptyResult(OverlayOp.DIFFERENCE, a, b, a.getFactory());
if (b.isEmpty()) return a.copy();
Geometry.checkNotGeometryCollection(a);
Geometry.checkNotGeometryCollection(b);
return overlay(a, b, OverlayOp.DIFFERENCE);
}
static Geometry intersection(Geometry a, Geometry b)
{
/**
* TODO: MD - add optimization for P-A case using Point-In-Polygon
*/
// special case: if one input is empty ==> empty
if (a.isEmpty() || b.isEmpty())
return OverlayOp.createEmptyResult(OverlayOp.INTERSECTION, a, b, a.getFactory());
// compute for GCs
// (An inefficient algorithm, but will work)
// TODO: improve efficiency of computation for GCs
if (a.isGeometryCollection()) {
final Geometry g2 = b;
return GeometryCollectionMapper.map(
(GeometryCollection) a,
new GeometryMapper.MapOp() {
public Geometry map(Geometry g) {
return g.intersection(g2);
}
});
}
// No longer needed since GCs are handled by previous code
//checkNotGeometryCollection(this);
//checkNotGeometryCollection(other);
return overlay(a, b, OverlayOp.INTERSECTION);
}
static Geometry symDifference(Geometry a, Geometry b)
{
// handle empty geometry cases
if (a.isEmpty() || b.isEmpty()) {
// both empty - check dimensions
if (a.isEmpty() && b.isEmpty())
return OverlayOp.createEmptyResult(OverlayOp.SYMDIFFERENCE, a, b, a.getFactory());
// special case: if either input is empty ==> result = other arg
if (a.isEmpty()) return b.copy();
if (b.isEmpty()) return a.copy();
}
Geometry.checkNotGeometryCollection(a);
Geometry.checkNotGeometryCollection(b);
return overlay(a, b, OverlayOp.SYMDIFFERENCE);
}
static Geometry union(Geometry a, Geometry b)
{
// handle empty geometry cases
if (a.isEmpty() || b.isEmpty()) {
if (a.isEmpty() && b.isEmpty())
return OverlayOp.createEmptyResult(OverlayOp.UNION, a, b, a.getFactory());
// special case: if either input is empty ==> other input
if (a.isEmpty()) return b.copy();
if (b.isEmpty()) return a.copy();
}
// TODO: optimize if envelopes of geometries do not intersect
Geometry.checkNotGeometryCollection(a);
Geometry.checkNotGeometryCollection(b);
return overlay(a, b, OverlayOp.UNION);
}
static Geometry union(Geometry a) {
if (isOverlayNG) {
return OverlayNGRobust.union(a);
}
else {
return UnaryUnionOp.union(a);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy