0

I need to extract (calculate) the length of the line crossing polygon. I can find the crossing points but I need 90 degrees angle from alignment projected to the edges of polygon.

Any ideas?

example

4
  • 1
    More info required...is this a one off task, do you need to do this programmatically?
    – Dan
    Commented Feb 7, 2018 at 22:29
  • If it possible I prefer to use standard tools Commented Feb 7, 2018 at 22:33
  • 1
    You can add a line perpendicular to the red line in edit: resources.arcgis.com/en/help/main/10.2/index.html#//… then intersect with the polygon. Commented Feb 7, 2018 at 22:41
  • Thank you but I have thousands of lines :-) Commented Feb 7, 2018 at 22:47

2 Answers 2

1
  1. Find the slope of the line (I assume this is the vertical red line)
  2. Add/subtract 90°, and create a line extending some distance outwards (this is your horizontal red line) in both directions so that it overlaps your polygon.
  3. Intersect/clip with the yellow polygon
  4. shape length gives you the "width"

Would be fairly straightforward in arcpy.

1

I saw a similar query here:

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

The answer provided uses a script from a Tool / Model published by T. 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

A workflow for you would be to convert the polygons to polylines. The tool provided in the link and code below requires points. Assuming the crossings are the blue lines in your example, you can perform an intersect between the newly created polylines and the crossing lines, setting the output type to Point.

Run the tool as provided, setting the distance to something a bit excessive / more than the maximum width of all your polygons.

Perform an intersect between the newly created station lines and the original polygon, setting the output type as line. This new line will now contain the ID of the polygon, and you can create a field called Length and calculate the length of the station line accordingly.

Code for the Python Toolbox is below, otherwise use the Model as supplied in the link:

'''
Name:        Create Perpendicular Lines
Purpose:

Author:      Tom Dilts

Created:     24 Jan2018
Copyright:   None
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

    def isLicensed(self):
        '''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[0].valueAsText
        Input_Points = parameters[1].valueAsText
        Trasect_Distance = parameters[2].valueAsText
        Output_Station_Lines= parameters[3].valueAsText

        WorkingDir = parameters[4].valueAsText

        arcpy.AddMessage (Input_Line_Shapefile + " Added to Inputs")
        arcpy.AddMessage (Input_Points + " Added to Inputs")
        arcpy.AddMessage (Trasect_Distance + " Added to Inputs")
        arcpy.AddMessage (Output_Station_Lines + " Added to Inputs")

        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"

# Process: Add XY Coordinates
        arcpy.AddXY_management(Input_Points)
        arcpy.AddMessage ("XY Added")

# Process: Add Field (3)
        arcpy.AddField_management(Output_Features, "Dist", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (3)
        arcpy.CalculateField_management(points, "Dist", Trasect_Distance, "VB", "")
        arcpy.AddMessage ("Calcs Done")
# Process: Split Line At Vertices
        arcpy.SplitLine_management(Input_Line_Shapefile, splitline_shp)
        arcpy.AddMessage ("Line split")
#Azimuth added
        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

# Process: Add Field
        arcpy.AddField_management(Input_Line_Features, "StartX", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Add Field (2)
        arcpy.AddField_management(Converted_Graphics_7, "StartY", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Add Field (3)
        arcpy.AddField_management(Converted_Graphics_7__2_, "EndX", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

        # Process: Add Field (4)
        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: Add Field (5)
        arcpy.AddField_management(Converted_Graphics_7__8_, "rad", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

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

        # Process: Add Field (6)
        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", "")

        # Process: Add Field (7)
        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", "")

        # Process: Add Field (8)
        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", "")

        # Process: Add Field (9)
        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
        arcpy.DeleteField_management(Export_Output_3_Layer__8_, "StartX;StartY;EndX;EndY;rad;Angle;EastWest;NorthSouth")

        # 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")
        arcpy.AddMessage ("Azimuth calculated")
#back
        # Process: Add Field
        arcpy.AddField_management(Output_Feature_Class, "left", "DOUBLE", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

        # Process: Add Field (2)
        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

NOTE: Do not house the information in a Geodatabase. The source of all information must be a folder on a local drive.

This tool needs an Advanced Licence

You can copy this code into IDLE and save it as a PYT file. THis can then be added directly into ArcMap.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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