# ArcMap Near Tool doesn't find nearest feature for some input points on the line

Using ArcMap's near tool, I have 'projected' the vertices of a trail onto a corresponding line (river), in order to find the closest point on the river to each trail vertex. However, as you can see in the screenshot, not all the trail points (from the green line) have found corresponding near points on the river... I tried first with no search radius and again with a search radius of 2000 m (the distance between the river and the trail in the area is under 300 m).

How can I find all the corresponding near points along the river? • What version of ArcGIS do you use? Does your data have a projected or geographic coordinate system? Are they shapefiles or gdb feature classes? Jan 22, 2018 at 12:09
• Should have mentioned: Version 10.5, projected coordinate system, and they are shapefiles. Jan 22, 2018 at 14:00
• Can't help but think a solution lies in identifying inflection points as discussed here. But not sure how to progress. Jan 22, 2018 at 15:47

Using the "Near" Tool may not be the best option in this case. From the help file:

The distance between any two features is calculated as the shortest separation between them, that is, where the two features are closest to each other.

So, using your example, it looks like the reason the points along the river (to the north of your screen shot), are not being picked up because the distance to the vertices to the east and west are closer. Also bear in mind the proximity tools in ArcMap use a set of rules to define distance:

Rule 1: The distance between two points is the straight line connecting the points

Rule 2: Distance from a point to a polyline is the perpendicular or the closest vertex

Rule 3: Distance between polylines is determined by line segment vertices

This is summarised in the following table - again from the help file: In order to try and fix your issue, you could try running "Point Distance" Tool. This tool needs an "Advanced License", it will create a table with Matching the FIDs between two features. You inputs need to be point features, so you will need to convert the vertices of the river and trail to points. From the tool's help file:

The results are recorded in the output table containing the following information:

INPUT_FID: The feature ID of the input features

NEAR_FID: The feature ID of the near features

DISTANCE: The distance from the input to near feature.The value of this field is in the linear unit of the input features coordinate system.

You could then decide some rules regarding distances and calculate the MIN, MAX and MEAN distances between the point features to select those points meeting your needs.

There may be better answers, but this is where I would start.

• Oh yeah, this makes sense! I was trying to get the perpendicular from the point to the river using the near tool and had reviewed the documentation for Near before but it didn't occur to me, somehow that those 'blank' parts of the river are farther and thus the near points don't show up on them. From the visual it just seems intuitively that some of the 'blank' part of the river are actually be closer to some of the trail vertices. I'm going to look into your suggestions. Jan 22, 2018 at 14:18
• @maps_spam Maybe try densifying the vertices in the river feature. Eyeballing the curve it looks like there aren't many. Which would explain why visually it seems there may be discrepancies in your output. Jan 22, 2018 at 16:46
• I'm not trying to find the nearest vertex on the river though, only the nearest point on the river - should be anywhere on the river, not necessarily a vertex. Jan 22, 2018 at 16:52
• Sorry I should have clarified. By densifying the number of vertices on the river you increase the chances of one of the proximity tools identifying a point along the river. That is, if you decide to go with one of the proximity tools. Jan 22, 2018 at 17:27
• How would that work? I meant earlier that I don't think the Near tool only seeks out vertices to identify as Near points; it can also find (or in this case, 'create', in a sense) Near features (points) on the line in the absence of defined vertices. Jan 22, 2018 at 19:51

While researching the answer I came across a potential solution from Tom Dilts. He created a Tool in Model Builder which will create perpendicular station lines from a a series of points along a line. His Tool is available to download from here: Station Lines Arc10.0.

Citation for the use of the tool is:

Preferred citation: Dilts, T.E. (2015) Station Lines for ArcGIS 10.1. University of Nevada Reno. Available at: http://www.arcgis.com/home/item.html?id=3f05ef15203e4a3ca88fc1d92347512b

The setup of the Tool is a little tricky, and you have to manually place the inputs and outputs into Model Builder. I have taken the model and created a *.PYT which simplifies the entry of a lot of the inputs. The code for the Python Toolbox is below. However, there are some limitations, the main being the input and outputs of the Tool need to be in a Directory...NOT a Geodatabase. The Tool will throw all sorts of errors if even one input / output is linked to a Geodatabase.

The way I would see your workflow:

1. Convert the vertices of your Trail or River to Points - these points are the input of the tool
2. Run the tool using the converted vertices as the point file and whatever line file you generated them from as the input line. Choose a distance that the Station Lines will be created to (in map units - try use a distance longer than the maximum distance between the river and trail).
3. The output will be a series of lines which run perpendicular to the input line and point. Intersect these lines with the Trail or River (depending on what you used as the input) to get the point at which the corresponding point is perpendicular. When you run the intersect choose the output feature type of the intersect as "Point".
4. You can use a spatial join to evaluate which points connect to which lines and intersect at which point.

Below please find the examples of the Inputs and Output. Below please see how the tool appears (1 - the original tool from the link and the circle...as the PYT appears) Intersecting, green dots are the corresponding points: Finally the Python Toolbox Code - Copy into a text file and saves as a *.PYT and "Add a Toolbox" in ArcMap. Just note, this code is as is, I took it straight from the source, I have no claim to it and full rights and credit goes to the author. I simply made it a Toolbox so I could use it easier.

``````'''
Name:        Create Perpendicular Lines
Purpose:

Author:      Tom Dilts

Created:     24 Jan2018
Licence:

Adapted from the Toolbox Authored by Tom Dilts
Preferred citation: Dilts, T.E. (2015) Station Lines for ArcGIS 10.1. University of Nevada Reno. Available at: http://www.arcgis.com/home/item.html?id=3f05ef15203e4a3ca88fc1d92347512b
'''

# import modules
import arcpy

'''Do not change the name of this class. It will break the toolbox.'''
class Toolbox(object):
def __init__(self):
'''Define toolbox properties (the toolbox anme is the .pyt filename).'''
self.label = "Create Station Lines"
self.alias = ""

# List of tool classes associated with this toolbox
self.tools = [Tool]

class Tool(object):
def __init__(self):
'''Define the tool (tool name is the class name).'''
self.label = "Station Lines"
self.description = "Creates station lines (perpendicular lines) at user-specified points along a polyline.  Station lines are a useful first step for hydraulic analysis of rivers"
self.canRunInBackground = False

def getParameterInfo(self):
'''parameter definitions for GUI'''
param0 = arcpy.Parameter(
displayName = "Input Line File",
name = "Input Line",
datatype = "GPFeatureLayer",
parameterType = "Required",
direction = "Input")

param0.filter.list = ['Polyline']
param0.value = ""

param1 = arcpy.Parameter(
displayName = "Input Converted Vertices",
name = "Input Points",
datatype = "GPFeatureLayer",
parameterType = "Required",
direction = "Input")

param1.filter.list = ['Point']
param1.value = ""

param2 = arcpy.Parameter(
displayName = "Input Transect Distance",
name = "Input Transect Distance",
datatype = "GPDouble",
parameterType = "Required",
direction = "Input")
param2.value = '1000'

param3 = arcpy.Parameter(
displayName = "Output File",
name = "Output",
datatype = "DEShapefile",
parameterType = "Required",
direction = "OutPut")

param4 = arcpy.Parameter(
displayName = "Working Directory",
name = "Working Directory",
datatype = "DEFolder",
parameterType = "Required",
direction = "Input")

params = [param0, param1, param2, param3, param4]

return params

'''Set whether tool is licensed to execute.'''
return True

def updateParameters(self, parameters):
'''Modify the values and properties of parameters before internal
validation is performed.  This method is called whenever a parameter
has been changed.'''

return

def updateMessages(self, parameters):
'''Modify the messages created by internal validation for each tool
parameter.  This method is called after internal validation.'''
return

def execute(self, parameters, messages):
'''The source code of the tool.'''

Input_Line_Shapefile = parameters.valueAsText
Input_Points = parameters.valueAsText
Trasect_Distance = parameters.valueAsText
Output_Station_Lines= parameters.valueAsText

WorkingDir = parameters.valueAsText

Output_Features = Input_Points
points = Output_Features
Trial_FeatureVerticesToPoint = points

splitline_shp = WorkingDir + "splitline.shp"
Output_Feature_Class = WorkingDir + "azimuth.shp"

copy_Select = Output_Feature_Class
copy_Select__2_ = copy_Select
splitline_shp__6_ = copy_Select__2_
splitline_shp__5_ = splitline_shp__6_

spatjoin_shp = WorkingDir + "spatjoin.shp"
Left = WorkingDir + "spatjoin_BearingDistanceToLi.shp"
Right = WorkingDir + "spatjoin_BearingDistanceToLi1.shp"
mergedata = WorkingDir + "merge.shp"

arcpy.AddField_management(Output_Features, "Dist", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (3)
arcpy.CalculateField_management(points, "Dist", Trasect_Distance, "VB", "")
# Process: Split Line At Vertices
arcpy.SplitLine_management(Input_Line_Shapefile, splitline_shp)
Input_Line_Features = splitline_shp
Output_Feature_Class = WorkingDir + "azimuth.shp"

# Local variables:
Converted_Graphics_7 = Input_Line_Features
Converted_Graphics_7__2_ = Converted_Graphics_7
Converted_Graphics_7__3_ = Converted_Graphics_7__2_
Converted_Graphics_7__4_ = Converted_Graphics_7__3_
Converted_Graphics_7__6_ = Converted_Graphics_7__4_
Converted_Graphics_7__9_ = Converted_Graphics_7__6_
Converted_Graphics_7__5_ = Converted_Graphics_7__9_
Converted_Graphics_7__8_ = Converted_Graphics_7__5_
Converted_Graphics_7__10_ = Converted_Graphics_7__8_
Converted_Graphics_7__7_ = Converted_Graphics_7__10_
Converted_Graphics_7__13_ = Converted_Graphics_7__7_
Converted_Graphics_7__12_ = Converted_Graphics_7__13_
Converted_Graphics_7__15_ = Converted_Graphics_7__12_
Converted_Graphics_7__11_ = Converted_Graphics_7__15_
Converted_Graphics_7__17_ = Converted_Graphics_7__11_
Converted_Graphics_7__16_ = Converted_Graphics_7__17_
Converted_Graphics_7__19_ = Converted_Graphics_7__16_
Output_Layer = "copy_Layer"
Export_Output_3_Layer = Output_Layer
Export_Output_3_Layer__3_ = Export_Output_3_Layer
Export_Output_3_Layer__4_ = Export_Output_3_Layer__3_
Export_Output_3_Layer__2_ = Export_Output_3_Layer__4_
Export_Output_3_Layer__6_ = Export_Output_3_Layer__2_
Export_Output_3_Layer__5_ = Export_Output_3_Layer__6_
Export_Output_3_Layer__7_ = Export_Output_3_Layer__5_
Export_Output_3_Layer__9_ = Export_Output_3_Layer__7_
Export_Output_3_Layer__11_ = Export_Output_3_Layer__9_
Export_Output_3_Layer__8_ = Export_Output_3_Layer__11_
Output_stuff = Export_Output_3_Layer__8_
copy_Layer = Output_stuff

arcpy.AddField_management(Input_Line_Features, "StartX", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

arcpy.AddField_management(Converted_Graphics_7, "StartY", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

arcpy.AddField_management(Converted_Graphics_7__2_, "EndX", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

arcpy.AddField_management(Converted_Graphics_7__3_, "EndY", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field
arcpy.CalculateField_management(Converted_Graphics_7__4_, "StartX", "!Shape!.firstpoint.X", "PYTHON_9.3", "")

# Process: Calculate Field (2)
arcpy.CalculateField_management(Converted_Graphics_7__6_, "StartY", "!shape.firstpoint.y!", "PYTHON_9.3", "")

# Process: Calculate Field (3)
arcpy.CalculateField_management(Converted_Graphics_7__9_, "EndX", "!shape.lastpoint.x!", "PYTHON_9.3", "")

# Process: Calculate Field (4)
arcpy.CalculateField_management(Converted_Graphics_7__5_, "EndY", "!shape.lastpoint.y!", "PYTHON_9.3", "")

# Process: Calculate Field (5)
arcpy.CalculateField_management(Converted_Graphics_7__10_, "rad", "Atn(( [StartX] - [EndX]) / ( [StartY] - [EndY] ))", "VB", "")

arcpy.AddField_management(Converted_Graphics_7__7_, "Angle", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (6)
arcpy.CalculateField_management(Converted_Graphics_7__13_, "Angle", "[rad] * (180 / 3.14159265)", "VB", "")

arcpy.AddField_management(Converted_Graphics_7__12_, "EastWest", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (7)
arcpy.CalculateField_management(Converted_Graphics_7__15_, "EastWest", "[StartX] - [EndX]", "VB", "")

arcpy.AddField_management(Converted_Graphics_7__11_, "NorthSouth", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (8)
arcpy.CalculateField_management(Converted_Graphics_7__17_, "NorthSouth", "[StartY] - [EndY]", "VB", "")

arcpy.AddField_management(Converted_Graphics_7__16_, "Azimuth", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Make Feature Layer
arcpy.MakeFeatureLayer_management(Converted_Graphics_7__19_, Output_Layer, "", "", "FID FID VISIBLE NONE;Shape Shape VISIBLE NONE;OBJECTID OBJECTID VISIBLE NONE;ARCID ARCID VISIBLE NONE;GRID_CODE GRID_CODE VISIBLE NONE;FROM_NODE FROM_NODE VISIBLE NONE;TO_NODE TO_NODE VISIBLE NONE;ET_ID ET_ID VISIBLE NONE;Shape_Le_1 Shape_Le_1 VISIBLE NONE;Year_ Year_ VISIBLE NONE;Shape_Leng Shape_Leng VISIBLE NONE;Name Name VISIBLE NONE;Azimuth Azimuth VISIBLE NONE;StartX StartX VISIBLE NONE;StartY StartY VISIBLE NONE;EndX EndX VISIBLE NONE;EndY EndY VISIBLE NONE;rad rad VISIBLE NONE;Angle Angle VISIBLE NONE;EastWest EastWest VISIBLE NONE;NorthSouth NorthSouth VISIBLE NONE")

# Process: Select Layer By Attribute
arcpy.SelectLayerByAttribute_management(Output_Layer, "NEW_SELECTION", "\"NorthSouth\" > 0")

# Process: Calculate Field (9)
arcpy.CalculateField_management(Export_Output_3_Layer, "Azimuth", "[Angle] + 180", "VB", "")

# Process: Select Layer By Attribute (2)
arcpy.SelectLayerByAttribute_management(Export_Output_3_Layer__3_, "NEW_SELECTION", "\"NorthSouth\" < 0 and \"EastWest\" > 0")

# Process: Calculate Field (10)
arcpy.CalculateField_management(Export_Output_3_Layer__4_, "Azimuth", "[Angle] + 360", "VB", "")

# Process: Select Layer By Attribute (3)
arcpy.SelectLayerByAttribute_management(Export_Output_3_Layer__2_, "NEW_SELECTION", "\"NorthSouth\" < 0 and \"EastWest\" < 0")

# Process: Calculate Field (11)
arcpy.CalculateField_management(Export_Output_3_Layer__6_, "Azimuth", "[Angle]", "VB", "")

# Process: Select Layer By Attribute (4)
arcpy.SelectLayerByAttribute_management(Export_Output_3_Layer__5_, "NEW_SELECTION", "\"NorthSouth\" = 0 and \"EastWest\" > 0")

# Process: Calculate Field (12)
arcpy.CalculateField_management(Export_Output_3_Layer__7_, "Azimuth", "270", "VB", "")

# Process: Select Layer By Attribute (5)
arcpy.SelectLayerByAttribute_management(Export_Output_3_Layer__9_, "NEW_SELECTION", "\"NorthSouth\" = 0 and \"EastWest\" < 0")

# Process: Calculate Field (13)
arcpy.CalculateField_management(Export_Output_3_Layer__11_, "Azimuth", "90", "VB", "")

# Process: Delete Field

# Process: Select Layer By Attribute (6)
arcpy.SelectLayerByAttribute_management(Output_stuff, "NEW_SELECTION", "\"Azimuth\" < 365")

# Process: Select
arcpy.Select_analysis(copy_Layer, Output_Feature_Class, "Azimuth <= 365")
#back
arcpy.AddField_management(Output_Feature_Class, "left", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

arcpy.AddField_management(copy_Select, "right", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field
arcpy.CalculateField_management(copy_Select__2_, "right", "[Azimuth] + 90", "VB", "")

# Process: Calculate Field (2)
arcpy.CalculateField_management(splitline_shp__6_, "left", "[Azimuth] - 90", "VB", "")

# Process: Spatial Join
arcpy.SpatialJoin_analysis(Trial_FeatureVerticesToPoint, splitline_shp__5_, spatjoin_shp, "JOIN_ONE_TO_ONE", "KEEP_ALL", "OBJECTID \"OBJECTID\" true true false 10 Long 0 10 ,First,#,vertex,OBJECTID,-1,-1;POINT_X \"POINT_X\" true true false 0 Double 0 0 ,First,#,vertex,POINT_X,-1,-1;POINT_Y \"POINT_Y\" true true false 0 Double 0 0 ,First,#,vertex,POINT_Y,-1,-1;POINT_Z \"POINT_Z\" true true false 0 Double 0 0 ,First,#,vertex,POINT_Z,-1,-1;POINT_M \"POINT_M\" true true false 0 Double 0 0 ,First,#,vertex,POINT_M,-1,-1;Dist \"Dist\" true true false 0 Long 0 0 ,First,#,vertex,Dist,-1,-1;Id \"Id\" true true false 10 Long 0 10 ,First,#,C:\\temp\\azimuth.shp,Id,-1,-1;NEAR_FID \"NEAR_FID\" true true false 10 Long 0 10 ,First,#,C:\\temp\\azimuth.shp,NEAR_FID,-1,-1;NEAR_DIST \"NEAR_DIST\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,NEAR_DIST,-1,-1;NEAR_X \"NEAR_X\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,NEAR_X,-1,-1;NEAR_Y \"NEAR_Y\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,NEAR_Y,-1,-1;Azimuth \"Azimuth\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,Azimuth,-1,-1;left \"left\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,left,-1,-1;right \"right\" true true false 19 Double 0 0 ,First,#,C:\\temp\\azimuth.shp,right,-1,-1", "INTERSECT", "", "")

# Process: Bearing Distance To Line
arcpy.BearingDistanceToLine_management(spatjoin_shp, Left, "POINT_X", "POINT_Y", "Dist", "9001", "left", "9102", "0", "TARGET_FID", "PROJCS['Hartebeeshoek94_Lo31',GEOGCS['GCS_Hartebeesthoek_1994',DATUM['D_Hartebeesthoek_1994',SPHEROID['WGS_1984',6378137.0,298.257223563]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Transverse_Mercator'],PARAMETER['False_Easting',0.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',31.0],PARAMETER['Scale_Factor',1.0],PARAMETER['Latitude_Of_Origin',0.0],UNIT['Meter',1.0]];-5623200 -10002100 10000;-100000 10000;-100000 10000;0.001;0.001;0.001;IsHighPrecision")

# Process: Bearing Distance To Line (2)
arcpy.BearingDistanceToLine_management(spatjoin_shp, Right, "POINT_X", "POINT_Y", "Dist", "9001", "right", "9102", "0", "TARGET_FID", "PROJCS['Hartebeeshoek94_Lo31',GEOGCS['GCS_Hartebeesthoek_1994',DATUM['D_Hartebeesthoek_1994',SPHEROID['WGS_1984',6378137.0,298.257223563]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Transverse_Mercator'],PARAMETER['False_Easting',0.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',31.0],PARAMETER['Scale_Factor',1.0],PARAMETER['Latitude_Of_Origin',0.0],UNIT['Meter',1.0]];-5623200 -10002100 10000;-100000 10000;-100000 10000;0.001;0.001;0.001;IsHighPrecision")

# Process: Merge
# Process: Merge
arcpy.Merge_management(WorkingDir + "spatjoin_BearingDistanceToLi.shp" + ";" + WorkingDir + "spatjoin_BearingDistanceToLi1.shp", mergedata, "POINT_X \"POINT_X\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi.shp,POINT_X,-1,-1,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi1.shp,POINT_X,-1,-1;POINT_Y \"POINT_Y\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi.shp,POINT_Y,-1,-1,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi1.shp,POINT_Y,-1,-1;Dist \"Dist\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi.shp,Dist,-1,-1,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi1.shp,Dist,-1,-1;left \"left\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi.shp,left,-1,-1;TARGET_FID \"TARGET_FID\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi.shp,TARGET_FID,-1,-1,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi1.shp,TARGET_FID,-1,-1;right \"right\" true true false 0 Double 0 0 ,First,#,C:\\temp\\DDP\\spatjoin_BearingDistanceToLi1.shp,right,-1,-1")

# Process: Dissolve
arcpy.Dissolve_management(mergedata, Output_Station_Lines, "TARGET_FID", "", "MULTI_PART", "DISSOLVE_LINES")

return
``````