Cari tahu titik yang berada di antara dua garis paralel


8

Saya menghadapi satu masalah di ArcGIS. Saya bekerja pada basis data navigasi. Dalam basis data kami, jalan jalur tunggal diwakili oleh satu Jalur, sedangkan jalan multi-jalur (jalan dengan pembagi di tengah) diwakili oleh dua garis paralel (garis berwarna merah pada gambar).

Saya memiliki titik shapefile dengan beberapa titik jatuh di dalam jalan multi-Lane dan beberapa di luar.

Saya ingin membuat skrip ArcPy yang akan menemukan titik-titik yang berada di dalam Multi-Lane Streets. yaitu antara garis-garis paralel ini (ditandai dalam gambar).

Saya tidak tahu bagaimana mencapai ini, Adakah yang bisa membantu saya?

Masalah Jalan multi-jalur

Saya melakukan beberapa latihan di atasnya dan saya menemukan bahwa membuat buffer di satu sisi garis dapat membuat di dalam Multi-Lane polygon (Ditampilkan dalam Gambar).

masukkan deskripsi gambar di sini

tetapi sekarang masalahnya adalah, poligon sebenarnya melintasi garis (yaitu tumpang tindih batas multi-jalur). sehingga akan menangkap poin yang tidak perlu. apakah ada cara untuk menyelaraskan poligon ini ke garis jalan?

Catatan: integrasi tidak akan berfungsi di sini, karena ia juga memindahkan garis jalan. saya hanya perlu menyelaraskan poligon ke garis jalan.


Sesuatu seperti Ukur azimuth jalan - Buat linestrings dari setiap titik menuju sudut Azimuth + 90 derajat - Hitung berapa banyak garis paralel Anda yang dilintasi garis ini. Jika nol atau dua -> di luar, jika satu -> Anda menemukannya. Hanya berpikir, mungkin berhasil atau tidak. Gagasan lain adalah mengubah jalan dua arah menjadi poligon dan memilih titik yang bersilangan. Yang terakhir mungkin sulit dilakukan dengan python. Nah, yang pertama juga kalau jalanan melengkung. Tetapi dengan buffer satu sisi Anda mungkin dapat membangun poligon jalanan yang cukup bagus.
user30184

1
apakah Anda memiliki lisensi lanjutan? Itu akan sangat mudah dengan alat yang dekat.
radouxju

ya saya punya lisensi lanjut.
Akhil Kumar

Pada awalnya saya berpikir untuk mengambil poligon penyangga dan kemudian memotong poligon tersebut. dan cari tahu titik mana yang jatuh dalam poligon berpotongan itu. tetapi masalah terbesar adalah bahwa Di antara jarak tidak Konsisten di mana-mana di jalan. suatu tempat hanya 10 meter di suatu tempat sekitar 20 meter, dalam hal ini logika perpotongan poligon akan gagal
Akhil Kumar

1
Buat buffer sisi kanan 10 m dari sisi kiri dan buffer sisi kiri dari sisi kanan. Dengan begitu Anda bisa menjangkau jarak 10-20 m. Tumpang tindih tidak membahayakan dan Anda juga dapat menggabungkan poligon terlebih dahulu. Atau buat poligon penyangga satu sisi yang lebih lebar dan rapikan dengan memotong dengan cara sisi yang lain. Gunakan imajinasi dan mainkan.
user30184

Jawaban:


4

Saya akan mencoba di bawah ini algoritma arcpy (bahkan manual!)

  1. Temukan lebar jalan dua lajur yang tepat - di sini Anda mungkin perlu mengelompokkan jalan dengan lebar yang sama dan ikuti prosedur di bawah ini untuk setiap kluster.
  2. Buat penyangga kedua garis ke arah kedua arah (kanan dan kiri) dengan lebar itu (atau sedikit kurang dari itu- untuk memastikan area jalan).
  3. Jalankan alat titik-temu untuk mendapatkan wilayah yang tumpang tindih.
  4. Jalankan Pilih berdasarkan lokasi untuk memilih titik yang termasuk dalam poligon ini.

Saya pikir ini adalah cara untuk pergi. Temukan cara mudah untuk bergabung dengan garis kerja bersama, baik dengan buffer atau entah bagaimana menutup garis untuk membuat satu poligon dan kemudian pilih di dalamnya.
Barrett

2

Saya akan mengatakan ini adalah latihan geometris.

KODE PSEUDO:

  • Untuk setiap titik (titik hitam) temukan jalan terdekat dan temukan proyeksi titik pada jalan ini (titik merah).
  • Gambar garis pendek (putus-putus) dalam arah yang berlawanan mulai dari titik hitam
  • Cari jika ada persimpangan antara garis pendek dan nama jalan yang sama, bintang biru. Jika ada satu, titik hitam adalah yang kita kejar.

masukkan deskripsi gambar di sini

Seperti yang dapat dilihat ada kasus khusus - titik hitam dilingkari:

  1. Jalan 1 baris sangat berkelok-kelok. Ini dapat dihilangkan dengan a) bekerja dengan 2 jalur jalan saja atau b) memastikan FID jalan yang memotong titik merah dan bintang berbeda. Namun jika jalan bendy memiliki persimpangan dengan jalan 1 jalur lainnya, ini mungkin tidak berfungsi.
  2. Titik hitam terletak pada perpanjangan jalan 1 garis persis tegak lurus. Dalam hal ini ada kemungkinan jalan 1 jalur dapat dipilih sebagai tetangga terdekat.
  3. Titik hitam berada di garis.

Semua kasus di atas sangat tidak mungkin, namun tampaknya opsi teraman adalah bekerja dengan 2 jalan saja, yaitu mengekspornya ke kelas fitur yang terpisah. Kasus 3 adalah yang lucu, kita akan membiarkannya kebetulan, karena jarak terpendek ke garis tidak pernah benar nol, dengan demikian arah sinar 'berlawanan' yang menghubungkan 2 titik dapat ditemukan.

Implementasi python:

import arcpy, traceback, os, sys
from arcpy import env
env.overwriteoutput=True

# things to change ---------
maxD=30
mxd = arcpy.mapping.MapDocument("CURRENT")
pointLR = arcpy.mapping.ListLayers(mxd,"NODES")[0]
lineLR = arcpy.mapping.ListLayers(mxd,"LINKS")[0]
sjOneToMany=r'D:\scratch\sj2.shp'
RDNAME='street'
# -------------------------
dDest=arcpy.Describe(lineLR)
SR=dDest.spatialReference

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
    g = arcpy.Geometry()
    geometryList=arcpy.CopyFeatures_management(pointLR,g)
    n=len(geometryList)
    endPoint=arcpy.Point()

    arcpy.SpatialJoin_analysis(pointLR, lineLR,sjOneToMany,"JOIN_ONE_TO_MANY","KEEP_COMMON","","WITHIN_A_DISTANCE",maxD)
    initFidList=(-1,)
    for fid in range(n):
        query='"TARGET_FID" = %s' %str(fid)
        nearTable=arcpy.da.TableToNumPyArray(sjOneToMany,("TARGET_FID","JOIN_FID"),query)
        if len(nearTable)<2:continue
        fidLines=[int(row[1]) for row in nearTable]
        query='"FID" in %s' %str(tuple(fidLines))
        listOfLines={}
        blackPoint=geometryList[fid]
        with arcpy.da.SearchCursor(lineLR,("FID", "Shape@","STREET"),query) as rows:
            dMin=100000
            for row in rows:
                shp=row[1];dCur=blackPoint.distanceTo(shp)
                listOfLines[row[0]]=row[-2:]
                if dCur<dMin:
                    fidNear,lineNear, roadNear=row
                    dMin=dCur
            chainage=lineNear.measureOnLine(blackPoint)
            redPoint=lineNear.positionAlongLine (chainage).firstPoint
            smallD=blackPoint.distanceTo(redPoint)
            fp=blackPoint.firstPoint
            dX=(redPoint.X-fp.X)*(maxD-smallD)/smallD
            dY=(redPoint.Y-fp.Y)*(maxD-smallD)/smallD
            endPoint.X=fp.X-dX;endPoint.Y=fp.Y-dY
            dashLine=arcpy.Polyline(arcpy.Array([fp,endPoint]),SR)

            for n in listOfLines:
                if n==fidNear:continue
                line, road=listOfLines[n]
                if road!=roadNear:continue
                blueStars=dashLine.intersect(line,1)
                if blueStars.partCount==0:continue
                initFidList+=(fid,); break
    query='"FID" in %s' %str(initFidList)
    arcpy.SelectLayerByAttribute_management(pointLR, "NEW_SELECTION", query)
    arcpy.AddMessage ('\n %i point(s) found' %(len(initFidList)-1))
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()            

Ada solusi lain yang mungkin lebih elegan. Ini melibatkan triangulasi. Beri tahu saya jika ini menarik dan saya akan memperbarui jawaban saya


Ini cukup rumit, wow. Sepertinya akan jauh lebih mudah untuk membuat poligon dari garis dan kemudian menggunakan ray-casting . Menentukan apakah suatu titik berada pada garis harus langsung juga.
Paul

1
Jika Anda dapat membuat poligon dari garis yang benar, tidak perlu casting. Pilih berdasarkan lokasi akan dilakukan. Membuat poligon adalah sebuah tantangan
FelixIP

Apakah ini akan bekerja dengan baik di tikungan- hanya untuk klarifikasi :)
SIslam

1
@ SIslam itu harus bekerja bahkan dengan tikungan besar mirip dengan kasus 1 (lihat apakah n == fidNear: lanjutkan) baris. Nah, jika tidak ada 1 jalur jalan masuk. Saya terus berpikir bahwa larut dapat membantu, tetapi tidak selalu
FelixIP

@Islam Ups! Tidak akan, karena kondisi (jika n == fidNear: lanjutkan) menghilangkan titik duduk di luar tikungan, tetapi tandai titik di dalam sebagai satu duduk di luar. Tajam belok diperlukan, radius lebih kecil dari lebar?
FelixIP

0

Karena jalanannya paralel, saya berasumsi mereka dibuat dengan Copy Parallelalat di bilah alat Edit sehingga membuat sepasang garis memiliki arah yang sama. Kita kemudian dapat beralih di atas koordinat baris pertama dan menambahkannya ke poligon dan kemudian beralih ke kebalikan dari baris kedua. Pasti ada cara yang lebih baik untuk mendekati meraih pasangan garis; pendekatan OID berfungsi, tetapi tidak terlalu cantik.

import collections
import arcpy

FC = "fc"
points = "points"
pgons = "pgons"
arcpy.env.overwriteOutput = True

def buildpoly(oid_coords):
    #create ddict of the form OID:<x1y1, x2y2, ..., xn-1yn-1, xnyn>
    ddict = collections.defaultdict(list)    
    for k,v in oid_coords:
        ddict[k].append(v)

    line1,line2 = ddict.keys()    

    #Assume that the parallel lines have same direction, so reverse the second
    arr = arcpy.Array()
    arr.extend(arcpy.Point(*pt) for pt in ddict[line1])    
    arr.extend(arcpy.Point(*pt) for pt in ddict[line2][::-1])

    return arcpy.Polygon(arr)

#id is an integer field that pairs parallel lines together
unique = list(set(t[0] for t in arcpy.da.SearchCursor(FC, "id")))
polygons = []
for uni in unique:
    polygons.append(buildpoly([r for r in row] for row in arcpy.da.SearchCursor(FC,
                                                                                ["OID@", "SHAPE@XY"],
                                                                                "id={}".format(uni),
                                                                                explode_to_points=True)))


arcpy.CopyFeatures_management(polygons, pgons)

Dari sana, itu panggilan ke Intersect / Select Layer dengan lokasi / apa pun. Perhatikan bahwa Spoligon yang berbentuk tidak sempurna karena saya menggambar secara bebas dan ada beberapa busur yang explode_to_pointstidak menanganinya dengan baik. Jalankan saja Densifyatau sederajat.

masukkan deskripsi gambar di sini


Ini adalah dataset jaringan jalan, sehingga 1 jalur jalan terhubung ke 2 jalur melalui simpul, yaitu tidak ada hal-hal seperti pasang fitur paralel
FelixIP

Anda mungkin ingin memperluas solusi Anda dengan menambahkan pembubaran dengan nama jalan individual terlebih dahulu (tanpa bagian-m) dan sebagai akibatnya perhatikan kasus 1 atau 2 garis
FelixIP

@ Feliks, saya tidak terlalu terbiasa dengan dataset jaringan. Solusi saya sebagian besar merupakan bukti konsep tentang bagaimana hal itu dapat dilakukan dengan garis-garis sederhana (OP dapat memperluasnya untuk mencakup mresolusi, multi-bagian, dll.). Saya tidak tahu bagaimana fitur seperti ini benar-benar diwakili dalam jaringan.
Paul

@ Paul Jalan nama yang sama dapat diwakili oleh segmen 100-an yang duduk di baris yang berbeda di tabel. Apalagi jalan jalur ganda bisa menjadi jalur tunggal di suatu tempat. Larutkan akan gagal parah jika tidak ada bagian yang tidak ada dalam (1,2), ini sebabnya saya tidak pergi dengan solusi triangulasi
FelixIP

1
@AkhilKumar, tidak masalah jika mereka kira-kira sejajar. Ini menelusuri garis yang ada.
Paul
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.