fix low level issues

This commit is contained in:
Davide Scaini
2026-03-31 23:22:12 +02:00
parent 8f91503cf7
commit 81438231b4
19 changed files with 126 additions and 44 deletions
+3 -2
View File
@@ -346,5 +346,6 @@ def _patch_duplicate_of(output_dir: Path, activity_id: str, canonical_id: str) -
data = json.loads(p.read_text())
data["duplicate_of"] = canonical_id
p.write_text(json.dumps(data, indent=2, ensure_ascii=False))
except Exception:
pass
except Exception as e:
import logging
logging.getLogger(__name__).warning("_patch_duplicate_of failed for %s: %s", activity_id, e)
+18 -8
View File
@@ -237,19 +237,29 @@ def _fastest_time_for_distance(speed_1hz: list[float], target_km: float) -> Opti
def _best_climb(ele_1hz: list[Optional[float]]) -> Optional[float]:
"""Maximum net elevation gain over any contiguous window (Kadane's on deltas).
Ignores samples where elevation is None. Returns None if fewer than two
valid elevation samples exist.
None samples are treated as breaks between segments — the Kadane window is
reset to 0 at each gap so non-contiguous elevation data is never joined.
Returns None if fewer than two non-None samples exist.
"""
valid = [e for e in ele_1hz if e is not None]
if len(valid) < 2:
non_null = sum(1 for e in ele_1hz if e is not None)
if non_null < 2:
return None
max_gain = 0.0
current = 0.0
for a, b in zip(valid, valid[1:]):
current = max(0.0, current + (b - a))
if current > max_gain:
max_gain = current
prev: Optional[float] = None
for e in ele_1hz:
if e is None:
# Gap — reset window so we don't bridge the discontinuity
current = 0.0
prev = None
continue
if prev is not None:
current = max(0.0, current + (e - prev))
if current > max_gain:
max_gain = current
prev = e
return round(max_gain, 1) if max_gain > 0 else None
+4 -4
View File
@@ -43,11 +43,11 @@ def preview_coords(
mask = rdp(coords, epsilon=0.001, return_mask=True)
reduced = [gps[i] for i, keep in enumerate(mask) if keep]
# Subsample if still too many
# Subsample if still too many — always include last point without exceeding max_points
if len(reduced) > max_points:
step = len(reduced) / max_points
reduced = [reduced[int(i * step)] for i in range(max_points)]
reduced.append(gps[-1]) # always include the last point
step = len(reduced) / (max_points - 1)
reduced = [reduced[int(i * step)] for i in range(max_points - 1)]
reduced.append(gps[-1])
return [[round(lat, 5), round(lon, 5)] for lat, lon in reduced]
+2 -2
View File
@@ -29,8 +29,8 @@ def build_timeseries(
t = int((p.timestamp - started_at).total_seconds())
if t < 0:
continue
if last_t is not None and t == last_t:
continue # skip sub-second duplicates
if last_t is not None and t <= last_t:
continue # skip sub-second duplicates and non-monotonic points
sampled.append(p)
last_t = t