forked from 1b-agent/opencadstudio-upstream
fix(rotate): apply a typed angle right after the centre (#159)
ROTATE's reference-point step prompts "or skip: type angle directly", but on_text_input only handled the later Angle step. So picking a centre and typing the angle did nothing, and the next Enter cancelled the command — the objects never rotated, which reads as the rotate "erasing" / losing them. Accept a typed angle at the reference-point step too, rotating directly about the centre (the reference point stays optional). Added an automation regression test that rotates a line 90° with centre + angle only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
c599c2ba09
commit
1a78e6c7ff
2 files changed
+43
-15
No files matched your search
@@ -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();
|
||||
|
||||
@@ -120,21 +120,26 @@ impl CadCommand for RotateCommand {
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
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<WireModel> {
|
||||
|
||||
Reference in new issue
Block a user