I’m looking for an ArcGIS tool or script that will delete all the collinear vertices in line features. I tried the Simplify Line tool and Generalize in the Advanced Toolbar. The tools sort of work, but they convert curves to segments by adding vertices. I want to keep the original curves intact.

I also tried several Generalize transformers in FME, but get similar results. Any thoughts?

Here is a before and after example of what I'm trying to achieve. This was done by deleting the vertices manually.

Before enter image description here

After enter image description here

  • I added a couple images to show what I'm trying to get to. Essentially delete only vertices that are not needed to preserve the shape of the line.
    – Mercator
    Nov 6, 2017 at 17:13
  • Have you seen desktop.arcgis.com/en/arcmap/10.3/tools/cartography-toolbox/… .Try to find the best tolerance to maintain curves. Another Tool that you can use is ET geotools.
    – BBG_GIS
    Nov 6, 2017 at 17:21

2 Answers 2


I've written a short Python script that uses arcpy to update the shapes of the features in a polyline feature class.

Take a backup of your data before running this as it modifies the features in place!

  1. Script works for single part as well as multipart lines.
  2. You can choose what to do with the curves: they are either preserved without removing any redundant vertices this particular feature might have OR densified with the specified distance value. Look up the .densify() method on arcpy.Geometry object. You could alternatively use the Densify GP tool to fix your curves before running this script if you would like to experiment with the deviation values.
  3. Only polyline feature classes are supported (no points/polygons). Could be extended to support polygons though.

The code:

import arcpy
def are_collinear(p1, p2, p3, tolerance=0.5):
    """return True if 3 points are collinear.
    tolerance value will decide whether lines are collinear; may need
    to adjust it based on the XY tolerance value used for feature class"""
    x1, y1 = p1[0], p1[1]
    x2, y2 = p2[0], p2[1]
    x3, y3 = p3[0], p3[1]
    res = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)
    if -tolerance <= res <= tolerance:
        return True

def get_redundant_vertices(vertices):
    """get redundant vertices from a line shape vertices"""
    indexes_of_vertices_to_remove = []
    start_idx, middle_index, end_index = 0, 1, 2
    for i in range(len(vertices)):
        p1, p2, p3 = vertices[start_idx:end_index + 1]
        if are_collinear(p1, p2, p3):

        start_idx += 1
        middle_index += 1
        end_index += 1
        if end_index == len(vertices):
    return indexes_of_vertices_to_remove

def clean_geometries(fc, densify_curves=False):
    """clean polyline features in the fc removing redundant vertices"""
    in_sr = arcpy.Describe(fc).spatialReference.factoryCode

    with arcpy.da.UpdateCursor(fc, ['SHAPE@', 'OID@']) as ucur:
        for row in ucur:
            print "OBJECTID", row[1]
            cleaned_parts = []
            shape = row[0]

            if 'curvePaths' in shape.JSON:
                if densify_curves:
                    shape = shape.densify('DISTANCE', 1, 1)

            for part in range(shape.partCount):
                vertices = [(p.X, p.Y) for p in shape.getPart(part)]
                if len(vertices) < 3:  #polyline's part consists of 2 vertices
                vertices_to_remove = get_redundant_vertices(vertices)
                vertices_to_keep = [
                    val for idx, val in enumerate(vertices)
                    if idx not in vertices_to_remove
                cleaned_part_as_array = arcpy.Array(
                    [arcpy.Point(*coords) for coords in vertices_to_keep])

            if cleaned_parts:
                cleaned_shape = arcpy.Polyline(
                    arcpy.Array(cleaned_parts), in_sr)
                row[0] = cleaned_shape

if __name__ == '__main__':
    fc = r'C:\GIS\Temp\ArcGISHomeFolder\Default.gdb\_SimpleRoads'
    clean_geometries(fc, densify_curves=False)
  • Alex T. regarding your 3rd point, how could we extend your solution to simplify polygon vertices knowing that when a shape is cleaned and updated the contiguous shapes to that one should follow that simplification so the output polygon layer would not have gaps? Generalize and Simplify tools (Arcgis) are not a good fit to our scenario. May 22, 2019 at 10:03
  • @AbreuFreire it has been a while since I worked with arcpy and unfortunately I don't use it any longer and would not be able to help further, so sorry. I think if you could post a new question explaining in detail what you are trying to achieve and link to the code in this answer for the reference, you should get help from other users. Good luck! May 22, 2019 at 20:26

I think that you will need to write a script that works along each line from its start node and takes three vertex coordinates at a time.

If the angle between the first and middle vertex is the same (within a tolerance you set) as between the middle and third vertex then when you re-write the line omit the middle vertex.

If you start writing such code and get stuck, then present it here and our users are often willing to help.

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.