Ich würde sagen, das ist eine geometrische Übung.
PSEUDO-CODE:
- Suchen Sie für jeden Punkt (schwarzer Punkt) die nächste Straße und die Punktprojektion auf dieser Straße (roter Punkt).
- Zeichnen Sie eine kurze Linie (gestrichelt) in entgegengesetzter Richtung, beginnend am schwarzen Punkt
- Finden Sie heraus, ob es einen Schnittpunkt zwischen der kurzen Linie und der gleichnamigen Straße gibt, blauer Stern. Wenn es einen gibt, ist der schwarze Punkt derjenige, nach dem wir suchen.
Wie man sieht, gibt es Sonderfälle - eingekreiste schwarze Punkte:
- Sehr kurvenreiche 1-Linien-Straße. Dies kann beseitigt werden, indem a) nur mit Straßen mit zwei Linien gearbeitet wird oder b) sichergestellt wird, dass die FIDs von Straßen, die roten Punkt und Stern schneiden, unterschiedlich sind. Wenn die kurvenreiche Straße jedoch eine Kreuzung mit einer anderen Straße mit einer Linie hat, funktioniert dies möglicherweise nicht.
- Der schwarze Punkt befindet sich auf der Verlängerung einer genau senkrechten Straße mit einer Linie. In diesem Fall besteht die Möglichkeit, dass eine einspurige Straße als nächster Nachbar ausgewählt wird.
- Schwarzer Punkt sitzt auf der Linie.
Alle oben genannten Fälle sind sehr unwahrscheinlich. Dennoch scheint es am sichersten zu sein, nur mit zweilinigen Straßen zu arbeiten, dh sie in eine separate Feature-Class zu exportieren. Fall 3 ist lustig, wir überlassen es dem Zufall, da der kürzeste Abstand zur Linie niemals Null ist und somit eine "entgegengesetzte" Richtung des Strahls gefunden werden kann, der 2 Punkte verbindet.
Python-Implementierung:
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()
Es gibt eine andere mögliche Lösung, die vielleicht eleganter ist. Es geht um Triangulation. Lassen Sie mich wissen, ob es von Interesse ist und ich werde meine Antwort aktualisieren