wbtopology
A pure-Rust topology suite inspired by JTS, designed for predictable performance with minimal dependencies and no unsafe code, and intended to serve as the computational geometry engine for Whitebox.
Optional parallel execution is available via the parallel feature (Rayon), intended for large datasets.
- Parallel paths use adaptive size thresholds to avoid small-input scheduling overhead.
Table of Contents
- Mission
- The Whitebox Project
- Is wbtopology Only for Whitebox?
- What wbtopology Is Not
- Design goals
- Current capabilities
- Installation
- Quick start
- wbvector interop
- Examples
- Parallel Feature
- CI Perf Gate
- Performance Optimization Strategy
- Extreme Diagnostics
- Known Limitations
- License
Mission
- Provide robust computational geometry and topology operations for Whitebox applications and workflows.
- Implement the core spatial predicates, overlay, buffer, hull, simplification, triangulation, and Voronoi operations needed by geospatial analysis tools.
- Keep all geometry logic in pure Rust with no unsafe code and minimal dependencies.
- Prioritize correctness and predictable behavior for production data pipelines.
The Whitebox Project
Whitebox is a suite of open-source geospatial data analysis software with roots at the University of Guelph, Canada, where Dr. John Lindsay began the project in 2009. Over more than fifteen years it has grown into a widely used platform for geomorphometry, spatial hydrology, LiDAR processing, and remote sensing research. In 2021 Dr. Lindsay and Anthony Francioni founded Whitebox Geospatial Inc. to ensure the project's long-term, sustainable development. Whitebox Next Gen is the current major iteration of that work, and this crate is part of that larger effort.
Whitebox Next Gen is a ground-up redesign that improves on its predecessor in nearly every dimension:
- CRS & reprojection — Full read/write of coordinate reference system metadata across raster, vector, and LiDAR data, with multiple resampling methods for raster reprojection.
- Raster I/O — More robust GeoTIFF handling (including Cloud-Optimized GeoTIFFs), plus newly supported formats such as GeoPackage Raster and JPEG2000.
- Vector I/O — Expanded from Esri Shapefile-only to 11 formats, including GeoPackage, FlatGeobuf, GeoParquet, and other modern interchange formats.
- Vector topology — A new, dedicated topology engine (
wbtopology) enabling robust overlay, buffering, and related operations. - LiDAR I/O — Full support for LAS 1.0–1.5, LAZ, COPC, E57, and PLY via
wblidar, a high-performance, modern LiDAR I/O engine. - Frontends — Whitebox Workflows for Python (WbW-Python), Whitebox Workflows for R (WbW-R), and a QGIS 4-compliant plugin are in active development.
Is wbtopology Only for Whitebox?
No. wbtopology is developed primarily to support Whitebox, but it is not restricted to Whitebox projects.
- Whitebox-first: API and roadmap decisions prioritize Whitebox geospatial processing needs.
- General-purpose: the crate is usable as a standalone computational geometry library in other Rust geospatial applications.
- JTS-inspired: the API and geometry model are inspired by JTS, making it familiar to users coming from Java GIS tooling.
What wbtopology Is Not
wbtopology is a computational geometry engine. It is not a full GIS framework.
- Not a format I/O library (file reading/writing belongs in
wbvector). - Not a rendering or visualization engine.
- Not a coordinate reference system engine (CRS and projection belong in
wbprojection). - Not a full JTS/GEOS replacement; coverage is broad but some less-common predicates, graph operations, or topology validation methods may be absent.
Design goals
- Pure Rust only
- No unsafe code
- Keep dependencies minimal
- High performance for both interactive and batch-scale workloads
- Fast core predicates and topology checks
- Interoperability with wbvector for vector read/write workflows
Current capabilities
- Core geometry model:
Coordwithx,y, and optionalzPoint,LineString,PolygonMultiPoint,MultiLineString,MultiPolygon,GeometryCollection
- Predicates:
intersects,contains,within,touches,crosses,overlapscovers,covered_by,disjoint- precision-aware and epsilon-aware variants for all major predicates
- Measurement and proximity:
geometry_area,geometry_length,geometry_centroidgeometry_distance,nearest_points,is_within_distance
- Hulls:
convex_hull,convex_hull_geometryconcave_hull,concave_hull_geometry- precision-aware hull wrappers:
*_with_precision - advanced concave hull tuning via
ConcaveHullOptions - scale-free concavity control via
relative_edge_length_ratio - selectable concave hull backend via
ConcaveHullEngine(DelaunayorFastRefine)
- Affine transforms:
translate,scale,rotate
- Simplification:
- Douglas-Peucker:
simplify_linestring,simplify_ring,simplify_polygon,simplify_geometry - conservative topology-preserving variants:
simplify_linestring_topology_preserving,simplify_ring_topology_preserving,simplify_polygon_topology_preserving,simplify_geometry_topology_preserving - shared-boundary polygon coverage simplification:
simplify_polygon_coverage_topology_preserving
- Douglas-Peucker:
- Constructive operations:
buffer_point,buffer_linestring,buffer_polygon- precision-aware buffer wrappers:
*_with_precision - configurable caps/joins via
BufferOptions - hole-aware polygon buffering with collapse/drop handling
make_valid_polygon,polygonize_closed_linestrings
- Prepared geometry:
PreparedPolygonfor repeated fast containment/intersection checks
- Spatial index:
SpatialIndexwith packed STR hierarchy- envelope/point/geometry query,
nearest_neighbor,nearest_k - mutation APIs:
insert,remove, andcompact - stable-id semantics:
removepreserves surviving ids;compactmay reassign ids densely
- Noding and graph foundations:
node_linestringsTopologyGraphconstruction and face-ring extraction helpers
- Overlay:
- dissolved outputs:
polygon_intersection,polygon_union,polygon_difference,polygon_sym_diff - one-pass multi-op API:
polygon_overlay_all - face decomposition APIs:
*_faces
- dissolved outputs:
- Triangulation and Voronoi:
- Delaunay APIs with options/precision/constraints
- Voronoi APIs with automatic or explicit clipping
- DE-9IM relation matrix:
relate,relate_with_precision,relate_with_epsilon
- Interoperability:
- WKB/WKT:
to_wkb,from_wkb,to_wkt,from_wkt - wbvector layer/file interop via
vector_io
- WKB/WKT:
Notes:
- Topology, predicates, overlay, buffering, hulls, triangulation, and simplification operate in XY; optional Z values are carried on coordinates and preserved where practical.
Installation
Crates.io dependency:
[]
= "0.1"
Enable the optional parallel feature when you want Rayon-backed parallel execution on larger workloads:
[]
= { = "0.1", = ["parallel"] }
Local workspace/path dependency:
[]
= { = "../wbtopology" }
Quick start
Then import the APIs you need:
use ;
let poly = Polygon;
let p = Point;
assert!;
assert!;
Multi-geometry + distance example:
use ;
let g1 = MultiPoint;
let g2 = LineString;
assert!;
assert_eq!;
Prepared polygon query example:
use ;
let poly = new;
let prepared = new;
assert!;
Simplification example:
use ;
let ls = new;
let _dp = simplify_linestring;
let poly = new;
let _topo = simplify_polygon_topology_preserving;
Notes:
- The default
simplify_*APIs use Douglas-Peucker vertex reduction. - The
*_topology_preservingAPIs are more conservative and only remove vertices when the result remains simple or polygon-valid under wbtopology's current validity checks. simplify_polygon_coverage_topology_preservingis the dataset-level option for polygon coverages with exact shared boundaries; it simplifies shared chains once and rebuilds all polygons from the same chain set.
Precision model example:
use ;
let pm = Fixed ;
let snapped = pm.apply_coord;
assert_eq!;
Constructive buffer example:
use ;
let ls = new;
let poly = buffer_linestring;
assert!;
Precision-aware buffer example:
use ;
let pm = Fixed ; // 0.1 grid
let poly = buffer_point_with_precision;
assert!;
Relate matrix example:
use ;
let a = Point;
let b = Point;
let m = relate;
assert_eq!;
assert!;
Precision-aware relate and predicate example:
use ;
let pm = Fixed ;
let a = Point;
let b = Point;
assert!;
let m = relate_with_precision;
assert_eq!;
let m_eps = relate_with_epsilon;
assert!;
Epsilon-aware predicate example (without snapping):
use ;
let a = Point;
let b = Point;
assert!;
let poly = Polygon;
let p = Point;
assert!;
WKB/WKT example:
use ;
let g = Point;
let wkt = to_wkt;
let _parsed_wkt = from_wkt.unwrap;
let wkb = to_wkb;
let _parsed_wkb = from_wkb.unwrap;
Spatial index example:
use ;
let geoms = vec!;
let idx = from_geometries;
let hits = idx.query_point;
assert_eq!;
Spatial index mutation and id-semantics example:
use ;
let geoms = vec!;
let mut idx = from_geometries;
assert!;
assert!;
// `remove` keeps surviving ids stable.
let ids_after_remove: = idx.all_entries.map.collect;
assert_eq!;
// `compact` reassigns ids densely and may invalidate external id handles.
idx.compact;
let ids_after_compact: = idx.all_entries.map.collect;
assert_eq!;
Hull example:
use ;
let pts = vec!;
let convex = convex_hull;
assert!;
let concave = concave_hull;
assert!;
Advanced concave hull options example:
use ;
let pts = vec!;
let hull = concave_hull_with_options;
assert!;
Relative concavity example:
use ;
let pts = vec!;
let _hull = concave_hull_with_options;
Concave hull engine selection example:
use ;
let pts = vec!;
let _fast_hull = concave_hull_with_options;
Polygon erosion multi-component example:
use ;
let poly = new;
let comps = buffer_polygon_multi;
assert!;
wbvector interop
use vector_io;
let geoms = read_geometries?;
write_geometries?;
# Ok::
Examples
The repository ships focused examples for interop, benchmarking, and perf diffing.
Core examples:
cargo run --example vector_interop
Criterion benches:
cargo bench --bench spatial_index_benchcargo bench --bench hull_bench
Maintainer benchmark and diff utilities:
- Internal benchmark utility sources now live under
dev/examples/internal/and are excluded from the published crate package. - Use the
dev/scripts/overlay_perf_gate.shhelper anddev/perf/baselines for repository-local perf gating workflows.
Notes:
vector_interopdemonstrates wbvector-backed file round-tripping through wbtopology.- Internal benchmark utilities (noding/overlay/triangulation/voronoi) remain available in the repository under
dev/examples/internal/for maintainer use. - Overlay CSV rows are
case,operation,iters,total_us,avg_us,repeats,min_avg_us,max_avg_us. - Triangulation CSV appends
triangles,input_points. - Voronoi CSV appends
cells,total_vertices. all_ops_speedup_xrows in overlay CSV reportall_ops_separate / all_ops_onepass.- Diff examples compare median runtime columns and exit with code 1 when regressions exceed configured thresholds.
- Threshold precedence is
case-opovercaseoveropover positional default. - Quote wildcard selectors in shells like zsh, for example
'nc_*=9'or'*:union=7'.
Parallel Feature
- Enable parallel execution (Rayon):
cargo test --features parallel - Run perf gating workflow (including parallel runs as configured):
bash dev/scripts/overlay_perf_gate.sh
The parallel feature is opt-in and keeps the default dependency footprint small.
Current parallel paths focus on larger workloads where scheduling overhead is worth it:
- noding candidate/intersection work
- overlay face-selection / classification hotspots
- Voronoi cell construction for larger site sets
Small workloads are intentionally left on lower-overhead serial paths.
CI Perf Gate
Use dev/scripts/overlay_perf_gate.sh to generate benchmark snapshots and run threshold-gated perf comparisons.
Targets:
overlay(default)voronoitriangulationall
Bootstrap a baseline snapshot (first run):
dev/scripts/overlay_perf_gate.sh --bootstrap-baseline --repeats 7dev/scripts/overlay_perf_gate.sh --target voronoi --bootstrap-baseline --repeats 5dev/scripts/overlay_perf_gate.sh --target triangulation --bootstrap-baseline --repeats 5dev/scripts/overlay_perf_gate.sh --target all --bootstrap-baseline --repeats 5
Run the gate against baseline with threshold policy:
dev/scripts/overlay_perf_gate.sh --default-threshold 5.0 --op-threshold intersection=8 --case-threshold 'nc_*=9' --case-op-threshold 'nc_complex:intersection=12'dev/scripts/overlay_perf_gate.sh --target voronoi --default-threshold 5.0 --case-threshold 'uniform_*=8' --case-threshold 'clustered_*=10'dev/scripts/overlay_perf_gate.sh --target triangulation --default-threshold 5.0 --case-threshold 'uniform_*=8' --case-threshold 'clustered_*=10'dev/scripts/overlay_perf_gate.sh --target all --default-threshold 5.0dev/scripts/overlay_perf_gate.sh --target all --overlay-default-threshold 20 --voronoi-default-threshold 5 --triangulation-default-threshold 8
Compare parallel mode directly against serial mode:
dev/scripts/overlay_perf_gate.sh --compare-serial-parallel --repeats 7 --default-threshold 5.0dev/scripts/overlay_perf_gate.sh --compare-serial-parallel --repeats 7 --op-threshold union=8 --case-threshold 'nc_*=10'dev/scripts/overlay_perf_gate.sh --target voronoi --compare-serial-parallel --repeats 5 --default-threshold 5.0dev/scripts/overlay_perf_gate.sh --target triangulation --compare-serial-parallel --repeats 5 --default-threshold 5.0
For small fixtures, thread scheduling overhead can dominate; prefer higher repeat counts and thresholds focused on medium/complex cases.
Useful options:
--baseline <path>to override baseline path (defaultdev/perf/overlay_bench_baseline.csv)--target <overlay|voronoi|triangulation|all>to choose benchmark and diff workflow (allruns all targets)--overlay-default-threshold <pct>to override default threshold for overlay when using--target all--voronoi-default-threshold <pct>to override default threshold for voronoi when using--target all--triangulation-default-threshold <pct>to override default threshold for triangulation when using--target all--write-current <path>to save the generated current snapshot as an artifact--features <list>to run the benchmark/build under specific cargo features (for exampleparallel)--compare-serial-parallelto benchmark serial and parallel in one run and gate parallel against serial--skip-buildto skipcargo check --exampleswhen build has already been validated
Performance Optimization Strategy
wbtopology is optimized across algorithm choice, memory behavior, numeric robustness, and measurement workflows so performance gains are practical and repeatable.
- Adaptive execution paths:
- per-op and one-pass overlay APIs (
polygon_overlay_all) with dispatch heuristics that route tiny/hole-rich inputs to lower-overhead paths - non-crossing boundary fallback for overlays to avoid unnecessary arrangement construction
- adaptive parallel thresholds so small workloads remain serial while larger workloads scale across cores
- per-op and one-pass overlay APIs (
- Candidate pruning and complexity reduction:
- noding uses grid and sweep-line AABB candidate filtering before exact segment intersection tests
- selective face classification and dissolved reconstruction keep work proportional to useful geometry
- Allocation and dataflow efficiency:
- one-pass overlay classification reused across intersection/union/difference/symmetric-difference outputs
- classification data is stored in compact side arrays to reduce cloning and intermediate churn
- Numeric stability without blanket slowdowns:
- adaptive roundoff-aware tolerances and uncertainty-triggered high-precision orientation fallback
- scale-aware noding tolerances for very large coordinate magnitudes
- Parallelism as an opt-in capability:
- Rayon behind
parallelfeature keeps default dependency footprint minimal - high-cost loops in noding and overlay face classification are parallelized when profitable
- Rayon behind
- Built-in perf observability and gating:
overlay_benchreports repeated-run medians and spread (min_avg_us,max_avg_us)- speedup telemetry rows (
all_ops_speedup_x) track separate-vs-one-pass efficiency per fixture overlay_bench_diffsupports default/op/case/case-op thresholds with wildcard selectors for CI gating- dev/scripts/overlay_perf_gate.sh automates baseline bootstrap, diff checks, and serial-vs-parallel comparisons
Extreme Diagnostics
An opt-in extreme fixture corpus is available for frontier robustness tracking. It is intentionally non-blocking for default CI.
- Run diagnostics corpus:
cargo test --test overlay_fixture_extreme_diagnostics_tests -- --ignored --nocapture - Enable strict failure mode:
WBTOPOLOGY_EXTREME_STRICT=1 cargo test --test overlay_fixture_extreme_diagnostics_tests -- --ignored --nocapture
Extreme cases are defined in tests/fixtures/overlay_invariants_extreme.txt.
Known Limitations
wbtopologyfocuses on XY geometry; Z values are preserved on coordinates but are not used in spatial predicates, overlay, buffering, hulls, or triangulation computations.- Overlay operations (intersection, union, difference, symmetric difference) operate on single-layer polygon collections; multi-layer cross-join overlays require external loop coordination.
- Buffer output for polygon collections uses per-polygon buffering; dissolving overlapping buffer rings into a single output requires a subsequent union pass.
- Delaunay triangulation and Voronoi use an incremental algorithm; very large point clouds may require batching for memory efficiency.
- Simplification is vertex-reduction only (Douglas-Peucker and topology-preserving variants); curve-fitting or spline generalization is not supported.
- DE-9IM
relatecomputations are exact for simple geometry types; complexGeometryCollectionDE-9IM semantics are approximated. - File I/O (reading/writing vector files) is out of scope; for that see
wbvector. Thevector_iointerop module is a convenience bridge, not a full format driver. - Optional parallelism (
parallelfeature) uses Rayon and adaptive size thresholds; very small workloads on large thread pools may see scheduling overhead rather than speedup.
License
Licensed under either of Apache License 2.0 or MIT License at your option.