Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

How do I distinguish between these cases in ArcGIS 10? I am looking at the Trim Line function but that's not what I want (destructive).

  • Case 1: Both endpoints of a line touch another line
  • Case 2: Both endpoints dangle over the lines it intersects

The real world use case is to distinguish between service roads connecting both roadways of a freeway, and other cases of roads intersecting with freeways.

enter image description here enter image description here

share|improve this question

4 Answers 4

up vote 9 down vote accepted

For a single feature at a time, you can do this pretty easily interactively using the normal Select By Location dialog, using the following key as a guide to the spatial relationship types for line on line overlays (from Select by Location: graphic examples):

image

Select line using line

INTERSECT              A, C, D, E, F, G, H, I, J

CONTAINS               G, H

COMPLETELY_CONTAINS    G

CONTAINS_CLEMENTINI    G, H

WITHIN                 F, H

COMPLETELY_WITHIN      F

WITHIN_CLEMENTINI      F, H

ARE_IDENTICAL_TO       H

BOUNDARY_TOUCHES       C, E

The relevant relationship types in this case are INTERSECT and BOUNDARY_TOUCHES. As you can see from the diagram above, you can use BOUNDARY_TOUCHES to select the features that touch an endpoint of the line. If exactly two features are selected then you have your Case 1. If a feature is not touched by any other features but only intersected by them, then BOUNDARY_TOUCHES will select nothing. INTERSECT will select all features that intersect regardless of whether they touch at an endpoint or not. So if you know there are no features touching endpoints, but you find there are features intersecting, then you have your Case 2.

To automate the process you can use the following Python script (implement as a script tool if desired) to calculate the number of touches and intersections for each feature in a feature class or layer:

import arcpy

################################ Configuration #################################
numTouchesField = "NUM_TOUCHES"
numIntersectionsField = "NUM_INTERSECTIONS"
################################################################################

def countTouches(layer, feature):
    """Returns the number of times the boundary of a feature touches other
    features in the same feature layer."""
    return countSpatialRelation(layer, feature, "BOUNDARY_TOUCHES")

def countIntersections(layer, feature):
    """Returns the number of times a feature intersects other features in the
    same feature layer."""
    return countSpatialRelation(layer, feature, "INTERSECT") - 1 # Subtract 1 because the feature will always intersect its clone in the feature layer

def countSpatialRelation(layer, feature, relation):
    """Returns the number of times a feature meets the specified spatial
    relationship with other features in the same feature layer."""
    arcpy.SelectLayerByLocation_management(layer, relation, feature)
    count = int(arcpy.GetCount_management(layer).getOutput(0))
    return count

def addField(table, fieldName, fieldType):
    """Adds a fields of the given name and type to a table, unless a field with
    the same name already exists."""
    desc = arcpy.Describe(table)
    fieldInfo = desc.fieldInfo
    fieldIndex = fieldInfo.findFieldByName(fieldName)
    if fieldIndex == -1:
        # Field does not exist, add it
        arcpy.AddField_management(table, fieldName, fieldType)

def countTouchesAndIntersections(layer):
    """Adds and populates fields describing the number of times each feature
    touches and intersects other features in the feature layer."""
    addField(layer, numTouchesField, "LONG")
    addField(layer, numIntersectionsField, "LONG")
    desc = arcpy.Describe(layer)
    shapeField = desc.shapeFieldName
    rows = arcpy.UpdateCursor(layer)
    for row in rows:
        feature = row.getValue(shapeField)
        row.setValue(numTouchesField, countTouches(layer, feature))
        row.setValue(numIntersectionsField, countIntersections(layer, feature))
        rows.updateRow(row)
    del row, rows

if __name__ == "__main__":
    layer = arcpy.MakeFeatureLayer_management(arcpy.GetParameterAsText(0))
    countTouchesAndIntersections(layer)

Once that has run, you can easily query for the features that touch exactly twice and intersect exactly twice (Case 1), and those that touch 0 times and intersect exactly twice (Case 2).

Example definition queries:

  • Case 1 (Touches twice, intersects twice): "NUM_TOUCHES" = 2 AND "NUM_INTERSECTIONS" = 2
  • Case 2 (Touches none, intersects twice): "NUM_TOUCHES" = 0 AND "NUM_INTERSECTIONS" = 2

See the below screenshot for an illustration of the instances of the two cases being found: ArcMap screenshot showing various line intersection/touch relationships

Note that with real world data, normally street segments are broken up at intersections, and dangles only occur when roads pass over one another as at an interchange or bridge. So normally you have the same number of features intersecting as touching.

For the more general case, you might want to look for any dangles by checking whether "NUM_INTERSECTIONS" > "NUM_TOUCHES".

share|improve this answer
    
Thanks for the elaborate answer. I have a little trouble turning it into a script tool (it freezes when I try to select a layer) but I am confident that the approach is valid. –  mvexel Apr 24 '12 at 18:00
    
One more comment: I had to reduce the field name length to less than 10 chars (probably because the layer source is a shapefile). –  mvexel Apr 26 '12 at 18:14

Split Line At Vertices (Data Management)

"Creates a feature class containing lines that are generated by splitting input lines or polygon boundaries at their vertices"

Keep Attribution.

enter image description here

http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00170000003z000000

share|improve this answer
    
I'm not sure how that is going to help me, but I realize I could have clarified what I need to achieve a little better. Edited the question. –  mvexel Apr 20 '12 at 22:01

How about copying the feature layer, trimming the lines, then comparing the trimmed feature set to the original to find the features that have changed? Not pretty, almost certainly requires using Python, but seems like it should work.

share|improve this answer

You could also extract out the nodes of the network. In case 1 you would get 2 nodes each with a valency of 4. In case 2 there are no nodes.

share|improve this answer
    
Can you suggest how to do this in ArcGIS? –  blah238 Apr 24 '12 at 23:33
    
You could use someones script or tool to add unique ids to the polyline that are the from and to nodes. I know archydro does it but im sure there are scripts on arcscripts website that do that. Then in a non programing way you could run the frequency tool on the from field and then on the to node field and sum them, this gives you node valency which you can join back to a point layer representing the nodes. –  Hornbydd Apr 27 '12 at 19:25

protected by whuber Sep 4 '12 at 17:43

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

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