สร้างรูปหลายเหลี่ยมบนพื้นที่ที่เข้าถึงได้


10

ฉันกำลังทำงานในด้านของไอโซนีและอัลกอริธึมพื้นฐาน ตอนนี้สิ่งที่ทำให้เกิดปัญหาไม่ใช่การคำนวณถ้า isochrone ตัวเอง แต่การสร้างภาพของผลลัพธ์
ผลลัพธ์ของอัลกอริทึม isochrone ของฉันคือจุดและขอบ ในความเป็นจริงฉันมีวิธีแก้ปัญหาการทำงาน แต่สำหรับ 3873 edge และสำหรับ 1529 nodes สิ่งต่าง ๆ ดูเหมือนจะใช้ตลอดไป (ประมาณ 2.0 วินาทีบนแล็ปท็อป Lenovo T440 ของฉันซึ่งมี CPU Core i7 และ SSD ความเร็วสูง) แทนที่จะวินาทีฉันต้องการอะไรมากกว่าเช่น msec :-)

บางทีใครบางคนสามารถช่วยฉันในการลดเวลาการคำนวณที่จำเป็นในการสร้างรูปหลายเหลี่ยมซึ่งมองเห็นพื้นที่ที่สามารถเข้าถึงได้

แต่รอ ... สิ่งแรกก่อน!
นี่คือการมองเห็นของขอบที่ฉันเป็นผลการคำนวณของ isochrone ของฉัน: ผลการคำนวณ Isochrone (โครงกระดูกที่มีอยู่ของ linestrings) ขอบเหล่านี้จะถูกเก็บไว้ในตารางฐานข้อมูล PostGIS และเป็น linestrings ง่าย

สิ่งที่ฉันต้องการแสดงต่อผู้ใช้มีลักษณะดังนี้: ป้อนคำอธิบายรูปภาพที่นี่ สังเกตบริเวณที่ไม่ได้เชื่อมต่อในทิศใต้และทิศตะวันออกของภาพ สิ่งเหล่านี้ควรวาดเป็นพื้นที่แยกต่างหาก (ดังนั้นจึงไม่อนุญาตการรวมที่นี่ :-))

ขณะนี้ฉันกำลังใช้การค้นหานี้:

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_MakePolygon(ST_ExteriorRing(ST_GeometryN(segments, generate_series(1, ST_NumGeometries(segments))))) AS polygons FROM (
        SELECT ST_Union(ST_Buffer("GEOMETRY", 20, 'quad_segs=2')) AS segments FROM my_edges AS a
    ) AS b
) AS c

ฉันทำการทดลองแล้วและยังอ่านเอกสารจำนวนมาก แต่ฉันไม่สามารถหาทางออกที่ดีกว่าได้
ในสายตาของฉันปัญหาใหญ่คือการใช้ ST_Union (ตามที่ระบุไว้ในเอกสารฟังก์ชั่นนี้อาจช้า) สิ่งที่น่าสนใจมากคือการแทนที่ด้วย ST_Collect ดูเหมือนจะทำให้การคำนวณ ST_Buffer ช้าลงดังนั้นแบบสอบถามทั้งหมดต่อไปนี้จะใช้เวลานานยิ่งขึ้นแม้ว่าจะไม่เติมเต็มพื้นที่ระหว่างขอบ (มันจะสร้างบัฟเฟอร์รอบ ๆ เส้นเท่านั้น ):

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_Buffer(ST_Collect(ST_LineMerge("GEOMETRY")), 20, 'quad_segs=2') AS polygons FROM my_edges AS a
) AS b

ระบบของฉันใช้เวลาประมาณ 3.8 วินาที (เกือบสองเท่าของเวลา) ข้อสรุปแรกของฉันจากเกณฑ์มาตรฐานเล็กน้อยนี้คือ ST_Buffer เริ่มช้าลงอย่างไม่คาดคิดเมื่อพูดถึง MultiLineStrings (ยิ่งช้ากว่าเมื่อสร้างบัฟเฟอร์สำหรับแต่ละบรรทัดและรวมบัฟเฟอร์ - ซึ่งในสายตาของฉันแปลกไป)

ฉันยังพยายามใช้รูปร่างอัลฟา (โดยใช้การดำเนินการจาก pgRouting) แต่เนื่องจากไม่มีค่าอัลฟาที่จะตั้งค่า (และในความเป็นจริงฉันจะไม่จริงตอนนี้ซึ่งเป็นค่าที่จะตั้งค่าดังกล่าว) ฉันเพิ่งได้รูปหลายเหลี่ยม ดังนั้นฉันจะสูญเสียพื้นที่ในภาคใต้และตะวันออกเป็นภูมิภาคแยกซึ่งไม่ใช่สิ่งที่ฉันต้องการ)
ST_Polygonize (ซึ่งเป็นสิ่งแรกที่อยู่ในใจของฉัน) ไม่ได้ให้ผลลัพธ์ที่ใช้ได้ แต่บางทีฉันอาจพลาดบางสิ่งที่นี่ ...

มีวิธีที่ดีกว่าในการสร้างพื้นที่ที่แสดงใน PostGIS หรือไม่ อาจจะด้วยการใช้รหัสจาวา (jts) หรือรหัสจาวาสคริปต์ฝั่งไคลเอ็นต์ (jsts)? ในความเป็นจริงฉันสามารถอยู่กับการสูญเสียรายละเอียดตราบใดที่พื้นที่ที่แสดงในผลลัพธ์ของฉันแยกจากกันและการคำนวณได้เร็วขึ้น (มาก)


คุณไม่เพียงแค่ใช้ ST_Exteriorring (ST_Dump (ST_Union (ST_Buffer (geom, .... )))) geom ที่เห็นว่าสิ่งที่บัฟเฟอร์จะเป็นรูปหลายเหลี่ยมอยู่แล้วและ ST_Union จะเชื่อมต่อรูปทรงเรขาคณิตที่ตัดกันทั้งหมด คุณอาจต้องทดสอบ Linestrings ซึ่งบางครั้งเป็นผลมาจาก ST_Union หลังจากบัฟเฟอร์ แต่มันง่ายกับ ST_GeometryType (geom) เท่าที่ใช้ Java หรือ jsts คุณสามารถทำได้ แต่ไม่น่าจะเร็วขึ้น ส่วนใหญ่ของ PostGIS (GEOS) ฟังก์ชั่น C / C ++ พอร์ตของเจทีเอสในสถานที่แรก.
จอห์นพาวเวล

คุณใช้งานได้ดี แต่ในความเป็นจริงมันไม่เร็วขึ้น (ใช้เวลา ~ 3.1 วินาทีในขณะที่ใช้ GeometryN ใช้เวลา 2 วินาที) นี่คือสิ่งที่ฉันใช้: SELECT ST_AsGeoJson (ST_Transform (ST_Externalring ((ST_Dump (ST_Union (ST_Union (ST_Buffer ("GEOMETRY", 20)))) geom), 4326) จาก my_edges;
Nikolaus Krismer

@ john-barça: โอ้ .. ฉันคิดผิด quad_segs = 2 ส่วนหนึ่งใน ST_Buffer เมื่อลองใช้วิธีของคุณ ... ด้วยการเปลี่ยนคำถามที่เป็นไปได้ (ทั้งที่ประมาณ 2secs) อย่างไรก็ตามนี่ยังช้ามาก (ในสายตาของฉัน) มีวิธีอื่นไหม
Nikolaus Krismer

ปัญหาที่น่าสนใจ .... คุณต้องการแบ่งปันข้อมูลการทดสอบหรือไม่?
dbaston

ถ้ามันช่วยให้ฉันมีความสุขที่จะแบ่งปันข้อมูลบางอย่าง ทุกสิ่งที่ฉันทำที่นี่เป็นโอเพ่นซอร์สดังนั้นนี่ไม่ควรเป็นปัญหาใหญ่ สิ่งแรกที่ต้องแจ้งให้ทราบล่วงหน้า: โปรแกรมประยุกต์บนเว็บสำหรับการทดสอบตั้งอยู่ที่dbis-isochrone.uibk.ac.at:8080/testing ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ฉันทำงานในสามารถพบได้ที่dbis-isochrone.uibk.ac.at ในส่วน "ลิงก์" ของเว็บไซต์มีการอ้างอิงเพิ่มเติมบางส่วน (รวมถึงข้อมูลการทดสอบบางอย่าง)
Nikolaus Krismer

คำตอบ:


5

นอกเหนือจากการจัดลำดับอนุกรม GeoJSON ต่อไปนี้จะใช้เวลาประมาณ 6.3 วินาทีบนแล็ปท็อปของฉัน:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(geom, 20, 2)))).geom))
FROM bz_edges

เมื่อดูข้อมูลใน OpenJUMP ฉันสังเกตเห็นรายละเอียดค่อนข้างน้อยในส่วนถนนเมื่อเทียบกับระดับรายละเอียดที่ต้องการในผลลัพธ์ ดูเหมือนว่าแม้แต่การทำให้เข้าใจง่ายของสายการผลิตเหล่านี้สามารถสร้างความเร็วที่ยิ่งใหญ่ใน PostGIS:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(ST_Simplify(geom, 10), 20, 2)))).geom))
FROM bz_edges

ซึ่งนำสิ่งต่าง ๆ ลงไป 2.3 วินาที ฉันคิดว่าฉันอาจจะทำได้ดีกว่านี้ด้วยการจัดเก็บรูปทรงเรขาคณิตทั่วไปในคอลัมน์แยกต่างหากแทนที่จะคำนวณมันแบบทันที แต่นั่นก็ไม่ได้ประโยชน์อะไรเลย

ขึ้นอยู่กับว่าคุณต้องการเขียนโค้ดเท่าใดคุณสามารถทำได้ดีกว่าใน Java อย่างแน่นอนหากไม่มีสิ่งอื่นใดเพราะคุณสามารถใช้ประโยชน์จากหลายคอร์ได้ (สำหรับสิ่งที่คุ้มค่า JTS จะดำเนินการด้านบนในเวลา 2.8 วินาที) วิธีการหนึ่งอาจจะขยายออกCascadedPolygonUnionไปเพื่อให้การดำเนินงานของสหภาพบางส่วนเกิดขึ้นพร้อมกัน (อัปเดต - นี่คือParallelCascadedPolygonUnion )

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

  1. ระบุส่วนประกอบที่เชื่อมต่อของกราฟ
  2. สำหรับแต่ละองค์ประกอบที่เชื่อมต่อให้ค้นหาโหนดที่มีพิกัด X ขั้นต่ำ (รับประกันว่าจะอยู่ด้านนอกองค์ประกอบ)
  3. เดินไปตามขอบของส่วนประกอบหันซ้าย (หรือขวา) เสมอเมื่อทำได้ สิ่งนี้จะให้วงแหวนภายนอกของแต่ละองค์ประกอบ
  4. ทำรูปวงแหวนวงแหวนด้านนอกและบัฟเฟอร์อย่างเหมาะสม

ขอบคุณ ... การทำให้เข้าใจง่ายคือการปรับปรุงที่ดีและแม้แต่ "เรียบง่าย" มันใช้เวลาในแล็ปท็อปของฉันลดลงเหลือ 1.5 วินาที มันไม่ใช่ที่ที่ฉันต้องการ แต่ก็ดีกว่า
Nikolaus Krismer

เกี่ยวกับโซลูชันที่คุณแนะนำ (คะแนน 1-4) ฟังดูง่ายและคุ้มค่าที่จะลอง ฉันคิดถึงสิ่งที่คล้ายกัน แต่ฉันติดอยู่ที่จุดที่ 1 (เร็วมาก :-)) วิธีหนึ่งจะระบุองค์ประกอบที่เชื่อมต่อ (สิ่งเดียวที่ฉันคิดได้คือแบบสอบถามแบบเรียกซ้ำซึ่งอาจช้ามาก)
Nikolaus Krismer

@NikolausKrismer ฉันใช้ทั้งJGraphTและกี่สำหรับงานแบบนี้ หากคุณเขียนวิธีกราฟของคุณเองแทน (ไม่ใช่ความคิดที่แย่สำหรับประสิทธิภาพที่ดีที่สุด) การค้นหาแบบเจาะลึกจะค้นหาส่วนประกอบให้คุณ (คุณสามารถค้นหาได้ใน PostGIS 2.2 ที่กำลังจะมาถึงST_ClusterIntersectingแต่ฉันคิดว่าคุณต้องการให้การประมวลผลกราฟชนิดใดเกิดขึ้นนอกฐานข้อมูลอยู่ดีดังนั้นสิ่งนี้อาจไม่มีประโยชน์)
dbaston

นี่คือคำแนะนำที่ดี ฉันดู JGraphT และนี่อาจช่วยแก้ปัญหาของฉันได้ อย่างไรก็ตามฉันยังดูที่ Postgis 2.2 และฟังก์ชัน ST_ClusterIntersecting -> ใช้เวลาประมาณ 200-250 มิลลิวินาทีในการระบุกลุ่มต่างๆในกรณีข้างต้น ไม่เป็นไรสำหรับฉัน (JGraphT สามารถทำได้ดีกว่าอย่างแน่นอน) ตอนนี้ฉันต้องจัดการกับการสร้าง exteriorRing (ST_ExfrontRing ล้มเหลวเนื่องจาก ST_MakePolygon บอกว่าลิงก์ของฉันไม่มีเปลือก)
Nikolaus Krismer

ฉันเห็นภาวะแทรกซ้อนสองประการ: (ก) คุณไม่เพียง แต่ต้องการวงแหวนภายนอกเท่านั้น แต่ยังรวมถึงส่วนใด ๆ ที่ยื่นออกไปด้านนอกจากวงแหวนนั้นและ (b) ดูเหมือนว่าเส้นของคุณไม่ได้ตัดกันที่สี่แยก คุณจะต้องแก้ไข (b) หากคุณกำลังพยายามสร้างรูปทรงเรขาคณิตจากผลลัพธ์ของการเดินกราฟ
dbaston
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.