Skip to content

Commit 6dd3228

Browse files
committed
Add edge iteration support in quadtree
1 parent a353512 commit 6dd3228

File tree

7 files changed

+774
-162
lines changed

7 files changed

+774
-162
lines changed

src/main/java/org/gephi/graph/api/SpatialIndex.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ public interface SpatialIndex {
4949
*/
5050
EdgeIterable getEdgesInArea(Rect2D rect);
5151

52+
/**
53+
* Returns the edges in the given area using a faster, but approximate method.
54+
* <p>
55+
* All edges in the provided area are guaranteed to be returned, but some edges
56+
* outside the area may also be returned.
57+
*
58+
* @param rect area to query
59+
* @return edges in the area
60+
*/
61+
EdgeIterable getApproximateEdgesInArea(Rect2D rect);
62+
5263
/**
5364
* Returns the bounding rectangle that contains all nodes in the graph. The
5465
* boundaries are calculated based on each node's position and size.

src/main/java/org/gephi/graph/impl/EdgeStore.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,10 @@ public boolean add(final Edge e) {
807807
undirectedSize++;
808808
}
809809

810+
if (spatialIndex != null) {
811+
spatialIndex.addEdge(edge);
812+
}
813+
810814
size++;
811815
typeSize[type]++;
812816
return true;
@@ -832,6 +836,10 @@ public boolean remove(final Object o) {
832836
viewStore.removeEdge(edge);
833837
}
834838

839+
if (spatialIndex != null) {
840+
spatialIndex.removeEdge(edge);
841+
}
842+
835843
edge.destroyAttributes();
836844

837845
int storeIndex = id / GraphStoreConfiguration.EDGESTORE_BLOCK_SIZE;

src/main/java/org/gephi/graph/impl/GraphViewDecorator.java

Lines changed: 19 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public boolean contains(Node node) {
299299
checkValidNodeObject(node);
300300
graphStore.autoReadLock();
301301
try {
302-
return view.containsNode((NodeImpl) node);
302+
return view.containsNode(node);
303303
} finally {
304304
graphStore.autoReadUnlock();
305305
}
@@ -812,15 +812,15 @@ void checkValidNodeObject(final Node n) {
812812
if (!(n instanceof NodeImpl)) {
813813
throw new ClassCastException("Object must be a NodeImpl object");
814814
}
815-
if (((NodeImpl) n).storeId == NodeStore.NULL_ID) {
815+
if (n.getStoreId() == NodeStore.NULL_ID) {
816816
throw new IllegalArgumentException("Node should belong to a store");
817817
}
818818
}
819819

820820
void checkValidInViewNodeObject(final Node n) {
821821
checkValidNodeObject(n);
822822

823-
if (!view.containsNode((NodeImpl) n)) {
823+
if (!view.containsNode(n)) {
824824
throw new RuntimeException("Node doesn't belong to this view");
825825
}
826826
}
@@ -832,15 +832,15 @@ void checkValidEdgeObject(final Edge n) {
832832
if (!(n instanceof EdgeImpl)) {
833833
throw new ClassCastException("Object must be a EdgeImpl object");
834834
}
835-
if (((EdgeImpl) n).storeId == EdgeStore.NULL_ID) {
835+
if (n.getStoreId() == EdgeStore.NULL_ID) {
836836
throw new IllegalArgumentException("Edge should belong to a store");
837837
}
838838
}
839839

840840
void checkValidInViewEdgeObject(final Edge e) {
841841
checkValidEdgeObject(e);
842842

843-
if (!view.containsEdge((EdgeImpl) e)) {
843+
if (!view.containsEdge(e)) {
844844
throw new RuntimeException("Edge doesn't belong to this view");
845845
}
846846
}
@@ -871,69 +871,39 @@ public NodeIterable getNodesInArea(Rect2D rect) {
871871
if (graphStore.spatialIndex == null) {
872872
throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
873873
}
874-
return new NodeIterableWrapper(
875-
() -> new NodeViewIterator(graphStore.spatialIndex.getNodesInArea(rect).iterator()),
876-
graphStore.spatialIndex.nodesTree.lock);
874+
return graphStore.spatialIndex.getNodesInArea(rect, view::containsNode);
877875
}
878876

879877
@Override
880878
public NodeIterable getApproximateNodesInArea(Rect2D rect) {
881879
if (graphStore.spatialIndex == null) {
882880
throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
883881
}
884-
return new NodeIterableWrapper(
885-
() -> new NodeViewIterator(graphStore.spatialIndex.getApproximateNodesInArea(rect).iterator()),
886-
graphStore.spatialIndex.nodesTree.lock);
882+
return graphStore.spatialIndex.getApproximateNodesInArea(rect, view::containsNode);
887883
}
888884

889885
@Override
890886
public EdgeIterable getEdgesInArea(Rect2D rect) {
891887
if (graphStore.spatialIndex == null) {
892888
throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
893889
}
894-
return new EdgeIterableWrapper(
895-
() -> new EdgeViewIterator(graphStore.spatialIndex.getEdgesInArea(rect).iterator()),
896-
graphStore.spatialIndex.nodesTree.lock);
890+
return graphStore.spatialIndex.getEdgesInArea(rect, view::containsEdge);
897891
}
898892

899893
@Override
900-
public Rect2D getBoundaries() {
901-
graphStore.autoReadLock();
902-
try {
903-
float minX = Float.POSITIVE_INFINITY;
904-
float minY = Float.POSITIVE_INFINITY;
905-
float maxX = Float.NEGATIVE_INFINITY;
906-
float maxY = Float.NEGATIVE_INFINITY;
907-
908-
boolean hasNodes = false;
909-
910-
// Iterate only through nodes visible in this view
911-
for (Node node : getNodes()) {
912-
hasNodes = true;
913-
final float x = node.x();
914-
final float y = node.y();
915-
final float size = node.size();
916-
917-
final float nodeMinX = x - size;
918-
final float nodeMinY = y - size;
919-
final float nodeMaxX = x + size;
920-
final float nodeMaxY = y + size;
921-
922-
if (nodeMinX < minX)
923-
minX = nodeMinX;
924-
if (nodeMinY < minY)
925-
minY = nodeMinY;
926-
if (nodeMaxX > maxX)
927-
maxX = nodeMaxX;
928-
if (nodeMaxY > maxY)
929-
maxY = nodeMaxY;
930-
}
894+
public EdgeIterable getApproximateEdgesInArea(Rect2D rect) {
895+
if (graphStore.spatialIndex == null) {
896+
throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
897+
}
898+
return graphStore.spatialIndex.getApproximateEdgesInArea(rect, view::containsEdge);
899+
}
931900

932-
return hasNodes ? new Rect2D(minX, minY, maxX, maxY) : new Rect2D(Float.NEGATIVE_INFINITY,
933-
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
934-
} finally {
935-
graphStore.autoReadUnlock();
901+
@Override
902+
public Rect2D getBoundaries() {
903+
if (graphStore.spatialIndex == null) {
904+
throw new UnsupportedOperationException("Spatial index is disabled (from Configuration)");
936905
}
906+
return graphStore.spatialIndex.getBoundaries(view::containsNode);
937907
}
938908

939909
private final class NodeViewSpliterator implements Spliterator<Node> {

src/main/java/org/gephi/graph/impl/GraphViewImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,15 +462,15 @@ public void fill() {
462462
}
463463
}
464464

465-
public boolean containsNode(final NodeImpl node) {
465+
public boolean containsNode(final Node node) {
466466
if (!nodeView) {
467467
return true;
468468
}
469-
return nodeBitVector.get(node.storeId);
469+
return nodeBitVector.get(node.getStoreId());
470470
}
471471

472-
public boolean containsEdge(final EdgeImpl edge) {
473-
return edgeBitVector.get(edge.storeId);
472+
public boolean containsEdge(final Edge edge) {
473+
return edgeBitVector.get(edge.getStoreId());
474474
}
475475

476476
public void intersection(final GraphViewImpl otherView) {
@@ -915,7 +915,7 @@ private void checkValidNodeObject(final Node n) {
915915
if (!(n instanceof NodeImpl)) {
916916
throw new ClassCastException("Object must be a NodeImpl object");
917917
}
918-
if (((NodeImpl) n).storeId == NodeStore.NULL_ID) {
918+
if (n.getStoreId() == NodeStore.NULL_ID) {
919919
throw new IllegalArgumentException("Node should belong to a store");
920920
}
921921
}

0 commit comments

Comments
 (0)