Skip to content

Commit

Permalink
Improve TopologyPredicate API
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts committed Jan 19, 2024
1 parent 2adb3db commit 74a0965
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,41 @@

import org.locationtech.jts.geom.Location;

public abstract class SimplePredicate implements TopologyPredicate {
public abstract class BasicPredicate implements TopologyPredicate {

private int value = TopologyPredicateValue.UNKNOWN;

public boolean isSelfNodingRequired() {
return false;
}

@Override
public boolean isKnown() {
return TopologyPredicateValue.isKnown(value);
}

@Override
public boolean value() {
return TopologyPredicateValue.toBoolean(value);
}

/**
* Updates the predicate value to the given state
* if it is currently unknown.
*
* @param val the predicate value to update
*/
protected void updateValue(boolean val) {
//-- don't change already-known value
if (isKnown())
return;
value = TopologyPredicateValue.toValue(val);
}

@Override
public int valuePartial(int dimA, int dimB) {
return value;
}

@Override
public boolean value(int dimA, int dimB) {
return TopologyPredicateValue.toBoolean(value);
updateValue(TopologyPredicateValue.toValue(val));
}

public boolean isKnown() {
return TopologyPredicateValue.isKnown(value);
protected void updateValue(int val) {
//-- don't change already-known value
if (isKnown())
return;
if (TopologyPredicateValue.isKnown(val)) {
value = val;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,30 @@
import org.locationtech.jts.geom.IntersectionMatrix;
import org.locationtech.jts.geom.Location;

public abstract class IMPredicate implements TopologyPredicate {
public abstract class IMPredicate extends BasicPredicate {

static final int DIM_UNKNOWN = Dimension.DONTCARE;

protected int dimA;
protected int dimB;
protected IntersectionMatrix intMatrix;

public IMPredicate() {
//TODO: add initializer for IntersectionMatrix to a single value?
//intMatrix = new IntersectionMatrix("*********");
intMatrix = new IntersectionMatrix();
//-- E/E is always dim = 2
intMatrix.set(Location.EXTERIOR, Location.EXTERIOR, Dimension.A);
}

@Override
public void init(int dimA, int dimB) {
this.dimA = dimA;
this.dimB = dimB;
}

public boolean isSelfNodingRequired() {
return true;
}

/**
* Gets the current state of the IM matrix (which may only be partially complete).
*
Expand All @@ -44,9 +54,14 @@ public void updateDim(int locA, int locB, int dimension) {
if (dimension <= intMatrix.get(locA, locB))
return;

intMatrix.set(locA, locB, dimension);
intMatrix.set(locA, locB, dimension);
updateValue( valuePartial());
}

protected int valuePartial() {
return TopologyPredicateValue.UNKNOWN;
}

protected boolean intersectsExteriorOf(boolean isA) {
if (isA) {
return isIntersects(Location.EXTERIOR, Location.INTERIOR)
Expand Down Expand Up @@ -81,7 +96,9 @@ public int getDim(int locA, int locB) {
/**
* Finalizes the matrix by setting UNKNOWN values to appropriate values.
*/
@Override
public void finish() {
updateValue(valueIM());
//TODO: is this needed?
/*
for (int ia = 0; ia < 3; ia++) {
Expand All @@ -93,6 +110,8 @@ public void finish() {
*/
}

protected abstract boolean valueIM();

public String toString() {
return name() + ": " + intMatrix;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
* The algorithm used provides the following:
* <ol>
* <li>Efficient short-circuited evaluation of all predicates
* <li>Optimized evaluation of repeated predicates against a single geometry
* (via cached spatial indexes)
* <li>Optimized evaluation of repeated predicates against a single geometry
* via cached spatial indexes (AKA prepared mode)
* <li>Robust computation (since only point-local topology is required)
* <li>FUTURE Support for {@link BoundaryNodeRule}
* <li>Support for {@link BoundaryNodeRule}
* <li>FUTURE Support for all GeometryCollection inputs, using union semantics
* <li>FUTURE Support for a distance tolerance to compute approximate predicates
* </ol>
Expand Down Expand Up @@ -111,15 +111,14 @@ public boolean evaluate(TopologyPredicate predicate, Geometry inputB) {
int dimA = geomA.getDimension();
int dimB = geomB.getDimension();

//-- check if predicate is determined by dimension
int dimValue = predicate.valueDimensions(dimA, dimB);
if (TopologyPredicateValue.isKnown(dimValue))
return TopologyPredicateValue.toBoolean(dimValue);
//-- check if predicate is determined by dimension or envelope
predicate.init(dimA, dimB);
if (predicate.isKnown())
return predicate.value();

//-- check if predicate is determined by envelopes
int envValue = predicate.valueEnvelopes(geomA.getEnvelope(), inputB.getEnvelopeInternal());
if (TopologyPredicateValue.isKnown(envValue))
return TopologyPredicateValue.toBoolean(envValue);
predicate.init(geomA.getEnvelope(), inputB.getEnvelopeInternal());
if (predicate.isKnown())
return predicate.value();

TopologyBuilder topoBuilder = new TopologyBuilder(predicate, geomA, geomB);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,16 @@ public RelatePredicate(String mask) {
public String name() { return "relate"; }

@Override
public int valuePartial(int dimA, int dimB) {
return TopologyPredicateValue.UNKNOWN;
}

@Override
public boolean value(int dimA, int dimB) {
public boolean valueIM() {
if (mask == null)
return false;

boolean val = intMatrix.matches(mask);
/*
if (! val) {
System.out.println( intMatrix + " does not equal mask " + mask);
System.out.println("DEBUG: " + intMatrix + " does not equal mask " + mask);
}
*/
return val;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class TopologyBuilder {
private RelateGeometry geomB;
private int dimA;
private int dimB;
private int predicateValue;
private Map<Coordinate, RelateNode> nodeMap = new HashMap<Coordinate, RelateNode>();

public TopologyBuilder(TopologyPredicate predicate, RelateGeometry geomA, RelateGeometry geomB) {
Expand All @@ -41,7 +40,6 @@ public TopologyBuilder(TopologyPredicate predicate, RelateGeometry geomA, Relate
this.dimB = geomB.getDimension();

initExteriorDims();
predicateValue = predicate.valueDimensions(dimA, dimB);
}

/**
Expand Down Expand Up @@ -136,7 +134,6 @@ public boolean isSelfNodingRequired() {
*/
private boolean updateDim(int locA, int locB, int dimension) {
predicate.updateDim(locA, locB, dimension);
predicateValue = predicate.valuePartial(dimA, dimB);
return true;
}

Expand All @@ -149,19 +146,18 @@ private boolean updateDim(boolean isAB, int loc1, int loc2, int dimension) {
}

public boolean isResultKnown() {
return TopologyPredicateValue.isKnown(predicateValue);
return predicate.isKnown();
}

public boolean getResult() {
return TopologyPredicateValue.toBoolean(predicateValue);
return predicate.value();
}

/**
* Finalizes the matrix by setting UNKNOWN values to Dimension.FALSE (empty).
* Finalize the evaluation.
*/
public void finish() {
predicate.finish();
predicateValue = TopologyPredicateValue.toValue(predicate.value(dimA, dimB));
}

private RelateNode getNode(Coordinate intPt) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@

/**
* The API for strategy classes implementing
* short-circuited spatial predicates based
* on the DE-9IM topology model,
* short-circuited spatial predicates based on the DE-9IM topology model,
* evaluated by {@link RelateNG}.
*
* @author Martin Davis
Expand All @@ -43,6 +42,30 @@ default boolean isSelfNodingRequired() {
return true;
}

/**
* Initializes the predicate for a specific geometric case.
* This may allow the predicate result to become known
* if it can be inferred from the dimensions.
*
* @param dimA the dimension of geometry A
* @param dimB the dimension of geometry B
*/
default void init(int dimA, int dimB) {

}

/**
* Initializes the predicate for a specific geometric case.
* This may allow the predicate result to become known
* if it can be inferred from the envelopes.
*
* @param envA the envelope of geometry A
* @param envB the envelope of geometry B
*/
default void init(Envelope envA, Envelope envB) {

}

/**
* Updates the entry in the DE-9IM intersection matrix
* for given {@link Location}s in the input geometries.
Expand All @@ -61,25 +84,24 @@ default boolean isSelfNodingRequired() {
void updateDim(int locA, int locB, int dimension);

/**
* Gets the predicate value if it can be determined
* solely from the geometry dimensions.
* Tests if the predicate value is known.
*
* @param dimA
* @param dimB
* @return
* @return true if the result is known
*/
default int valueDimensions(int dimA, int dimB) {
return TopologyPredicateValue.UNKNOWN;
}

default int valueEnvelopes(Envelope envA, Envelope envB) {
return TopologyPredicateValue.UNKNOWN;
}

int valuePartial(int dimA, int dimB);
boolean isKnown();

/**
* Indicates that the value of the predicate can be finalized
* based on its current state.
*/
void finish();

boolean value(int dimA, int dimB);
/**
* Gets the current value of the predicate result.
* The value is only valid if {@link #isKnown()} is true.
*
* @return the predicate result value
*/
boolean value();

}
Loading

0 comments on commit 74a0965

Please sign in to comment.