Fix/Unfix on every sketch entity: points (Fix constraint) and lines, arcs, circles, ellipses, splines and conics (fixed curves hold their points and radius); ConstraintFix takes entities (fixes them all unless all are fixed); the toolbar button and the context menu act on the whole selection; fixed points never move when dragged or solved; projected geometry counts as fixed; fixed geometry is drawn green; sketch.inspect reports fixed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 05:12:13 +00:00
1 parent b457b6b7b6
commit 5b8816aa7d
11 files changed
+252 -35

No files matched your search

+9 -1
View File
@@ -407,7 +407,15 @@ impl Sketch {
}
};
let cid = self.fresh(prefix);
self.curves.push(Curve { id: cid, kind, construction: false, reversed: false, link: Some(id.to_string()), centerline: false });
self.curves.push(Curve {
id: cid,
kind,
construction: false,
reversed: false,
link: Some(id.to_string()),
centerline: false,
fixed: false,
});
}
for li in &lay.lone {
point(self, *li)?;
+65 -4
View File
@@ -140,6 +140,9 @@ pub struct Curve {
/// an axis (revolve, diameter dimensions).
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub centerline: bool,
/// Fixed (locked): its points and radius are constants for the solver.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub fixed: bool,
}
/// Geometric constraints and dimensions. Indices refer to `Sketch::points` (`p`, `q`) or
@@ -536,7 +539,15 @@ impl Sketch {
return Err(SketchError::Invalid("line needs two distinct points".into()));
}
let id = self.curve_id(id, "l")?;
self.curves.push(Curve { id, kind: CurveKind::Line { a, b }, construction: false, reversed: false, link: None, centerline: false });
self.curves.push(Curve {
id,
kind: CurveKind::Line { a, b },
construction: false,
reversed: false,
link: None,
centerline: false,
fixed: false,
});
Ok(self.curves.len() - 1)
}
@@ -565,7 +576,15 @@ impl Sketch {
Some(i) if i < self.points.len() => i,
_ => self.own_point(&id, "center", center)?,
};
self.curves.push(Curve { id, kind: CurveKind::Circle { c, r }, construction: false, reversed: false, link: None, centerline: false });
self.curves.push(Curve {
id,
kind: CurveKind::Circle { c, r },
construction: false,
reversed: false,
link: None,
centerline: false,
fixed: false,
});
Ok(self.curves.len() - 1)
}
@@ -591,7 +610,15 @@ impl Sketch {
Some(i) if i < n && i != a => i,
_ => self.own_point(&id, "end", p1)?,
};
self.curves.push(Curve { id, kind: CurveKind::Arc { c, a, b }, construction: false, reversed: false, link: None, centerline: false });
self.curves.push(Curve {
id,
kind: CurveKind::Arc { c, a, b },
construction: false,
reversed: false,
link: None,
centerline: false,
fixed: false,
});
Ok(self.curves.len() - 1)
}
@@ -680,6 +707,40 @@ impl Sketch {
Ok(())
}
/// Is point `i` held in place: fixed, projected (linked), fixed by a Fix constraint or a
/// point of a fixed curve.
pub fn point_locked(&self, i: usize) -> bool {
self.points.get(i).is_some_and(|p| p.fixed || p.link.is_some())
|| self.constraints.iter().any(|c| c.kind == ConstraintKind::Fix { p: i })
|| self.curves.iter().any(|c| c.fixed && c.kind.uses(i))
}
/// [`Sketch::point_locked`] for every point at once.
pub fn locked_points(&self) -> Vec<bool> {
let mut out: Vec<bool> = self.points.iter().map(|p| p.fixed || p.link.is_some()).collect();
let mut set = |i: usize| {
if let Some(x) = out.get_mut(i) {
*x = true;
}
};
for c in &self.constraints {
if let ConstraintKind::Fix { p } = c.kind {
set(p);
}
}
for c in self.curves.iter().filter(|c| c.fixed) {
for p in c.kind.point_ids() {
set(p);
}
}
out
}
/// Is curve `c` held in place: fixed or projected (linked).
pub fn curve_locked(&self, c: usize) -> bool {
self.curves.get(c).is_some_and(|c| c.fixed || c.link.is_some())
}
/// Radius of a circle or arc.
pub fn radius(&self, ci: usize) -> Option<f64> {
match self.curves.get(ci)?.kind {
@@ -834,7 +895,7 @@ impl Sketch {
}
};
let id = self.curve_id(id, prefix)?;
self.curves.push(Curve { id, kind, construction: false, reversed: false, link: None, centerline: false });
self.curves.push(Curve { id, kind, construction: false, reversed: false, link: None, centerline: false, fixed: false });
Ok(self.curves.len() - 1)
}
+8 -1
View File
@@ -70,6 +70,13 @@ fn layout(sk: &Sketch) -> Layout {
*f = true;
}
}
for c in sk.curves.iter().filter(|c| c.fixed) {
for p in c.kind.point_ids() {
if let Some(f) = fixed.get_mut(p) {
*f = true;
}
}
}
let mut n = 0;
let pvar = fixed
.iter()
@@ -86,7 +93,7 @@ fn layout(sk: &Sketch) -> Layout {
.curves
.iter()
.map(|c| match c.kind {
CurveKind::Circle { .. } | CurveKind::Ellipse { .. } if c.link.is_none() => {
CurveKind::Circle { .. } | CurveKind::Ellipse { .. } if c.link.is_none() && !c.fixed => {
n += 1;
Some(n - 1)
}