From 0cfed8de5790852668121cc261ec6e6265626fc6 Mon Sep 17 00:00:00 2001 From: clarisma <56932851+clarisma@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:03:07 +0200 Subject: [PATCH] fix for relational queries (wip) --- README.md | 2 +- pom.xml | 2 +- src/main/java/com/geodesk/feature/Features.java | 13 +++++++++++++ .../geodesk/feature/query/NodeParentView.java | 17 ++++++++++++++++- .../feature/query/ParentRelationView.java | 1 + .../java/com/geodesk/feature/query/Query.java | 3 ++- .../java/com/geodesk/feature/query/View.java | 14 +++++++++++++- .../com/geodesk/feature/store/StoredNode.java | 14 ++++++++++---- src/main/java/com/geodesk/geom/Tile.java | 1 + 9 files changed, 58 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 41c742a..a130103 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Include this dependency in your project's `pom.xml`: com.geodesk geodesk - 0.2.0 + 0.2.1-SNAPSHOT ``` diff --git a/pom.xml b/pom.xml index 31c6d0b..1c4def8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.geodesk geodesk - 0.2.0 + 0.2.1-SNAPSHOT jar GeoDesk diff --git a/src/main/java/com/geodesk/feature/Features.java b/src/main/java/com/geodesk/feature/Features.java index b308b1b..12a443c 100644 --- a/src/main/java/com/geodesk/feature/Features.java +++ b/src/main/java/com/geodesk/feature/Features.java @@ -16,6 +16,7 @@ import org.locationtech.jts.geom.prep.PreparedGeometry; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -496,4 +497,16 @@ default Features within(PreparedGeometry prepared) * @return */ Features select(Features other); + + /** + * Adds all features in this collection to the given collection. + * + * @param collection a general-purpose collection (such as `List`, `Set`, + * o another type derived from `java.util.Collection`) + */ + default void addTo(Collection collection) + { + for(Feature f: this) collection.add(f); + } + } diff --git a/src/main/java/com/geodesk/feature/query/NodeParentView.java b/src/main/java/com/geodesk/feature/query/NodeParentView.java index 67074e6..c021b8b 100644 --- a/src/main/java/com/geodesk/feature/query/NodeParentView.java +++ b/src/main/java/com/geodesk/feature/query/NodeParentView.java @@ -31,12 +31,26 @@ public NodeParentView(FeatureStore store, ByteBuffer buf, StoredNode node, int pRelations, int types, Matcher matcher, Filter filter) { super(store, buf, pRelations, types, matcher, filter); + assert((types & TypeBits.WAYS) != 0 && (types & TypeBits.RELATIONS) != 0); this.node = node; } @Override protected Features newWith(int types, Matcher matcher, Filter filter) { - return node.parents(types, matcher, filter); + if((types & TypeBits.RELATIONS) == 0) + { + // view has been restricted to ways only + assert((types & TypeBits.WAYS) != 0); + return node.parentWays(types, matcher, filter); + } + else if ((types & TypeBits.WAYS) == 0) + { + // view has been restricted to relations only + assert((types & TypeBits.RELATIONS) != 0); + return new ParentRelationView(store, buf, ptr, types, matcher, filter); + } + assert((types & TypeBits.WAYS) != 0 && (types & TypeBits.RELATIONS) != 0); + return new NodeParentView(store, buf, node, ptr, types, matcher, filter); } @Override public Iterator iterator() @@ -52,6 +66,7 @@ private class Iter extends ParentRelationView.Iter public Iter() { + assert((types & (TypeBits.RELATIONS | TypeBits.WAYS)) != 0); wayQuery = new Query(node.parentWays(types, matcher, filter)); // TODO: To improve performance, we could start the query so it // can fetch the parent ways in the background, while the caller diff --git a/src/main/java/com/geodesk/feature/query/ParentRelationView.java b/src/main/java/com/geodesk/feature/query/ParentRelationView.java index e650bca..fa70656 100644 --- a/src/main/java/com/geodesk/feature/query/ParentRelationView.java +++ b/src/main/java/com/geodesk/feature/query/ParentRelationView.java @@ -96,6 +96,7 @@ private void fetchNext() pRel = (pCurrent & 0xffff_fffe) + ((rel >> 2) << 1); // TODO: simplify alignment rules! // TODO: Doesn't need rebasing; pointer is always 2-byte aligned + // But we still need to mask off the last-flag } if (matcher.accept(relBuf, pRel)) { diff --git a/src/main/java/com/geodesk/feature/query/Query.java b/src/main/java/com/geodesk/feature/query/Query.java index 6f199d5..705d432 100644 --- a/src/main/java/com/geodesk/feature/query/Query.java +++ b/src/main/java/com/geodesk/feature/query/Query.java @@ -183,7 +183,8 @@ public void start(Filter filter) currentPos = -1; // Submit initial tasks - int maxPendingTiles = 8; // TODO + int maxPendingTiles = 8; + // TODO: Uncap this limit, set at runtime based on core count while(pendingTiles < maxPendingTiles) { if(!tileWalker.next()) diff --git a/src/main/java/com/geodesk/feature/query/View.java b/src/main/java/com/geodesk/feature/query/View.java index 21f8973..b369384 100644 --- a/src/main/java/com/geodesk/feature/query/View.java +++ b/src/main/java/com/geodesk/feature/query/View.java @@ -116,14 +116,18 @@ protected Features select(int newTypes, String query) { if (child instanceof AnonymousWayNode wayNode) { + // An anonymous nodes *always* has at least one parent way, + // and *never* has parent relations return wayNode.parents(types, matcher, filter); } return ((StoredNode)child).parents(types, matcher, filter); } else { + // Ways and relations can only have relations as parents if ((types & TypeBits.RELATIONS) == 0) return EmptyView.ANY; StoredFeature f = (StoredFeature) child; + if(!f.belongsToRelation()) return EmptyView.ANY; return new ParentRelationView(store, f.buffer(), f.getRelationTablePtr(), types, matcher, filter); } @@ -142,10 +146,18 @@ protected Features select(int newTypes, String query) @Override public Features nodesOf(Feature parent) { + if ((types & TypeBits.NODES) == 0) return EmptyView.ANY; if(parent.isWay()) { StoredWay way = (StoredWay) parent; - if ((types & TypeBits.NODES) == 0) return EmptyView.ANY; + if(matcher != Matcher.ALL && + (way.flags() & FeatureFlags.WAYNODE_FLAG) == 0) + { + // GOQL queries only return feature nodes; if the Way's + // waynode_flag is cleared, it only contains anonymous + // nodes, so we return an empty set + return EmptyView.ANY; + } return new WayNodeView(store, way.buffer(), way.pointer(), types, matcher, filter); } diff --git a/src/main/java/com/geodesk/feature/store/StoredNode.java b/src/main/java/com/geodesk/feature/store/StoredNode.java index 9610318..50ee370 100644 --- a/src/main/java/com/geodesk/feature/store/StoredNode.java +++ b/src/main/java/com/geodesk/feature/store/StoredNode.java @@ -106,6 +106,8 @@ public WorldView parentWays(int types, Matcher matcher, Filter filter) public Features parents(int types, Matcher matcher, Filter filter) { + // types &= TypeBits.WAYS | TypeBits.RELATIONS; // TODO: should not be needed? (added 9/9/24) + int acceptedFlags = ((types & TypeBits.RELATIONS) != 0) ? FeatureFlags.RELATION_MEMBER_FLAG : 0; acceptedFlags |= ((types & TypeBits.WAYS) != 0) ? @@ -129,10 +131,14 @@ public Features parents(int types, Matcher matcher, Filter filter) return EmptyView.ANY; } - @Override public Features parents() - { - return parents(TypeBits.ALL, Matcher.ALL, null); - } + @Override public Features parents() + { + if(id() == 3465728159L) + { + System.out.print("!!!"); + } + return parents(TypeBits.RELATIONS | TypeBits.WAYS, Matcher.ALL, null); + } @Override public Features parents(String query) { diff --git a/src/main/java/com/geodesk/geom/Tile.java b/src/main/java/com/geodesk/geom/Tile.java index 61131f5..901b3b9 100644 --- a/src/main/java/com/geodesk/geom/Tile.java +++ b/src/main/java/com/geodesk/geom/Tile.java @@ -384,6 +384,7 @@ public static TileBox childrenOfTileAtZoom(int tile, int zoom) return box; } + // TODO: only works for positive deltas, and does not wrap! public static int relative(int tile, int deltaCol, int deltaRow) { return tile + (deltaRow << 12) + deltaCol;