나는 이것에 대해 생각을 멈출 수 없었다 ... 나는 루프 계산을 수행하기 위해 저장 프로 시저를 생각해 낼 수 있었다. 예제 경로에는 109 개의 루프가 있습니다!
다음은 루프 중심이 빨간색으로 표시된 비행 지점입니다.
기본적으로 캡처 된 순서대로 점을 통과하고 점을 반복 할 때 선을 만듭니다. 우리가 만들고있는 선이 ST_BuildArea를 사용하여 루프를 만들면 루프를 세고 그 지점부터 다시 선을 만들기 시작합니다.
이 함수는 루프 번호, 지오메트리, 시작 / 종료 지점 및 중심을 포함하는 각 루프의 레코드 세트를 반환합니다 (또한 일부를 정리하고 더 나은 변수 이름을 만들었습니다).
DROP FUNCTION test.find_loop_count(flightid int);
create function test.find_Loop_count(
IN flightid int,
OUT loopnumber int,
OUT loopgeometry geometry,
OUT loopstartend geometry,
OUT loopcentroid geometry
)
RETURNS SETOF record AS
$BODY$
-- s schema 'test' must exist
-- a table 'points' of flight points must exist
-- we are going to iterate through the point path, building a line as we go
-- If the line creates a loop then we count a loop and start over building a new line
-- add the intersection point to the returning recordset
-- add the centroid of the loop to the resulting recordset
-- pass in the flight ID of the flight that you wish to count its loops for example:
-- SELECT * FROM find_loop_count(37);
DECLARE
rPoint RECORD;
gSegment geometry = NULL;
gLastPoint geometry = NULL;
gLoopPolygon geometry = NULL;
gIntersectionPoint geometry = NULL;
gLoopCentroid geometry = NULL;
iLoops integer := 0;
BEGIN
-- for each line segment in Point Path
FOR rPoint IN
WITH
pts as (
SELECT location as geom,datetime,row_number() OVER () as rnum
FROM test.points
WHERE flight_id=flightid
ORDER BY 2)
SELECT ST_AsText(ST_MakeLine(ARRAY[a.geom, b.geom])) AS geom, a.rnum, b.rnum
FROM pts as a, pts as b
WHERE a.rnum = b.rnum-1 AND b.rnum > 1
LOOP
-- if this is the start of a new line then start the segment otherwise add the point to the segment
if gSegment is null then
gSegment=rPoint.geom;
elseif rPoint.geom::geometry=gLastPoint::geometry then
-- do not add this point to the segment because it is at the same location as the last point
else
-- add this point to the line
gSegment=ST_Makeline(gSegment,rPoint.geom);
end if;
-- ST_BuildArea will return true if the line segment is noded and closed
-- we must also flatten the line to 2D
-- lets also make sure that there are more than three points in our line to define a loop
gLoopPolygon=ST_BuildArea(ST_Node(ST_Force2D(gSegment)));
if gLoopPolygon is not NULL and ST_Numpoints(gSegment) > 3 then
-- we found a loop
iLoops:=iLoops+1;
-- get the intersection point (start/end)
gIntersectionPoint=ST_Intersection(gSegment::geometry,rPoint.geom::geometry);
-- get the centroid of the loop
gLoopCentroid=ST_Centroid(gLoopPolygon);
-- start building a new line
gSegment=null;
LOOPNUMBER := iLoops;
LOOPGEOMETRY := gLoopPolygon;
LOOPSTARTEND := gIntersectionPoint;
LOOPCENTROID := gLoopCentroid;
RETURN NEXT;
end if;
-- keep track of last segment
gLastPoint=rPoint.geom;
END LOOP;
RAISE NOTICE 'Total loop count is %.', iLoops;
END;
$BODY$
LANGUAGE plpgsql STABLE
COST 100
ROWS 1000;
이것은 루프 카운트 만 반환하는 간단한 함수입니다.
DROP FUNCTION test.find_loop_count(flightid int);
create function test.find_Loop_count(flightid int) RETURNS integer AS $$
-- s schema 'test' must exist
-- a table 'points' of flight points must exist
-- we are going to iterate through the line path, building the line as we go
-- If the line creates a loop then we count a loop and start over building a new line
-- pass in the flight ID of the flight that you wish to count its loops for example:
-- SELECT find_loop_count(37);
DECLARE
segment RECORD;
s geometry = NULL;
lastS geometry = NULL;
b geometry = NULL;
loops integer := 1;
BEGIN
-- for each line segment is Point Path
FOR segment IN
WITH
pts as (
SELECT location as geom,datetime,row_number() OVER () as rnum
FROM test.points
WHERE flight_id=flightid
ORDER BY 2)
SELECT ST_AsText(ST_MakeLine(ARRAY[a.geom, b.geom])) AS geom, a.rnum, b.rnum
FROM pts as a, pts as b
WHERE a.rnum = b.rnum-1 AND b.rnum > 1
LOOP
-- if this is the start of a new line then make s be the segment otherwise add the segment to s
if s is null then
s=segment.geom;
elseif segment.geom::geometry=lastS::geometry then
else
s=ST_Makeline(s,segment.geom);
end if;
-- ST_BuildArea will return true if the line segment is noded and closed
-- we must also flatten the line to 2D
b=ST_BuildArea(st_node(ST_Force2D(s)));
if b is not NULL and st_numpoints(s) > 3 then
RAISE NOTICE 's: %', s;
RAISE NOTICE 'vvvvv %',st_numpoints(s);
RAISE NOTICE 'I found a loop! Loop count is now %', loops;
RAISE NOTICE '^^^^^';
s=null;
loops:=loops +1;
end if;
lastS=segment.geom;
END LOOP;
RAISE NOTICE 'Total loop count is %.', loops-1;
RETURN loops-1;
END;
$$ LANGUAGE plpgsql;