From 84a0748f0b8854b34e334f975872fc009019859a Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Wed, 17 Sep 2025 15:05:12 +0200 Subject: [PATCH] Implement snapping functionality for tracking points in VideoEditor This commit enhances the VideoEditor class by adding a snapping feature that allows users to snap new tracking points to existing points from any frame within a 50px radius. The logic first checks for the removal of existing points before determining if a new point should be added or if it should snap to a nearby point. The specification has been updated to reflect this new snapping behavior, improving the precision of motion tracking. --- croppa/main.py | 24 ++++++++++++++++++++++-- croppa/spec.md | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/croppa/main.py b/croppa/main.py index 1c3d162..750ceba 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -2227,6 +2227,8 @@ class VideoEditor: rx, ry = self._map_screen_to_rotated(x, y) threshold = 50 removed = False + + # First check for removal of existing points on current frame if self.current_frame in self.tracking_points: pts_screen = [] for idx, (px, py) in enumerate(self.tracking_points[self.current_frame]): @@ -2240,9 +2242,27 @@ class VideoEditor: # self.show_feedback_message("Tracking point removed") removed = True break + + # If not removed, check for snapping to nearby points from other frames if not removed: - self.tracking_points.setdefault(self.current_frame, []).append((int(rx), int(ry))) - # self.show_feedback_message("Tracking point added") + snapped = False + # Check all tracking points from all frames for snapping + for frame_num, points in self.tracking_points.items(): + for (px, py) in points: + sxp, syp = self._map_rotated_to_screen(px, py) + if (sxp - x) ** 2 + (syp - y) ** 2 <= threshold ** 2: + # Snap to this existing point + self.tracking_points.setdefault(self.current_frame, []).append((int(px), int(py))) + snapped = True + break + if snapped: + break + + # If no snapping, add new point at clicked location + if not snapped: + self.tracking_points.setdefault(self.current_frame, []).append((int(rx), int(ry))) + # self.show_feedback_message("Tracking point added") + self.clear_transformation_cache() self.save_state() diff --git a/croppa/spec.md b/croppa/spec.md index dc6f7cb..a3152bd 100644 --- a/croppa/spec.md +++ b/croppa/spec.md @@ -58,6 +58,7 @@ Be careful to save and load settings when navigating this way ### Motion Tracking - **Right-click**: Add tracking point (green circle with white border) - **Right-click existing point**: Remove tracking point (within 50px) +- **Right-click near existing point**: Snap to existing point from any frame (within 50px radius) - **v**: Toggle motion tracking on/off - **V**: Clear all tracking points - **Blue cross**: Shows computed tracking position