2つの平行線の間にある点を見つける


8

ArcGISで1つの問題に直面しています。私はナビゲーションデータベースに取り組んでいます。私たちのデータベースでは、単一車線の道路は1本の線で表され、複数車線の道路(中央に仕切りのある道路)は2本の平行線(図では赤い色の線)で表されます。

私はいくつかのポイントがマルチレーンストリートの内側と外側にあるポイントシェープファイルを持っています。

マルチレーンストリート内にあるポイントを見つけるArcPyスクリプトを作成したいと思います。つまり、これらの平行線の間(写真でマーク)。

これを達成する方法がわかりません。誰かが私を助けてくれますか?

マルチレーンのストリート問題

私はそれにいくつかの練習をしました、そして私はラインの片側にバッファを作成することはマルチレーンポリゴン(写真で示される)の中に作成することができることを発見しました。

ここに画像の説明を入力してください

しかし今問題は、ポリゴンが実際にラインと交差している(つまり、マルチレーン境界に重なっている)ことです。不要なポイントをキャッチします。このポリゴンをストリートラインに合わせる方法はありますか?

注:ストリートラインも移動するため、ここでは統合は機能しません。ストリートラインに沿ってポリゴンを揃えるだけです。


通りの方位角を測定するようなもの-各ポイントから角度Azimuth + 90度に向かってラインストリングを作成-この線が交差する平行線の数を数えます。ゼロまたは2つの場合->外、1つの場合->見つけた。考えているだけで、うまくいくかもしれません。もう1つのアイデアは、デュアルウェイストリートをポリゴンに変換し、交差するポイントを選択することです。後者はpythonで行うのが難しいかもしれません。まあ、道が曲がっている場合も同様です。ただし、片側バッファを使用すると、非常に優れたストリートポリゴンを構築できる場合があります。
user30184

1
高度なライセンスをお持ちですか?これは、nearツールを使用すると非常に簡単です。
radouxju 2015年

はい、私は高度なライセンスを持っています。
Akhil Kumar

最初にバッファポリゴンを取得し、それらのポリゴンを交差させることを考えました。そして、その交差したポリゴンに該当するポイントを見つけます。しかし、最大の問題は、距離の中間が通りのどこでも一貫していないことです。どこかそれはわずか10メートル、どこか約20メートルです。その場合、ポリゴン交差ロジックは失敗します
Akhil Kumar

1
左側から10mの右側緩衝液と右側から左側緩衝液を作る。このようにして、範囲10〜20 mをカバーします。オーバーラップは害を及ぼすことはなく、最初にポリゴンをマージすることもできます。または、幅の広い片側バッファポリゴンを作成し、反対側のウェイと交差するようにトリミングします。想像力を駆使して遊びましょう。
user30184

回答:


4

以下のarcpy(手動でも!)アルゴリズムを試してみます-

  1. 2つの車線道路の適切な幅を見つけます。ここでは、同じ幅で道路をクラスター化し、クラスターごとに以下の手順に従う必要がある場合があります。
  2. 両方の方向(右と左)に向けてその幅(またはそれより少し小さい-道路領域を確保するため)に両方のラインのバッファーを作成します。
  3. 交差ツールを実行して重複領域を取得します。
  4. このポリゴンの内側にあるポイントを選択するには、[場所で選択]を実行します。

これが道だと思います。バッファリングするか、何とかラインを閉じて1つのポリゴンを作成し、その中から選択することにより、ラインワークを結合する簡単な方法を見つけます。
バレット

2

これは幾何学的な運動だと思います。

疑似コード:

  • すべてのポイント(黒いポイント)について、最も近い道路を見つけ、この道路(赤いポイント)上のポイントの投影を見つけます。
  • 黒い点から反対方向に短い線(破線)を描画します
  • 短い線と同じ名前の道路、青い星の間に交差点があるかどうかを確認します。1つある場合は、黒い点が後のものです。

ここに画像の説明を入力してください

ご覧のとおり、特殊なケースがあります–丸で囲まれた黒い点:

  1. 非常にツイスティな1ラインの道路。これは、a)2線の道路のみで作業するか、b)赤い点と星と交差する道路のFIDが異なることを確認することで解消できます。ただし、曲がりくねった道路に別の単線道路との交差点がある場合、これは機能しない可能性があります。
  2. ブラックポイントは、正確に垂直な1線道路の延長上にあります。この場合、1車線の道路が最も近い隣人として選択される可能性があります。
  3. 黒い点が線上にあります。

上記のすべてのケースが発生する可能性は非常に低いですが、それでも、最も安全なオプションは2線の道路のみを処理すること、つまり別のフィーチャクラスにエクスポートすることです。ケース3は面白いものです。ラインまでの最短距離が真のゼロになることはないため、偶然に任せます。したがって、2点を結ぶ光線の「反対」方向が見つかります。

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()            

おそらくもっとエレガントな別の解決策があります。三角測量が含まれます。興味がある場合はお知らせください。回答を更新します


これは非常に複雑です。ラインからポリゴンを作成し、レイキャスティングを使用する方がはるかに簡単なようです。ポイントがライン上にあるかどうかを判断することも簡単です。
Paul

1
正しいラインからポリゴンを作成できる場合は、キャストする必要はありません。場所で選択してください。ただし、ポリゴンの作成は困難です
FelixIP、2015年

わかりやすくするために、曲がりでもうまく機能しますか?)
SIslam、2015年

1
@SIslamは、ケース1(n == fidNear:continueであるかどうかを確認)の行と同様に大きな曲げでも機能するはずです。まあ、1車線の道路がない場合。ディゾルブが役立つとは思いますが、常にそうとは限りません
FelixIP

@イスラムおっと!条件(n == fidNear:continueの場合)はベンドの外側にあるポイントを排除するため、そうなりませんが、内側のポイントを外側にあるものとしてマークします。半径は幅よりも小さいですが、鋭い回転が必要ですか?
FelixIP、2015年

0

道路は平行なので、Copy Parallel編集ツールバーのツールを使用して作成されたものと想定し、線のペアが同じ方向になるようにしました。次に、最初のラインの座標を反復処理してそれらをポリゴンに追加し、次に2番目のラインのを反復処理します。ラインペアをつかむためのより良い方法は間違いなくあります。OIDアプローチは機能しますが、あまりきれいではありません。

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)

そこから、交差/レイヤーによる場所の選択/何を持っているかを呼び出します。Sフリーハンドで描画したため、シェイプされたポリゴンは完全ではないことに注意してくださいexplode_to_points。適切に処理できない円弧がいくつかあります。実行するDensifyか、同等のものです。

ここに画像の説明を入力してください


これは道路ネットワークデータセットであるため、1車線の道路はノードを介して2車線に接続されています。つまり、平行フィーチャのペアなどはありません
FelixIP

最初に個別の道路名(mパーツではない)でディゾルブを追加してソリューションを拡張し、結果として1行または2行のケースを検討することをお勧めします
FelixIP

@FelixIP、私はネットワークデータセットにはあまり詳しくありません。私の解決策は主に、単純な線でそれを行う方法の概念の証明でした(OPはm、解像度、マルチパートなどをカバーするように拡張できます)。このような機能が実際にネットワークでどのように表現されているかはわかりません。
ポール

@ Paul同じ名前の道路は、テーブルの異なる行にある100のセグメントで表すことができます。さらに、二重車線道路はどこかで単一車線になる可能性があります。(1,2)にないパーツがない場合、ディゾルブはひどく失敗します。これが、三角形分割ソリューションを使用しなかった理由です
FelixIP

1
@AkhilKumar、それらがほぼ平行であるかどうかは問題ではありません。これは既存の線をたどっています。
ポール・
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.