Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.5.0] - 2026-10-24

Smoothed lines and polygons now get points spaced at equal arc length, and three options join the Gaussian filter: a sigma measured along the line (sigma_units="length"), Taubin smoothing (taubin_iterations), and curvature-continuous curves (continuity="g2" or "c2"). Smoothing 10,000 lines runs about 8 times faster, smoothed rings close exactly, and bad input raises ValueError where 0.4.1 panicked or returned NaN. Upgrading needs Python 3.13 or newer, and smoothed coordinates differ from 0.4.1: distances now caps the gap between points in coordinate units, CatmullRom.evaluate returns derivatives with respect to the curve parameter, and vertex arrays must have exactly two columns. tolerance and max_iterations are ignored, raise a DeprecationWarning, and must be passed by keyword.

Added

  • sigma_units="length" measures the Gaussian sigma in coordinate length along the line. Each vertex is weighted by the length of line it stands for, so unevenly spaced vertices are smoothed evenly. Available on CatmullRom, smooth_linestrings, smooth_polygon, and linestrings_tangent_angles.
  • taubin_iterations applies Taubin lambda/mu smoothing (lambda 0.5, mu -0.53) to the vertices before fitting. It damps jitter and keeps the size of curves drawn with more than about a dozen vertices per turn, which Gaussian smoothing shrinks. Available on the same functions as sigma_units.
  • continuity="g2" or "c2" makes curvature (G2), or also the second derivative (C2), continuous where spline pieces join, using Yuksel's continuity-enhancing splits (SIGGRAPH 2026). Each piece becomes three cubics; vertices and their tangents are unchanged, and the curve stays within a few percent of a chord of the C1 shape. Available on CatmullRom, smooth_linestrings, and smooth_polygon.

Changed

  • tolerance and max_iterations of smooth_linestrings and smooth_polygon are keyword-only.
  • Supported Python versions are 3.13 to 3.15; Python 3.10 to 3.12 are no longer supported. Extension builds use PyO3 0.30, which supports Python 3.15.
  • smooth_linestrings, smooth_polygon, and CatmullRom.uniform_distances space points by equal arc length, computed with adaptive 16-point Gauss-Legendre quadrature and a bracketed Newton inverse. The old fixed-point chord iteration converged on 0 of 200 noisy test lines and returned chords up to three times the mean; spacing is now equal within about 2e-8 relative, including across points where a curve doubles back. In Rust, smoothing a 2000-vertex line is about 20x faster than in 0.4.1, and 2000 lines of 100 vertices about 15x faster; from Python, 10,000 lines of 100 vertices take about 66 ms where 0.4.1 took about 650 ms.
  • Spline segments store their cubic coefficients inline and evaluate with Horner's rule, and per-line work runs serially below 4096 points. Building a 2000-vertex spline is about 6x faster, and smoothing 2000 lines of 100 vertices about 2x faster.
  • The Python bindings release the GIL while Rust computes, and linestrings_tangent_angles processes lines in parallel like smooth_linestrings.
  • smooth_linestrings and linestrings_tangent_angles pass all coordinates to Rust in one array and build geometries in bulk, which cut about 20 ms from smoothing 10,000 lines of 100 vertices.
  • Gaussian pre-smoothing extends open lines by point reflection through their end vertices, so evenly spaced straight runs stay in place; the old mirror reflection shifted vertices near the ends along the line. Closed rings wrap around, so the seam vertex is smoothed like every other vertex instead of staying pinned.
  • CatmullRom documents and enforces 2D vertices: arrays without exactly two columns raise ValueError. A third column used to be dropped silently.

Deprecated

  • The tolerance and max_iterations arguments are ignored and raise a DeprecationWarning; they will be removed in a future release.

Fixed

  • distances (and distance in smooth_polygon) are in the coordinates' length units. They were compared against the centripetal parameter (a sum of square roots of chord lengths) and counted intervals as points, so distances=10 on a 100-unit line returned 2 points. Points are now spaced evenly, no wider than the given distance.
  • The last point of a curve is returned exactly, so smoothed rings close exactly. At projected-CRS magnitudes rounding left them open by about 1e-9, and shapely then appended an extra closing vertex.
  • linestrings_tangent_angles fits LinearRing inputs with periodic splines, so the first and last angles (the same vertex) agree. Natural ends gave two different angles at the seam.
  • Open two-vertex lines no longer fail with "Internal error in tangent calculation"; they produce a straight segment.
  • CatmullRom.evaluate with n=1 or n=2 now returns derivatives with respect to the curve parameter. They were scaled by each segment's grid step (and its square), so magnitudes change on any non-unit grid. Tangent angles are unaffected.
  • CatmullRom.uniform_distances starts at the first grid value; it assumed a grid starting at zero.
  • Gaussian smoothing mirrors correctly when the kernel (4 * gaussian_sigma vertices on each side) is wider than the line. Debug builds panicked and release builds read wrapped indices.
  • A Gaussian sigma at least one period of the extended line wide returns its limit (the chord for open lines, the centroid for rings) where it used to allocate a kernel proportional to sigma, so any finite sigma finishes quickly.
  • The RAYON_NUM_THREADS environment variable is honored. Constructing a CatmullRom before any batch call used to pin the thread pool to all available cores.
  • Invalid inputs raise ValueError where they used to raise PanicException or return NaN: n_pts below 2, nonpositive or nonfinite distances, vertex arrays without exactly two columns, nonfinite vertices, alpha or gaussian_sigma, and explicit grids that are not strictly increasing.
  • Non-contiguous NumPy arrays (for example d[::2]) are accepted everywhere.
  • Coordinates so large that curve lengths overflow raise ValueError.
  • Repeated consecutive vertices are dropped before fitting whenever the grid is generated (no explicit grid, or alpha overriding it). They produced all-NaN output.
  • Closed curves decide whether the last vertex repeats the first with a tolerance relative to the ring's extent. The old test scaled with the coordinate values, so rings at projected-CRS magnitudes lost real vertices within tens of meters of the start.

[0.4.1] - 2026-02-22

Fixed

  • Include AUTHORS.md in the sdist by adding it to the Cargo.toml include list.
  • Fix mkdocstrings configuration by renaming import to inventories for compatibility with mkdocstrings-python 2.0.
  • Fix mkdocstrings directive in docs/reference.md.

[0.4.0] - 2026-02-21

This release adds Python 3.14 support and brings significant improvements to both the Rust core and the Python API. Key highlights include a corrected second derivative formula, proper handling of mixed LineString/LinearRing inputs, and better error handling by returning Result instead of panicking. On the Rust side, two crate dependencies (lazy_static and num_cpus) have been removed in favor of standard library alternatives, and all major dependencies have been bumped. The Python API gains __repr__ and __slots__ on CatmullRom, along with cleaner data passing to Rust by using plain lists instead of numpy array intermediaries.

Added

  • Python 3.14 support.
  • __repr__ method on CatmullRom class for better debugging output.
  • __slots__ on CatmullRom class for reduced memory usage and prevention of dynamic attribute creation.
  • Length validation in linestrings_tangent_angles to raise an error when gaussian_sigmas length does not match the number of input lines.
  • grid property in _catsmoothing.pyi type stubs.

Fixed

  • Fixed second derivative formula in spline evaluation (was constant 6.0 instead of correct 6.0 * t).
  • In smooth_linestrings, if the input was a mix of LineString and LinearRing the output was either a LineString or a LinearRing depending on the type of the first input. Now, the output correctly is a mix of LineString and LinearRing depending on the type of each element in the input.
  • Fixed _catsmoothing.pyi type stubs to match the actual Rust API signatures.
  • Removed outdated scipy requirement mention from smooth_polygon docstring.

Changed

  • evaluate() and uniform_distances() now return Result instead of panicking on invalid input, propagating errors to Python as ValueError.
  • Replaced lazy_static with std::sync::LazyLock and num_cpus with std::thread::available_parallelism(), removing two crate dependencies.
  • Enforce valid polygon generation in smooth_polygon using shapely.make_valid function.
  • Vec2D now derives Copy for reduced heap allocations.
  • Improved spline evaluation by using partition_point for binary search and ordered tangent construction instead of insert(0, ...).
  • Pass bc_types as a plain list[str] to Rust instead of converting through a numpy string array.
  • Pass gaussian_sigmas as a plain list in linestrings_tangent_angles instead of converting through a numpy array.
  • Bumped Rust dependencies: ndarray 0.16 to 0.17, pyo3 0.24 to 0.28, numpy (crate) to 0.28, rand to 0.10, rand_distr to 0.6.

[0.3.1] - 2025-04-16

Fixed

  • Fix the threading issue when initializing Rayon.

[0.3.0] - 2025-04-16

Changed

  • Refactor the Rust code base to use ndarray instead of nalgebra for matrix operations since the Python API uses numpy. This change improves the performance of the code as it avoids unnecessary conversions between nalgebra and numpy arrays.
  • Added specialized Vec2D structure to replace generic Array1<f64> for 2D vectors
  • Improved memory management with preallocation and reduced temporary allocations
  • Optimized mathematical operations with direct 2D vector calculations
  • Added lazy_static Hermitian matrix to avoid recreation
  • Eliminated redundant vector storage and minimized cloning
  • Improved Gaussian smoothing for better cache utilization
  • Fixed thread safety issues for proper parallel execution

[0.2.2] - 2024-12-06

Changed

  • Improved the code performance by creating a global thread pool that is shared across all functions that run in parallel. This avoids creating a new thread pool for each function call, which was causing a performance overhead.
  • Improved the performance of the gaussian_smoothing function by using a more efficient algorithm to compute the convolution of the input data with a Gaussian kernel.

[0.2.1] - 2024-12-02

Fixed

  • Fix the smooth_linestrings function to correctly handle returning multiple LineString geometries when a list of LineString geometries is passed as input.

[0.2.0] - 2024-12-01

This is a major release with breaking changes. The codebase has been written from scratch in Rust and the Python bindings have been updated to reflect the changes in the underlying implementation.

Changed

  • The bc_types argument of CatmullRom class has been renamed to bc_type and custom boundary conditions have been removed. The available boundary conditions are 'natural', 'closed', and 'clamped'.
  • The smooth_linstring function has been renamed to smooth_linestrings. This function now handles a list of LineString geometries instead of a single geometry. The code runs in parallel in Rust and is significantly faster than the previous implementation. If a single LineString geometry is passed a single LineString geometry is returned, otherwise a list of LineString geometries is returned.
  • The compute_tangents has been renamed to linestrings_tangent_angles. This function now handles a list of LineString geometries and returns the tangent angles at each vertex of the input geometries. The code runs in parallel in Rust and is significantly faster than the previous. If a single LineString geometry is passed a single array of tangent angles is returned, otherwise a list of arrays is returned.

[0.1.1] - 2024-09-25

Added

  • Add a new boundary condition for the CatmullRom class called 'clamped', which allows anchoring the first and last points of the curve to the first and last control points. This is particularly useful for smoothing MultiLineString geometries where the first and last points of each line segment must remain connected to the previous and next line segment.

Changed

  • Freeze attributes of CatmullRom since they are not supposed to be changed, once the class is instantiated. If needed, a new instance should be created.

[0.1.0] - 2024-08-31

  • Initial release.