Skip to content

Coordinate Processing

Purpose and Scope

This document describes Turf.js modules that manipulate coordinate data within GeoJSON geometries. Coordinate processing operations modify the position values themselves—removing duplicates, controlling precision, and transforming coordinate order—without changing the geometric shape significantly or performing spatial analysis.

For geometric transformations that change shape and size (rotate, scale, translate), see Measurements and Transformations. For distance and bearing calculations, see Distance and Bearing.

Coordinate Processing Module Overview

Turf.js provides three primary modules for coordinate processing:

ModulePackagePrimary FunctionMutability
clean-coords@turf/clean-coordsRemove redundant coordinates from geometriesOptional via mutate flag
truncate@turf/truncateRound coordinate precision to specified decimal placesOptional via mutate flag
flip@turf/flipSwap longitude and latitude coordinatesOptional via mutate flag

These modules operate at the coordinate level, iterating through position arrays to perform transformations or filtering operations. They depend on foundation modules for geometry access and validation.

Module Dependency Structure

SVG
100%

Clean Coords: Redundant Coordinate Removal

The cleanCoords function in @turf/clean-coords removes duplicate and collinear coordinates from GeoJSON geometries, reducing file size and processing overhead while preserving geometric shape.

Core Algorithm

The implementation uses a segment-based approach to detect redundant points:

SVG
100%

The algorithm maintains three indices (a, b, c) and extends segment a-c while testing if intermediate point b lies on the line. This continues until a point is found that is not collinear, at which point the segment is committed.

Implementation Details

The cleanLine function implements the core logic:

SVG
100%

Key implementation aspects:

  1. Collinearity Test: Uses booleanPointOnLine(points[b], lineString([points[a], points[c]])) to determine if point b can be removed packages/turf-clean-coords/index.ts121

  2. Geometry-Specific Handling:

  3. Polygon Start Point Optimization: After cleaning, checks if the start/end point is collinear with the first and last interior points, removing it if redundant packages/turf-clean-coords/index.ts149-158

Validation and Edge Cases

The implementation handles several edge cases identified through issue resolution:

IssueProblemSolution
#2305North-south lines with turnaround points incorrectly cleanedFixed segment comparison logic to preserve direction changes
#2740Overly aggressive removal of valid intermediate pointsRefined collinearity test to distinguish turnaround from through points
#2406Polygon start point not removed when redundantAdded post-processing check for start/end point collinearity
#918Degenerate polygons with all identical points caused hangsAdded validation to throw error for polygons with fewer than 4 points

Usage Patterns

// cleanCoords(geojson, options?)
// options: { mutate?: boolean }

The function accepts any GeoJSON Geometry or Feature and returns the same type with cleaned coordinates. The mutate option controls whether the input is modified in place or a new object is returned packages/turf-clean-coords/index.ts27-32

Truncate: Precision Control

The @turf/truncate module rounds coordinate values to a specified number of decimal places, useful for reducing file size, normalizing precision, and ensuring coordinate equality comparisons.

Module Dependencies

SVG
100%

The truncate function uses coordEach from @turf/meta to iterate through all coordinates in a geometry, applying precision rounding to each position value.

Integration with Clean Coords

Truncation is commonly applied before coordinate cleaning to normalize precision:

// Pattern: Truncate then clean
const normalized = cleanCoords(
  truncate(lineString([[0, 0], [1.1, 1.123], [2.12, 2.32], [3, 3]]), 
    { precision: 0 }
  )
);
// Result: [[0, 0], [3, 3]] - intermediate points removed after truncation

This pattern ensures that floating-point precision differences don't prevent redundant coordinate detection.

Flip: Coordinate Order Transformation

The @turf/flip module swaps the order of coordinates in a position array, typically used to convert between [longitude, latitude] and [latitude, longitude] formats.

Module Structure

SVG
100%

The flip function optionally clones the input geometry before iterating through coordinates with coordEach and reversing each position array.

Usage Pattern

Like other coordinate processing modules, flip supports both immutable (default) and mutable operations:

// Immutable (creates new object)
const flipped = flip(feature);

// Mutable (modifies in place)
flip(feature, { mutate: true });

Coordinate Processing Workflow

Coordinate processing operations are often chained together in data pipelines:

SVG
100%

Common Use Cases

Use CaseOperationsPurpose
Pre-processing for boolean opscleanCoords()Remove artifacts that could cause intersection failures
File size optimizationtruncate()cleanCoords()Reduce precision then remove resulting duplicates
Coordinate system conversionflip()Switch between [lon,lat] and [lat,lon] formats
Geometry validationcleanCoords()Ensure polygons have valid ring structure

Performance Characteristics

Clean Coords Complexity

The cleanLine algorithm has the following characteristics:

  • Time Complexity: O(n) where n is the number of coordinates

    • Each coordinate is visited once as index c advances
    • booleanPointOnLine is O(1) for each test
    • Worst case: no points removed, all points tested
  • Space Complexity: O(n) for output array

    • Best case: O(2) for highly redundant straight lines
    • Worst case: O(n) when no points can be removed

Iteration Strategy

All coordinate processing modules use coordEach or geomEach from @turf/meta for geometry traversal:

SVG
100%

The @turf/meta module provides optimized iteration primitives that handle FeatureCollections, GeometryCollections, and nested Multi* geometries efficiently.

Integration with Other Modules

Clean Coords Consumers

Several modules depend on cleanCoords for pre-processing:

SVG
100%

Truncate Consumers

The truncate module is widely used across the codebase for test fixture generation and coordinate normalization:

  • Used in test suites to create predictable coordinate values for assertions
  • Applied before buffer operations to prevent floating-point precision issues
  • Commonly paired with grid generation to ensure cell boundaries align precisely

Error Handling and Validation

Clean Coords Validation

The cleanCoords function performs strict validation for polygon geometries:

// From cleanLine function
if (newPoints.length < 4) {
  throw new Error("invalid polygon, fewer than 4 points");
}
if (!equals(newPoints[0], newPoints[newPoints.length - 1])) {
  throw new Error("invalid polygon, first and last points not equal");
}

These checks ensure that cleaned polygons maintain GeoJSON validity:

  • Minimum 4 points (3 unique vertices + closing point)
  • First and last coordinates must be identical (closed ring)

Input Validation

All coordinate processing functions validate input types:

if (!geojson) throw new Error("geojson is required");
var type = getType(geojson);

The getType function from @turf/invariant ensures the input is a valid GeoJSON structure before processing begins.

Mutation Patterns

All three coordinate processing modules follow a consistent mutation pattern:

ModuleDefault BehaviorMutation FlagReturn Value
cleanCoordsImmutableoptions.mutateNew geometry or mutated input
truncateImmutableoptions.mutateNew geometry or mutated input
flipImmutableoptions.mutateNew geometry or mutated input

The immutable default ensures functional programming patterns work correctly, while the mutation option provides performance optimization for large geometries when the original data is not needed:

// Immutable - safe for functional chains
const result = cleanCoords(truncate(flip(input)));

// Mutable - optimized for memory
truncate(input, { mutate: true });
flip(input, { mutate: true });
cleanCoords(input, { mutate: true });