我已经在#qgis和#postgis之间的stackoverflow和irc上多次问过这个问题,我也尝试在postgis中对其进行编码或实现,但没有真正的答案。
使用编程(最好是python),我想从点层绘制一条线,使其投影到线或多边形层最近的线上。 >截至目前,我的大部分数据都采用ESRI的格式和邮政格式。但是,我宁愿远离postgis解决方案,因为我主要是shp + qgis用户。
理想的解决方案是使用python或类似的库来实现GDAL / OGR
我应该从哪里开始使用GDAL / OGR库?
可以使用解决方案吗?
我可以使用NetworkX进行最近邻分析吗?
这真的可行吗?到线段终点,而不是投影点
#1 楼
结果这个问题比我认为正确的要棘手。最短距离本身有很多实现方式,例如Shapely提供的距离(距GEOS)。但是,很少有解决方案提供交点本身,但是仅提供了距离。从给出确切答案。以下是使用Shapely的完整解决方案,它基于以下方程式:很好,太糟糕了,它在用死语编写的死语平台上...
评论
我想知道是否有一种方法可以索引多边形点以避免显式枚举...
– mlt
13年5月15日在0:04
@mlt不确定确切的想法,但是有些方法可以根据几何图形提供帮助。如果性能存在问题,可以进行一些基本的射线投射以确定相关的最近段。从这个角度来看,将其移入C或Pyrex会改善性能。
– scw
13年5月15日在11:24
我的意思是说成对算法是O(n)或其他东西。 @eprand解决方案也许可以修改为使用KNN,但是到目前为止,我设法在没有PostGIS的情况下生活了...
– mlt
13年5月15日在17:26
我不能再编辑以前的评论了:(如果选择PostGIS,也许用ST_Closestpoint和ST_Shortestline解决NicklasAvén最快。
– mlt
13年5月15日在17:40
正确,您可以直接在Python中使用KNN算法。我不相信ST_Shortestline使用KNN,它也会基于我对postgis.refractions.net/documentation/postgis-doxygen/d1/dbf/的阅读而进行迭代。
– scw
2013年6月4日下午5:17
#2 楼
PostGIS答案(对于多线串,如果为线串,请删除st_geometryn函数)select t2.gid as point_gid, t1.gid as line_gid,
st_makeline(t2.geom,st_line_interpolate_point(st_geometryn(t1.geom,1),st_line_locate_point(st_geometryn(t1.geom,1),t2.geom))) as geom
from your_line_layer t1, your_point_layer t2,
(
select gid as point_gid,
(select gid
from your_line_layer
order by st_distance(your_line_layer.geom, your_point_layer.geom)
limit 1 ) as line_gid
from your_point_layer
) as t3
where t1.gid = t3.line_gid
and t2.gid = t3.point_gid
#3 楼
这有点老了,但是我今天正在寻找解决这个问题的方法(点->行)。针对此相关问题,我遇到的最简单的解决方案是:>>> from shapely.geometry import Point, LineString
>>> line = LineString([(0, 0), (1, 1), (2, 2)])
>>> point = Point(0.3, 0.7)
>>> point
POINT (0.3000000000000000 0.7000000000000000)
>>> line.interpolate(line.project(point))
POINT (0.5000000000000000 0.5000000000000000)
#4 楼
如果我理解正确,那么您所要求的功能是内置于PostGIS中的。有关如何使用它的提示,可以在这里阅读:http://blog.jordogskog.no/2010/02/07/how-to-use-the-new-distance-related-functions-in-postgis -part1 /
例如,也可以找到一个多边形上与另一个多边形的最近点。
如果要在两个几何上的两个最接近点之间建立直线,可以使用ST_Shortestline。 ST_Closestpoint是ST_Shortestline中的第一个点
两个几何之间的ST_Shortestline的长度与几何之间的ST_Distance相同。
#5 楼
请参阅以下有关如何将我的答案视为不可靠解决方案的评论...我将把此原始帖子保留在这里,以便其他人可以检查问题。该过程应该起作用。查找点(由x,y或x,y,z定义)和一个polyine(由x,y或x的连接集定义)之间的最短路径,y,z)在欧几里得空间内:
1)从给定的用户定义点(我称其为pt0),找到折线(pt1)的最近顶点。 OGRinfo可以轮询折线的顶点,然后可以通过标准方法进行距离计算。例如,对距离calc进行迭代,例如:distance_in_radians = 2 * math.asin(math.sqrt(math.pow((math.sin((pt0_radians-ptx_radians)/ 2)),2)+ math.cos(pt0_radians) * math.cos(ptx_radians)* math.pow((math.sin((pt0_radians-ptx_radians)/ 2),2))))
2)存储关联的最小距离值(d1)和(pt1)
3)观察远离pt1的两个片段(在ogrinfo线串中,这将是先前和随后的顶点)。记录这些顶点(n2和n3)。
4)为每个线段创建y = mx + b公式
5)将每个点的点(pt0)与垂直线相关联这两个公式中的一个
6)计算距离和交点(d2和d3; pt2,pt3)
7)比较三个距离(d1,d2,d3)最短的。您到关联节点(pt1,pt2或pt3)的pt0是最短的链接。 >
评论
一般来说,这是行不通的。例如。点=(1,1),线=((0,2),(0,3),(3,0),(2,0))。如果您进行素描,则可以看到线上的“最近”顶点与经过最接近该点的线段不相邻...我认为处理此问题的唯一方法是检查每个线段(可能使用包围盒以避免对其进行优化)。 HTH。
–汤姆
2011-3-22在5:27
#6 楼
这是QGIS> 2.0的python脚本,由上面给出的提示和解决方案组成。对于合理数量的点和线,它可以正常工作。但是我并没有尝试使用大量的对象。 py”。
在QGIS工具箱中查找脚本,工具,添加脚本,然后选择脚本。
##Vector=group
##CLosest_Point_V2=name
##Couche_de_Points=vector
##Couche_de_Lignes=vector
"""
This script intent to provide a count as for the SQL Funciton CLosestPoint
Ce script vise a recréer dans QGIS la Focntion SQL : CLosest Point
It rely on the solutions provided in "Nearest neighbor between a point layer and a line layer"
http://gis.stackexchange.com/questions/396/nearest-pojected-point-from-a-point- layer-on-a-line-or-polygon-outer-ring-layer
V2 du 8 aout 2016
jean-christophe.baudin@onema.fr
"""
from qgis.core import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os
import sys
import unicodedata
from osgeo import ogr
from math import sqrt
from sys import maxint
from processing import *
def magnitude(p1, p2):
if p1==p2: return 1
else:
vect_x = p2.x() - p1.x()
vect_y = p2.y() - p1.y()
return sqrt(vect_x**2 + vect_y**2)
def intersect_point_to_line(point, line_start, line_end):
line_magnitude = magnitude(line_end, line_start)
u = ((point.x()-line_start.x())*(line_end.x()-line_start.x())+(point.y()-line_start.y())*(line_end.y()-line_start.y()))/(line_magnitude**2)
# closest point does not fall within the line segment,
# take the shorter distance to an endpoint
if u < 0.0001 or u > 1:
ix = magnitude(point, line_start)
iy = magnitude(point, line_end)
if ix > iy:
return line_end
else:
return line_start
else:
ix = line_start.x() + u * (line_end.x() - line_start.x())
iy = line_start.y() + u * (line_end.y() - line_start.y())
return QgsPoint(ix, iy)
layerP = processing.getObject(Couche_de_Points)
providerP = layerP.dataProvider()
fieldsP = providerP.fields()
inFeatP = QgsFeature()
layerL = processing.getObject(Couche_de_Lignes)
providerL = layerL.dataProvider()
fieldsL = providerL.fields()
inFeatL = QgsFeature()
counterP = counterL= nElement=0
for featP in layerP.selectedFeatures():
counterP+=1
if counterP==0:
QMessageBox.information(None,"information:","Choose at least one point from point layer_"+ str(layerP.name()))
indexLine=QgsSpatialIndex()
for featL in layerL.selectedFeatures():
indexLine.insertFeature(featL)
counterL+=1
if counterL==0:
QMessageBox.information(None,"information:","Choose at least one line from point layer_"+ str(layerL.name()))
#QMessageBox.information(None,"DEBUGindex:",str(indexBerge))
ClosestP=QgsVectorLayer("Point", "Projected_ Points_From_"+ str(layerP.name()), "memory")
QgsMapLayerRegistry.instance().addMapLayer(ClosestP)
prClosestP = ClosestP.dataProvider()
for f in fieldsP:
znameField= f.name()
Type= str(f.typeName())
if Type == 'Integer': prClosestP.addAttributes([ QgsField( znameField, QVariant.Int)])
if Type == 'Real': prClosestP.addAttributes([ QgsField( znameField, QVariant.Double)])
if Type == 'String': prClosestP.addAttributes([ QgsField( znameField, QVariant.String)])
else : prClosestP.addAttributes([ QgsField( znameField, QVariant.String)])
prClosestP.addAttributes([QgsField("DistanceP", QVariant.Double),
QgsField("XDep", QVariant.Double),
QgsField("YDep", QVariant.Double),
QgsField("XProj", QVariant.Double),
QgsField("YProj", QVariant.Double),
QgsField("Xmed", QVariant.Double),
QgsField("Ymed", QVariant.Double)])
featsP = processing.features(layerP)
nFeat = len(featsP)
"""
for inFeatP in featsP:
progress.setPercentage(int(100 * nElement / nFeatL))
nElement += 1
# pour avoir l'attribut d'un objet/feat ....
attributs = inFeatP.attributes()
"""
for inFeatP in layerP.selectedFeatures():
progress.setPercentage(int(100 * nElement / counterL))
nElement += 1
attributs=inFeatP.attributes()
geomP=inFeatP.geometry()
nearest_point = None
minVal=0.0
counterSelec=1
first= True
nearestsfids=indexLine.nearestNeighbor(geomP.asPoint(),counterSelec)
#http://blog.vitu.ch/10212013-1331/advanced-feature-requests-qgis
#layer.getFeatures( QgsFeatureRequest().setFilterFid( fid ) )
request = QgsFeatureRequest().setFilterFids( nearestsfids )
#list = [ feat for feat in CoucheL.getFeatures( request ) ]
# QMessageBox.information(None,"DEBUGnearestIndex:",str(list))
NBNodes=0
Dist=DistT=minValT=Distance=0.0
for featL in layerL.getFeatures(request):
geomL=featL.geometry()
firstM=True
geomL2=geomL.asPolyline()
NBNodes=len(geomL2)
for i in range(1,NBNodes):
lineStart,lineEnd=geomL2[i-1],geomL2[i]
ProjPoint=intersect_point_to_line(geomP.asPoint(),QgsPoint(lineStart),QgsPoint(lineEnd))
Distance=magnitude(geomP.asPoint(),ProjPoint)
toto=''
toto=toto+ 'lineStart :'+ str(lineStart)+ ' lineEnd : '+ str(lineEnd)+ '\n'+ '\n'
toto=toto+ 'ProjPoint '+ str(ProjPoint)+ '\n'+ '\n'
toto=toto+ 'Distance '+ str(Distance)
#QMessageBox.information(None,"DEBUG", toto)
if firstM:
minValT,nearest_pointT,firstM = Distance,ProjPoint,False
else:
if Distance < minValT:
minValT=Distance
nearest_pointT=ProjPoint
#at the end of the loop save the nearest point for a line object
#min_dist=magnitude(ObjetPoint,PProjMin)
#QMessageBox.information(None,"DEBUG", " Dist min: "+ str(minValT))
if first:
minVal,nearest_point,first = minValT,nearest_pointT,False
else:
if minValT < minVal:
minVal=minValT
nearest_point=nearest_pointT
#at loop end give the nearest Projected points on Line nearest Line
PProjMin=nearest_point
Geom= QgsGeometry().fromPoint(PProjMin)
min_dist=minVal
PX=geomP.asPoint().x()
PY=geomP.asPoint().y()
Xmed=(PX+PProjMin.x())/2
Ymed=(PY+PProjMin.y())/2
newfeat = QgsFeature()
newfeat.setGeometry(Geom)
Values=[]
#Values.extend(attributs)
fields=layerP.pendingFields()
Values=[attributs[i] for i in range(len(fields))]
Values.append(min_dist)
Values.append(PX)
Values.append(PY)
Values.append(PProjMin.x())
Values.append(PProjMin.y())
Values.append(Xmed)
Values.append(Ymed)
newfeat.setAttributes(Values)
ClosestP.startEditing()
prClosestP.addFeatures([ newfeat ])
#prClosestP.updateExtents()
ClosestP.commitChanges()
iface.mapCanvas().refresh()
!!!警告!!!
请注意,由于此行命令可能会产生一些“怪异” /错误的投影点:
设置返回的最近邻数。
实际上,每个点都应以距每个线对象尽可能短的距离进行投影;并且找到的最小距离将给出正确的直线和投影点,作为我们寻求的最接近的邻居。选择一个减少到1的
counterSelec
值将返回遇到的“第一个”对象(更确切地说是边界框),它可能不是正确的对象。为了确定最短距离,可能不得不选择3或5个不同的线尺寸对象,或者甚至更接近的对象。该值越高,花费的时间越长。随着数百个点和线的出现,与3个或5个最近的邻居开始变得非常慢,而成千上万个点和线可能会出现这种值。#7 楼
根据您的兴趣和用例,研究“地图匹配算法”可能会很有用。例如,OSM Wiki上有一个RoadMatcher项目:http://wiki.openstreetmap.org/wiki/Roadmatcher。评论
它用于旅行需求和预测。通常,我们将区域划分为流量分析区域(多边形),然后将多边形的质心确定为该区域中所有流量的“虚拟”发起者。然后,我们从该点到最近的道路绘制x或y个“虚拟道路链接”线,并将来自该区域的流量平均分配到这些虚拟链接和实际道路层上
– dassouki
2010年7月27日19:00
嗯,所以您的目标是自动创建此“虚拟道路链接”?
– Underdark♦
10年7月27日在19:42
实际上:)或虚拟链接
– dassouki
10年7月27日在19:52
评论
线是否可以限制为与线段正交?@wolfOdrade-总体而言,没关系。