ฉันมีสองคุณลักษณะตัดกันบรรทัด ฉันต้องการค้นหามุมที่จุดตัดของแต่ละจุดโดยใช้ ArcGIS 10 และ Python
ใครช่วยได้บ้าง
ฉันมีสองคุณลักษณะตัดกันบรรทัด ฉันต้องการค้นหามุมที่จุดตัดของแต่ละจุดโดยใช้ ArcGIS 10 และ Python
ใครช่วยได้บ้าง
คำตอบ:
มีขั้นตอนการทำงานค่อนข้างง่าย มันเอาชนะปัญหาที่อาจเกิดขึ้นซึ่งคุณสมบัติสองอย่างอาจตัดกันในมากกว่าหนึ่งจุด ไม่จำเป็นต้องใช้สคริปต์ (แต่สามารถเปลี่ยนเป็นสคริปต์ได้อย่างง่ายดาย) สามารถทำได้เป็นหลักจากเมนู ArcGIS
ความคิดคือการใช้ประโยชน์จากชั้นของจุดตัดหนึ่งจุดสำหรับแต่ละคู่ของ polylines ตัดกัน คุณต้องได้รับชิ้นส่วนเล็ก ๆของแต่ละเส้นตัดกันที่จุดตัดเหล่านี้ ใช้การวางแนวของชิ้นส่วนเหล่านี้เพื่อคำนวณมุมตัดกัน
นี่คือขั้นตอน:
ตรวจสอบให้แน่ใจว่าฟีเจอร์ polyline แต่ละรายการมีตัวระบุที่ไม่ซ้ำกันภายในตารางแอตทริบิวต์ สิ่งนี้จะถูกใช้ในภายหลังเพื่อเข้าร่วมคุณลักษณะทางเรขาคณิตของ polylines ไปยังตารางจุดตัด
การประมวลผลทางภูมิศาสตร์ | ตัดได้รับคะแนน (ตรวจสอบให้แน่ใจว่าคุณระบุจุดที่ต้องการสำหรับการส่งออก)
การประมวลผลทางภูมิศาสตร์ | บัฟเฟอร์ช่วยให้คุณบัฟเฟอร์จุดโดยจำนวนเล็กน้อย ทำให้มันเล็กจริงๆ เพื่อให้ส่วนของแต่ละบรรทัดภายในบัฟเฟอร์ไม่โค้งงอ
การประมวลผลทางภูมิศาสตร์ | คลิป (นำไปใช้สองครั้ง) จำกัด ชั้นโพลีไลน์ดั้งเดิมให้เหลือเพียงบัฟเฟอร์ เนื่องจากสิ่งนี้สร้างชุดข้อมูลใหม่สำหรับเอาท์พุทการดำเนินการที่ตามมาจะไม่แก้ไขข้อมูลต้นฉบับ (ซึ่งเป็นสิ่งที่ดี)
นี่คือแผนผังของสิ่งที่เกิดขึ้น: สองชั้น polyline ที่แสดงในสีฟ้าอ่อนและสีแดงอ่อนได้สร้างจุดตัดมืด บริเวณรอบ ๆ บัฟเฟอร์เล็ก ๆ จะแสดงเป็นสีเหลือง ส่วนสีน้ำเงินและสีแดงเข้มแสดงผลลัพธ์ของการตัดคุณสมบัติดั้งเดิมของบัฟเฟอร์เหล่านี้ อัลกอริทึมที่เหลือทำงานร่วมกับส่วนที่มืด (คุณมองไม่เห็นที่นี่ แต่โพลีไลน์สีแดงเล็ก ๆ ตัดสองเส้นสีฟ้าที่จุดร่วมทำให้เกิดสิ่งที่ดูเหมือนเป็นบัฟเฟอร์รอบ polylines สีน้ำเงินสองอันจริงๆแล้วมันเป็นบัฟเฟอร์สองอันรอบ ๆ จุดซ้อนกันสองจุดของการแยกสีแดงน้ำเงิน แผนภาพนี้แสดงห้าบัฟเฟอร์ในทุกรายการ)
ใช้เครื่องมือAddFieldเพื่อสร้างฟิลด์ใหม่สี่ฟิลด์ในแต่ละเลเยอร์ที่ถูกตัด: [X0], [Y0], [X1] และ [Y1] พวกเขาจะเก็บพิกัดจุดเพื่อให้พวกเขาเป็นสองเท่าและให้พวกเขามีความแม่นยำมาก
คำนวณเรขาคณิต (เรียกใช้โดยการคลิกขวาที่แต่ละส่วนหัวของฟิลด์ใหม่) ช่วยให้คุณสามารถคำนวณพิกัด x- และ y- ของจุดเริ่มต้นและจุดสิ้นสุดของแต่ละรูปหลายเหลี่ยมตัด: ใส่เหล่านี้ลงใน [X0], [Y0], [X1] และ [Y1] ตามลำดับ สิ่งนี้ทำสำหรับเลเยอร์ที่ถูกตัดแต่ละชั้นดังนั้นจำเป็นต้องมีการคำนวณ 8 รายการ
ใช้เครื่องมือAddFieldเพื่อสร้างฟิลด์ [Angle] ใหม่ในเลเยอร์จุดตัด
เข้าร่วมตารางที่ถูกตัดเข้ากับตารางจุดตัดตามตัวระบุวัตถุทั่วไป (การเข้าร่วมทำได้โดยการคลิกขวาที่ชื่อเลเยอร์และเลือก "เข้าร่วมและเกี่ยวข้อง")
ณ จุดนี้ตารางจุดตัดกันมี 9 ฟิลด์ใหม่: สองชื่อ [X0] ฯลฯ และอีกหนึ่งชื่อ [มุม] ชื่อแทนฟิลด์ [X0], [Y0], [X1] และ [Y1] ซึ่งเป็นของหนึ่งในตารางที่เข้าร่วม ลองเรียกสิ่งเหล่านี้ (พูด) "X0a", "Y0a", "X1a" และ "Y1a"
ใช้เครื่องคำนวณภาคสนามเพื่อคำนวณมุมในตารางสี่แยก นี่คือบล็อกโค้ด Python สำหรับการคำนวณ:
dx = !x1!-!x0!
dy = !y1!-!y0!
dxa = !x1a!-!x0a!
dya = !y1a!-!y0a!
r = math.sqrt(math.pow(dx,2) + math.pow(dy,2))
ra = math.sqrt(math.pow(dxa,2) + math.pow(dya,2))
c = math.asin(abs((dx*dya - dy*dxa))/(r*ra)) / math.pi * 180
แน่นอนการแสดงออกของการคำนวณภาคสนามเป็นของหลักสูตรเพียง
c
แม้จะมีความยาวของบล็อคโค้ดนี้ แต่คณิตศาสตร์ก็ง่าย: (dx, dy) เป็นเวกเตอร์ทิศทางสำหรับโพลีไลน์แรกและ (dxa, dya) เป็นเวกเตอร์ทิศทางสำหรับวินาที ความยาว r และ ra ของพวกเขา (คำนวณผ่านทฤษฎีบทพีทาโกรัส) ใช้เพื่อทำให้ปกติเป็นเวกเตอร์หน่วย (ไม่ควรมีปัญหากับความยาวเป็นศูนย์เนื่องจากการตัดควรสร้างคุณลักษณะของความยาวเป็นบวก) ขนาดของผลิตภัณฑ์ลิ่ม dx dya - dydxa (หลังจากหารด้วย r และ ra) คือไซน์ของมุม (การใช้ผลิตภัณฑ์ลิ่มแทนที่จะเป็นผลิตภัณฑ์ภายในควรให้ความแม่นยำเชิงตัวเลขที่ดีกว่าสำหรับมุมที่ใกล้ศูนย์) ในที่สุดมุมจะถูกแปลงจากเรเดียนเป็นองศา ผลลัพธ์จะอยู่ระหว่าง 0 ถึง 90 โปรดสังเกตการหลีกเลี่ยงตรีโกณมิติจนถึงจุดสิ้นสุด: วิธีการนี้มีแนวโน้มที่จะให้ผลลัพธ์ที่เชื่อถือได้และคำนวณได้ง่าย
บางจุดอาจปรากฏขึ้นหลายครั้งในเลเยอร์สี่แยก ถ้าเป็นเช่นนั้นพวกเขาจะได้รับหลายมุมที่เกี่ยวข้องกับพวกเขา
การบัฟเฟอร์และการตัดในโซลูชันนี้มีราคาค่อนข้างแพง (ขั้นตอนที่ 3 และ 4): คุณไม่ต้องการที่จะทำเช่นนี้เมื่อมีจุดตัดหลายล้านจุดที่เกี่ยวข้อง ฉันได้แนะนำไว้เพราะ (a) ลดความซับซ้อนของกระบวนการค้นหาจุดต่อเนื่องสองจุดตามแต่ละจุดภายในจุดแยกและ (b) การบัฟเฟอร์เป็นพื้นฐานดังนั้นจึงง่ายในการทำ GIS ใด ๆ - ไม่จำเป็นต้องมีใบอนุญาตเพิ่มเติม เหนือระดับ ArcMap พื้นฐาน - และมักจะให้ผลลัพธ์ที่ถูกต้อง (การดำเนินการ "การประมวลผล" อื่น ๆ อาจไม่น่าเชื่อถือ)
!table1.x0!
และเมื่อใช้งูหลามคุณไม่จำเป็นต้องนามแฝงตัวแปรที่คุณสามารถเข้าร่วมย่อหน้าชื่อตารางในการอ้างอิงข้อมูลเช่น
ฉันเชื่อว่าคุณต้องสร้างสคริปต์หลาม
คุณสามารถทำได้โดยใช้เครื่องมือการประมวลผลทางภูมิศาสตร์และ arcpy
นี่คือเครื่องมือและแนวคิดหลักที่เป็นประโยชน์สำหรับคุณ:
อาจเป็นเรื่องยากที่จะเขียนโค้ดขั้นตอนที่ 2 (เช่นเดียวกับเครื่องมือบางอย่างที่ต้องมีใบอนุญาต ArcInfo) จากนั้นคุณสามารถลองวิเคราะห์จุดยอดของโพลีไลน์ทุกอัน (จัดกลุ่มตาม ID หลังจากทางแยก)
นี่คือวิธีที่จะทำ:
point_x
, point_y
)vert0_x
, vert0_y
) แรกและวินาที ( vert1_x
, vert1_y
) ของมันtan0 = (point_y - vert0_y) / (point_x - vert0_x)
tan1 = (vert1_y - point_y) / (vert1_x - point_x)
tan1
เท่ากับtan2
คุณจะพบจุดยอดสองจุดของเส้นที่มีจุดตัดระหว่างและคุณสามารถคำนวณมุมของจุดตัดสำหรับเส้นนี้ มิฉะนั้นคุณจะต้องดำเนินการกับคู่ต่อไปของจุดยอด (สองสาม) และอื่น ๆเมื่อเร็ว ๆ นี้ฉันพยายามทำด้วยตัวเอง
คุณลักษณะเบาะแสของฉันขึ้นอยู่กับจุดวงกลมรอบจุดตัดของเส้นตลอดจนจุดที่อยู่ห่างจากจุดแยกหนึ่งเมตร เอาต์พุตคือคลาสคุณลักษณะ polyline ที่มีแอ็ตทริบิวต์ของหมายเลขมุมบนจุดตัดและมุม
โปรดทราบว่าเส้นควรจะเป็นรูปวงแหวนเพื่อหาจุดตัดและการอ้างอิงเชิงพื้นที่จะต้องตั้งค่าด้วยการแสดงความยาวบรรทัดที่ถูกต้อง (เหมืองคือ WGS_1984_Web_Mercator_Auxiliary_Sphere)
ทำงานในคอนโซล ArcMap แต่สามารถเปลี่ยนเป็นสคริปต์ในกล่องเครื่องมือได้อย่างง่ายดาย สคริปต์นี้ใช้เฉพาะเลเยอร์บรรทัดใน TOC ไม่มีอะไรเพิ่มเติม
import arcpy
import time
mxd = arcpy.mapping.MapDocument("CURRENT")
df = mxd.activeDataFrame
line = ' * YOUR POLYLINE FEATURE LAYER * ' # paste the name of line layer here
def crossing_cors(line_layer):
mxd = arcpy.mapping.MapDocument("CURRENT")
df = mxd.activeDataFrame
arcpy.env.overwriteOutput = True
sr = arcpy.Describe(line_layer).spatialReference
dict_cors = {}
dang_list = []
with arcpy.da.UpdateCursor(line_layer, ['SHAPE@', 'OID@']) as uc:
for row in uc:
if row[0] is None:
uc.deleteRow()
with arcpy.da.UpdateCursor(line_layer, 'SHAPE@', spatial_reference = sr) as uc:
for row in uc:
line = row[0].getPart(0)
for cor in line:
coord = (cor.X, cor.Y)
try:
dict_cors[coord] += 1
except:
dict_cors[coord] = 1
cors_only = [f for f in dict_cors if dict_cors[f]!=1]
cors_layer = arcpy.CreateFeatureclass_management('in_memory', 'cross_pnt', "POINT", spatial_reference = sr)
arcpy.AddField_management(cors_layer[0], 'ANGLE_NUM', 'LONG')
with arcpy.da.InsertCursor(cors_layer[0], ['SHAPE@', 'ANGLE_NUM']) as ic:
for x in cors_only:
pnt_geom = arcpy.PointGeometry(arcpy.Point(x[0], x[1]), sr)
ic.insertRow([pnt_geom, dict_cors[x]])
return cors_layer
def one_meter_dist(line_layer):
mxd = arcpy.mapping.MapDocument("CURRENT")
df = mxd.activeDataFrame
arcpy.env.overwriteOutput = True
sr = arcpy.Describe(line_layer).spatialReference
dict_cors = {}
dang_list = []
cors_list = []
with arcpy.da.UpdateCursor(line_layer, 'SHAPE@', spatial_reference = sr) as uc:
for row in uc:
line = row[0]
length_line = line.length
if length_line > 2.0:
pnt1 = line.positionAlongLine(1.0)
pnt2 = line.positionAlongLine(length_line - 1.0)
cors_list.append(pnt1)
cors_list.append(pnt2)
else:
pnt = line.positionAlongLine(0.5, True)
cors_layer = arcpy.CreateFeatureclass_management('in_memory', 'cross_one_meter', "POINT", spatial_reference = sr)
ic = arcpy.da.InsertCursor(cors_layer[0], 'SHAPE@')
for x in cors_list:
ic.insertRow([x])
return cors_layer
def circles(pnts):
import math
mxd = arcpy.mapping.MapDocument("CURRENT")
df = mxd.activeDataFrame
arcpy.env.overwriteOutput = True
sr = df.spatialReference
circle_layer = arcpy.CreateFeatureclass_management('in_memory', 'circles', "POINT", spatial_reference = sr)
ic = arcpy.da.InsertCursor(circle_layer[0], 'SHAPE@')
with arcpy.da.SearchCursor(pnts, 'SHAPE@', spatial_reference = sr) as sc:
for row in sc:
fp = row[0].centroid
list_circle =[]
for i in xrange(0,36):
an = math.radians(i * 10)
np_x = fp.X + (1* math.sin(an))
np_y = fp.Y + (1* math.cos(an))
pnt_new = arcpy.PointGeometry(arcpy.Point(np_x,np_y), sr)
ic.insertRow([pnt_new])
del ic
return circle_layer
def angles(centers, pnts, rnd):
mxd = arcpy.mapping.MapDocument("CURRENT")
df = mxd.activeDataFrame
sr = df.spatialReference
line_lyr = arcpy.CreateFeatureclass_management('in_memory', 'line_angles', "POLYLINE", spatial_reference = sr)
arcpy.AddField_management(line_lyr[0], 'ANGLE', "DOUBLE")
arcpy.AddField_management(line_lyr[0], 'ANGLE_COUNT', "LONG")
ic = arcpy.da.InsertCursor(line_lyr[0], ['SHAPE@', 'ANGLE', 'ANGLE_COUNT'])
arcpy.AddField_management(pnts, 'ID_CENT', "LONG")
arcpy.AddField_management(pnts, 'CENT_X', "DOUBLE")
arcpy.AddField_management(pnts, 'CENT_Y', "DOUBLE")
arcpy.Near_analysis(pnts, centers,'',"LOCATION")
with arcpy.da.UpdateCursor(line, ['SHAPE@', 'OID@']) as uc:
for row in uc:
if row[0] is None:
uc.deleteRow()
with arcpy.da.UpdateCursor(pnts, [u'ID_CENT', u'CENT_X', u'CENT_Y', u'NEAR_FID', u'NEAR_DIST', u'NEAR_X', u'NEAR_Y'], spatial_reference = sr) as uc:
for row in uc:
row[0] = row[3]
row[1] = row[5]
row[2] = row[6]
uc.updateRow(row)
if row[4] > 1.1:
uc.deleteRow()
arcpy.Near_analysis(pnts, rnd,'',"LOCATION")
list_id_cent = []
with arcpy.da.UpdateCursor(pnts, [u'ID_CENT', u'CENT_X', u'CENT_Y', u'NEAR_FID', u'NEAR_DIST', u'NEAR_X', u'NEAR_Y', 'SHAPE@'], spatial_reference = sr) as uc:
for row in uc:
pnt_init = (row[-1].centroid.X, row[-1].centroid.Y)
list_id_cent.append([(row[1], row[2]), row[3], pnt_init])
list_id_cent.sort()
values = set(map(lambda x:x[0], list_id_cent))
newlist = [[y for y in list_id_cent if y[0]==x] for x in values]
dict_cent_angle = {}
for comp in newlist:
dict_ang = {}
for i, val in enumerate(comp):
curr_pnt = comp[i][2]
prev_p = comp[i-1][2]
init_p = comp[i][0]
angle_prev = math.degrees(math.atan2(prev_p[1]-init_p[1], prev_p[0]-init_p[0]))
angle_next = math.degrees(math.atan2(curr_pnt[1]-init_p[1], curr_pnt[0]-init_p[0]))
diff = abs(angle_next-angle_prev)%180
vec1 = [(curr_pnt[0] - init_p[0]), (curr_pnt[1] - init_p[1])]
vec2 = [(prev_p[0] - init_p[0]), (prev_p[1] - init_p[1])]
ab = (vec1[0] * vec2[0]) + (vec1[1] * vec2[1])
mod_ab = math.sqrt(math.pow(vec1[0], 2) + math.pow(vec1[1], 2)) * math.sqrt(math.pow(vec2[0], 2) + math.pow(vec2[1], 2))
cos_a = round(ab/mod_ab, 2)
diff = math.degrees(math.acos(cos_a))
pnt1 = arcpy.Point(prev_p[0], prev_p[1])
pnt2 = arcpy.Point(init_p[0], init_p[1])
pnt3 = arcpy.Point(curr_pnt[0], curr_pnt[1])
line_ar = arcpy.Array([pnt1, pnt2, pnt3])
line_geom = arcpy.Polyline(line_ar, sr)
ic.insertRow([line_geom , diff, len(comp)])
del ic
lyr_lst = [f.name for f in arcpy.mapping.ListLayers(mxd)]
if 'line_angles' not in lyr_lst:
arcpy.mapping.AddLayer(df, arcpy.mapping.Layer(line_lyr[0]))
centers = crossing_cors(line)
pnts = one_meter_dist(line)
rnd = circles(centers)
angle_dict = angles(centers, pnts, rnd)