src.utils.curve.simple_topological_stitcher
Classes
|
- class src.utils.curve.simple_topological_stitcher.SimpleTopologicalStitcher(merge_radius=None, spatial_scale=0.0, sce=None)
- Author:
Alberto M. Esmoris Pena
Endpoint-merger and chain-builder helper for the curves produced by
SimpleCurveExtractor. Bundles the union-find endpoint merge with bridge creation, the direction-aware per-CURVE_ID chain builder, the post-chain merge cascade with its fixed-point wrapper and the sub-chain attachment helper.Instances are constructed once per consuming SCE pipeline phase from the private orchestrator helpers
_step_endpoint_merge,_step_chain_segments,_step_merge_resolve_split_pipeline,_merge_resolve_sanitize_triplet,_step_adopt_short_cidsand_step_global_optimization(and therefine_coveragepath onSimpleCoverageRefiner); they take a snapshot of the relevant SCE attributes (merge_radius,spatial_scale) plus a back-reference to the extractor for the_max_dzcross-class invocation. SeeSimpleCurveExtractorfor the upstream pipeline that producessmooth_curvesandmetadata.Two methods are user-mandated public entry points:
merge_endpoints()(cross-CURVE_ID union-find endpoint merge that creates bridge segments) andchain_segments()(direction-aware per-CID chain builder). The remaining four methods (post_chain_merge(),attach_chain(),post_chain_merge_until_stable()and the staticchain_curve_segments_extend()) are phase helpers consumed by the post-chain cascade.- Variables:
merge_radius (float or None) – Spatial radius governing the cross-CURVE_ID endpoint merge in
merge_endpoints()and the default radius forpost_chain_merge_until_stable().Nonefalls back at use time inside the wrapper.spatial_scale (float) – Scale forwarded to
make_bridgeonSimpleGlobalCurveOptimizerwhen attaching sub-chains inattach_chain(). Values<= 0are coerced to1.0at use time._sce (SimpleCurveExtractor or None) – Back-reference to the consuming
SimpleCurveExtractorinstance, used only to dispatch the_max_dzhelper that stays on SCE.
- __init__(merge_radius=None, spatial_scale=0.0, sce=None)
Snapshot the SCE configuration relevant to the topological stitching cascade.
- merge_endpoints(smooth_curves, metadata)
Merge curves whose segment endpoints are within
``merge_radius``. Creates bridge segments (straight lines) between merged endpoints to fill visual gaps.Uses union-find on original CURVE_IDs from metadata so un-merged segments keep their original curve assignment. Only segments from DIFFERENT curves are merged.
Modifies
smooth_curvesandmetadatain-place: updates CURVE_IDs and appends bridge segments.- Parameters:
smooth_curves (list of dict) – Refined curve segments.
metadata (list of dict) – Per-segment metadata dicts with CURVE_ID and SEG_ID keys.
- chain_segments(smooth_curves, metadata, chain_radius)
Chain segments within each curve into continuous polylines using direction-aware topological adjacency. Only segments whose endpoints are within
chain_radius(typicallychain_radius_factortimes the skeleton voxel size) are connected, preventing wrong long-distance connections.Extension is direction-aware: at each step the algorithm computes the cosine between the current segment’s exit direction and each candidate neighbor’s connecting direction, picking the neighbor with the best (highest) cosine alignment. This ensures the chain follows the smoothest geometric continuation.
At T-junctions, the chain follows the longest branch. Remaining branches become separate polylines. Segments are flipped as needed so concatenated points flow continuously; bridge points are inserted across gaps.
- Parameters:
smooth_curves (list of dict) – Refined curve segments.
metadata (list of dict) – Per-segment metadata.
chain_radius (float) – Max distance between endpoints to consider them adjacent.
- Returns:
Chained (smooth_curves, metadata).
- Return type:
tuple
- post_chain_merge(smooth_curves, metadata, merge_radius, max_dz_override=None)
Merge chains with the same
CURVE_IDwhose endpoints are withinmerge_radius. Uses union-find on chain indices for transitive merges (A–B and B–C become one chain).Concatenation uses a global best-first strategy: at each iteration, the remaining chain whose endpoint is closest to the current polyline head or tail is attached next, with automatic flipping to maintain continuity. A bridge point is inserted across each gap. The loop is convergent: it terminates when no remaining chain has an endpoint within
merge_radius.- Parameters:
smooth_curves (list of dict) – Chained curve segments.
metadata (list of dict) – Per-chain metadata dicts.
merge_radius (float) – Maximum endpoint distance for merging.
- Returns:
Merged (smooth_curves, metadata).
- Return type:
tuple
- attach_chain(chain_pts, chain_sl, head, tail, mp, ms, best_type, svs)
Attach a sub-chain
(mp, ms)to the running(chain_pts, chain_sl)polyline using one of the fourbest_typeorientation codes used bypost_chain_merge(). Extracted in iter4 (Phase 6, L-17).Behaviour mirrors the original inline branches verbatim:
'ts'– tail tompstart: appendmp(no flip), update tail tomp[-1].'te'– tail tompend: appendmp[::-1](flip), update tail tomp[0].'he'– head tompend: prependmp(no flip), update head tomp[0].any other (
'hs') – head tompstart: prependmp[::-1](flip), update head tomp[-1].
For each branch, a bridge is inserted in the same order as the original code when the gap between the touching endpoints exceeds
1e-3. The bridge endpoints (and the slope-segment list ordering) match the inline sequence exactly somake_bridge(now onSimpleGlobalCurveOptimizer) is invoked with the same(p0, p1, svs)tuple as before.- Parameters:
chain_pts (list of
np.ndarray) – List of point arrays.chain_sl (list of
np.ndarray) – List of slope arrays.head (
np.ndarray) – Current head endpoint.tail (
np.ndarray) – Current tail endpoint.mp (
np.ndarray) – Sub-chain points.ms (
np.ndarray) – Sub-chain slopes.best_type (str) – One of
'ts','te','he', or any other value (treated as'hs') – the original code uses anelsebranch for'hs', which this helper preserves.svs (float) – Spatial scale forwarded to
make_bridgeonSimpleGlobalCurveOptimizer.
- Returns:
Updated
(chain_pts, chain_sl, head, tail).- Return type:
tuple
- post_chain_merge_until_stable(smooth_curves, metadata, radius=None, max_dz_override=None)
Run
post_chain_merge()to fixed point via theapply_until_stablehelper onSimpleCurveExtractor. Wraps the lambda boilerplate that was repeated at every cascade site (eight call-sites in_step_merge_resolve_split_pipeline/_step_adopt_short_cids/_step_global_optimization). Extracted in iter4 (Phase 1, L-25).- Parameters:
smooth_curves (list of dict) – Curve segments.
metadata (list of dict) – Per-segment metadata dicts.
radius (float or None) – Override merge radius.
Nonefalls back toself.merge_radius.max_dz_override (float or None) – Optional Z-tolerance override forwarded verbatim to
post_chain_merge().
- Returns:
Final
(smooth_curves, metadata).- Return type:
tuple
- static chain_curve_segments_extend(segs, used, seg_adj, max_dz, start_k, from_end)
Extend a chain from one end of segment
start_k, picking the neighbour that best continues the current direction (best 2D cosine alignment). Mutatesusedin place to mark visited segments.Lifted from a closure inside
chain_segments()(L-21). The arithmetic and control flow are byte-output preserving relative to the original closure; the only structural change is the boundedfor _ in range(len(segs))which terminates at the same step as the originalwhile Truebecause each iteration consumes oneusedslot.- Parameters:
segs (list of dict) – Per-CID segments (list of dict with
'pts','slopes','arc','meta_idx'keys).used (list of bool) – Mutable boolean list (length
n_segs) tracking visited segments; updated in place.seg_adj (dict) – Endpoint adjacency map; for each segment index, a list of
(neighbour, my_end, their_end)triples.max_dz (float) – Max vertical distance for cross-terrace rejection.
start_k (int) – Index of the segment to extend from.
from_end (bool) – True to extend from the tail of
segs[start_k], False from the head.
- Returns:
Ordered list of newly chained neighbour indices.
- Return type:
list of int