An angle dimension between two lines takes the reading nearest its value and reports degrees: without text_at the angle was measured between the lines' directions, so a riser pointing up and an outlet pointing down-left (meeting at 30°, directions 150° apart) asked for 30° swung the outlet round by 120°, which the fillets between them could not follow, and the dimension was refused as over-constraining with a degree of freedom left. Two lines make two angles, θ and 180° − θ; the dimension now takes the one nearer the value (the acute one without a value), and text_at still picks a sector. sketch.dimension reports measured in the dimension's unit (deg for angles, mm for lengths) with a unit field, instead of radians for angles
This commit is contained in:
1 parent
81be4e74b8
commit
90ce5261b3
2 files changed
+90
-9
No files matched your search
@@ -1,7 +1,7 @@
|
||||
//! Sketch commands: create/edit/finish sketches, draw curves, constraints and dimensions.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use solvecraft_doc::{FeatureKind, PlaneRef};
|
||||
use solvecraft_doc::{FeatureKind, PlaneRef, expr::Kind};
|
||||
use solvecraft_geom::{Plane, Vec2, Vec3};
|
||||
use solvecraft_sketch::{ConstraintKind, CurveKind, Hold, Sketch, SolveReport, solve, solve_holding};
|
||||
|
||||
@@ -94,7 +94,7 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
.params(concat!("p0, p1: overall ends, width", connect_doc!())),
|
||||
CommandSpec::new("sketch.point", "Point", draw_point).at("SKETCH", "CREATE").icon("point").enabled(in_sketch).params(concat!("point: [x,y], id?", connect_doc!())),
|
||||
CommandSpec::new("sketch.dimension", "Sketch Dimension", dimension).at("SKETCH", "CREATE").icon("dimension").key("D").enabled(in_sketch).params(
|
||||
"entities: [refs], type?: auto|distance|horizontal|vertical|length|radius|diameter|angle, value?: number or expression (default: current)",
|
||||
"entities: [refs], type?: auto|distance|horizontal|vertical|length|radius|diameter|angle, value?: number or expression (default: current); text_at?: [x, y]. Two lines: the angle between them (acute, or 180° − it when the value is nearer that) unless text_at picks a sector. Returns measured in unit (mm or deg)",
|
||||
),
|
||||
CommandSpec::new("sketch.constraint.horizontal_vertical", "Horizontal/Vertical", c_horizontal_vertical)
|
||||
.at("SKETCH", "CONSTRAINTS")
|
||||
@@ -1332,7 +1332,9 @@ fn dimension(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
};
|
||||
let is_line = |c: usize| matches!(sk.curves.get(c).map(|c| &c.kind), Some(CurveKind::Line { .. }));
|
||||
let is_circle = |c: usize| matches!(sk.curves.get(c).map(|c| &c.kind), Some(CurveKind::Circle { .. }));
|
||||
let (k, cur): (ConstraintKind, f64) = match (e0, e1) {
|
||||
// The other reading of an angle between two lines (see below).
|
||||
let mut alt: Option<(ConstraintKind, f64)> = None;
|
||||
let (mut k, mut cur): (ConstraintKind, f64) = match (e0, e1) {
|
||||
((None, Some(c)), None) if is_line(c) => {
|
||||
let (a, b) = line_pts(sk, c).unwrap_or_default();
|
||||
match ty.as_str() {
|
||||
@@ -1409,7 +1411,14 @@ fn dimension(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
ang = -ang;
|
||||
std::mem::swap(&mut ka, &mut kb);
|
||||
}
|
||||
(ConstraintKind::Angle { a: ka, b: kb, value: ang, flip: false }, ang)
|
||||
// Two lines make two angles, θ and 180° − θ, whichever way they were
|
||||
// drawn: the acute one unless the value asks for the other.
|
||||
let direct = (ConstraintKind::Angle { a: ka, b: kb, value: ang, flip: false }, ang);
|
||||
let supplement =
|
||||
(ConstraintKind::Angle { a: kb, b: ka, value: std::f64::consts::PI - ang, flip: true }, std::f64::consts::PI - ang);
|
||||
let (acute, obtuse) = if ang <= std::f64::consts::FRAC_PI_2 { (direct, supplement) } else { (supplement, direct) };
|
||||
alt = Some(obtuse);
|
||||
acute
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1426,7 +1435,7 @@ fn dimension(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
c.driven = true;
|
||||
}
|
||||
before = None;
|
||||
return Ok((String::new(), name, cur));
|
||||
return Ok((String::new(), name, measured(is_angle, cur)));
|
||||
}
|
||||
let (unit, default_expr) =
|
||||
if is_angle { ("deg", format!("{} deg", round6(cur.to_degrees()))) } else { ("mm", format!("{} mm", round6(cur))) };
|
||||
@@ -1437,20 +1446,30 @@ fn dimension(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(err) = errs.get(&pname) {
|
||||
return Err(bad(cmd, format!("value: {err}")));
|
||||
}
|
||||
let _ = vals;
|
||||
// An angle between two lines dimensions whichever of its two readings is nearer the value.
|
||||
if let (Some((ka, ca)), Some(want)) = (alt, vals.get(&pname).and_then(|v| v.to_kind(Kind::Angle).ok()))
|
||||
&& (want - ca).abs() < (want - cur).abs()
|
||||
{
|
||||
(k, cur) = (ka, ca);
|
||||
}
|
||||
let name = k.name();
|
||||
let id = sk.add_constraint(k, Some(pname.clone()))?;
|
||||
place_text(sk, &id, text_at);
|
||||
Ok((pname, name, cur))
|
||||
Ok((pname, name, measured(is_angle, cur)))
|
||||
})?;
|
||||
if driven {
|
||||
return Ok(json!({"param": Value::Null, "driven": true, "type": kind_name, "measured": current, "sketch": info}));
|
||||
return Ok(json!({"param": Value::Null, "driven": true, "type": kind_name, "measured": current.0, "unit": current.1, "sketch": info}));
|
||||
}
|
||||
if reject_redundant(before, &info, cmd).is_err() {
|
||||
return Err(bad(cmd, "that dimension would over-constrain the sketch; add it as a driven (reference) dimension with driven: true"));
|
||||
}
|
||||
let v = s.doc.param(¶m).map(|p| p.expr.clone()).unwrap_or_default();
|
||||
Ok(json!({"param": param, "type": kind_name, "expression": v, "measured": current, "sketch": info}))
|
||||
Ok(json!({"param": param, "type": kind_name, "expression": v, "measured": current.0, "unit": current.1, "sketch": info}))
|
||||
}
|
||||
|
||||
/// A dimension's measured value as reported, in the unit its expression is written in.
|
||||
fn measured(is_angle: bool, v: f64) -> (f64, &'static str) {
|
||||
if is_angle { (round6(v.to_degrees()), "deg") } else { (round6(v), "mm") }
|
||||
}
|
||||
|
||||
/// Keep a dimension's text where it was placed (`at`, sketch coordinates), relative to the
|
||||
|
||||
Reference in new issue
Block a user