พื้นหลัง
จากจุดที่รู้จักฉันต้องสร้าง "ปริมณฑลที่มองเห็นได้" ใกล้เคียงที่สุดกับตารางของ MultiLineStrings ดังที่แสดงในแผนภาพ
ฉันค้นหาไซต์นี้ด้วยคำศัพท์จำนวนหนึ่ง (เช่นขอบต่ำสุด, ขอบเขตต่ำสุด, เพื่อนบ้านที่อยู่ใกล้ที่สุด, คลิป, มีรูปหลายเหลี่ยม, การมองเห็น, snap, โหนดตัด, การติดตามเรย์, การเติมน้ำท่วม, ขอบเขตภายใน, เส้นทาง, ลำเรือเว้า) ไม่พบคำถามก่อนหน้านี้ที่ดูเหมือนจะตรงกับสถานการณ์นี้
แผนภาพ
- วงกลมสีเขียวคือจุดที่รู้จัก
- เส้นสีดำเป็นที่รู้จักกันในชื่อ MultiLineStrings
- เส้นสีเทาเป็นตัวบ่งชี้การกวาดแบบเรเดียลจากจุดที่รู้จัก
- จุดสีแดงคือจุดตัดที่ใกล้ที่สุดของการกวาดด้วยรัศมีและ MultiLineStrings
พารามิเตอร์
- จุดจะไม่ตัดกัน MultiLineStrings
- คะแนนจะถูกจัดให้อยู่กึ่งกลางชื่อใน MultiLineStrings
- MultiLineStrings จะไม่ล้อมรอบจุดทั้งหมดดังนั้นปริมณฑลจะเป็น MultiLineString
- จะมีตารางที่มี MultiLineStrings ประมาณ 1,000 (ปกติจะมีบรรทัดเดียวประมาณ 100 คะแนน)
พิจารณาวิธีการ
- ดำเนินการกวาดแนวรัศมีด้วยการสร้างชุดของเส้นจากจุดที่รู้จัก (ที่, พูด, เพิ่มทีละ 1 องศา)
- สร้างจุดตัดที่ใกล้ที่สุดของแต่ละบรรทัดกวาดเรเดียลด้วย MultiLineStrings
- เมื่อหนึ่งในสายการกวาดแบบเรเดียลไม่ได้ตัดกับ MultiLineStrings ใด ๆ สิ่งนี้จะบ่งบอกถึงช่องว่างในขอบเขตซึ่งจะอยู่ในขอบเขตการก่อสร้าง MultiLineString
สรุป
แม้ว่าเทคนิคนี้จะพบจุดตัดที่ใกล้ที่สุด แต่ก็ไม่จำเป็นว่าจะต้องพบจุดโหนที่ใกล้เคียงที่สุดทั้งหมดขึ้นอยู่กับความละเอียดของการกวาดรัศมี ใครบ้างที่สามารถแนะนำวิธีการทางเลือกในการสร้างคะแนนรอบนอกหรือเสริมเทคนิคการกวาดแบบเรเดียลด้วยรูปแบบการบัฟเฟอร์เซกเตอร์หรือการชดเชยบางอย่าง?
ซอฟต์แวร์
การตั้งค่าของฉันคือการใช้ SpatiaLite และ / หรือ Shapely สำหรับการแก้ปัญหา แต่ยินดีต้อนรับข้อเสนอแนะใด ๆ ที่สามารถนำมาใช้โดยใช้ซอฟต์แวร์โอเพ่นซอร์ส
แก้ไข: วิธีแก้ปัญหาการทำงาน (ตามคำตอบของ @gene)
from shapely.geometry import Point, LineString, mapping, shape
from shapely.ops import cascaded_union
from shapely import affinity
import fiona
sweep_res = 10 # sweep resolution (degrees)
focal_pt = Point(0, 0) # radial sweep centre point
sweep_radius = 100.0 # sweep radius
# create the radial sweep lines
line = LineString([(focal_pt.x,focal_pt.y), \
(focal_pt.x, focal_pt.y + sweep_radius)])
sweep_lines = [affinity.rotate(line, i, (focal_pt.x, focal_pt.y)) \
for i in range(0, 360, sweep_res)]
radial_sweep = cascaded_union(sweep_lines)
# load the input lines and combine them into one geometry
input_lines = fiona.open("input_lines.shp")
input_shapes = [shape(f['geometry']) for f in input_lines]
all_input_lines = cascaded_union(input_shapes)
perimeter = []
# traverse each radial sweep line and check for intersection with input lines
for radial_line in radial_sweep:
inter = radial_line.intersection(all_input_lines)
if inter.type == "MultiPoint":
# radial line intersects at multiple points
inter_dict = {}
for inter_pt in inter:
inter_dict[focal_pt.distance(inter_pt)] = inter_pt
# save the nearest intersected point to the sweep centre point
perimeter.append(inter_dict[min(inter_dict.keys())])
if inter.type == "Point":
# radial line intersects at one point only
perimeter.append(inter)
if inter.type == "GeometryCollection":
# radial line doesn't intersect, so skip
pass
# combine the nearest perimeter points into one geometry
solution = cascaded_union(perimeter)
# save the perimeter geometry
schema = {'geometry': 'MultiPoint', 'properties': {'test': 'int'}}
with fiona.open('perimeter.shp', 'w', 'ESRI Shapefile', schema) as e:
e.write({'geometry':mapping(solution), 'properties':{'test':1}})