mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
solidcraft-smlib: blend faces come from the edge they replace
SMLib makes a fillet or chamfer face with no tag, so history::blends gives each Generated face FaceOrigin::Edge for every blended edge whose two faces both lie next to it and no longer meet directly. For the fillet shim's history once it lands; a corner patch between blends keeps no origin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -164,6 +164,53 @@ impl Raw {
|
||||
}
|
||||
}
|
||||
|
||||
/// A blend's faces (fillet, chamfer) in `h`, the history of a blend of edges `blended` of its
|
||||
/// one operand (operand 0), whose own edges `operand` lists (the faces each bounds, as in the
|
||||
/// operand's identity history): SMLib makes a blend face with no tag, so each Generated face is
|
||||
/// given [`FaceOrigin::Edge`] for every blended edge whose two faces both lie under faces next
|
||||
/// to it and no longer meet each other directly. A corner patch between several blends matches
|
||||
/// none of them and stays without origin.
|
||||
pub fn blends(h: &mut History, operand: &[EdgeProv], blended: &[usize]) {
|
||||
let mut next_to: Vec<BTreeSet<FaceOrigin>> = vec![BTreeSet::new(); h.faces.len()];
|
||||
for e in &h.edges {
|
||||
for f in &e.faces {
|
||||
for g in &e.faces {
|
||||
if let (Some(set), Some(p)) = (next_to.get_mut(*f), h.faces.get(*g))
|
||||
&& f != g
|
||||
{
|
||||
set.extend(p.origins.iter().copied());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pairs of operand faces whose result faces still meet along an edge.
|
||||
let mut meeting: BTreeSet<(FaceOrigin, FaceOrigin)> = BTreeSet::new();
|
||||
for e in &h.edges {
|
||||
if let [a, b] = e.faces.as_slice()
|
||||
&& let (Some(a), Some(b)) = (h.faces.get(*a), h.faces.get(*b))
|
||||
{
|
||||
for x in &a.origins {
|
||||
for y in &b.origins {
|
||||
meeting.insert((*x.min(y), *x.max(y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (f, around) in h.faces.iter_mut().zip(&next_to) {
|
||||
if f.change != Change::Generated || !f.origins.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let edges = blended.iter().filter(|e| {
|
||||
operand.get(**e).is_some_and(|p| {
|
||||
let [a, b] = p.faces.as_slice() else { return false };
|
||||
let (a, b) = (FaceOrigin::Face { operand: 0, face: *a }, FaceOrigin::Face { operand: 0, face: *b });
|
||||
around.contains(&a) && around.contains(&b) && !meeting.contains(&(a.min(b), a.max(b)))
|
||||
})
|
||||
});
|
||||
f.origins = edges.map(|e| FaceOrigin::Edge { operand: 0, edge: *e }).collect();
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads non-negative values off the records.
|
||||
struct Reader<'a>(std::slice::Iter<'a, i64>);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use solidcraft_geom::brep::history::{Change, EdgeOrigin, FaceOrigin};
|
||||
use solidcraft_geom::brep::history::{Change, EdgeOrigin, EdgeProv, FaceOrigin, FaceProv, History};
|
||||
|
||||
fn face(operand: usize, face: usize) -> FaceOrigin {
|
||||
FaceOrigin::Face { operand, face }
|
||||
@@ -85,6 +85,22 @@ fn bad_orders_are_errors() {
|
||||
assert!(raw.history(&[ok.clone(), ok.clone()], &Order { faces: vec![0, 1, 3], edges: vec![] }).is_err());
|
||||
}
|
||||
|
||||
/// A box with its edge 0 (between faces 4 and 5) filleted, as SMLib reports it: the fillet face
|
||||
/// (6) has no tag; it lies between faces from 4 and 5 and two end faces.
|
||||
#[test]
|
||||
fn a_fillet_face_comes_from_its_edge() {
|
||||
let kept = |i: usize| FaceProv { origins: vec![face(0, i)], change: Change::Modified };
|
||||
let mut faces: Vec<FaceProv> = (0..6).map(kept).collect();
|
||||
faces.push(FaceProv { origins: vec![], change: Change::Generated });
|
||||
let edge = |a: usize, b: usize| EdgeProv { faces: vec![a, b], origins: vec![] };
|
||||
let mut h = History { operands: 1, faces, edges: vec![edge(4, 6), edge(5, 6), edge(0, 6), edge(2, 6), edge(0, 4)] };
|
||||
// The operand's own edges: edge 0 between faces 4 and 5, edge 1 between 0 and 4.
|
||||
let operand = vec![edge(4, 5), edge(0, 4)];
|
||||
blends(&mut h, &operand, &[0, 1]);
|
||||
assert_eq!(h.faces[6].origins, vec![FaceOrigin::Edge { operand: 0, edge: 0 }]);
|
||||
assert!(h.faces[..6].iter().all(|f| f.origins.len() == 1));
|
||||
}
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
#[test]
|
||||
fn a_tagged_body_is_its_own_history() {
|
||||
|
||||
Reference in New Issue
Block a user