การระบุทางแยกถนนโดยใช้ PostGIS


17

ฉันพยายามระบุว่าถนนตัดกันซึ่งกันและกันและหาจุดที่สี่แยกนี้ด้วยจำนวนถนนที่เป็นจุดตัดของรายการ

ป้อนคำอธิบายรูปภาพที่นี่

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

CREATE TABLE test_points as
SELECT      
    ST_Intersection(a.geom, b.geom),
    a.gid
FROM
    roads as a,
    roads as b
WHERE
    ST_Touches(a.geom, b.geom);

หากฉันเรียกใช้สิ่งนี้บนถนนตัวอย่างฉันจะได้รับตารางคะแนนต่อไปนี้ (ถนนจะแสดงเพื่อเป็นภาพประกอบ):

ป้อนคำอธิบายรูปภาพที่นี่

หากฉันตรวจสอบจุดใดจุดหนึ่งฉันเห็นว่ามีหลายจุดซ้อนกันอยู่ด้านบนของกันและกัน:

ป้อนคำอธิบายรูปภาพที่นี่

GID ที่นี่เป็นรหัสถนน แต่ฉันไม่เข้าใจว่าทำไมมีหลายจุด ฉันสามารถเข้าใจ 4 คะแนนที่นับเป็นจุดตัดถนนกลาง แต่มี 12 จุดที่ระบุไว้ที่นี่ มีวิธีที่ดีกว่าในการคำนวณใน PostGIS หรือไม่

คำตอบ:


21

หากคุณจัดกลุ่มคุณควรได้รับคะแนนที่ไม่ซ้ำกันเท่านั้น

CREATE TABLE test_points as
SELECT      
    ST_Intersection(a.geom, b.geom),
    Count(Distinct a.gid)
FROM
    roads as a,
    roads as b
WHERE
    ST_Touches(a.geom, b.geom)
    AND a.gid != b.gid
GROUP BY
    ST_Intersection(a.geom, b.geom)
;

เพียงแจ้งให้ทราบการจัดกลุ่มตามรูปทรงเรขาคณิตนั้นส่งผลให้เกิดการจัดกลุ่มตามกล่องข้อความของรูปทรงเรขาคณิตไม่ใช่รูปทรงเรขาคณิตเอง นั่นไม่สำคัญเมื่อจัดการกับคะแนน เกือบแล้ว กล่องมีความแม่นยำน้อยกว่าจุดซึ่งในทางทฤษฎีสามารถนำไปสู่การจัดกลุ่มจุดสองจุดด้วยกันที่ไม่เหมือนกัน
Nicklas Avén

ขอบคุณ @ NicklasAvén การเปรียบเทียบ Bbox มีความแม่นยำเพียงใด ฉันคาดหวังว่ามันจะเพียงพอสำหรับกรณีการใช้งานนี้
underdark

1
ขอบคุณ @underdark คุณรู้หรือไม่ว่าฉันจะนับจำนวนบรรทัดที่ตัดกันได้อย่างไร ฉันได้พยายามรวมกันไม่กี่COUNT()เช่นCOUNT(ST_Touches(..))และแต่ตอนนี้ดูเหมือนจะไม่ทำงานเป็นค่าทั้งหมดที่มีCOUNT(ST_Intersection(..)) 12
djq

@underdark ใช่มันก็เพียงพอแล้วนั่นคือเหตุผลที่ฉันเขียน "ในทางทฤษฎี" กล่องอยู่ใน float4 และพิกัดของจุดอยู่ในความแม่นยำสองเท่า ดังนั้นกล่องจะมีลักษณะเหมือนกันสำหรับ ST_Point (1.000001,1.0) และ ST_Point (1.000002,1.0) (อย่างน้อยในระบบของฉันฉันเพิ่งลองแล้วมันจะจัดกลุ่มคะแนนเข้าด้วยกัน) ความแตกต่างระหว่างกล่องและรูปทรงเรขาคณิตที่แท้จริงได้รับการปฏิเสธเป็นเวลาที่ dev-list
Nicklas Avén

ดู @AlexOs ที่แนะนำการปรับเปลี่ยนgis.stackexchange.com/a/151277/3195
Martin F

6

นี่เป็นเรื่องยากกว่าที่คุณคิด นั่นเป็นเพราะไม่มีวิธีที่ดีในการวิเคราะห์ความสัมพันธ์มากกว่าคู่ คุณไม่สามารถใส่สามบรรทัดลงในฟังก์ชั่นและถามว่าพวกมันทั้งหมดตัดกันหรือไม่

แต่อย่างน้อยหนึ่งวิธีสามารถค้นหาจุดตัดแรกได้จากนั้นตรวจสอบว่ามีกี่ถนนที่สัมผัสกันในแต่ละจุดตัด (สามารถทำได้ในแบบสอบถามเดียวกัน)

หากถนนของคุณเชื่อมต่อกันอย่างสมบูรณ์และไม่มีถนนตัดผ่านคุณสามารถทำสิ่งนี้ (ไม่ทดสอบ):
แก้ไขด้วยประโยคกลุ่มที่ถูกลืม (ยังไม่ผ่านการทดสอบ):

SELECT distinct_crosspoints.geom as crossing, array_agg(roads.gid), count(*) FROM
  (SELECT DISTINCT (geom) geom FROM 
    (SELECT ST_Intersection(a.geom, b.geom) geom 
     FROM roads a, roads b 
     WHERE ST_Intersects(a.geom, b.geom)
    ) all_crosspoints
   ) distinct_crosspoints
   ,roads 
 WHERE ST_Intersects(distinct_crosspoints.geom, roads.geom)
 GROUP BY distinct_crosspoints.geom;

หากถนนเชื่อมต่อไม่ถูกต้องและ / หรือถนนบางสายผ่านทางข้ามจะมีความซับซ้อนมากขึ้น

HTH

Nicklas


สวัสดี @Nicklas ฉันไม่สามารถเรียกใช้งานได้ อนุประโยคด้านในสองข้อทำงานได้ดี; ฉันควรจะแทนที่distinct_crosspoints ,roadsด้วยชื่อตารางของฉัน ( roads_test)? ฉันลองแล้ว แต่มีข้อผิดพลาดเกี่ยวกับgeomความคลุมเครือ
djq

1
@celenius ขออภัยฉันลืมประโยคของกลุ่ม ฉันเห็นด้วยเช่นกันว่าคุณไม่จำเป็นต้องเพิ่มความแตกต่างให้ชัดเจน คุณสามารถวางมันลงบนสี่แยกโดยตรง โปรดทราบว่า Distinct มีพฤติกรรมเช่นเดียวกับกลุ่มโดยอ้างอิงจากการสนทนาภายใต้คำตอบ underdarks
Nicklas Avén

ฉันเพิ่ม differ_crosspoints.geom ไปยังคำตอบของ Nicklas เพื่อให้แบบสอบถามทำงาน ทำงานได้แล้วสำหรับฉัน
แฟรงก์

1
 CREATE TABLE test_points as
    SELECT      
        ST_Intersection(a.geom, b.geom),
        Count(Distinct a.gid)
    FROM
        roads as a,
        roads as b
    WHERE
        ST_Touches(a.geom, b.geom)
        AND a.gid < b.gid   /* !!! Changed "!=" for "<"  */
    GROUP BY
        ST_Intersection(a.geom, b.geom)
    ;

หากบรรทัด A (id 1) ข้ามเส้น B (id 2) มันเป็นจุดตัดที่เราต้องการ แต่บรรทัด B ก็ตัดกันบรรทัด A ในจุดเดียวกัน แต่เราไม่ต้องการจุดนี้สองครั้ง นั่นเป็นเหตุผลที่ฉันใช้a.gid < b.gid แทนa.gid != b.gid

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