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;