diff --git a/src/app/automation.rs b/src/app/automation.rs index 6598a0652..b1dcaefbe 100644 --- a/src/app/automation.rs +++ b/src/app/automation.rs @@ -518,6 +518,29 @@ mod tests { assert!(app.tabs[i].active_cmd.is_none(), "command must have finished"); } + #[test] + fn rotate_by_typed_angle_after_center() { + // ROTATE: after picking the centre, typing the angle directly must + // rotate the selection (the reference point is optional, as the prompt + // says). Before the fix this did nothing and the command cancelled, so + // the objects never rotated. Regression for #159. + let mut app = OpenCADStudio::new_for_test(); + app.automation_op(r#"{"op":"new"}"#); + app.automation_op(r#"{"op":"run","cmd":"LINE 0,0 10,0"}"#); + app.automation_op(r#"{"op":"select","type":"Line"}"#); + // Centre (0,0) then 90° — no reference point. + app.automation_op(r#"{"op":"run","cmd":"ROTATE 0,0 90"}"#); + let q = app.automation_op(r#"{"op":"query","type":"Line"}"#); + assert_eq!(q["count"], 1, "the line must survive the rotate"); + let ex = q["entities"][0]["end"][0].as_f64().unwrap(); + let ey = q["entities"][0]["end"][1].as_f64().unwrap(); + // (10,0) rotated 90° about the origin → (0,10). + assert!( + ex.abs() < 1e-3 && (ey - 10.0).abs() < 1e-3, + "line end after ROTATE 90 = ({ex}, {ey})" + ); + } + #[test] fn save_then_open_round_trips() { let mut app = OpenCADStudio::new_for_test(); diff --git a/src/modules/draw/modify/rotate.rs b/src/modules/draw/modify/rotate.rs index 9898447d3..fbf772855 100644 --- a/src/modules/draw/modify/rotate.rs +++ b/src/modules/draw/modify/rotate.rs @@ -120,21 +120,26 @@ impl CadCommand for RotateCommand { } fn on_text_input(&mut self, text: &str) -> Option { - if let Step::Angle { center, .. } = &self.step { - // The value already carries the correct sign (the dynamic-input - // layer applies the cursor's side for a bare magnitude). - let deg: f32 = text.trim().replace(',', ".").parse().ok()?; - let center = *center; - defaults::set_rotate_angle(deg); - return Some(CmdResult::TransformSelected( - self.handles.clone(), - EntityTransform::Rotate { - center, - angle_rad: deg.to_radians(), - }, - )); - } - None + // A typed angle rotates directly about the centre. Accept it at the + // reference-point step too (the prompt offers "skip: type angle + // directly") — otherwise typing the angle there did nothing and the + // command cancelled on the next Enter, so the objects never rotated. + let center = match &self.step { + Step::RefPoint { center } => *center, + Step::Angle { center, .. } => *center, + Step::Center => return None, + }; + // The value already carries the correct sign (the dynamic-input + // layer applies the cursor's side for a bare magnitude). + let deg: f32 = text.trim().replace(',', ".").parse().ok()?; + defaults::set_rotate_angle(deg); + Some(CmdResult::TransformSelected( + self.handles.clone(), + EntityTransform::Rotate { + center, + angle_rad: deg.to_radians(), + }, + )) } fn on_preview_wires(&mut self, pt: DVec3) -> Vec {