Skip to content

Commit 77014b3

Browse files
Address temporal geometries by their sequence-set member index
The temporal geometry sequence enumerates the trajectory's gap-separated member sequences as the OGC temporal primitive geometries, each with its 1-based index (sequenceN / numSequences): GET .../tgsequence returns one entry per member with that id and its own datetimes/coordinates (a gap-separated trajectory no longer collapses to a single empty entry); the velocity and distance queries run on the addressed member (out-of-range id -> 404); DELETE .../tgsequence/{id} removes the member by rebuilding the sequence set from the kept members (409 when it is the only one).
1 parent fc2e5db commit 77014b3

4 files changed

Lines changed: 83 additions & 58 deletions

File tree

resource/temporal_geom_query/distance.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,30 @@ def get_distance(self, collection_id, feature_id, geometry_id, connection, curso
2828
self.handle_error(404, f"Feature '{feature_id}' not found in collection '{collection_id}'")
2929
return
3030

31-
#geometry exists for feature
31+
# {geometry_id} is the 1-based index of a member sequence of the trajectory
32+
try:
33+
member = int(geometry_id)
34+
except (TypeError, ValueError):
35+
self.handle_error(400, "invalid temporal geometry id (1-based index into the sequence)")
36+
return
3237
cursor.execute("""
33-
SELECT id FROM temporal_geometries
34-
WHERE id = %s AND feature_id = %s and collection_id = %s
35-
""", (geometry_id, feature_id, collection_id))
36-
38+
SELECT 1 FROM temporal_geometries
39+
WHERE feature_id = %s AND collection_id = %s
40+
AND %s BETWEEN 1 AND numSequences(trajectory)
41+
""", (feature_id, collection_id, member))
3742
if cursor.fetchone() is None:
3843
self.handle_error(404, f"Temporal geometry '{geometry_id}' not found for feature '{feature_id}'")
3944
return
4045
##############################################################################################################################
4146

4247
# API returns derived time-to-distance curve data from all available time of the specified TemporalPrimitiveGeometry object ref ogc p65
4348
cursor.execute("""
44-
SELECT
45-
getTimestamp(unnest(instants(round(cumulativeLength(trajectory),6)))) as time,
46-
getValue(unnest(instants(round(cumulativeLength(trajectory),6)))) as distance
49+
SELECT
50+
getTimestamp(unnest(instants(round(cumulativeLength(sequenceN(trajectory, %s)),6)))) as time,
51+
getValue(unnest(instants(round(cumulativeLength(sequenceN(trajectory, %s)),6)))) as distance
4752
FROM temporal_geometries
48-
WHERE id = %s AND feature_id = %s AND collection_id = %s
49-
""", (geometry_id, feature_id, collection_id))
53+
WHERE feature_id = %s AND collection_id = %s
54+
""", (member, member, feature_id, collection_id))
5055
#eg t[0@08:00, 14.1@08:01, 27.1@08:02, 42.4@08:03] clean ?
5156
rows = cursor.fetchall()
5257
if not rows:

resource/temporal_geom_query/velocity.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,29 @@ def get_velocity(self, collection_id, feature_id, geometry_id, connection, curso
2828
self.handle_error(404, f"Feature '{feature_id}' not found in collection '{collection_id}'")
2929
return
3030

31-
#geometry exists for feature
31+
# {geometry_id} is the 1-based index of a member sequence of the trajectory
32+
try:
33+
member = int(geometry_id)
34+
except (TypeError, ValueError):
35+
self.handle_error(400, "invalid temporal geometry id (1-based index into the sequence)")
36+
return
3237
cursor.execute("""
33-
SELECT id FROM temporal_geometries
34-
WHERE id = %s AND feature_id = %s AND collection_id = %s
35-
""", (geometry_id, feature_id, collection_id))
36-
38+
SELECT 1 FROM temporal_geometries
39+
WHERE feature_id = %s AND collection_id = %s
40+
AND %s BETWEEN 1 AND numSequences(trajectory)
41+
""", (feature_id, collection_id, member))
3742
if cursor.fetchone() is None:
3843
self.handle_error(404, f"Temporal geometry '{geometry_id}' not found for feature '{feature_id}'")
3944
return
4045
##############################################################################################################################
41-
#speed
46+
#speed of the addressed member sequence
4247
cursor.execute("""
43-
SELECT
44-
getTimestamp(unnest(instants(speed(trajectory)))) as time,
45-
getValue(unnest(instants(speed(trajectory)))) as speed
48+
SELECT
49+
getTimestamp(unnest(instants(speed(sequenceN(trajectory, %s))))) as time,
50+
getValue(unnest(instants(speed(sequenceN(trajectory, %s))))) as speed
4651
FROM temporal_geometries
47-
WHERE id = %s AND feature_id = %s AND collection_id = %s
48-
""", (geometry_id, feature_id, collection_id))
52+
WHERE feature_id = %s AND collection_id = %s
53+
""", (member, member, feature_id, collection_id))
4954
rows = cursor.fetchall()
5055

5156
if not rows:

resource/temporal_geom_seq/Retrieve.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,35 @@ def get_tgsequence(self, connection, cursor):
3232
return
3333
# """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""":::
3434

35-
# Get temporal geometries for this feature
35+
# The trajectory is a tgeompoint sequence set; each member sequence is one
36+
# OGC temporal primitive geometry, addressed by its 1-based index
37+
# (sequenceN / numSequences). Enumerate the members so the {tGeometryId}
38+
# values are discoverable and a gap-separated trajectory exposes them all.
3639
cursor.execute("""
37-
SELECT
38-
id,
39-
geometry_type,
40-
asMFJSON(trajectory) as trajectory,
41-
interpolation,
42-
base
43-
FROM temporal_geometries
44-
WHERE feature_id = %s and collection_id = %s
45-
ORDER BY id
46-
""", (feature_id,collection_id))
47-
40+
SELECT
41+
n,
42+
tg.geometry_type,
43+
asMFJSON(sequenceN(tg.trajectory, n)) AS member,
44+
tg.interpolation,
45+
tg.base
46+
FROM temporal_geometries tg,
47+
generate_series(1, numSequences(tg.trajectory)) AS n
48+
WHERE tg.feature_id = %s AND tg.collection_id = %s
49+
ORDER BY n
50+
""", (feature_id, collection_id))
51+
4852
rows = cursor.fetchall()
49-
53+
5054
geometries = []
51-
for row in rows:
52-
traj = json.loads(row[2]) if row[2] else {}
55+
for n, gtype, member, interp, base in rows:
56+
traj = json.loads(member) if member else {}
5357
geometries.append({
54-
"id": row[0],
55-
"type": row[1],
58+
"id": n,
59+
"type": gtype or "MovingPoint",
5660
"datetimes": traj.get("datetimes", []),
5761
"coordinates": traj.get("coordinates", []),
58-
"interpolation": row[3],
59-
"base": row[4]
62+
"interpolation": interp,
63+
"base": base
6064
})
6165

6266
# ref Table 9 ogc

resource/temporal_prim_geom/Delete.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,40 @@ def delete_single_temporal_primitive_geo(self, collection_id, feature_id, geomet
2525
if cursor.fetchone() is None:
2626
self.handle_error(404, f"Feature '{feature_id}' not found")
2727
return
28-
# geometry exists (by collection by mf)
29-
cursor.execute("""
30-
SELECT tg.id
31-
FROM temporal_geometries tg
32-
JOIN moving_features mf ON tg.feature_id = mf.id
33-
WHERE tg.id = %s
34-
AND mf.id = %s
35-
AND mf.collection_id = %s
36-
""", (geometry_id, feature_id, collection_id))
37-
38-
if cursor.fetchone() is None:
28+
# {geometry_id} is the 1-based index of a member sequence of the trajectory
29+
try:
30+
member = int(geometry_id)
31+
except (TypeError, ValueError):
32+
self.handle_error(400, "invalid temporal geometry id (1-based index into the sequence)")
33+
return
34+
cursor.execute(
35+
"SELECT numSequences(trajectory) FROM temporal_geometries WHERE feature_id = %s AND collection_id = %s",
36+
(feature_id, collection_id),
37+
)
38+
row = cursor.fetchone()
39+
if row is None or row[0] is None:
3940
self.handle_error(404, f"Temporal geometry {geometry_id} not found")
4041
return
42+
nseq = row[0]
43+
if member < 1 or member > nseq:
44+
self.handle_error(404, f"Temporal geometry {geometry_id} not found")
45+
return
46+
if nseq == 1:
47+
self.handle_error(409, "the feature has a single temporal geometry; delete the feature to remove it")
48+
return
4149
#----------------------------------------------------------------------------------------------------------------------
42-
# delete
50+
# Remove the member sequence by rebuilding the sequence set from the kept
51+
# members (deleteTime on a tgeompoint is avoided — it crashes the backend).
4352
cursor.execute(
44-
"""DELETE FROM temporal_geometries tg
45-
WHERE tg.id = %s
46-
AND tg.feature_id = %s
47-
AND tg.collection_id = %s
48-
""", (geometry_id, feature_id, collection_id)
53+
"""UPDATE temporal_geometries SET trajectory = (
54+
SELECT merge(seq)
55+
FROM unnest(sequences(trajectory)) WITH ORDINALITY AS u(seq, ord)
56+
WHERE ord <> %s
57+
)
58+
WHERE feature_id = %s AND collection_id = %s
59+
""", (member, feature_id, collection_id)
4960
)
50-
61+
5162
connection.commit()
5263

5364
# response Req 31)

0 commit comments

Comments
 (0)