I am trying to join centerline attributes to a blockface shapefile using the "near" tool. The problem is that on many streets, the tool gets confused because of intersections and varying width. My idea is to select streets that are oriented similarly and run the near tool, omitting any street segment that might confuse the tool. I need to affix the angle of orientation to each individual segment in both the centerline and the blockface layers.

I'm not very good at python and am hoping to find an answer within ArcGIS 10.5


This can be tackled pretty easily with Python...I ran the code below on 52K records and it completed in less than 10 seconds:

import arcpy
import os
import math

def get_angle(xy1, xy2):
    """Calculate azimuth angle from two points. (Zero is north.)

    This function was written by Curtis V Price at USGS
        # ArcPy point objects
        x1, y1, x2, y2 = xy1.X, xy1.Y, xy2.X, xy2.Y
        # xy strings, e.g. "0 0"
        if isinstance(xy1, basestring) and isinstance(xy2, basestring):
            xy1, xy2 = xy1.replace('NaN',''), xy2.replace('NaN','')
        x1, y1 = map(float, xy1.split())
        x2, y2 = map(float, xy2.split())
    dx, dy = (x2 - x1, y2 - y1)
    return 90 - math.degrees(math.atan2(dy, dx))

def add_line_angles(lines, angle_field='LINE_ANGLE'):
    """Adds field for line angles (first point to last point)

        lines -- input lines feature class or shapefile

        angle_field -- name of angle field.  If it does not exist
            it will be added. If shapefile, this must be 10 characters or less.
    # add new angle field if it doesn't exists already
    existing_fields = [f.name for f in arcpy.ListFields(lines)]
    if angle_field not in existing_fields:
        arcpy.management.AddField(lines, angle_field, 'FLOAT')

    # now add angles
    with arcpy.da.UpdateCursor(lines, ['SHAPE@', angle_field]) as rows:
        for r in rows:
            if isinstance(r[0], arcpy.Polyline): # skip null geometry
                r[1] = get_angle(r[0].firstPoint, r[0].lastPoint)

if __name__ == '__main__':

    # reference lines feature class
    fc = r'C:\TEMP\test.gdb\Maplewood_Carrier_Routes'

    # run it

The second argument of the add_line_angles() function is the new (or existing) float field to store the angles. If using a shapefile and the field will be added, make sure the new field's name is 10 characters or less. It uses a default name of LINE_ANGLE.

  • I discovered the "Bearing" tool. Thanks for the awesome python though...this is a language I am in the process of learning and seeing this helps a lot! – cpbride Nov 6 '17 at 20:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.