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 onCatmullRom,smooth_linestrings,smooth_polygon, andlinestrings_tangent_angles.taubin_iterationsapplies 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 assigma_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 onCatmullRom,smooth_linestrings, andsmooth_polygon.
Changed¶
toleranceandmax_iterationsofsmooth_linestringsandsmooth_polygonare 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, andCatmullRom.uniform_distancesspace 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_anglesprocesses lines in parallel likesmooth_linestrings. smooth_linestringsandlinestrings_tangent_anglespass 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.
CatmullRomdocuments and enforces 2D vertices: arrays without exactly two columns raiseValueError. A third column used to be dropped silently.
Deprecated¶
- The
toleranceandmax_iterationsarguments are ignored and raise aDeprecationWarning; they will be removed in a future release.
Fixed¶
distances(anddistanceinsmooth_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, sodistances=10on 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_anglesfitsLinearRinginputs 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.evaluatewithn=1orn=2now 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_distancesstarts at the first grid value; it assumed a grid starting at zero.- Gaussian smoothing mirrors correctly when the kernel (
4 * gaussian_sigmavertices 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_THREADSenvironment variable is honored. Constructing aCatmullRombefore any batch call used to pin the thread pool to all available cores. - Invalid inputs raise
ValueErrorwhere they used to raisePanicExceptionor return NaN:n_ptsbelow 2, nonpositive or nonfinitedistances, vertex arrays without exactly two columns, nonfinite vertices,alphaorgaussian_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, oralphaoverriding 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.mdin the sdist by adding it to theCargo.tomlincludelist. - Fix
mkdocstringsconfiguration by renamingimporttoinventoriesfor compatibility withmkdocstrings-python2.0. - Fix
mkdocstringsdirective indocs/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 onCatmullRomclass for better debugging output.__slots__onCatmullRomclass for reduced memory usage and prevention of dynamic attribute creation.- Length validation in
linestrings_tangent_anglesto raise an error whengaussian_sigmaslength does not match the number of input lines. gridproperty in_catsmoothing.pyitype stubs.
Fixed¶
- Fixed second derivative formula in spline evaluation (was constant
6.0instead of correct6.0 * t). - In
smooth_linestrings, if the input was a mix ofLineStringandLinearRingthe output was either aLineStringor aLinearRingdepending on the type of the first input. Now, the output correctly is a mix ofLineStringandLinearRingdepending on the type of each element in the input. - Fixed
_catsmoothing.pyitype stubs to match the actual Rust API signatures. - Removed outdated
scipyrequirement mention fromsmooth_polygondocstring.
Changed¶
evaluate()anduniform_distances()now returnResultinstead of panicking on invalid input, propagating errors to Python asValueError.- Replaced
lazy_staticwithstd::sync::LazyLockandnum_cpuswithstd::thread::available_parallelism(), removing two crate dependencies. - Enforce valid polygon generation in
smooth_polygonusingshapely.make_validfunction. Vec2Dnow derivesCopyfor reduced heap allocations.- Improved spline evaluation by using
partition_pointfor binary search and ordered tangent construction instead ofinsert(0, ...). - Pass
bc_typesas a plainlist[str]to Rust instead of converting through anumpystring array. - Pass
gaussian_sigmasas a plainlistinlinestrings_tangent_anglesinstead of converting through anumpyarray. - Bumped Rust dependencies:
ndarray0.16 to 0.17,pyo30.24 to 0.28,numpy(crate) to 0.28,randto 0.10,rand_distrto 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
ndarrayinstead ofnalgebrafor matrix operations since the Python API usesnumpy. This change improves the performance of the code as it avoids unnecessary conversions betweennalgebraandnumpyarrays. - Added specialized
Vec2Dstructure to replace genericArray1<f64>for 2D vectors - Improved memory management with preallocation and reduced temporary allocations
- Optimized mathematical operations with direct 2D vector calculations
- Added
lazy_staticHermitian 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_smoothingfunction 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_linestringsfunction to correctly handle returning multipleLineStringgeometries when a list ofLineStringgeometries 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_typesargument ofCatmullRomclass has been renamed tobc_typeand custom boundary conditions have been removed. The available boundary conditions are'natural','closed', and'clamped'. - The
smooth_linstringfunction has been renamed tosmooth_linestrings. This function now handles a list ofLineStringgeometries instead of a single geometry. The code runs in parallel in Rust and is significantly faster than the previous implementation. If a singleLineStringgeometry is passed a singleLineStringgeometry is returned, otherwise a list ofLineStringgeometries is returned. - The
compute_tangentshas been renamed tolinestrings_tangent_angles. This function now handles a list ofLineStringgeometries 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 singleLineStringgeometry 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
CatmullRomclass 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 smoothingMultiLineStringgeometries where the first and last points of each line segment must remain connected to the previous and next line segment.
Changed¶
- Freeze attributes of
CatmullRomsince 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.