Fix modelling regressions and reconcile WIP UI work

This commit is contained in:
bherbruck committed 2026-10-10 15:37:00 -04:00
1 parent 49bd89de13
commit d6cdec40da
67 files changed
+1793 -260

No files matched your search

+45 -3
View File
@@ -2691,11 +2691,50 @@ pub(crate) fn profile_indices(ss: &solvecraft_engine::doc::SolvedSketch, sel: &P
}
}
thread_local! {
/// A dialog is being filled from a feature: its points are in component frames.
static REFILL: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
/// While filling a dialog from a feature (dropped at the end).
struct Refill;
impl Refill {
fn start() -> Refill {
REFILL.with(|r| r.set(true));
Refill
}
}
impl Drop for Refill {
fn drop(&mut self) {
REFILL.with(|r| r.set(false));
}
}
/// A point stored in a feature, as it shows on world body `body`: features keep their picks in
/// the frame of the body they were on, so each body's placement takes the point to the world
/// (a moved component, a pasted instance). Other points are the world already.
fn stored_on(frames: &Option<Vec<(String, solvecraft_engine::doc::Mat)>>, body: &str, p: Vec3) -> Vec3 {
frames.as_ref().and_then(|f| f.iter().find(|(n, _)| n == body)).map(|(_, m)| solvecraft_engine::doc::apply_point(m, p)).unwrap_or(p)
}
/// Body placements while filling a dialog from a feature (when anything is placed).
fn stored_frames(s: &Session) -> Option<Vec<(String, solvecraft_engine::doc::Mat)>> {
if !REFILL.with(std::cell::Cell::get) || !solvecraft_engine::frames::placed(s) {
return None;
}
let st = s.model.state();
Some(s.doc.body_frames(&st).into_iter().map(|(w, _, _, m)| (w, m)).collect())
}
/// The edge of a visible body through (or nearest) a point.
pub(crate) fn edge_sel(s: &Session, p: Vec3) -> Option<Sel> {
pub(crate) fn edge_sel(s: &Session, p0: Vec3) -> Option<Sel> {
let st = s.world_state();
let frames = stored_frames(s);
let mut best: Option<(f64, Sel)> = None;
for b in &st.bodies {
let p = stored_on(&frames, &b.name, p0);
let m = b.mesh();
for (i, e) in m.edges.iter().enumerate() {
let d = e.windows(2).map(|w| p.dist_to_segment(w[0], w[1])).fold(f64::INFINITY, f64::min);
@@ -2708,10 +2747,12 @@ pub(crate) fn edge_sel(s: &Session, p: Vec3) -> Option<Sel> {
}
/// The body face containing a point (nearest triangle).
pub(crate) fn face_sel(s: &Session, p: Vec3) -> Option<Sel> {
pub(crate) fn face_sel(s: &Session, p0: Vec3) -> Option<Sel> {
let st = s.world_state();
let frames = stored_frames(s);
let mut best: Option<(f64, Sel)> = None;
for b in &st.bodies {
let p = stored_on(&frames, &b.name, p0);
let m = b.mesh();
for (t, f) in m.triangles.iter().zip(&m.tri_face) {
let Some([a, bb, c]) = m.tri(t) else { continue };
@@ -2721,7 +2762,7 @@ pub(crate) fn face_sel(s: &Session, p: Vec3) -> Option<Sel> {
}
}
}
best.filter(|(d, _)| *d < 1e-3 + 1e-6 * p.len()).map(|x| x.1)
best.filter(|(d, _)| *d < 1e-3 + 1e-6 * p0.len()).map(|x| x.1)
}
pub(crate) fn plane_sel(s: &Session, pl: &PlaneRef) -> Option<Sel> {
@@ -2756,6 +2797,7 @@ fn pt3(v: Vec3) -> Value {
/// A dialog that edits an existing feature, filled from it. The timeline is rolled back to just
/// before the feature, so its references show on the geometry they refer to.
pub fn for_feature(app: &SolveApp, id: u64, marker: Option<usize>) -> Option<Dialog> {
let _refill = Refill::start();
let s = &app.session;
let f = s.doc.feature(id)?.clone();
let st = s.world_state();