mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
Tests: edges are read on their NURBS forms, a chamfer's chain is its caller's, the cap test's hatch
- An SMLib circle edge's `interval` is on its NURBS form (`Edge::parameters`), and an analytic face's `domain` on the form's (u, v). edges_are_on_smlibs_curves evaluated `curve` at the form's interval and took the domain for angles; it checks the side's whole turn and height on the form and a rim's turn by `curve_interval`. The tangent hole test's edge middles were read the same way (the copy seemed to join faces on opposite sides of the line). - kernel::chamfer blends the edges it is given; a feature's pick is extended by kernel::tangent_chain first (doc eval). The chamfer tests do the same: one_chamfer_pick_follows_the_tangent_chain_at_any_part_size removes its 54.66 mm³ again. - Since the section hatch per part (#8529) a cut is tinted with the hatch colour its body's name picks (Body1: steel); the GPU cap test turns the part hatch off, as the CPU one does (2885f101b on devgreen-engine-builds). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -160,6 +160,8 @@ fn pictures_show_the_section_and_its_cap() {
|
||||
let mut cam = view::home_camera(&s).unwrap();
|
||||
cam.fov = fov;
|
||||
let mut sc = view::scene(&s, &cam).unwrap();
|
||||
// The cap in the cap colour: a part's hatch colour is the one its name picks (#8529).
|
||||
sc.part_hatch = None;
|
||||
// A marker inside the body, behind the cut face.
|
||||
let red = Rgb(255, 0, 0);
|
||||
sc.lines.push(SceneLine {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! against the round wall instead of extending that short seam outside the solid.
|
||||
|
||||
use solidcraft_geom::{Loop2, Plane, Region2, Seg2, Vec2, Vec3};
|
||||
use solidcraft_kernel::{Body, BoolOp, boolean, chamfer, cylinder, extrude};
|
||||
use solidcraft_kernel::{Body, BoolOp, boolean, chamfer, cylinder, extrude, tangent_chain};
|
||||
use std::f64::consts::PI;
|
||||
|
||||
fn holder() -> Body {
|
||||
@@ -54,7 +54,9 @@ fn expected_removed(distance: f64) -> f64 {
|
||||
#[test]
|
||||
fn chamfer_the_top_lip_at_a_tangent_wall_junction() {
|
||||
let body = holder();
|
||||
let made = chamfer(&body, &[Vec3::new(10.0, 10.0, 60.0)], 2.0).unwrap();
|
||||
// The pick's tangent chain, as a chamfer feature selects it (the kernel blends the edges it
|
||||
// is given).
|
||||
let made = chamfer(&body, &tangent_chain(&body, &[Vec3::new(10.0, 10.0, 60.0)]).unwrap(), 2.0).unwrap();
|
||||
assert!(made.validity().is_empty(), "{:?}", made.validity());
|
||||
assert_eq!(made.crossed_face_loops().unwrap(), 0);
|
||||
let history = made.history().expect("the chamfer retains exact face provenance");
|
||||
@@ -115,7 +117,7 @@ fn plate_with_stadium(plate: f64) -> Body {
|
||||
fn one_chamfer_pick_follows_the_tangent_chain_at_any_part_size() {
|
||||
for plate in [140.0, 145.0, 250.0] {
|
||||
let body = plate_with_stadium(plate);
|
||||
let made = chamfer(&body, &[Vec3::new(0.0, 5.0, 20.0)], 1.0).unwrap();
|
||||
let made = chamfer(&body, &tangent_chain(&body, &[Vec3::new(0.0, 5.0, 20.0)]).unwrap(), 1.0).unwrap();
|
||||
assert!(made.validity().is_empty(), "{:?}", made.validity());
|
||||
// Two straight edges (c^2/2 * 40 each) and both end arcs (Pappus, c^2/2 * 2 pi (R - c/3)).
|
||||
let expected = 40.0 + 0.5 * 2.0 * PI * (5.0 - 1.0 / 3.0);
|
||||
|
||||
@@ -82,10 +82,19 @@ mod native_tests {
|
||||
fn edges_are_on_smlibs_curves() {
|
||||
let cyl = Brep::make_cylinder([0.0; 3], 5.0, 10.0).unwrap().to_native().unwrap();
|
||||
let side = cyl.faces.iter().find(|f| matches!(f.surface, b::Surface::Cylinder { .. })).unwrap();
|
||||
assert!((side.domain[0][1] - side.domain[0][0] - TAU).abs() < 1e-12);
|
||||
assert_eq!(side.domain[1], [0.0, 10.0]);
|
||||
// The side is on SMLib's NURBS form of the cylinder (its domain is the form's): the whole
|
||||
// turn, so its domain's two u ends meet, from the base to the top.
|
||||
let form = b::eval::SurfaceEval::new(side.parameters()).unwrap();
|
||||
let [[u0, u1], [v0, v1]] = side.domain;
|
||||
for v in [v0, v1] {
|
||||
let (a, z) = (form.point([u0, v]).unwrap(), form.point([u1, v]).unwrap());
|
||||
assert!(a.dist(z) < 1e-9, "{a:?} {z:?}");
|
||||
}
|
||||
let heights = [form.point([u0, v0]).unwrap().z, form.point([u0, v1]).unwrap().z];
|
||||
assert!(heights.iter().any(|h| h.abs() < 1e-9) && heights.iter().any(|h| (h - 10.0).abs() < 1e-9), "{heights:?}");
|
||||
for e in &cyl.edges {
|
||||
let eval = b::eval::CurveEval::new(&e.curve).unwrap();
|
||||
// Evaluated on the curve its interval is on (a circle's NURBS form).
|
||||
let eval = b::eval::CurveEval::new(e.parameters()).unwrap();
|
||||
let [a, z] = e.interval;
|
||||
// Ends on the edge's vertices.
|
||||
for (t, v) in [(a, e.vertices[0]), (z, e.vertices[1])] {
|
||||
@@ -94,6 +103,7 @@ mod native_tests {
|
||||
assert!((p - Vec3::new(q[0], q[1], q[2])).len() < 1e-9, "{:?} at {t}", e.curve);
|
||||
}
|
||||
if let b::Curve::Circle { radius, .. } = e.curve {
|
||||
let [a, z] = e.curve_interval().unwrap();
|
||||
assert!((radius - 5.0).abs() < 1e-12 && (z - a - TAU).abs() < 1e-9);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +136,8 @@ mod native_tests {
|
||||
p[0].abs() < 1e-9 && (p[1] - 14.5).abs() < 1e-9
|
||||
})
|
||||
};
|
||||
let middle = |e: &b::Edge| b::eval::CurveEval::new(&e.curve).unwrap().point(0.5 * (e.interval[0] + e.interval[1])).unwrap();
|
||||
// On the curve the interval is on (a circle's NURBS form).
|
||||
let middle = |e: &b::Edge| b::eval::CurveEval::new(e.parameters()).unwrap().point(0.5 * (e.interval[0] + e.interval[1])).unwrap();
|
||||
let copies: Vec<&b::Edge> = record.edges.iter().filter(|e| on_line(e)).collect();
|
||||
assert_eq!(copies.len(), 2);
|
||||
for copy in copies {
|
||||
|
||||
Reference in New Issue
Block a user