You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
4
4
5
5
## [Unreleased]
6
6
7
+
### Changed
8
+
- Start-point variants are now merged by a per-point median consensus instead of a geometric union. Douglas-Peucker is start-vertex dependent, so the four rotated variants disagree slightly about where a feature's vertices land; the union superimposed those disagreements, whereas the median resamples the variants to a common point count, brings them into phase via an FFT cross-correlation, and takes the coordinate-wise median — a start-invariant consensus that outvotes a single bad variant instead of averaging toward it. This is also faster than the union it replaces (~1.3x end-to-end at the default 3 iterations, ~1.4x at 5, on `examples/Water.gpkg`). The median sits at the consensus interior rather than the outer envelope, so the merged ring is marginally smaller before area preservation restores it (with `preserve_area=True`); with `preserve_area=False` the small reduction is left as-is.
9
+
- Faster smoothing with no meaningful change to output. Start-point variants now begin at evenly spaced arc-length positions, computed by interpolating a single new start vertex, rather than rotating to a vertex index on a fully densified ring. The old path segmentized the whole ring only so that index-based rotation would land on evenly spaced points — but every vertex it added was collinear and immediately stripped by the following Douglas-Peucker. Feeding DP just the original vertices plus one cuts its input roughly 3.4x and the simplify step ~3.5x on `examples/Water.gpkg` (total single-core CPU work ~4.4s → ~2.7s, about 1.25x faster end-to-end at the default 3 iterations). The per-point median phase-alignment and Chaikin corner cutting also replace `numpy.roll` with a slice-based cyclic shift (bit-identical, fewer allocations). Output is unchanged within tolerance (per-polygon area drift ≤ 0.01%, worst concave turn unchanged).
10
+
11
+
### Fixed
12
+
- Eliminated the residual "dimple" fold that appeared where the start-point variants disagreed about a shallow feature near the simplify tolerance. Their union superimposed the disagreement as a double peak with a valley that the area-preservation buffer then sharpened into a fold slipping under the concave-turn seal threshold. The per-point median consensus (see Changed) resolves the variants to one boundary instead of overlaying them, removing the artifact (raster-noise fuzz harness: 4 → 0 residual folds; `examples/Water.gpkg`: 8 → 0).
1. Joins touching holes (for Polygons, when `merge_holes=True`) so they smooth as one opening
207
-
2. Adds intermediate vertices along line segments (segmentize)
208
-
3. Generates multiple rotated variants (for Polygons) to avoid artifacts
209
-
4. Simplifies each variant to remove noise
210
-
5. Applies Chaikin corner cutting to smooth
211
-
6. Merges all variants via union to eliminate start-point artifacts
212
-
7. Applies final smoothing pass
213
-
8. Optionally restores original area via buffering (for Polygons)
214
-
9. Detects and repairs any sharp folds left by features near the smoothing scale (e.g. one-pixel-wide arms), using a small morphological opening/closing bounded at `segment_length / 4`
206
+
1.**Pixelated input** — a polygon straight from raster-to-vector conversion, with a stair-stepped boundary
207
+
2.**Multiple variants** (for Polygons) that start at evenly spaced arc-length positions, each simplified to strip staircase noise, so no artifact is tied to a fixed start vertex
208
+
3.**Chaikin corner cutting** applied to each variant
209
+
4.**Per-point median merge** — a start-invariant consensus that resolves the variants' disagreements
210
+
5.**Final smoothing pass** on the merged result
211
+
6.**Restore original area** via buffering (for Polygons, when `preserve_area=True`)
212
+
213
+
Two steps are not shown in the figure: before step 2, touching holes are joined (for Polygons, when `merge_holes=True`) so they smooth as one opening; and after step 6, the result is checked for sharp concave folds left by features near the smoothing scale (e.g. one-pixel-wide arms) and repaired with a small morphological opening/closing bounded at `segment_length / 4`.
0 commit comments