fix: select complete circular rims and curved surfaces in 3D

Group kernel pieces across circular rims and hidden surface seams for hovering, selection, dialogs, and measurement. Preserve physical references and cover full-item toggling and picking with regression tests.

Fixes #88
This commit is contained in:
bherbruck committed 2026-10-10 17:13:36 -04:00
1 parent e042a7b555
commit acf4669f73
6 files changed
+424 -34

No files matched your search

+11 -4
View File
@@ -480,10 +480,12 @@ impl Dialog {
.collect::<Vec<_>>()
})
.unwrap_or_else(|| vec![sel.clone()]),
(Kind::Measure { .. }, _) => vec![crate::viewport::measurement_selection(s, sel)],
_ if inp.multi => crate::viewport::grouped_selection(s, sel),
_ => vec![sel.clone()],
};
for x in picked {
if !inp.items.contains(&x) {
if !inp.items.iter().any(|y| selection::same_item(y, &x)) {
inp.items.push(x);
}
}
@@ -631,8 +633,11 @@ impl Dialog {
/// A pick in the viewport (already accepted by the active input).
pub fn pick(&mut self, s: &Session, sel: Sel) {
let measure = matches!(self.kind, Kind::Measure { .. });
let sel = if measure { crate::viewport::measurement_selection(s, &sel) } else { sel };
let chain = matches!(self.kind, Kind::Fillet { chain: true, .. });
let mut picked = vec![sel.clone()];
let mut picked =
if !measure && self.active_input().is_some_and(|i| i.multi) { crate::viewport::grouped_selection(s, &sel) } else { vec![sel.clone()] };
// Tangent chain: an edge brings the edges that continue it smoothly.
if chain
&& let Sel::Edge { body, index, .. } = &sel
@@ -667,13 +672,15 @@ impl Dialog {
}
/// Box selection result: replace (or add to) the active input.
pub fn take_box(&mut self, sels: Vec<Sel>, add: bool) {
pub fn take_box(&mut self, s: &Session, sels: Vec<Sel>, add: bool) {
let measure = matches!(self.kind, Kind::Measure { .. });
let Some(inp) = self.inputs.get_mut(self.active) else { return };
if !add {
inp.items.clear();
}
for x in sels {
if fits(inp.accept, &x) && !inp.items.contains(&x) {
let x = if measure { crate::viewport::measurement_selection(s, &x) } else { x };
if fits(inp.accept, &x) && !inp.items.iter().any(|y| selection::same_item(y, &x)) {
inp.items.push(x);
}
}