geokit/simplify

Douglas-Peucker line simplification.

Reduces the number of points in a LineString while preserving its general shape: any point further than tolerance from the straight line between its neighbours is kept; closer ones are discarded.

tolerance is a distance in degrees on the lat/lng plane — no projection is applied. For polylines spanning more than a few degrees, project to Web Mercator first (see geokit/mercator) and convert your tolerance to pixels. For short segments (city-scale and below) the planar approximation is well within rendering tolerance.

Reference: Douglas, D.; Peucker, T. (1973), “Algorithms for the reduction of the number of points required to represent a digitized line or its caricature”.

Types

Errors returned by line_string.

pub type SimplifyError {
  NegativeTolerance(tolerance: Float)
}

Constructors

  • NegativeTolerance(tolerance: Float)

    tolerance was negative.

Values

pub fn compute(
  geometry geometry: geometry.Geometry,
  tolerance tolerance: Float,
) -> Result(geometry.Geometry, SimplifyError)

Simplify any Geometry, matching the bbox.compute / centroid.compute call shape.

  • Point is returned unchanged.
  • LineString is simplified via line_string.
  • Polygon simplifies each ring; closure is preserved by always keeping the first and last vertex of each ring.
  • MultiPolygon recurses into each polygon.
import geokit/geometry
import geokit/simplify

let result =
  geometry.LineString([a, b, c])
  |> simplify.compute(tolerance: 0.001)
pub fn line_string(
  points points: List(latlng.LatLng),
  tolerance tolerance: Float,
) -> Result(List(latlng.LatLng), SimplifyError)

Simplify a sequence of points using Douglas-Peucker. tolerance is in degrees. Larger values keep fewer points.

A tolerance of 0.0 is the canonical Douglas-Peucker behaviour: it drops every intermediate point that lies exactly on the straight line between its surviving neighbours, because the comparison perpendicular_distance >. tolerance is strict. Use a tiny positive value (for example 1.0e-12) if you want to preserve every point.

import geokit/simplify
import geokit/latlng

let assert Ok(a) = latlng.new(lat: 0.0, lng: 0.0)
let assert Ok(b) = latlng.new(lat: 0.0, lng: 0.5)
let assert Ok(c) = latlng.new(lat: 0.0, lng: 1.0)
let assert Ok(simplified) =
  simplify.line_string(points: [a, b, c], tolerance: 0.001)
// simplified == [a, c]  (b is on the straight line between a and c)
Search Document