# Deleting collinear vertex / vertices using ArcGIS Desktop?

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.

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, p1
x2, y2 = p2, p2
x3, y3 = p3, p3
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):
indexes_of_vertices_to_remove.append(middle_index)

start_idx += 1
middle_index += 1
end_index += 1
if end_index == len(vertices):
break
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
cleaned_parts = []
shape = row

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

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
continue
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])
cleaned_parts.append(cleaned_part_as_array)

if cleaned_parts:
cleaned_shape = arcpy.Polyline(
arcpy.Array(cleaned_parts), in_sr)
row = cleaned_shape
ucur.updateRow(row)

if __name__ == '__main__':
• @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! – Alex Tereshenkov May 22 at 20:26