From 15434d87acbed5ee4c3c85a7f335c0d19e728f6f Mon Sep 17 00:00:00 2001 From: chordpli Date: Tue, 20 Oct 2026 09:02:38 +0900 Subject: [PATCH] LR-CROP-RECT: a too-small crop's corner drag reaches the minimum size (#2308) The free-corner solve clamped its minimum-size bounds to zero, so a crop already under the minimum stayed under it when a corner was dragged out a little (2 px grew to 4 px where 8 px is the minimum). Keep the bounds as given: the solve then grows it to the minimum, as the unrotated path does, and falls back to that path when the minimum doesn't fit. --- crates/geom/src/crop_drag.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/geom/src/crop_drag.rs b/crates/geom/src/crop_drag.rs index 983ed2c34..01944d6ce 100644 --- a/crates/geom/src/crop_drag.rs +++ b/crates/geom/src/crop_drag.rs @@ -236,7 +236,7 @@ fn nearest_offset(points: &[(Point, Vec2)], extra: &[(Vec2, f64)], angle: f64, w planes.push((n, b.max(0.0) + s)); } } - planes.extend(extra.iter().map(|(n, b)| (*n, b.max(0.0)))); + planes.extend_from_slice(extra); if planes.iter().all(|(n, b)| n.dot(want) <= *b) { return Some(want); } @@ -707,6 +707,15 @@ mod tests { } } + // Scenario: a free corner of a crop under the minimum size on a straightened photo + #[test] + fn given_straightened_photo_when_a_corner_of_a_too_small_crop_is_dragged_then_it_reaches_the_minimum() { + let start = CropGeometry { rect: Rect::new(0.3, 0.3, 0.3 + 2.0 / W, 0.6), angle: 6.0 }; + let g = drag(start, BottomRight, p(start.rect.x1, 0.6), p(start.rect.x1 + 2.0 / W, 0.62), None); + assert!(g.rect.width() * W >= MIN_CROP_FRACTION * H - EPS, "{:?}", g.rect); + assert!(g.is_within_image(W, H) && near(g.rect.x0, 0.3) && near(g.rect.y0, 0.3), "{:?}", g.rect); + } + // Scenario: a free corner moved inside, or across its anchor, on a straightened photo #[test] fn given_straightened_photo_when_a_free_corner_moves_inside_then_it_follows_and_keeps_a_minimum_size() {