forked from 1b-agent/fieldcraft-upstream
geometry.face.absorb: tiny and sliver faces into a neighbour (#506)
A face merge may keep one of its faces' names (Merge::into, model FaceMerge::into): absorbing a tiny face leaves the neighbour by its own name, so sets on it still select it. Shape::absorbing_neighbour finds the face a tiny one shares the longest edges with. geometry.face.absorb absorbs one face (into a named or the best neighbour) or, from_check, every small and sliver face the last geometry.check marked; check marks now carry the small face they found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
ce02d263c7
commit
58174ba168
14 files changed
+283
-27
No files matched your search
@@ -25,6 +25,9 @@ pub struct FaceMerge {
|
||||
/// Two or more faces by persistent name (a name also stands for the pieces a partition cut
|
||||
/// it into).
|
||||
pub faces: Vec<String>,
|
||||
/// Absorb (`geometry.face.absorb`): the merged face keeps this one's name (one of `faces`).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub into: Option<String>,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
@@ -59,6 +62,9 @@ impl Model {
|
||||
return Err(invalid(format!("face `{f}` is listed twice")));
|
||||
}
|
||||
}
|
||||
if merge.into.as_ref().is_some_and(|i| !merge.faces.contains(i)) {
|
||||
return Err(invalid("the face it keeps is not one of its faces".into()));
|
||||
}
|
||||
self.face_merges.push(merge);
|
||||
Ok(())
|
||||
}
|
||||
@@ -74,7 +80,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn merge(name: &str, faces: &[&str]) -> FaceMerge {
|
||||
FaceMerge { name: name.into(), body: "Base".into(), faces: faces.iter().map(|f| f.to_string()).collect() }
|
||||
FaceMerge { name: name.into(), body: "Base".into(), faces: faces.iter().map(|f| f.to_string()).collect(), into: None }
|
||||
}
|
||||
|
||||
/// Merges keep their order, are saved and read back, and bad ones are refused.
|
||||
@@ -89,10 +95,12 @@ mod tests {
|
||||
assert!(m.add_face_merge(merge("Blank", &["x", " "])).is_err());
|
||||
assert!(m.add_face_merge(merge("9bad", &["x", "y"])).is_err());
|
||||
assert!(m.add_face_merge(FaceMerge { body: String::new(), ..merge("NoBody", &["x", "y"]) }).is_err());
|
||||
assert!(m.add_face_merge(FaceMerge { into: Some("z".into()), ..merge("Into", &["x", "y"]) }).is_err());
|
||||
m.add_face_merge(FaceMerge { into: Some("y".into()), ..merge("Absorb", &["x", "y"]) }).unwrap();
|
||||
let back: Model = serde_json::from_str(&serde_json::to_string(&m).unwrap()).unwrap();
|
||||
assert_eq!(back.face_merges(), m.face_merges());
|
||||
assert_eq!(m.remove_face_merge("Fillet").unwrap().name, "Fillet");
|
||||
assert!(m.remove_face_merge("Fillet").is_err());
|
||||
assert_eq!(m.face_merges().len(), 1);
|
||||
assert_eq!(m.face_merges().len(), 2);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user