124 lines
4.1 KiB
Python
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")
|