Identifies curves in a trajectory and returns the curvature radius and position of each curve's center point.
Syntax
Syntax 1 — Use when the default expansion radii are sufficient:
SETOF trpeak ST_CurveRecognize(trajectory traj, float8 radius_threshold, float8 angle_threshold, float8 angle_compress_threshold DEFAULT 0);Syntax 2 — Use when you need precise control over how far the curve boundary extends from the center point:
SETOF trpeak ST_CurveRecognize(trajectory traj, float8 radius_threshold, float8 angle_threshold, float8 expansion_radius1, float8 expansion_radius2, float8 angle_compress_threshold DEFAULT 0);With Syntax 1, expansion_radius1 defaults to radius_threshold * 2 and expansion_radius2 defaults to radius_threshold * 4.
Parameters
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
traj | trajectory | — | The trajectory to analyze. |
radius_threshold | float8 | — | The curvature radius threshold for identifying the center point of a curve. The function collects all consecutive trajectory points whose curvature radius is smaller than this value, then selects the point with the smallest curvature radius as the center point. |
angle_threshold | float8 | — | The minimum rotation angle for a boundary point to be retained. If a boundary point's rotation angle is smaller than this value, the point is removed and the curve is split into two separate curves at that location. |
expansion_radius1 | float8 | radius_threshold * 2 | The curvature radius threshold at each candidate boundary point. Only points whose curvature radius is smaller than this value are included in the curve boundary. (Syntax 2 only) |
expansion_radius2 | float8 | radius_threshold * 4 | The average curvature radius threshold from a candidate boundary point to the center point. Only points where this average is smaller than this value are included in the curve boundary. (Syntax 2 only) |
angle_compress_threshold | float8 | 0 | The minimum rotation angle for a point to be sampled. Points with a rotation angle smaller than this value are skipped, reducing sampling density and preventing over-sampling from obscuring curve detection. |
Return values
ST_CurveRecognize returns a set of trpeak records, one per detected curve. Each record contains:
| Field | Description |
|---|---|
loc | The serial number of the center point within the trajectory's turning-point sequence. If loc = n, the center point is the (n + 1)th turning point of the trajectory. |
height | The curvature radius at the center point. A positive value indicates a clockwise curve; a negative value indicates a counterclockwise curve. |
startloc | The serial number of the curve's start point. |
endloc | The serial number of the curve's end point. |
How it works
ST_CurveRecognize identifies curves in three steps:
Identify center points. Scan all consecutive trajectory points whose curvature radius is smaller than
radius_threshold. From each such group, select the point with the smallest curvature radius as the curve's center point.Expand the curve boundary. Starting from each center point, extend the boundary outward to include adjacent points that meet both conditions:
The point's curvature radius is smaller than
expansion_radius1.The average curvature radius from that point to the center point is smaller than
expansion_radius2.
Validate and split boundary points. For each boundary point, compare its rotation angle against
angle_threshold:If the rotation angle exceeds the threshold, the boundary expands outward in both directions.
If the rotation angle falls below the threshold, the boundary point is removed. The curve splits into two parts at that point, each with a rotation angle above the threshold at every boundary.
Example
The following example runs ST_CurveRecognize on a 16-point trajectory with radius_threshold = 15 and angle_threshold = 1. The trajectory data repeats the same 8-point path twice, so the same physical curves appear at two different time segments.
SELECT (ST_CurveRecognize(
'{"trajectory":{"version":1,"type":"STPOINT","leafcount":16,
"start_time":"2000-01-01 00:00:00","end_time":"2000-01-16 00:00:00",
"spatial":"LINESTRING(0 0,1 1,2 2,4 3,3 4,5 7,8 8,7 4,0 0,1 1,2 2,4 3,3 4,5 7,8 8,7 4)",
"timeline":["2000-01-01 00:00:00","2000-01-02 00:00:00","2000-01-03 00:00:00",
"2000-01-04 00:00:00","2000-01-05 00:00:00","2000-01-06 00:00:00",
"2000-01-07 00:00:00","2000-01-08 00:00:00","2000-01-09 00:00:00",
"2000-01-10 00:00:00","2000-01-11 00:00:00","2000-01-12 00:00:00",
"2000-01-13 00:00:00","2000-01-14 00:00:00","2000-01-15 00:00:00",
"2000-01-16 00:00:00"]}}',
15, -- radius_threshold
1 -- angle_threshold
)).*;Output:
loc | height | startloc | endloc
-----+---------------------+----------+--------
2 | 5.70087712549569 | 2 | 2
4 | 2.1023796041628637 | 4 | 8
10 | 5.70087712549569 | 10 | 10
12 | 2.1023796041628637 | 12 | 15
3 | -1.1785113019775793 | 3 | 3
11 | -1.1785113019775793 | 11 | 11
(6 rows)The output contains 6 rows representing 3 distinct curves, each detected twice because the trajectory repeats:
Rows with
loc = 2andloc = 10(height ≈ 5.70, positive): the same clockwise curve, encountered in the first and second pass through the path.Rows with
loc = 4andloc = 12(height ≈ 2.10, positive,startloctoendlocspanning multiple points): a wider clockwise curve with an extended boundary.Rows with
loc = 3andloc = 11(height ≈ −1.18, negative): the same counterclockwise curve in both passes.