From da4aa413c69cfd30eeea70cc7162c582290f3e42 Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Sat, 10 Oct 2026 20:36:27 +0200 Subject: [PATCH] Reject two-line angular constraints over 180 degrees that can never be satisfied (#73) (#190) --- crates/constraints/src/residual.rs | 5 ++++- crates/constraints/src/tests.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/constraints/src/residual.rs b/crates/constraints/src/residual.rs index eb2131a6..fa6b4703 100644 --- a/crates/constraints/src/residual.rs +++ b/crates/constraints/src/residual.rs @@ -244,7 +244,10 @@ impl Built { return need("two lines or an arc"); } b.target = target.to_radians(); - if !b.target.is_finite() || b.target.abs() > std::f64::consts::TAU { + // Two lines measure a signed angle in [-180, 180] and the sign is re-read from the geometry, so a larger + // target would flip the sign once solved and never be satisfied; only an arc sweep can reach a full turn. + let max = if b.form == Form::LL { std::f64::consts::PI } else { std::f64::consts::TAU }; + if !b.target.is_finite() || b.target.abs() > max { return Err("angle out of range".into()); } } diff --git a/crates/constraints/src/tests.rs b/crates/constraints/src/tests.rs index 4924c46a..ece0146e 100644 --- a/crates/constraints/src/tests.rs +++ b/crates/constraints/src/tests.rs @@ -155,6 +155,19 @@ fn symmetric_fix() { ok(&mut d, con(ConstraintKind::Symmetric, &[w(p), w(q), w(axis)])); } +#[test] +fn two_line_angle_over_180_is_rejected() { + let mut d = Drawing::default(); + let a = line(&mut d, (0.0, 0.0), (10.0, 0.0)); + let b = line(&mut d, (0.0, 0.0), (0.0, 5.0)); + let before = (ln(&d, a), ln(&d, b)); + assert!(add(&mut d, dim(ConstraintKind::Angular, &[w(a), w(b)], "", "200"), &SolveOptions::default()).is_err()); + assert!(d.constraints.is_empty()); + assert_eq!((ln(&d, a), ln(&d, b)), before); + ok(&mut d, dim(ConstraintKind::Angular, &[w(a), w(b)], "", "180")); + assert!(all_satisfied(&d)); +} + #[test] fn dimensional_constraints() { let mut d = Drawing::default();