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")