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