147 lines
4.8 KiB
Python
147 lines
4.8 KiB
Python
|
|
import sys
|
|
import os
|
|
import math
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
import logging
|
|
|
|
sys.path.append('/app/backend')
|
|
|
|
from src.services.discovery import SegmentDiscoveryService
|
|
from src.models.activity import Activity
|
|
from src.utils.geo import calculate_bearing, haversine_distance
|
|
from src.services.parsers import extract_activity_data
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
def trace_activity(activity_id):
|
|
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:password@localhost:5433/fitbit_garmin_sync")
|
|
|
|
engine = create_engine(DATABASE_URL)
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
db = SessionLocal()
|
|
|
|
# 1. Fetch Activity
|
|
act = db.query(Activity).filter(Activity.garmin_activity_id == str(activity_id)).first()
|
|
if not act:
|
|
print(f"Activity {activity_id} NOT FOUND.")
|
|
return
|
|
|
|
print(f"Tracing Activity {act.id} ({act.garmin_activity_id})")
|
|
|
|
# 2. Extract Data
|
|
# Parser returns a dict: {'points': [], 'timestamps': [], ...}
|
|
result = extract_activity_data(act.file_content, act.file_type)
|
|
points = result['points']
|
|
timestamps = result['timestamps']
|
|
|
|
# Filter points (same logic as service)
|
|
clean_points = []
|
|
clean_ts = []
|
|
for i in range(len(points)):
|
|
if points[i][0] is not None and points[i][1] is not None:
|
|
clean_points.append(points[i])
|
|
clean_ts.append(timestamps[i])
|
|
|
|
print(f"Clean points: {len(clean_points)}")
|
|
|
|
# 3. Simulate Analysis Loop
|
|
current_segment = [clean_points[0]]
|
|
last_bearing = None
|
|
|
|
segments_found = 0
|
|
|
|
skipped_dist = 0
|
|
max_dist = 0
|
|
max_time_diff = 0
|
|
max_bearing_diff = 0
|
|
|
|
for i in range(1, len(clean_points)):
|
|
p1 = clean_points[i-1]
|
|
p2 = clean_points[i]
|
|
|
|
# dist
|
|
dist = haversine_distance(p1[1], p1[0], p2[1], p2[0])
|
|
max_dist = max(max_dist, dist)
|
|
|
|
if dist < 2.0:
|
|
skipped_dist += 1
|
|
continue
|
|
|
|
bearing = calculate_bearing(p1[1], p1[0], p2[1], p2[0])
|
|
|
|
is_turn = False
|
|
diff = 0
|
|
if last_bearing is not None:
|
|
diff = abs(bearing - last_bearing)
|
|
if diff > 180: diff = 360 - diff
|
|
max_bearing_diff = max(max_bearing_diff, diff)
|
|
|
|
if diff > 60:
|
|
is_turn = True
|
|
print(f"TURN DETECTED at index {i}: Bearing {last_bearing:.1f} -> {bearing:.1f} (Diff: {diff:.1f})")
|
|
elif diff > 10: # Log even smaller turns to see noise
|
|
print(f" Minor Turn at index {i}: Bearing {last_bearing:.1f} -> {bearing:.1f} (Diff: {diff:.1f})")
|
|
|
|
last_bearing = bearing
|
|
|
|
t1 = clean_ts[i-1]
|
|
t2 = clean_ts[i]
|
|
time_diff = (t2 - t1).total_seconds()
|
|
max_time_diff = max(max_time_diff, time_diff)
|
|
|
|
is_pause = time_diff > 10
|
|
if is_pause:
|
|
print(f"PAUSE DETECTED at index {i}: {time_diff}s")
|
|
|
|
if is_pause or is_turn:
|
|
if len(current_segment) > 10:
|
|
segments_found += 1
|
|
print(f" -> Segment Created (Points: {len(current_segment)})")
|
|
|
|
current_segment = [p2]
|
|
else:
|
|
current_segment.append(p2)
|
|
|
|
print(f"\nStats:")
|
|
print(f" Total Points: {len(clean_points)}")
|
|
print(f" Skipped (dist < 5m): {skipped_dist}")
|
|
print(f" Max Point-to-Point Dist: {max_dist:.2f}m")
|
|
print(f" Max Time Diff: {max_time_diff}s")
|
|
print(f" Max Bearing Diff: {max_bearing_diff:.1f}")
|
|
print(f" Segments Found (from splits): {segments_found}")
|
|
|
|
from src.utils.geo import ramer_douglas_peucker
|
|
|
|
for eps in [2.0, 5.0, 10.0, 15.0]:
|
|
print(f"\n--- Riper RDP Trace (epsilon={eps}m) ---")
|
|
simplified = ramer_douglas_peucker(clean_points, eps)
|
|
print(f"Simplified points: {len(simplified)} (from {len(clean_points)})")
|
|
|
|
last_bearing = None
|
|
turns_found = 0
|
|
|
|
for i in range(1, len(simplified)):
|
|
p1 = simplified[i-1]
|
|
p2 = simplified[i]
|
|
|
|
bearing = calculate_bearing(p1[1], p1[0], p2[1], p2[0])
|
|
|
|
if last_bearing is not None:
|
|
diff = abs(bearing - last_bearing)
|
|
if diff > 180: diff = 360 - diff
|
|
|
|
if diff > 60:
|
|
print(f"TURN: {last_bearing:.1f} -> {bearing:.1f} (Diff: {diff:.1f})")
|
|
turns_found += 1
|
|
elif diff > 45:
|
|
print(f" Minor Turn (>45): {last_bearing:.1f} -> {bearing:.1f} (Diff: {diff:.1f})")
|
|
|
|
last_bearing = bearing
|
|
|
|
print(f"Total Turns > 60: {turns_found}")
|
|
|
|
if __name__ == "__main__":
|
|
trace_activity(21465710074)
|