Yo diría que este es un ejercicio geométrico.
CÓDIGO PSEUDO:
- Para cada punto (punto negro) encuentre el camino más cercano y encuentre la proyección del punto en este camino (punto rojo).
- Dibuje una línea corta (discontinua) en dirección opuesta comenzando en el punto negro
- Encuentre si hay una intersección entre la línea corta y la carretera del mismo nombre, estrella azul. Si hay uno, el punto negro es el que buscamos.
Como se puede ver, hay casos especiales: puntos negros dentro de un círculo:
- Muy sinuosa carretera de 1 línea. Esto puede eliminarse a) trabajando solo con carreteras de 2 líneas ob) asegurándose de que los FID de las carreteras que cruzan el punto rojo y la estrella son diferentes. Sin embargo, si la carretera curva tiene un cruce con otra carretera de 1 línea, esto podría no funcionar.
- El punto negro se encuentra en la extensión de una carretera exactamente perpendicular de 1 línea. En este caso, existe la posibilidad de que se pueda elegir una carretera de 1 carril como vecino más cercano.
- Punto negro se sienta en la línea.
Todos los casos anteriores son muy poco probables, sin embargo, parece que la opción más segura es trabajar solo con carreteras de 2 líneas, es decir, exportarlas a una clase de entidad separada. El caso 3 es divertido, lo dejaremos al azar, porque la distancia más corta a la línea nunca es cero verdadero, por lo tanto, se puede encontrar la dirección 'opuesta' del rayo que conecta 2 puntos.
Implementación de 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()
Hay otra posible solución quizás más elegante. Implica triangulación. Avíseme si le interesa y actualizaré mi respuesta