9

How do I distinguish between these cases in ArcGIS 10?

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

I am looking at the Trim Line function but that's not what I want (destructive).

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

13

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
(source: arcgis.com)

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".

  • 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
  • There seems to be a URL to an ArcGIS documentation image that has gone astray at the beginning of this answer. – PolyGeo Apr 2 '16 at 7:18
  • @PolyGeo which one? Seems fine to me. – blah238 Apr 4 '16 at 0:17
  • That's weird, the first picture (on what would be about the fourth line) was showing as a small cross yesterday. Today it looks fine. I think I saw it in the browser (which I am using now) rather than the iOS client that I often use. – PolyGeo Apr 4 '16 at 0:24
2

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

  • 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
-1

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.

-1

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.

  • 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

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.