diff --git a/croppa/main.py b/croppa/main.py index 066700d..3f6fb00 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -1142,15 +1142,28 @@ class VideoEditor: # --- Motion tracking helpers --- def _get_effective_crop_rect_for_frame(self, frame_number): - """Return crop_rect in ROTATED frame coordinates for this frame.""" - # When cropping after rotation, the crop_rect is directly in rotated frame coords - # so no translation is needed for mapping overlays. + """Return EFFECTIVE crop_rect in ROTATED frame coords for this frame (applies tracking follow).""" + # Rotated base dims + if self.rotation_angle in (90, 270): + rot_w, rot_h = self.frame_height, self.frame_width + else: + rot_w, rot_h = self.frame_width, self.frame_height + # Default full-frame if not self.crop_rect: - # Compute rotated dimensions of the full frame - if self.rotation_angle in (90, 270): - return (0, 0, self.frame_height, self.frame_width) - return (0, 0, self.frame_width, self.frame_height) + return (0, 0, rot_w, rot_h) x, y, w, h = map(int, self.crop_rect) + # Tracking follow: center crop on interpolated rotated position + if self.tracking_enabled: + pos = self._get_interpolated_tracking_position(frame_number) + if pos: + cx, cy = pos + x = int(round(cx - w / 2)) + y = int(round(cy - h / 2)) + # Clamp in rotated space + x = max(0, min(x, rot_w - 1)) + y = max(0, min(y, rot_h - 1)) + w = min(w, rot_w - x) + h = min(h, rot_h - y) return (x, y, w, h) def _get_interpolated_tracking_position(self, frame_number): @@ -1299,7 +1312,7 @@ class VideoEditor: def _map_rotated_to_screen(self, rx, ry): """Map a point in ROTATED frame coords to canvas screen coords (post-crop).""" - # Subtract crop offset in rotated space + # Subtract crop offset in rotated space (use current EFFECTIVE crop) cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(getattr(self, 'current_frame', 0)) rx2 = rx - cx ry2 = ry - cy @@ -1365,7 +1378,7 @@ class VideoEditor: # Reverse zoom rx = zx / max(1e-6, self.zoom_factor) ry = zy / max(1e-6, self.zoom_factor) - # Unapply current crop to get PRE-crop rotated coords + # Unapply current EFFECTIVE crop to get PRE-crop rotated coords cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(frame_number) rx = rx + cx ry = ry + cy