Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Shortcut for spatial.intersects procedure #412

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
*/
package org.neo4j.gis.spatial.filter;

import org.locationtech.jts.algorithm.Orientation;
import org.locationtech.jts.geom.Geometry;
import org.neo4j.gis.spatial.Layer;
import org.neo4j.gis.spatial.Utilities;
import org.neo4j.gis.spatial.index.Envelope;
import org.neo4j.gis.spatial.rtree.filter.AbstractSearchEnvelopeIntersection;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;


/**
* Find geometries that intersect with the specified search window.
Expand All @@ -35,6 +38,7 @@ public class SearchIntersectWindow extends AbstractSearchEnvelopeIntersection {

private final Layer layer;
private final Geometry windowGeom;
private final boolean isBBox;

public SearchIntersectWindow(Layer layer, Envelope envelope) {
this(layer, Utilities.fromNeo4jToJts(envelope));
Expand All @@ -44,6 +48,32 @@ public SearchIntersectWindow(Layer layer, org.locationtech.jts.geom.Envelope oth
super(layer.getGeometryEncoder(), Utilities.fromJtsToNeo4j(other));
this.layer = layer;
this.windowGeom = layer.getGeometryFactory().toGeometry(other);
this.isBBox = this.windowGeom.isRectangle()
// not a hole
&& !Orientation.isCCW(windowGeom.getCoordinates());
}

@Override
public EnvelopFilterResult needsToVisitExtended(org.neo4j.gis.spatial.rtree.Envelope indexNodeEnvelope) {
if (isBBox && referenceEnvelope.contains(indexNodeEnvelope)) {
return EnvelopFilterResult.INCLUDE_ALL;
}
if (indexNodeEnvelope.intersects(referenceEnvelope)) {
return EnvelopFilterResult.FILTER;
}
return EnvelopFilterResult.EXCLUDE_ALL;
}

@Override
public boolean geometryMatches(Transaction tx, Node geomNode) {
var geomEnvelope = decoder.decodeEnvelope(geomNode);
if (isBBox && referenceEnvelope.contains(geomEnvelope)) {
return true;
}
if (geomEnvelope.intersects(referenceEnvelope)) {
return onEnvelopeIntersection(geomNode, geomEnvelope);
}
return false;
}

@Override
Expand Down
26 changes: 21 additions & 5 deletions src/main/java/org/neo4j/gis/spatial/rtree/RTreeIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.impl.StandardExpander;
import org.neo4j.graphdb.traversal.BranchState;
import org.neo4j.graphdb.traversal.Evaluation;
import org.neo4j.graphdb.traversal.Evaluator;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.PathEvaluator;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.kernel.impl.traversal.MonoDirectionalTraversalDescription;
Expand Down Expand Up @@ -754,7 +756,7 @@ public Iterable<Node> getAllIndexedNodes(Transaction tx) {
return new IndexNodeToGeometryNodeIterable(getAllIndexInternalNodes(tx));
}

private class SearchEvaluator implements Evaluator {
private class SearchEvaluator extends PathEvaluator.Adapter<SearchFilter.EnvelopFilterResult> {

private final SearchFilter filter;
private final Transaction tx;
Expand All @@ -765,14 +767,22 @@ public SearchEvaluator(Transaction tx, SearchFilter filter) {
}

@Override
public Evaluation evaluate(Path path) {
public Evaluation evaluate(Path path, BranchState<SearchFilter.EnvelopFilterResult> state) {
Relationship rel = path.lastRelationship();
Node node = path.endNode();
if (rel == null) {
return Evaluation.EXCLUDE_AND_CONTINUE;
}
if (rel.isType(RTreeRelationshipTypes.RTREE_CHILD)) {
boolean shouldContinue = filter.needsToVisit(getIndexNodeEnvelope(node));
boolean shouldContinue;
if (state.getState() == SearchFilter.EnvelopFilterResult.INCLUDE_ALL) {
shouldContinue = true;
} else {
SearchFilter.EnvelopFilterResult envelopFilterResult = filter.needsToVisitExtended(
getIndexNodeEnvelope(node));
state.setState(envelopFilterResult);
shouldContinue = envelopFilterResult != SearchFilter.EnvelopFilterResult.EXCLUDE_ALL;
}
if (shouldContinue) {
monitor.matchedTreeNode(path.length(), node);
}
Expand All @@ -782,7 +792,12 @@ public Evaluation evaluate(Path path) {
Evaluation.EXCLUDE_AND_PRUNE;
}
if (rel.isType(RTreeRelationshipTypes.RTREE_REFERENCE)) {
boolean found = filter.geometryMatches(tx, node);
boolean found;
if (state.getState() == SearchFilter.EnvelopFilterResult.INCLUDE_ALL) {
found = true;
} else {
found = filter.geometryMatches(tx, node);
}
monitor.addCase(found ? "Geometry Matches" : "Geometry Does NOT Match");
if (found) {
monitor.setHeight(path.length());
Expand All @@ -801,6 +816,7 @@ public SearchResults searchIndex(Transaction tx, SearchFilter filter) {
MonoDirectionalTraversalDescription traversal = new MonoDirectionalTraversalDescription();
TraversalDescription td = traversal
.depthFirst()
.expand(StandardExpander.DEFAULT, path -> SearchFilter.EnvelopFilterResult.FILTER)
.relationships(RTreeRelationshipTypes.RTREE_CHILD, Direction.OUTGOING)
.relationships(RTreeRelationshipTypes.RTREE_REFERENCE, Direction.OUTGOING)
.evaluator(searchEvaluator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@ public boolean needsToVisit(Envelope indexNodeEnvelope) {
}

@Override
public final boolean geometryMatches(Transaction tx, Node geomNode) {
public boolean geometryMatches(Transaction tx, Node geomNode) {
Envelope geomEnvelope = decoder.decodeEnvelope(geomNode);
if (geomEnvelope.intersects(referenceEnvelope)) {
return onEnvelopeIntersection(geomNode, geomEnvelope);
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@

public interface SearchFilter {

enum EnvelopFilterResult {
INCLUDE_ALL, EXCLUDE_ALL, FILTER
}
boolean needsToVisit(Envelope envelope);

default EnvelopFilterResult needsToVisitExtended(Envelope envelope) {
return needsToVisit(envelope) ? EnvelopFilterResult.FILTER : EnvelopFilterResult.EXCLUDE_ALL;
}
boolean geometryMatches(Transaction tx, Node geomNode);

}