Line tools#
The line tools live in shapelib.tools.lines and cover the post-processing
of detected planting lines: clustering them, removing phantom
duplicates, fusing fragments and generating interlines.
Two conventions apply to all of them:
Warning
Distances are in CRS units — reproject to a metric CRS first (
lines.to_utm()).Filtering by talhão is the caller’s responsibility: pass only the lines of a single field to process it in isolation.
from shapelib import read_file
from shapelib.tools.lines import (
group_lines, deduplicate_lines, merge_lines,
generate_interlines, choose_optimal_interlines,
remove_close_segments,
)
lines = read_file("planting_lines.shp")
lines.to_utm()
Group nearby lines — group_lines#
Clusters nearby, roughly parallel lines and tags each one with a
group_id (stray “matacão” lines are kept out of the clusters):
grouped = group_lines(lines, distance_threshold=2.5)
Remove stacked duplicates — deduplicate_lines#
Two lines tracing the same physical row a few centimeters apart are phantom duplicates. This keeps the longest of each cluster and passes everything else through:
clean = deduplicate_lines(lines, tolerance=0.05)
Fuse fragmented rows — merge_lines#
Fragments of one physical row (collinear, end-to-end, with a hole between them) are detected and concatenated back into a single line, following the curvature of the neighboring row:
fused = merge_lines(
lines,
gap_tolerance=50.0, # max hole length to bridge (m)
angle_tolerance=10.0, # max deviation for tips to be collinear (deg)
)
Generate interlines — generate_interlines#
Interpolates the line midway between each pair of neighboring rows,
scores it against a target spacing and classifies the alternating
classes. Chain with choose_optimal_interlines to keep the
better-scoring class of each group:
interlines = generate_interlines(lines, reference_distance=1.5)
best = choose_optimal_interlines(interlines)
Enforce a minimum separation — remove_close_segments#
Guarantees that no location exists where two lines are closer than a threshold — a safety preprocessing step before exporting lines to machinery. Lines are processed from the longest to the shortest; the portions of a line that invade the corridor of an already-kept line are removed, breaking the line into pieces or dropping it entirely:
safe = remove_close_segments(lines, min_distance=2.0, min_length=5.0)
min_length discards resulting pieces shorter than the given value.
Estimate spacing — estimate_line_spacing#
Available directly on the Lines object:
spacing = lines.estimate_line_spacing()
See also
Full signatures in the API reference.