# Redistribute linestring vertices to specified distance

I use a groundwater model program called GMS, and it has a very useful function "Redistribute vertices" (more info). I use this function all the time to both simplify and provide regular spacings between points (vertices) in linestrings.

See this image from GMS where the black lines are original stream with irregular spacings, and the grey lines have redistributed vertices using 50.0 m

I haven't seen the equivalent function anywhere else in the GIS-processing world (Esri, JTS, PostGIS, etc.). Redistribute vertices requires a specified spacing distance, whereas simplify-type functions use a tolerance and don't use a specified spacing. Does anyone know if there is something equivalent in either ArcGIS or open source GIS projects?

-

This type of processing is achieved using linear referencing. ArcGIS has a number of tools to work with linear referenced features, however for equidistant points it is often easier to create a small script to generate the points and then join them together as new lines.

In the opensource world most spatial databases have this funcitonality, as do spatial libraries such as Shapely for Python.

-
The `linear referencing` keyword is a good start, but it looks like this will be a custom tool – Mike T Mar 9 '11 at 1:25

Since the version 2.x, PyQGIS has an has an `interpolate` function similar to that of Shapely :

``````for distance in xrange(0,lenght_line,20):
point = line.interpolate(distance)
``````

-
Thanks for the hint. I was able to redistribute the vertices to a specified distance in this question – Dave X Jul 24 '14 at 8:16

``````from qgis.core import (QgsFeature, QgsGeometry,
QgsVectorLayer, QgsMapLayerRegistry,
QgsField)
from PyQt4.QtCore import QVariant
from qgis.utils import iface
import math

def redistribute_geometry_vertices(geom,dist):
mylen=geom.length()
line=geom.asPolyline()
return QgsGeometry.fromPolyline([geom.interpolate(i*float(dist)).asPoint() for i in range(int(math.ceil(mylen/dist)))])

def selection_update_geometry(userFunction, *args):
"""Redistribute the vertices along a polyline """
layer = iface.mapCanvas().currentLayer()
for feature in layer.selectedFeatures():
geom = feature.geometry()
newgeom=userFunction(geom,*args)
layer.changeGeometry(feature.id(),newgeom)
``````

Then select the layer, make it editable, select the features, then type this in the console:

``````import mytools
mytools.selection_update_geometry(mytools.redistribute_geometry_vertices,50)
``````

-

I've written a function for PostGIS which uses linear referencing functions to redistribute vertices for [Multi]LineString and [Multi]Polygon geometries. For PostGIS 2.0 and earlier, `ST_LineInterpolatePoint` needs to be renamed to `ST_Line_Interpolate_Point`.

``````CREATE OR REPLACE FUNCTION ST_RedistributeVertices(geom geometry, distance double precision)
RETURNS geometry AS \$body\$
DECLARE
num_vert integer;
BEGIN
CASE
WHEN GeometryType(geom) ILIKE 'LineString%' THEN
num_vert := round(ST_Length(geom) / distance);
IF num_vert = 0 THEN
num_vert := 1;
END IF;
RETURN ST_MakeLine(array_agg(
ST_LineInterpolatePoint(geom, n::float8 / num_vert::float8)
)) FROM generate_series(0, num_vert) AS n;
WHEN GeometryType(geom) ILIKE 'Polygon%' AND ST_NRings(geom) = 1 THEN
RETURN ST_MakePolygon(ST_RedistributeVertices(ST_ExteriorRing(geom), distance));
WHEN GeometryType(geom) ILIKE 'Multi%' OR
GeometryType(geom) ILIKE 'GeometryCollection%' THEN
RETURN ST_Multi(ST_Collect(g))
FROM (SELECT ST_RedistributeVertices((ST_Dump(geom)).geom, distance) AS g) AS f;
ELSE
RAISE EXCEPTION 'Unhandled geometry %', GeometryType(geom);
END CASE;
END;
\$body\$ LANGUAGE plpgsql IMMUTABLE STRICT;
``````

A warning on using a simple linear referencing technique is that the resulting vertices are not necessary spaced the specified `distance` apart. This would require a more complicated iterative function, which is beyond what you can comfortably do with PL/pgSQL.

-