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:
| Module | Package | Primary Function | Mutability |
|---|---|---|---|
| clean-coords | @turf/clean-coords | Remove redundant coordinates from geometries | Optional via mutate flag |
| truncate | @turf/truncate | Round coordinate precision to specified decimal places | Optional via mutate flag |
| flip | @turf/flip | Swap longitude and latitude coordinates | Optional 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
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:
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:
Key implementation aspects:
Collinearity Test: Uses
booleanPointOnLine(points[b], lineString([points[a], points[c]]))to determine if point b can be removed packages/turf-clean-coords/index.ts121Geometry-Specific Handling:
- Point/MultiPoint: No-op for Point, removes duplicates from MultiPoint packages/turf-clean-coords/index.ts60-71
- LineString: Direct application of segment algorithm packages/turf-clean-coords/index.ts42-44
- Polygon/MultiPolygon: Additional validation for closed rings and minimum 4 points packages/turf-clean-coords/index.ts142-167
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:
| Issue | Problem | Solution |
|---|---|---|
| #2305 | North-south lines with turnaround points incorrectly cleaned | Fixed segment comparison logic to preserve direction changes |
| #2740 | Overly aggressive removal of valid intermediate points | Refined collinearity test to distinguish turnaround from through points |
| #2406 | Polygon start point not removed when redundant | Added post-processing check for start/end point collinearity |
| #918 | Degenerate polygons with all identical points caused hangs | Added 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
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 truncationThis 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
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:
Common Use Cases
| Use Case | Operations | Purpose |
|---|---|---|
| Pre-processing for boolean ops | cleanCoords() | Remove artifacts that could cause intersection failures |
| File size optimization | truncate() → cleanCoords() | Reduce precision then remove resulting duplicates |
| Coordinate system conversion | flip() | Switch between [lon,lat] and [lat,lon] formats |
| Geometry validation | cleanCoords() | 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
booleanPointOnLineis 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:
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:
@turf/simplify: Calls
cleanCoordsbefore and after applying the Ramer-Douglas-Peucker algorithm to ensure valid geometry structure packages/turf-simplify/package.json73-80@turf/boolean-equal: Uses
cleanCoordsto normalize geometries before comparison, ensuring coordinate order and redundancy don't affect equality tests packages/turf-boolean-equal/package.json158-177
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:
| Module | Default Behavior | Mutation Flag | Return Value |
|---|---|---|---|
cleanCoords | Immutable | options.mutate | New geometry or mutated input |
truncate | Immutable | options.mutate | New geometry or mutated input |
flip | Immutable | options.mutate | New 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 });