I have a road_vertices
table:
create table road_vertices
(
road_id number,
vertex_index number,
x number,
y number
);
insert into road_vertices values ('100',1,0,5);
insert into road_vertices values ('100',2,10,10);
insert into road_vertices values ('100',3,30,0);
insert into road_vertices values ('100',4,50,10);
insert into road_vertices values ('100',5,60,10);
select * from road_vertices;
ROAD_ID VERTEX_INDEX X Y
---------- --------------- ---------- ----------
100 1 0 5
100 2 10 10
100 3 30 0
100 4 50 10
100 5 60 10
I need to:
- Calculate the cumulative length of line segments (as shown in the grey text in the image above).
- Collapse the coordinates and cumulative lengths into a linestring.
This is the end-goal:
ROAD_ID LINESTRING
----------------------------------------------------------------------------
100 LINESTRING M ( 0 5 0, 10 10 11.18, 30 0 33.54, 50 10 55.9, 60 10 65.9)
I've figured out a way to do it:
--Step #3: Collapse the coordinates and cumulative lengths into a linestring
SELECT
ROAD_ID,
'LINESTRING M ( ' || LISTAGG(CUMULATIVE_LENGTH, ', ')
WITHIN GROUP (ORDER BY VERTEX_INDEX) || ')' AS LINESTRING
FROM
(
--Step #2: Calculate each line segment's length using the Pythagorean theorem, and add together to get cumulative length
SELECT
ROAD_ID,
VERTEX_INDEX,
X || ' ' || Y || ' ' || ROUND(SUM(NVL(SQRT(POWER((X - PREV_X),2) + POWER((Y - PREV_Y),2)),0))
OVER (PARTITION BY ROAD_ID ORDER BY ROAD_ID,VERTEX_INDEX),2)
AS CUMULATIVE_LENGTH
FROM
(
--Step #1: Get the previous X and previous Y for Step #2's Pythagorean theorem calculation
SELECT
ROAD_ID,
VERTEX_INDEX,
ROUND(X,2) AS X,
ROUND(Y,2) AS Y,
LAG (X,1) OVER (PARTITION BY ROAD_ID ORDER BY VERTEX_INDEX) AS PREV_X,
LAG (Y,1) OVER (PARTITION BY ROAD_ID ORDER BY VERTEX_INDEX) AS PREV_Y
FROM
INFRASTR.ROAD_VERTICES
)
)
GROUP BY
ROAD_ID;
However, this solution is quite complicated. Can it simplified/improved?
ROAD_ID
fromORDER BY ROAD_ID,VERTEX_INDEX
since it is part ofPARTITION
GIS
orRDF
functions that simplify it, I don't know. On the other hand you can easily create your own set of functions for special needs like theseglength
function below.