Query point and distance

This recipe shows how to find the point on a specified line nearest the input point and the distance between those points.

querypointdistance

Finding only the distance can be done using the geometry’s distanceTo() method.

distance = point.distanceTo(line)

If you need to find the distance and the closest point on the line, use the Generate Near Table tool. As shown in the previous recipe, geometry objects can be inputs to Geoprocessing tools.

# Find the closest point on a line. Also, return the location of that closest point.
near_result = arcpy.analysis.GenerateNearTable(
       point, 
       line, 
       r'in_memory\neartable', 
       '', 
       'LOCATION', 
       'NO_ANGLE', 
       'CLOSEST')

with arcpy.da.SearchCursor(near_result, ['NEAR_DIST', 'NEAR_X', 'NEAR_Y']) as rows:
    row = rows.next()
    distance = row[0]
    x = row[1]
    y = row[2]

Our previous recipe demonstrates how to split a line with a point. In this case, if you needed to split the line, you can either do two things:

1. Use the distance as search radius for the Split Line at Point tool:

 split_lines = arcpy.management.SplitLineAtPoint(
        in_line,
        in_point,
        arcpy.Geometry(),
        distance)

2. Construct a point geometry and use it as the input points for the Split Line At Point tool.

pnt_on_line = arcpy.PointGeometry(arcpy.Point(x, y), point.spatialReference)
split_lines = arcpy.management.SplitLineAtPoint(
       in_line,
       pnt_on_line,
       arcpy.Geometry())

Splitting a line with a point

Recently I got an email where a colleague was trying to determine the distance a point on a line was from the beginning.  They were spinning their wheels looking at geometry operators and not seeing a solution.

First and foremost arcpy offers a broad broad collection of geoprocessing tools. What is perhaps less obvious is how those tools can be used directly with geometry objects. In the above scenario, using geometry as both input and output offers the solution to the problem. At a functional level, the Split Line at Points tool offers the solution. Being able to use it directly with geometry saves the hassle (and mess) of creating temporary datasets to work with.

import arcpy

def split_line_with_point(in_line, in_point, search_radius=0):
    """Splits a Polyline object with a PointGeometry object. Returns
    a list of two Polyline geometries. First line will include the
    starting point of the in_line. Curves are supported.

    Parameters:
    in_line: arcpy.Polyline
    in_point: arcpy.PointGeometry
    search_radius: string | float | int
        Use to split the lines based on its proximity to the point.
        Line will be split at the nearest location to the point.
        If search_radius is 0, the point must be on the line.
        Can be expressed as a number or linear unit.
    """

    split_lines = arcpy.management.SplitLineAtPoint(
        in_line,
        in_point,
        arcpy.Geometry(),
        search_radius)

    if len(split_lines) == 1:
        raise Exception('Line could not be split')
    else:
        return split_lines

So to answer the original question, to get the distance a point on a line is from the beginning, you could use the above function and then ask for the length property of the first Polyline returned in the list.

distance = split_line_with_point(line, point)[0].length

Adding Fields: Performance Tips

Two approaches to help increase performance when adding numerous fields to a table or feature class.

1. Always load or create the table or feature class in-memory:

import arcpy
# Add fields to a feature class loaded into memory.
fc = r'c:\data\boston.gdb\parcels'
arcpy.management.MakeFeatureLayer(fc, 'parcels_lyr')
for f in out_fields:
    arcpy.AddField_management('parcels_layer',
                              f.name,
                              field_type=f.type,
                              field_length=f.length,
                              field_alias=f.aliasName)

 

import os
import arcpy

# Add the fields to an in_memory table.
tmp_table = os.path.join('in_memory', 'table_template')
arcpy.management.CreateTable(*os.path.split(tmp_table))
for f in out_fields:
    arcpy.AddField_management(tmp_table,
                              f.name,
                              field_type=f.type,
                              field_length=f.length,
                              field_alias=f.aliasName)

# Create the actual output table.
arcpy.CreateTable_management(out_path,
                             out_table_name,
                             template=tmp_table)
arcpy.Delete_management(tmp_table)

2. Use the data access and NumPy modules. The data access module function named ExtendTable() joins the contents of a NumPy structured array to a table based on a common attribute field.
This is the faster approach, however, the types of fields you can add using numpy are limited. There is no support for adding blobs, raster, and date fields.  In addition, the field alias can not be defined or altered.

import arcpy
import numpy

fc = r"c:\data\water.gdb\wells"

narray = numpy.array([],
numpy.dtype([('_ID', numpy.int),
             ('WELL_ID', numpy.int),
             ('DESC', '|S100'),
             ('DEPTH', numpy.float),
             ]))

arcpy.da.ExtendTable(fc, "OID@", narray, "_ID")