กำลังค้นหาอัลกอริทึมในการตรวจจับการวนรอบและจุดเริ่มต้นและจุดสิ้นสุดของวงกลมหรือไม่?


24

ฉันมีข้อมูลเที่ยวบินมากมายจากนักบินเครื่องร่อนในรูปแบบของการแก้ไข gps ในช่วงเวลาที่แน่นอน ฉันต้องการวิเคราะห์เส้นทางการบินและตรวจจับจุดเริ่มต้นและจุดสิ้นสุดของ 'วง' นักบินเครื่องร่อนจะทำเมื่อเขาพบความร้อน

อัลกอริทึมจะให้ฉันเริ่มต้นและจุดสิ้นสุดในบรรทัดกำหนดหนึ่ง "วงกลม" คะแนนเหล่านี้อาจเท่ากับหนึ่งในการแก้ไข gps และไม่จำเป็นต้องถูกแก้ไข

ฉันสามารถเดินไปตามเส้นทางบินตรวจสอบอัตราการหมุนและมีเกณฑ์ตัดสินว่าเครื่องร่อนกำลังหมุนวนหรือไม่

ในขณะที่ฉันใช้ PostgreSQL กับส่วนขยาย PostGIS ฉันสงสัยว่ามีวิธีที่ดีกว่าในการแก้ไขปัญหานี้หรือไม่ ฉันมีขั้นตอนการคำนวณมุมของส่วนของเส้นสองส่วนแล้ว:

CREATE OR REPLACE FUNCTION angle_between(
  _p1 GEOMETRY(PointZ,4326),
  _p2 GEOMETRY(PointZ,4326),
  _p3 GEOMETRY(PointZ,4326)
) RETURNS DECIMAL AS $$
DECLARE
  az1 FLOAT;
  az3 FLOAT;
BEGIN
  az1 = st_azimuth(_p2,_p1);
  az3 = st_azimuth(_p2,_p3);
IF az3 > az1 THEN
  RETURN (
      degrees(az3 - az1)::decimal - 180
  );
ELSE
  RETURN (
      degrees(az3 - az1)::decimal + 180
  );
END IF;
END;
$$ LANGUAGE plpgsql;

เป็นไปได้ที่จะวนซ้ำทุกส่วนของเส้นและตรวจสอบเมื่อผลรวมของมุมมีค่ามากกว่า 360 หรือน้อยกว่า -360 องศา จากนั้นฉันสามารถใช้ st_centroid เพื่อตรวจหาศูนย์กลางของวงกลมถ้าจำเป็น

มีแนวทางที่ดีกว่านี้ไหม?


ตามที่ร้องขอผมอัปโหลดเที่ยวบินตัวอย่างเช่น

เส้นทางการบินตัวอย่าง


1
มองไปรอบ ๆ เตะ Hough Circle Transform มีการอภิปรายผู้ใช้ postgis ที่คล้ายกัน (กับรูปหลายเหลี่ยม) ที่นี่: lists.osgeo.org/pipermail/postgis-users/2015-F กุมภาพันธ์/20
บาร์เร็ตต์

ขอบคุณทั้งคู่ ฉันจะดู Hough Transform การอภิปรายที่ osgeo.org ถือว่าฉันรู้อยู่แล้วว่าวงกลมเริ่มต้นและสิ้นสุดที่ใดถ้าฉันเข้าใจถูกต้อง
pgross

คุณเคยเห็นสิ่งนี้ไหม
Devdatta Tengshe

@DevdattaTengshe ใช่ แต่ก็ขอบคุณอยู่ดี นั่นจะเป็นวิธีที่ฉันจะต้องคำนวณเส้นโค้งและความโค้งจากภายนอกใช่ไหม? โดยภายนอกฉันหมายถึงไม่เป็นขั้นตอนหรือแบบสอบถามโดยตรงบนฐานข้อมูล เนื่องจากเที่ยวบินไม่เปลี่ยนแปลงเมื่ออยู่ในฐานข้อมูลจึงเป็นตัวเลือก
pgross

คุณสามารถโพสต์ข้อมูลตัวอย่างบางส่วนเป็นไฟล์. sql ได้หรือไม่
dbaston

คำตอบ:


14

ฉันไม่สามารถหยุดคิดเกี่ยวกับเรื่องนี้ ... ฉันสามารถคิดขั้นตอนการจัดเก็บเพื่อทำการนับลูป เส้นทางตัวอย่างมี 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;


สิ่งนี้ดูมีแนวโน้มมาก ขอบคุณมาก. ฉันจะต้องปรับปรุงมันเพราะฉันไม่ได้สนใจในจำนวนแวดวง แต่เป็นจุดเริ่มต้น / จุดสิ้นสุด แต่นั่นน่าจะเป็นไปได้อย่างง่ายดายที่จะกลับมาฉันเดา
pgross

นั่นฟังดูฉลาดดี มันจัดการกับสถานการณ์ที่วงวนหนึ่งตัดวงวนอื่นอย่างไร หรือคุณข้ามจุดเริ่มต้นเมื่อคุณหาวง?
Peter HorsbøllMøller

@ PeterHorsbøllMøllerมันจะวิเคราะห์เมื่อบรรทัดสร้างลูป (ST_BuildArea จะคืนค่าเป็นจริงเมื่อบรรทัดสร้างพื้นที่ปิด) แทนที่จะมองหาจุดตัด
kttii

@pgross oops จริง! ฉันได้รับการเบี่ยงเบนไปเล็กน้อยและลืมเกี่ยวกับจุดเริ่มต้น / จุดสิ้นสุด แต่ใช่นั่นเป็นการตัดสินใจที่ง่ายพอในขณะนี้ที่ลูปแตกต่าง
kttii

@pgross ดูเหมือนว่าคุณอาจจะได้ตำแหน่งที่เหมาะสมมากขึ้นของ thermals โดยการค้นหา ST_Centroid ของแต่ละวงแทนที่จะค้นหาตำแหน่งเริ่มต้น / สิ้นสุดของแต่ละวง คุณคิดอย่างไร? แน่นอนฟังก์ชั่นสามารถให้สถิติทั้งสาม
kttii

3

ฉันสังเกตเห็นว่าไฟล์ gpx มีการประทับเวลาซึ่งสามารถใช้ประโยชน์ได้ บางทีวิธีการด้านล่างอาจใช้งานได้

Make a linesegement with Vi,Vi+1
Make it Polyline
Proceed to Vi+2,Vi+3 check intersection with Polyline
  if it intersects 
      find the point of intersection-Designate this as start/end point of the loop
      Make this intersection point as Vi and Vi+1 would next gpx point per time sequence  
  if the linesegement does not intersect with polyyline then  increment 'i' 

ฉันพบว่ามันยากที่จะใช้ ST_Intersects เนื่องจากวงกลมที่ทับซ้อนกันซึ่งทำให้ฉันใช้ ST_BuildArea
kttii

ฉันให้ความโปรดปรานแก่คุณเพราะคำตอบของคุณโดยทั่วไปคือเพลงเดียวกัน
kttii
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.