ポイントをライン上に移動する(〜近所)


14

2つのベクターレイヤーがあります。そのうちの1つはリモートセンシングによる「イベント」に基づくポイントレイヤーで、もう1つは地元の研究によるラインレイヤーです。

私の場合、これらは地震と構造断層ですが、一般的な例として「自動車事故と道路」を選択するだけでよいと思います。

したがって、新しいポイントレイヤー(+ attrを移動した状態)で許容範囲内(たとえば、1-2kmまたは0.0xx°)にある限り、ポイントをラインの最も近いポイントに移動/コピーしますy / n)。

何か案は ?

Linux、QGIS 1.8



これを行うための完全に自動化された機能を探していますか、それとも手作業で行うスナップツールのようなものをお探しですか?
シンバマング

同様の質問をしました。線をポイントにスナップしようとしていましたが、簡単な解決策は見つかりませんでした。 gis.stackexchange.com/questions/52232/...
GreyHippo

三角測量と距離マッチングはどうですか?
huckfinn

Nearを使用してArcGISで機能する方法に関するこの質問を見つけました。同等のQGISを検索して、誰かがGRASS v.distanceを提案したこのフォーラムの投稿を見つけました。それで、このチュートリアルでメソッドを特定できるようになりました。おそらく誰かが今までにプラグインを書いたことがありますか?
クリスW 14

回答:


13

以下を実行しないコードスニペット(Pythonコンソールでテスト済み)を投稿しました

  1. QgsSpatialIndexを使用して、ポイントに最も近いラインフィーチャを見つける
  2. この線上のポイントに最も近いポイントを見つけます。このショートカットとして、shapelyパッケージを使用しました。私はこれのためのQGisメソッドが不十分であるとわかりました(またはおそらく私はそれらを適切に理解していない)
  3. スナップの場所にラバーバンドを追加しました
from shapely.wkt import *
from shapely.geometry import *
from qgis.gui import *
from PyQt4.QtCore import Qt
lineLayer = iface.mapCanvas().layer(0)
pointLayer =  iface.mapCanvas().layer(1)
canvas =  iface.mapCanvas()
spIndex = QgsSpatialIndex() #create spatial index object
lineIter =  lineLayer.getFeatures()
for lineFeature in lineIter:
    spIndex.insertFeature(lineFeature)        
pointIter =  pointLayer.getFeatures()
for feature in pointIter:
    ptGeom = feature.geometry()
    pt = feature.geometry().asPoint()
    nearestIds = spIndex.nearestNeighbor(pt,1) # we need only one neighbour
    featureId = nearestIds[0]
    nearestIterator = lineLayer.getFeatures(QgsFeatureRequest().setFilterFid(featureId))
    nearFeature = QgsFeature()
    nearestIterator.nextFeature(nearFeature)
    shplyLineString = shapely.wkt.loads(nearFeature.geometry().exportToWkt())
    shplyPoint = shapely.wkt.loads(ptGeom.exportToWkt())
    #nearest distance from point to line
    dist = shplyLineString.distance(shplyPoint)
    print dist
    #the point on the road where the point should snap
    shplySnapPoint = shplyLineString.interpolate(shplyLineString.project(shplyPoint))
    #add rubber bands to the new points
    snapGeometry = QgsGeometry.fromWkt(shapely.wkt.dumps(shplySnapPoint))
    r = QgsRubberBand(canvas,QGis.Point)
    r.setColor(Qt.red)
    r.setToGeometry(snapGeometry,pointLayer)

編集: 最近、closestSegmentWithContextを使用する@radouxjuメソッドが、より少ないコード行で同じ結果をもたらすことがわかりました。なぜこの奇妙なメソッド名を思いついたのだろうか?nearestPointOnGeometryのようなものである必要がありました。

だから私たちは形を避けることができます

nearFeature = QgsFeature()
nearestIterator.nextFeature(nearFeature)   

closeSegResult = nearFeature.geometry().closestSegmentWithContext(ptGeom.asPoint())
closePoint = closeSegResult[1]
snapGeometry = QgsGeometry.fromPoint(QgsPoint(closePoint[0],closePoint[1])) 

p1 = ptGeom.asPoint()
p2 = snapGeometry.asPoint()

dist = math.hypot(p2.x() - p1.x(), p2.y() - p1.y())
print dist

1
このpython code..arghをフォーマットしようとする悪夢に走ります!!
ビナヤン

5

ここから開始する擬似コードです。これが助けになり、誰かが完全なコードを提供する時間があることを願っています(現時点ではありません)

最初に行うことは、ポイントでループし、各ポイントまでのしきい値距離内にあるラインを選択することです。これはQgsSpatialIndexで実行できます

最初のループ内で、2番目に行うことは、選択した行でループし、その行で最も近い点を見つけることです。これはQgsGeometry :: closestSegmentWithContextに基づいて直接行うことができます

double QgsGeometry :: closestSegmentWithContext(const QgsPoint&point、QgsPoint&minDistPoint、int&afterVertex、double * leftOf = 0、double epsilon = DEFAULT_SEGMENT_EPSILON)

指定されたポイントに最も近いジオメトリのセグメントを検索します。

パラメータpoint検索のポイントを指定します

minDistPoint  Receives the nearest point on the segment

afterVertex   Receives index of the vertex after the closest segment. The vertex before the closest segment is always afterVertex -

1 leftOf Out:ポイントがセグメントの右側の左側にあるかどうかを返します(<0は左、> 0は右を意味します)セグメントスナップのイプシロンイプシロン(1.8で追加)

3番目のステップ(最初のループ内)は、ポイントのジオメトリを最小距離のminDistPointのジオメトリで更新することで構成されます

いくつかのコードで更新(QGIS3)

pointlayer = QgsProject.instance().mapLayersByName('point')[0] #iface.mapCanvas().layer(0)
lineLayer = QgsProject.instance().mapLayersByName('lines')[0] # iface.mapCanvas().layer(1)

epsg = pointlayer.crs().postgisSrid()
uri = "Point?crs=epsg:" + str(epsg) + "&field=id:integer&field=distance:double(20,2)&field=left:integer&index=yes"
snapped = QgsVectorLayer(uri,'snapped', 'memory')

prov = snapped.dataProvider()

testIndex = QgsSpatialIndex(lineLayer)
i=0

feats=[]

for p in pointlayer.getFeatures():
    i+=1
    mindist = 10000.
    near_ids = testIndex.nearestNeighbor(p.geometry().asPoint(),4) #nearest neighbor works with bounding boxes, so I need to take more than one closest results and further check all of them. 
    features = lineLayer.getFeatures(QgsFeatureRequest().setFilterFids(near_ids))
    for tline in features:
        closeSegResult = tline.geometry().closestSegmentWithContext(p.geometry().asPoint())
        if mindist > closeSegResult[0]:
            closePoint = closeSegResult[1]
            mindist = closeSegResult[0]
            side = closeSegResult[3]
    feat = QgsFeature()
    feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(closePoint[0],closePoint[1])))
    feat.setAttributes([i,mindist,side])
    feats.append(feat)

prov.addFeatures(feats)
QgsProject.instance().addMapLayer(snapped)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.