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.