İki kesişen çizgi özelliği var. ArcGIS 10 ve Python kullanarak her kesişme noktasındaki açıyı bulmak istiyorum.
Biri yardım edebilir mi?
İki kesişen çizgi özelliği var. ArcGIS 10 ve Python kullanarak her kesişme noktasındaki açıyı bulmak istiyorum.
Biri yardım edebilir mi?
Yanıtlar:
Nispeten basit bir iş akışı vardır. İki özelliğin birden fazla noktada kesişebileceği potansiyel sorunların üstesinden gelir. Komut dosyası gerektirmez (ancak kolayca bir komut dosyasına dönüştürülebilir). Öncelikle ArcGIS menüsünden yapılabilir.
Buradaki fikir, kesişen her farklı çift hat için bir nokta olan bir kesişim noktası katmanından faydalanmaktır. Bu kesişme noktalarında her kesişen çoklu çizginin küçük bir parçasını almanız gerekir . Kesişme açılarını hesaplamak için bu parçaların yönlerini kullanın.
İşte adımlar:
Çoklu çizgi özelliklerinin her birinin, özellik tablosunda benzersiz bir tanımlayıcıya sahip olduğundan emin olun . Bu daha sonra, çoklu çizgilerin bazı geometrik özelliklerini kesişim noktası tablosuna birleştirmek için kullanılacaktır.
Kesişme noktaları alır ( çıktı için istediğiniz noktaları belirttiğinizden emin olun ).
Geoprocessing | Buffer noktaları küçük bir miktarda tamponlamanızı sağlar. Bir arabellekteki her satırın bölümünün bükülmemesi için gerçekten küçük yapın .
Geoprocessing | Clip (iki kez uygulanır) orijinal çoklu çizgi katmanlarını sadece tamponlarla sınırlar. Bu, çıktısı için yeni veri kümeleri ürettiğinden, sonraki işlemler orijinal verileri değiştirmez (bu iyi bir şeydir).
İşte olanların şeması: açık mavi ve açık kırmızı ile gösterilen iki çoklu çizgi katmanı koyu kesişme noktaları oluşturdu. Bu noktaların etrafında küçük tamponlar sarı renkte gösterilir. Koyu mavi ve kırmızı segmentler, orijinal özelliklerin bu arabelleklere kırpılmasının sonuçlarını gösterir. Algoritmanın geri kalanı karanlık segmentlerle çalışır. (Burada göremezsiniz, ancak küçük bir kırmızı çoklu çizgi, mavi çizgilerin ikisini ortak bir noktada keser ve iki mavi poliilin etrafında tampon gibi görünen şeyi üretir. , bu şemada toplam beş tampon görüntülenir.)
Bu kırpılmış katmanların her birinde dört yeni alan oluşturmak için AddField aracını kullanın : [X0], [Y0], [X1] ve [Y1]. Nokta koordinatlarını tutacaklar, bu yüzden onları iki katına çıkarın ve onlara çok fazla hassasiyet verin.
Geometri Hesapla (her yeni alan başlığına sağ tıklayarak çağrılır), kırpılan her çoklu çizginin başlangıç ve bitiş noktalarının x ve y koordinatlarını hesaplamanızı sağlar: bunları [X0], [Y0], [X1] ve [Y1]. Bu, her kırpılmış katman için yapılır, bu nedenle 8 hesaplama gereklidir.
Kesişme noktası katmanında yeni bir [Açı] alanı oluşturmak için AddField aracını kullanın .
Üyelik ortak nesne tanımlayıcıları temel kesişme noktası tabloya kırpılmış tablolar. (Birleşimler katman adına sağ tıklanarak ve "Birleştir ve İlişkiler" seçilerek gerçekleştirilir.)
Bu noktada nokta kesişim tablosunda 9 yeni alan vardır: ikisi [X0] vb. Olarak adlandırılır ve biri de [Açı] olarak adlandırılır. Birleştirilen tablolardan birine ait olan [X0], [Y0], [X1] ve [Y1] alanlarını diğer adla değiştirin. Bunlara "X0a", "Y0a", "X1a" ve "Y1a" diyelim.
Kavşak tablosundaki açıyı hesaplamak için Alan Hesaplayıcı'yı kullanın . Hesaplama için bir Python kod bloğu:
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
Alan hesaplama ifadesi elbette sadece
c
Bu kod bloğunun uzunluğuna rağmen, matematik basittir: (dx, dy) birinci çoklu çizgi için bir yön vektörü ve (dxa, dya) ikinci için bir yön vektörüdür. Uzunlukları, r ve ra (Pisagor Teoremi ile hesaplanır), bunları birim vektörlere normalleştirmek için kullanılır. (Kırpma uzunluğuyla ilgili bir sorun olmamalıdır, çünkü kırpma pozitif uzunluk özellikleri üretmelidir.) Kama ürünlerinin boyutu dx dya - dydxa (r ve ra ile bölündükten sonra) açının sinüsüdür. (Normal iç ürün yerine kama ürününün kullanılması, sıfıra yakın açılar için daha iyi sayısal hassasiyet sağlamalıdır.) Son olarak, açı radyandan dereceye dönüştürülür. Sonuç 0 ile 90 arasında olacaktır. Trigonometrinin sonuna kadar kaçınılmasına dikkat edin: bu yaklaşım güvenilir ve kolayca hesaplanan sonuçlar üretme eğilimindedir.
Bazı noktalar, kesişim katmanında birden çok kez görünebilir. Eğer öyleyse, kendileriyle ilişkili birden fazla açı elde ederler.
Bu çözümde tamponlama ve kırpma nispeten pahalıdır (adım 3 ve 4): milyonlarca kavşak noktası söz konusu olduğunda bunu yapmak istemezsiniz. Bunu tavsiye ettim, çünkü (a) kavşak noktası mahallesindeki her bir çoklu çizgi boyunca birbirini takip eden iki nokta bulma işlemini basitleştirir ve (b) arabelleğe alma o kadar basittir ki herhangi bir CBS'de yapılması kolaydır - ek lisanslamaya gerek yoktur temel ArcMap seviyesinin üstünde - ve genellikle doğru sonuçlar verir. (Diğer "coğrafi işleme" işlemleri bu kadar güvenilir olmayabilir.)
!table1.x0!
.
Python betiği oluşturmanız gerektiğine inanıyorum.
Geoprocessing araçları ve arcpy kullanarak yapabilirsiniz.
İşte sizin için yararlı olabilecek ana araçlar ve fikirler:
2. adımı kodlamak çok zor olabilir (ayrıca bazı araçlar ArcInfo lisansı gerektirir). Ardından her çoklu çizginin dikey noktalarını analiz etmeyi deneyebilirsiniz (kesişimden sonra bunları kimliğe göre gruplandırın).
İşte bunu yapmanın yolu:
point_x
, point_y
)vert0_x
, vert0_y
) ve ikinci ( vert1_x
, vert1_y
) köşelerini alın.tan0 = (point_y - vert0_y) / (point_x - vert0_x)
tan1 = (vert1_y - point_y) / (vert1_x - point_x)
tan1
is için eşit tan2
, o zaman aradaki kesişim noktasına sahip çizginin iki verteces bulduk ve bu hat için kesişme açısını hesaplayabilir. Aksi takdirde, bir sonraki köşe çiftine (ikinci, üçüncü) devam etmeniz gerekir.Son zamanlarda kendi başıma yapmaya çalışıyordum.
İpucu özelliğim, çizgilerin kesişme noktalarındaki dairesel noktalara ve kesişim noktalarına bir metre mesafede bulunan noktalara dayanıyor. Çıktı, kavşaklar ve açı üzerinde açıların sayısı özelliklerine sahip olan çoklu çizgi özellik sınıfıdır.
Kesişmeleri bulmak için çizgilerin düzlemselleştirilmesi ve uzamsal referansın doğru çizgi uzunluğu gösterimi ile ayarlanması gerektiğini unutmayın (benimki WGS_1984_Web_Mercator_Auxiliary_Sphere).
ArcMap konsolunda çalışıyor ancak kolayca araç kutusundaki bir betiğe dönüştürülebilir. Bu komut dosyası yalnızca TOK'da satır katmanı kullanıyor, başka bir şey kullanmıyor.
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)