diff --git a/data_only_viz/iphone_usb_source.py b/data_only_viz/iphone_usb_source.py index 4351d60..0cecdb8 100644 --- a/data_only_viz/iphone_usb_source.py +++ b/data_only_viz/iphone_usb_source.py @@ -114,6 +114,9 @@ class IphoneUSBSource: return self._opened def _run(self, sock) -> None: + if self.state is not None: + with self.state.lock(): + self.state.mirror_2d = self._mirror while not self._stop.is_set(): if sock is None: # no connection yet (startup or post-drop) sock = self._reconnect() diff --git a/data_only_viz/renderer.py b/data_only_viz/renderer.py index 3e623ef..ca2906c 100644 --- a/data_only_viz/renderer.py +++ b/data_only_viz/renderer.py @@ -327,6 +327,9 @@ class MetalRenderer(NSObject): buf = self._skel_cpu_buf segs = 0 + # Mirror overlays in X to match the (already mirrored) iPhone video + # background. Display-only: gesture data is untouched. + mirror = bool(getattr(s, "mirror_2d", False)) def push(A, B, conf, pid): """Empile un segment (2 verts) dans le buffer CPU prealloque.""" @@ -335,6 +338,8 @@ class MetalRenderer(NSObject): return False ax = A.x * 2.0 - 1.0; ay = 1.0 - A.y * 2.0 bx = B.x * 2.0 - 1.0; by = 1.0 - B.y * 2.0 + if mirror: + ax = -ax; bx = -bx i = segs * 10 buf[i+0] = ax; buf[i+1] = ay; buf[i+2] = float(A.z); buf[i+3] = conf; buf[i+4] = float(pid) buf[i+5] = bx; buf[i+6] = by; buf[i+7] = float(B.z); buf[i+8] = conf; buf[i+9] = float(pid) @@ -348,6 +353,8 @@ class MetalRenderer(NSObject): return False cax = ax * 2.0 - 1.0; cay = 1.0 - ay * 2.0 cbx = bx * 2.0 - 1.0; cby = 1.0 - by * 2.0 + if mirror: + cax = -cax; cbx = -cbx i = segs * 10 buf[i+0] = cax; buf[i+1] = cay; buf[i+2] = 0.0 buf[i+3] = conf; buf[i+4] = float(pid) diff --git a/data_only_viz/state.py b/data_only_viz/state.py index d2f730b..0cb6bfa 100644 --- a/data_only_viz/state.py +++ b/data_only_viz/state.py @@ -151,6 +151,8 @@ class State: persons_arkit_2d_valid: dict = field(default_factory=dict) arkit_joint_names: list = field(default_factory=list) arkit_parents: list = field(default_factory=list) + # iPhone video is mirrored (CONCERT_MIRROR); renderer mirrors overlays to match. + mirror_2d: bool = False # ---- LiDAR / ICP mesh fusion (Task 8 - 2026-05-14) ---- # Set by the LidarTCPReader poller; consumed by FusionWorker.run_once.