mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 10:35:58 +00:00
kernel tests: a blend meant to run along a tangent chain asks for it
The kernel blends exactly the edges given; the Fillet and Chamfer features
expand each pick to its tangent chain (kernel::tangent_chain) before the call
(4593fd07). Six tests written before that passed one pick and expected the
chain: they now ask for it as the features do, with their analytic expectations
unchanged (10 faces along the rounded corner, the sphere corners of #1557, the
boss's half circle, the rounded rectangle's tiny end, the rounded box's loops).
blend_smlib's notes no longer say SMLib follows the chains.
fillet_tabbed_plate_outer_loop_and_partial_selection_after_hole is left as it
is: it fillets every exact subset of the outer edges, and SMLib still fails some.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BnQawySUFx57iaJZq7z1Fm
This commit is contained in:
@@ -698,11 +698,14 @@ mod tests {
|
||||
#[test]
|
||||
fn a_blend_of_an_edge_running_into_a_rounded_corner_follows_it() {
|
||||
// A box with one vertical edge rounded: a top edge meeting that round smoothly is blended
|
||||
// with the round's top arc and the next top edge, as one smooth chain.
|
||||
// with the round's top arc and the next top edge, as one smooth chain (its tangent chain,
|
||||
// as the Fillet and Chamfer features ask for it).
|
||||
let b = crate::build::box_solid(Vec3::ZERO, Vec3::new(40.0, 30.0, 20.0)).unwrap();
|
||||
let rounded = fillet(&b, &[Vec3::new(40.0, 30.0, 10.0)], 5.0).unwrap();
|
||||
let chain = tangent_chain(&rounded, &[Vec3::new(20.0, 30.0, 20.0)]).unwrap();
|
||||
assert_eq!(chain.len(), 3, "the top edge, the round's top arc and the next top edge");
|
||||
for round in [true, false] {
|
||||
let out = blend(&rounded, &[Vec3::new(20.0, 30.0, 20.0)], 1.0, round).unwrap();
|
||||
let out = blend(&rounded, &chain, 1.0, round).unwrap();
|
||||
assert!(out.validity().is_empty(), "{:?}", out.validity());
|
||||
assert_eq!(out.face_count(), rounded.face_count() + 3);
|
||||
}
|
||||
@@ -733,7 +736,8 @@ mod tests {
|
||||
(true, (1.0 - std::f64::consts::PI / 4.0) * 0.64, 0.8 * (10.0 - 3.0 * std::f64::consts::PI) / (3.0 * (4.0 - std::f64::consts::PI))),
|
||||
(false, 0.32, 0.8 / 3.0),
|
||||
] {
|
||||
let out = blend(&body, &[Vec3::new(52.0, 20.0, 0.0)], 0.8, round).unwrap();
|
||||
// The half circle's tangent chain, as the Fillet and Chamfer features ask for it.
|
||||
let out = blend(&body, &tangent_chain(&body, &[Vec3::new(52.0, 20.0, 0.0)]).unwrap(), 0.8, round).unwrap();
|
||||
assert!(out.validity().is_empty(), "{:?}", out.validity());
|
||||
// Pappus: the section turned half round the axis at its centroid's radius.
|
||||
let want = area * std::f64::consts::PI * (12.0 - c);
|
||||
|
||||
@@ -128,8 +128,10 @@ mod tests {
|
||||
let mut together = bottom.to_vec();
|
||||
together.push(vertical);
|
||||
let reference = fillet(&b, &together, 2.0).unwrap();
|
||||
// The vertical edge, alone or with the seam, with its tangent chain (as the Fillet feature
|
||||
// asks for it): every pick gives the same body.
|
||||
for picks in [vec![vertical], vec![vertical, seam], vec![seam, vertical]] {
|
||||
let result = fillet(&rounded, &picks, 2.0).unwrap();
|
||||
let result = fillet(&rounded, &crate::tangent_chain(&rounded, &picks).unwrap(), 2.0).unwrap();
|
||||
assert_eq!(result.face_count(), reference.face_count());
|
||||
assert_eq!(result.unmeshed_faces(), 0);
|
||||
assert!(result.validity().is_empty(), "{:?}", result.validity());
|
||||
@@ -201,7 +203,9 @@ mod tests {
|
||||
let vertical =
|
||||
[Vec3::new(0.0, 0.0, 6.0), Vec3::new(25.0, 0.0, 6.0), Vec3::new(25.0, 25.0, 6.0), Vec3::new(0.0, 25.0, 6.0)].map(|p| p + origin);
|
||||
let rounded = fillet(&b, &bottom, 2.0).unwrap();
|
||||
let result = fillet(&rounded, &vertical, 2.0).unwrap();
|
||||
// Each vertical edge with its tangent chain (on through the bottom rounds' corners), as
|
||||
// the Fillet feature asks for it.
|
||||
let result = fillet(&rounded, &crate::tangent_chain(&rounded, &vertical).unwrap(), 2.0).unwrap();
|
||||
assert!(result.validity().is_empty(), "{:?}", result.validity());
|
||||
assert!(kink(&result) < 0.05);
|
||||
// Integrate rounded-square horizontal sections. Above z=r the area is
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
//! unchanged: the body goes into SMLib as its schema 4 record (healed where SMLib's check refuses
|
||||
//! it as given), tagged as operand 0; each point picks the body's nearest edge in its own edge
|
||||
//! order, and SMLib is given that edge's midpoint, which no other edge is as near to (a point at
|
||||
//! a vertex between two edges would leave SMLib to choose); SMLib blends those edges with their
|
||||
//! tangent chains and the corners where they meet, its check must pass, and the result comes
|
||||
//! a vertex between two edges would leave SMLib to choose); SMLib blends exactly those edges and
|
||||
//! the corners where they meet (a pick's tangent chain is the caller's to ask for,
|
||||
//! [`crate::tangent_chain`]), its check must pass, and the result comes
|
||||
//! back decoded with its geometry checked. An option SMLib has no construction for is refused as
|
||||
//! "not supported yet".
|
||||
//!
|
||||
@@ -267,7 +268,7 @@ mod imp {
|
||||
}
|
||||
|
||||
/// The operand's edges the blend replaced: each picked edge, and every edge no result edge
|
||||
/// comes from (the rest of the tangent chains), in the operand's edge order.
|
||||
/// comes from (one the blend's corners took up), in the operand's edge order.
|
||||
fn blended(body: &Body, picked: &[usize], h: &History) -> Vec<usize> {
|
||||
let mut out: BTreeSet<usize> = picked.iter().copied().collect();
|
||||
let kept: BTreeSet<usize> = h
|
||||
|
||||
@@ -1509,8 +1509,9 @@ fn rounded_corners_rounded_again_make_spheres() {
|
||||
let bx = box_solid(Vec3::ZERO, Vec3::new(a, b, c)).unwrap();
|
||||
let vert: Vec<Vec3> = [(0.0, 0.0), (a, 0.0), (a, b), (0.0, b)].iter().map(|(x, y)| Vec3::new(*x, *y, c / 2.0)).collect();
|
||||
let f = fillet(&bx, &vert, r).unwrap();
|
||||
let f = fillet(&f, &[Vec3::new(a / 2.0, 0.0, c)], r).unwrap();
|
||||
let f = fillet(&f, &[Vec3::new(a / 2.0, 0.0, 0.0)], r).unwrap();
|
||||
// Each loop by one pick and its tangent chain, as the Fillet feature asks for it.
|
||||
let f = fillet(&f, &crate::tangent_chain(&f, &[Vec3::new(a / 2.0, 0.0, c)]).unwrap(), r).unwrap();
|
||||
let f = fillet(&f, &crate::tangent_chain(&f, &[Vec3::new(a / 2.0, 0.0, 0.0)]).unwrap(), r).unwrap();
|
||||
let (ai, bi, ci) = (a - 2.0 * r, b - 2.0 * r, c - 2.0 * r);
|
||||
let area = 2.0 * (ai * bi + bi * ci + ai * ci) + PI * r * (ai + bi + ci) * 2.0 + 4.0 * PI * r * r;
|
||||
let vol = ai * bi * ci + 2.0 * r * (ai * bi + bi * ci + ai * ci) + PI * r * r * (ai + bi + ci) + 4.0 / 3.0 * PI * r * r * r;
|
||||
@@ -1719,7 +1720,7 @@ fn fillet_rounded_rectangle_with_tiny_end_edges() {
|
||||
let initial = fine(&body);
|
||||
// Every rim edge, the tiny end alone (tangent chain), and the opposite selection order.
|
||||
for selection in [picks.to_vec(), vec![picks[3]], picks.into_iter().rev().collect()] {
|
||||
let blended = fillet(&body, &selection, radius).unwrap();
|
||||
let blended = fillet(&body, &crate::tangent_chain(&body, &selection).unwrap(), radius).unwrap();
|
||||
assert!(blended.validity().is_empty(), "{:?}", blended.validity());
|
||||
assert_eq!(blended.crossed_face_loops().unwrap(), 0);
|
||||
assert_eq!((blended.face_count(), blended.edge_count(), blended.vertex_count()), (18, 40, 24));
|
||||
|
||||
Reference in New Issue
Block a user