Source code for shapelib.tools.lines.distance

import numpy as np
import geopandas as gpd
from shapely.strtree import STRtree


[docs] def estimate_line_spacing( lines: gpd.GeoDataFrame, sample: float = 0.1, min_samples: int = 30, seed: int | None = None, ) -> float: """ Estimate the spacing between parallel planting lines (e.g. rows every 1.5 m or 2.4 m). Samples a few lines, measures each one's center-to-nearest-line distance, and returns the median (robust to far-apart edge/stray lines). Assumes lines are roughly parallel with uniform spacing, so a small sample suffices. Parameters ---------- lines : gpd.GeoDataFrame Line geometries in a metric CRS (e.g. UTM). sample : float, default 0.1 Fraction of lines to sample if ``<= 1``, else an absolute count. min_samples : int, default 30 Minimum lines to sample, clamped to the total. seed : int, optional Seed for reproducible sampling. Returns ------- float Estimated spacing in CRS units (meters for UTM). """ geometries = lines.geometry.values n = len(geometries) if n < 2: return 0.0 k = int(sample) if sample > 1 else int(round(n * sample)) k = max(k, min_samples) k = min(k, n) rng = np.random.default_rng(seed) sampled_indices = rng.choice(n, size=k, replace=False) tree = STRtree(geometries) distances = [] for i in sampled_indices: geom = geometries[i] if geom.is_empty: continue # ``exclusive=True`` skips the line itself, returning its closest # neighbor in the index. neighbor_index = tree.query_nearest(geom, exclusive=True)[0] center = geom.interpolate(0.5, normalized=True) distances.append(center.distance(geometries[neighbor_index])) return float(np.median(distances)) if distances else 0.0