src.utils.curve.simple_polyline_sanitizer
Module Attributes
Default threshold (in radians) for the vertical-grade test of |
Classes
|
- src.utils.curve.simple_polyline_sanitizer.DEFAULT_SPLIT_ZJUMP_BRIDGES_THRESHOLD = 0.7853981633974483
Default threshold (in radians) for the vertical-grade test of
split_zjump_bridges(). A windowed-grade value greater than \(\tan(\text{threshold})\) flags a vertical column. Default \(\pi/4 = 45^{\circ}\), whose tangent is \(1.0\) (the pre-rename hardcoded value).
- class src.utils.curve.simple_polyline_sanitizer.SimplePolylineSanitizer(merge_radius=None, z_tolerance=2.0, min_voxel_size=0.1)
- Author:
Alberto M. Esmoris Pena
Polyline-sanitization helper for the curves produced by
SimpleCurveExtractor. Runs the Z-jump bridge split, Z-reversal split, consecutive-vertex dedup and self-intersection clip cascade used by the clustering orchestrator.Instances are constructed once per consuming SCE pipeline phase from the private orchestrator helpers
_refine_coverage,_step_merge_resolve_split_pipeline,_merge_resolve_sanitize_tripletand_step_global_optimization; they take a snapshot of the relevant SCE attributes (merge_radius,z_tolerance,min_voxel_size) and run the split / dedup / self-intersection-clip cascade without further coupling to the orchestrator. SeeSimpleCurveExtractorfor the upstream pipeline that producessmooth_curvesandmetadata.- Variables:
merge_radius (float or None) – Spatial radius governing the long-bridge XY threshold derivation in
split_zjump_bridges().Nonefalls back to the legacy10.0m default at use time.z_tolerance (float) – Z-tolerance (3-sigma bound) used as the long-bridge
dzthreshold bysplit_zjump_bridges().min_voxel_size (float) – Floor scale used by
split_zjump_bridges()to keep the bridge-XY threshold portable across coordinate systems.
- __init__(merge_radius=None, z_tolerance=2.0, min_voxel_size=0.1)
Snapshot the SCE configuration relevant to the polyline-sanitisation cascade.
- sanitize_polylines(smooth_curves, metadata)
Final geometric cleanup of all polylines before output. Performs two operations:
Remove self-intersections by detecting where the polyline crosses itself and clipping the loop (keeping the shorter path).
Remove consecutive duplicate points that could cause degenerate zero-length segments.
- Parameters:
smooth_curves (list of dict) – Chained curve segments.
metadata (list of dict) – Per-chain metadata dicts.
- Returns:
Sanitized (smooth_curves, metadata).
- Return type:
tuple
- split_zjump_bridges(smooth_curves, metadata, max_dz_split)
Split features at Z-jump bridge segments.
Uses a dual criterion to detect bridges:
Any bridge: XY gap \(> 3\) times the median point spacing AND \(|\Delta z| >\)
max_dz_split.Long bridge: XY gap \(> 10\) m AND \(|\Delta z| > 2\) m.
The long-bridge criterion catches moderate Z-jumps that are visually prominent because the bridge spans a large horizontal distance.
- Parameters:
smooth_curves (list of dict) – Curve segments.
metadata (list of dict) – Per-segment metadata dicts.
max_dz_split (float) – Z-difference threshold for the general bridge criterion.
- Returns:
(smooth_curves, metadata) after split.
- Return type:
tuple
- static split_z_reversals(smooth_curves, metadata, max_reversal)
Split features at Z-reversals.
A Z-reversal occurs when the elevation profile of a polyline climbs to a peak and then drops back by more than
max_reversal. This detects multi-terrace chaining artifacts where the consecutive-point dZ is small but the cumulative pattern visits different elevation levels.Uses drawdown analysis: the running maximum of Z is computed, and the feature is split wherever \(Z_{\max}^{\text{run}}(i) - Z(i) > \Delta z_{\text{rev}}\).
- Parameters:
smooth_curves (list of dict) – Curve segments.
metadata (list of dict) – Per-segment metadata dicts.
max_reversal (float) – Maximum allowed drawdown.
- Returns:
(smooth_curves, metadata) after split.
- Return type:
tuple
- static emit_split_segments(pts, slopes, meta, bounds, out_c, out_m)
Emit one polyline per consecutive
boundspair into the caller’sout_c/out_mlists. The caller is responsible for fillingbounds(must be[0, ..., len(pts)]). Sub-segments shorter than 2 vertices are skipped. Each emitted polyline carries the same slopes slice and a copy ofmetawithLENGTH_3D/LENGTH_2Doverwritten with the sub-polyline’s own length. Extracted in iter4 (Phase 1, L-20) to fold the duplicated 18-line tail ofsplit_zjump_bridges()andsplit_z_reversals()into a single helper.- Parameters:
pts (
np.ndarray) – Source polyline points (N x 3).slopes (
np.ndarray) – Source per-vertex slopes.meta (dict) – Source feature metadata dict.
bounds (list of int) – Sorted list of split indices including the leading
0and trailinglen(pts).out_c (list of dict) – Destination list for emitted curve dicts (mutated in place).
out_m (list of dict) – Destination list for emitted metadata dicts (mutated in place).
- Returns:
None.- Return type:
NoneType
- static slopes_from_z_diffs(pts)
Compute per-vertex slope (project-canonical
slope = dZ / ds_3D = sin(theta)) from the consecutive-vertex differences of a polyline. Per-vertex slope is the average of adjacent segment slopes; the first and last vertex copy the slope of the touching segment. Bounded in \([-1, 1]\); well-defined at near-vertical segments wheretan(theta) = dZ/dxywould diverge. Extracted in iter4 (Phase 1, L-19) to fold the duplicated formula at the SCE helpers_drop_hallucinated_featuresand_concatenate_orphan_into_neighbour.- Parameters:
pts (
np.ndarray) – Polyline points (N x C,C >= 3).- Returns:
Per-vertex slopes (length
N).- Return type:
np.ndarray
- static dedup_points(pts, slopes)
Remove consecutive duplicate points from a polyline. Two points are considered duplicate when their Euclidean distance is below \(10^{-9}\).
- Parameters:
pts (
np.ndarray) – Polyline points (N x 3).slopes (
np.ndarray) – Per-point slopes (N,).
- Returns:
Deduplicated (pts, slopes).
- Return type:
tuple
- static remove_self_ix(pts, slopes)
Detect and remove self-intersections in a polyline by iteratively finding the first crossing and clipping out the loop.
The grid-build, first-hit scan, and intersection point are computed by the
pyvl3dpp.curve_self_intersection_{f,d}C++ binding. The binding returns(found, i, j, ix, iy, iz)withi < jand the intersection point already computed; the outer 20-pass loop and the polyline clip remain in Python. When segments i–(i+1) and j–(j+1) cross, the loop from i+1 to j is removed: the polyline jumps directly from point i to the intersection point to point j+1.Precision dispatch follows the
pts.dtype: float32 routes to_f, everything else to_d(mixed-precision arrays are cast to float64 to preserve numeric fidelity).- Parameters:
pts (
np.ndarray) – Polyline points (N x 3).slopes (
np.ndarray) – Per-point slopes (N,).
- Returns:
(cleaned pts, cleaned slopes, changed flag).
- Return type:
tuple