Update the visualization for a given frame.
(self, frame_idx)
| 369 | self.fig.canvas.draw_idle() |
| 370 | |
| 371 | def update_frame(self, frame_idx): |
| 372 | """Update the visualization for a given frame.""" |
| 373 | self.current_frame = int(frame_idx) |
| 374 | frame = self.frames[self.current_frame] |
| 375 | |
| 376 | self.ax.clear() |
| 377 | |
| 378 | # Draw head frame |
| 379 | if frame.get("headMatrix"): |
| 380 | head_matrix = matrix_from_array(frame["headMatrix"]) |
| 381 | draw_coordinate_frame(self.ax, head_matrix, "Head", scale=0.1) |
| 382 | |
| 383 | # Draw camera if extrinsic calibration available |
| 384 | draw_camera_frame(self.ax, head_matrix, self.extrinsic) |
| 385 | else: |
| 386 | head_matrix = None |
| 387 | |
| 388 | # Set axis labels (native ARKit coordinates: X-right, Y-up, Z-backward) |
| 389 | self.ax.set_xlabel('X (m)') |
| 390 | self.ax.set_ylabel('Y (m)') |
| 391 | self.ax.set_zlabel('Z (m)') |
| 392 | |
| 393 | # Auto-scale based on data with equal aspect ratio |
| 394 | self._set_axis_limits(frame) |
| 395 | |
| 396 | # Set viewing angle |
| 397 | self.ax.view_init(elev=20, azim=self.azim) |
| 398 | |
| 399 | # Title with frame info |
| 400 | timestamp = frame.get("timestamp", 0) |
| 401 | self.ax.set_title(f'Frame {self.current_frame + 1}/{len(self.frames)} | Time: {timestamp:.2f}s | ' |
| 402 | f'Head: {"✓" if frame.get("headMatrix") else "✗"}') |
| 403 | |
| 404 | self.ax.legend(loc='upper left', fontsize=8) |
| 405 | self.fig.canvas.draw_idle() |
| 406 | |
| 407 | def _set_axis_limits(self, frame): |
| 408 | """Set axis limits centered on head with fixed range to see cameras.""" |
no test coverage detected