4485cbf702
Split monolithic files into focused modules: - app/core: settings, logging, lifecycle - app/signaling: websocket server, ICE parser, message models - app/webrtc: peer session, video receiver, frame source - app/vision: pose landmarker wrapper, model config, pose types - app/exercises/dead_bug: detector, metrics, rules, state machine, types - app/rendering: skeleton renderer, status overlay, window display - app/audio: rep announcer - app/diagnostics: perf timer, crash handler - configs: environment-based settings - tests: unit tests for rules, state machine, ICE parser - run.py: entry point
25 lines
1014 B
Python
25 lines
1014 B
Python
from __future__ import annotations
|
|
|
|
from app.exercises.dead_bug.types import DeadBugMetrics, Point
|
|
|
|
|
|
def has_required_visibility(landmarks: list[Point], required_indices: tuple[int, ...], visibility_threshold: float) -> bool:
|
|
return all(landmarks[i].visibility >= visibility_threshold for i in required_indices)
|
|
|
|
|
|
def detect_diagonal_extension(metrics: DeadBugMetrics) -> str | None:
|
|
if metrics.left_leg_extended and metrics.right_leg_extended:
|
|
return None
|
|
|
|
if metrics.right_leg_extended and metrics.left_arm_extended:
|
|
return "left_arm_right_leg"
|
|
if metrics.left_leg_extended and metrics.right_arm_extended:
|
|
return "right_arm_left_leg"
|
|
return None
|
|
|
|
|
|
def is_ready_position(metrics: DeadBugMetrics) -> bool:
|
|
knees_bent = metrics.left_knee_angle <= 140 and metrics.right_knee_angle <= 140
|
|
legs_not_extended = not metrics.left_leg_extended and not metrics.right_leg_extended
|
|
return knees_bent and legs_not_extended and detect_diagonal_extension(metrics) is None
|