shapelib.tools.lines.merge package#
Submodules#
shapelib.tools.lines.merge.core module#
Merge fragmented planting rows back into continuous lines.
Drone-mapped rows are sometimes “picotadas”: one physical row is split into
several LineString fragments separated by holes. This tool reconstructs the
continuous rows by bridging each hole — guided, always, by a continuous neighbor
row (the “rail”) that runs alongside it.
The algorithm follows each tip’s neighbor to its partner. Every fragment starts as its own one-piece run; each round, for every dangling tip it first picks the rail — the nearest line running forward past the tip — and then joins the tip to the next tip lying in the same lane: at the tip’s own offset from that rail, on the same side, with the rail still its direct neighbor there too. The destination follows from riding the rail, so a tip can only ever reach its row’s direct continuation. The nearest such partner along the rail is taken first, and each freshly merged line becomes a rail for the next round — so the reconstruction grows outward from solid ground until nothing reconstructable is left.
Three properties are core to the algorithm (not optional toggles):
Same-lane joining. A tip is joined to another only when its rail is the direct neighbor of both tips — same side, same offset, with no other row between the rail and either tip. A same-row continuation rides alongside the rail one spacing away at both ends; a link that skips a row sits two spacings off, or reaches the far side of a row that lies between them, and is rejected. This is what keeps the merge from joining different rows on curves.
Easy-first, outside-in. A tip is joined to its nearest in-lane partner first, and only when a rail already runs past it. A hole in the middle of a band that has broken across several rows has no rail yet, so it waits; once the rows around it are rebuilt they become its rail and it is bridged in turn. The reconstruction never starts from an estimate in the middle of a hole, and a single row’s several holes are bridged one at a time as each gains a rail.
A fill always needs a rail. Holes are never bridged with a coarse straight guess: a hole with no neighbor running alongside it is left open. Every fill in the output is guided by a real neighbor row.
The public entry point is merge_lines().
- shapelib.tools.lines.merge.core.merge_lines(lines, distance_threshold=2.5, gap_tolerance=50.0, angle_tolerance=10.0, max_reference_distance=2.0)[source]#
Merge fragmented rows back into continuous lines, filling the holes.
Takes the input lines and returns the fully fused set: fragments of one physical row (collinear, end-to-end, with a hole between them) are detected and concatenated into a single
LineString, and every line that was not part of a merge is passed through unchanged — so the output is one self-contained, de-fragmented line set, not just the rebuilt rows.Each tip is joined by following its rail — the nearest neighbor row running alongside it — to the next tip in the same lane (the same offset from the rail, on the same side, with the rail still its direct neighbor there). The fill follows the rail’s curvature, each freshly merged line becomes a rail for the rows around it (so curvature propagates outward across holes that span several rows, and a single row’s several holes are bridged one at a time), and a hole with no neighbor running alongside it is left open rather than guessed straight. Filtering by talhão is the caller’s responsibility — pass only the lines of a single talhão.
- Parameters:
lines (
GeoDataFrame) – Line geometries. Must be in a projected CRS (metres), since the tolerances are in CRS units. MultiLineStrings are flattened.distance_threshold (
float) – Maximum spacing (CRS units) for two rows to be grouped as neighbors (used only to tag the output with agroup_id).gap_tolerance (
float) – Maximum hole length (CRS units) that may be bridged between two fragments.angle_tolerance (
float) – Maximum angular deviation (degrees) for two fragment tips to be considered collinear, and for a reference row to be considered parallel.max_reference_distance (
float) – Maximum perpendicular distance (CRS units) from a tip to a row for that row to be used as its rail — about one row spacing, so only the immediate neighbor guides the join. Holes with no row this close are left open.
- Returns:
The full fused line set — one row per merged line plus every line that was not merged, passed through unchanged. Each row carries the attributes of its longest contributing fragment plus:
group_id: proximity-cluster id the row belongs to.n_fragments_merged: number of fragments combined (>= 2 for merged rows,1for passed-through lines).n_gaps_filled: number of holes bridged in the row.
- Return type:
Examples
>>> import shapelib >>> lines = shapelib.read_file("rows.shp") >>> lines.to_utm() >>> fused = merge_lines(lines) >>> rebuilt = fused[fused["n_fragments_merged"] >= 2] # only the merged rows
shapelib.tools.lines.merge.models module#
Internal value object used by the line merging algorithm.
_Fragment is a private implementation detail of
shapelib.tools.lines.merge. It wraps a (flattened) LineString fragment
and caches the data the merger needs repeatedly: the two endpoints and the
outward unit direction at each tip, estimated from a short stretch near the tip
for robustness against noisy vertices. It carries no shared mutable state.