[general]
name=Align Features to Path
qgisMinimumVersion=3.28
qgisMaximumVersion=4.99
description=Snap and align polygon/line features to a digitised alignment path with gap-free shared boundaries (Global Master Path Snapping).
version=14.0.0
author=Mustafa Elghazaly
email=mustafa@example.com
about=Draw an alignment path on the map, then align nearby polygon or line features to it using one of two methods: Fit to Path (near-path edges are densified and traced onto the path) or Preserve Shape (only vertices inside the tolerance zone move). v11 introduces Global Master Path Snapping: every aligned vertex is quantised to a single canonical master vertex list derived from the drawn path, so adjacent features receive bitwise-identical shared-boundary coordinates — zero gaps or slivers by construction. Tolerance is a hard boundary: only features intersecting the tolerance buffer are touched and only vertices within tolerance move.
tracker=https://github.com/ghazaaly23/align-features-to-path/issues
repository=https://github.com/ghazaaly23/align-features-to-path
tags=alignment, snap, polygon, cadastral, topology, trace, curve, qgis4
homepage=https://github.com/ghazaaly23/align-features-to-path
category=Vector
icon=icon.png
experimental=False
deprecated=False
changelog=
    v14.0.0: Trace mode rebuilt on a local edge graph (_TraceGraph), replacing the previous single-feature tracer. Every visible line feature and every ring of every visible polygon's boundary() (incl. holes) within a tight search corridor around the drag is merged into one planar graph; coincident vertices from different features collapse onto shared nodes, so the trace now hands off cleanly onto a touching/adjacent feature at a shared vertex instead of jumping or freezing partway through an edge. Dijkstra finds the shortest connecting path, which automatically picks the shorter direction around closed rings, while a direction-continuity bias (penalises the first hop if it points backwards relative to the current stroke) stops it flip-flopping sides as the cursor passes a ring's midpoint. Multi-part geometries and curved segments (segmentized first) trace correctly since every ring/part/arc is just more edges in the same graph. _visible_layers() now actually filters by layer-tree visibility and scale-based visibility, not just project membership. The graph is cached per anchor point and only rebuilt when the cursor leaves the cached search corridor, keeping live preview responsive on large layers.
    v13.3.0: Trace + UI refinements. Trace mode: (1) start-anchored feature selection — the traced feature must pass near the last committed point, not merely near the cursor (turning onto neighbours at shared junctions still works); prevents the trace jumping to distant features. (2) Direction continuity — on closed rings the candidate arc that continues the current drawing direction (dot(initial_dir, stroke_tangent) >= 0.2) is preferred over the merely-shorter arc, so the trace no longer flips sides mid-ring. (3) Feature scans request geometry only (setSubsetOfAttributes([])) for faster live preview on wide tables. UI: Snap Line Ends method card removed (the method remains available via the algorithm API); dock slimmed 270-320px -> 235-280px; compact control heights, paddings and spacings throughout.
    v13.2.0: Edge/run-based Fit-to-Path rewrite (crossing-line fix, complete). v13.1's vertex-eligibility guard was insufficient: a divider endpoint touching a near-parallel boundary still joined an eligible run, and entry/exit crossings were computed on the transverse divider itself, inserting a buffer-boundary stub point on every crossing. _process_ring now classifies EDGES: an edge is alignable only when it touches the alignment zone AND abs(dot(edge_unit, master_tangent)) >= cos(30°). Runs are maximal sequences of alignable edges; entry/exit buffer crossings are computed only on the run's own near-parallel edges, never on a transverse neighbour. A divider therefore keeps one straight segment from its outside endpoint directly to the snapped boundary corner — no intermediate buffer-boundary points, no doglegs, no path-shaped stubs. Single-vertex eligible corners between two transverse edges are left untouched (no span). Shared-boundary bitwise-identical coordinates, square/round caps and tolerance-buffer filtering unchanged.
    v13.1.0: Crossing-line directional guard. Transverse parcel dividers that cross the alignment path nearly perpendicular to it no longer receive path-shaped doglegs/spikes at the intersection. A run-level directional filter now requires abs(dot(edge_unit, master_tangent)) >= cos(30°) before any boundary portion is snapped/traced: only near-parallel edges join snap runs, transverse edges keep their original straight shape and are also excluded from densification. Corner vertices where a parallel boundary meets a divider retain one parallel neighbour, so they still snap — the divider ends exactly ON the path with no dogleg. Applies to Fit to Path and Preserve Shape; square/round ends, tolerance-buffer logic and bitwise-identical shared boundaries unchanged.
    v13.0.0: Single-source-of-truth eligibility fix. Vertex eligibility is now a direct point-in-polygon test against the same tolerance-buffer polygon already used for feature filtering and entry/exit crossing search (via a prepared GEOS engine, _BufferTest), instead of a separate analytic distance formula. The two used to disagree by a sliver near bends and square-capped ends (GEOS facets round joins/caps; the analytic test didn't), which is what caused the residual entry/exit kinks in v12. The old segment-index-dependent square-cap special case is removed entirely — no longer needed, since the real buffer already has the correct flat caps baked in.
    v12.0.0: Entry/exit rewrite. For every ring/line edge crossing the tolerance buffer, the exact entry/exit crossing points are found, snapped to the nearest master-path vertex, and the inside-buffer portion is either replaced by real path vertices (Fit to Path) or individually re-anchored (Preserve Shape) — removing the old hand-off kink between raw and snapped geometry.
    v11.0.0: Simplified rewrite. Methods reduced to Fit to Path and Preserve Shape (Smart Fit, Snap Ends Only, Trace & Smooth removed). New Global Master Path Snapping core: all aligned vertices are quantised to one canonical master vertex list (curve-aware segmentize + fixed-step densify at tolerance*0.1), guaranteeing bitwise-identical shared boundaries between adjacent features. Intelligent densification now uses exact segment-to-segment distance so long edges near the path are always subdivided and pulled (fixes 'Fit to Path doesn't move long edges'). Fit mode gap-fills intermediate master vertices between consecutive snapped vertices, so traced boundaries never cut chords across curves. Tolerance is the strict hard boundary (no hidden *1.5/*2 expansions). Grid-bucketed spatial index; algorithm reduced from ~2900 to ~800 lines.
    v10.2.0: Smart Fit mode + Square End audit. New METHOD_SMART_FIT adds (1) intersection-significance pre-filter: features that only clip a corner of the buffer (L-corner pulls, crossing lines) are skipped based on a configurable overlap-ratio threshold; (2) proximity-weighted vertex movement: vertices near the path snap almost fully, distant vertices move gently (quadratic falloff), eliminating aggressive global pull. UI: new "Smart Fit" method card between "Fit to Path" and "Preserve Shape"; Advanced panel grows a Smart Fit Options section (Min. Overlap %% spinner + Proximity-weighted checkbox) visible only in Smart Fit mode. Square End buffer preview (_update_tol_preview, _on_path_updated) already uses _get_end() — confirmed correct. Backward compatible: all previous methods unchanged.
    v10.1.8: Buffer Distance Fix. The Tolerance value now correctly acts as the hard containment boundary — only features whose geometry intersects the tolerance buffer of the drawn path are aligned (matching ArcGIS Pro behaviour). Previously the algorithm silently expanded search_buffer to tolerance*2, pulling in features outside the drawn buffer. Fixed: search_buffer clamp is now max(search_buffer, tolerance) instead of tolerance*2. Dialog _get_features() bbox pre-filter updated from tol*2 to tol to match.
    v10.1.7: Coherent Fit to Path gap-closing fix. Densification + master-path projection for Fit to Path so adjacent parcels share identical boundary coordinates.
    v10.1.1: QGIS 4 loading fixes. Declared qgisMaximumVersion=4.99 so the plugin is allowed to load under QGIS 4 (a 3.x-only maximum silently blocked it before). Fully scoped every Qt and QGIS enum that PyQt6 no longer exposes in unscoped form (Qt.*, Qgis.MessageLevel.*, QgsWkbTypes.GeometryType/Type.*, QFrame/QSizePolicy/QSlider widget enums, QgsVertexMarker.IconType.*, QgsPointLocator.Type.*). QAction import now falls back from QtWidgets to QtGui (moved in Qt6). Enums relocated to the Qgis namespace in QGIS 4 (layer filters, feature-request flags, tolerance unit) are resolved defensively at import time with QGIS 3 fallbacks. All v10 master-path snapping logic and the v10.1 buffer/curve shims are unchanged.
    v10.1.0: QGIS 4 compatibility groundwork. Buffer style resolution now uses a module-level _resolve_buffer_styles() helper that probes five API strategies (Qgis.EndCapStyle, QgsGeometry.CapRound, QgsBufferParameters, integer fallback) at import time. _make_buffer() tries four QgsGeometry.buffer() call signatures. QgsWkbTypes.isCurvedType wrapped in _is_curved_wkb_type() shim. QgsMessageLog guarded for headless environments. QgsWkbTypes.displayString guarded for QGIS 4. All v10 master-path snapping logic unchanged.
    v10.0.0: Global Master Boundary Alignment. Deterministic master-path snap forces all near-path vertices to the exact same coordinates across all polygons — bitwise-identical shared boundary, zero gaps. Two-tier: exact vertex pin at kinks (Tier 1) + segment projection (Tier 2).
    v9.2.0: Hardened shared-boundary alignment. Global merge via spatial hash, deterministic trace direction, zero-length edge cleanup.
    v9.0.0: Coherent Multi-Polygon Boundary Alignment. Enforce Shared Boundary option (default ON).
    v8.0.0: True path tracing. Trace Mode button. Arc/curve-aware densification. Improved Chaikin smoothing.
    v7.1.0: Trace & Smooth method with resample + snap + Chaikin smoothing.
    v7.0.0: 4-step dock UI, spatial index, 5-level undo, preview rubber band.
