Files
FitTrack2/FitnessSync/scratch/debug_segment_match.py
2026-01-09 12:10:58 -08:00

124 lines
4.1 KiB
Python

import sys
import os
import json
import logging
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# Add backend to path
sys.path.append(os.path.join(os.getcwd(), 'backend'))
from src.models.activity import Activity
from src.models.segment import Segment
from src.utils.geo import haversine_distance, perpendicular_distance
from src.services.segment_matcher import SegmentMatcher
from src.utils.config import config
# Setup DB
engine = create_engine(config.DATABASE_URL)
Session = sessionmaker(bind=engine)
db = Session()
# Helpers
def _min_dist_to_segment_path(point, seg_points):
min_d = float('inf')
for i in range(len(seg_points) - 1):
d = perpendicular_distance(point, seg_points[i], seg_points[i+1])
if d < min_d:
min_d = d
return min_d
def debug_match(activity_garmin_id, segment_name):
print(f"\n--- Debugging Match: Activity {activity_garmin_id} vs Segment {segment_name} ---")
activity = db.query(Activity).filter(Activity.garmin_activity_id == activity_garmin_id).first()
if not activity:
print("Activity not found")
return
segment = db.query(Segment).filter(Segment.name == segment_name).first()
if not segment:
print(f"Segment {segment_name} not found")
return
# Load points
from src.services.parsers import extract_points_from_file
act_points = extract_points_from_file(activity.file_content, activity.file_type)
seg_points = json.loads(segment.points) if isinstance(segment.points, str) else segment.points
print(f"Activity Points: {len(act_points)}")
print(f"Segment Points: {len(seg_points)}")
print(f"Segment DB Distance: {segment.distance:.2f}m")
# Parameters
ENTRY_RADIUS = 25.0
CORRIDOR_RADIUS = 35.0
start_node = seg_points[0]
end_node = seg_points[-1]
# 1. Find all start candidates
start_candidates = []
for i, p in enumerate(act_points):
dist = haversine_distance(p[1], p[0], start_node[1], start_node[0])
if dist <= ENTRY_RADIUS:
start_candidates.append(i)
print(f"Found {len(start_candidates)} candidates for Start.")
for idx in start_candidates:
print(f" Candidate Index: {idx}")
if not start_candidates:
print("No matches expected (No start found).")
return
# 2. Trace each candidate
match_found = False
for start_idx in start_candidates:
print(f"\n--- Tracing Candidate {start_idx} ---")
if _trace(start_idx, act_points, seg_points, segment.distance, end_node, ENTRY_RADIUS, CORRIDOR_RADIUS):
print("MATCH SUCCESS FOUND!")
match_found = True
break
else:
print("Candidate failed.")
if not match_found:
print("\nAll candidates failed.")
def _trace(start_idx, act_points, seg_points, seg_dist, end_node, ENTRY_RADIUS, CORRIDOR_RADIUS):
effort_accum_dist = 0.0
for j in range(start_idx, len(act_points)):
p = act_points[j]
# Accumulate dist
if j > start_idx:
prev = act_points[j-1]
effort_accum_dist += haversine_distance(p[1], p[0], prev[1], prev[0])
d_path = _min_dist_to_segment_path(p, seg_points)
d_end = haversine_distance(p[1], p[0], end_node[1], end_node[0])
status = "OK"
if d_path > CORRIDOR_RADIUS:
print(f" Idx {j} (Accum {effort_accum_dist:.1f}m): DEVIATED (DistPath={d_path:.2f}m)")
return False
if d_end <= ENTRY_RADIUS:
if effort_accum_dist >= 0.8 * seg_dist:
print(f" Idx {j} (Accum {effort_accum_dist:.1f}m): FINISHED! (Valid Distance)")
return True
else:
status = f"NEAR_END (Short: {effort_accum_dist:.1f}/{seg_dist:.1f}m)"
# Logging
if (j - start_idx) % 100 == 0 or status != "OK":
print(f" Idx {j}: Path={d_path:.1f}m End={d_end:.1f}m Accum={effort_accum_dist:.0f}m -> {status}")
print(" End of activity stream reached.")
return False
if __name__ == "__main__":
debug_match("21249259141", "Climb1")