Shell and Offset Face on drill tips and tori: samples skip points where the normal is undefined (a cone's apex), the apex moves with its cone, tori offset their tube (the tube circle scaled and revolved again); a box with a drilled hole now shells to its analytic volume
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
7e2d45602b
commit
0670de3f57
3 files changed
+177
-10
No files matched your search
@@ -0,0 +1,65 @@
|
||||
//! Delete Face and shells/offsets on cones and spheres, through the engine.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::Session;
|
||||
|
||||
fn run(s: &mut Session, id: &str, p: Value) -> Value {
|
||||
match s.execute(id, &p) {
|
||||
Ok(v) => v,
|
||||
Err(e) => panic!("{id} {p}: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn volume(s: &mut Session) -> f64 {
|
||||
run(s, "MeasureCommand", json!({}))["total"]["volume_mm3"].as_f64().unwrap()
|
||||
}
|
||||
|
||||
/// A box with a drilled hole (cone tip) shells: the cavity is the box shrunk by the wall and the
|
||||
/// hole grown by it (its cone slid down its axis), measured against that analytic volume.
|
||||
#[test]
|
||||
fn shell_a_box_with_a_drilled_hole() {
|
||||
use std::f64::consts::PI;
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 40, "width": 30, "height": 20}));
|
||||
run(&mut s, "FusionHoleCommand", json!({"position": [20, 15, 20], "diameter": 8, "depth": 10, "type": "drilled", "tip_angle": 118}));
|
||||
let v_body = volume(&mut s);
|
||||
let (r, t) = (4.0, 2.0);
|
||||
let a = (59.0f64).to_radians();
|
||||
// Cylinder depth from the measured body: 24000 − π r² h − π r² (r / tan α) / 3.
|
||||
let h = (24000.0 - v_body - PI * r * r * (r / a.tan()) / 3.0) / (PI * r * r);
|
||||
assert!(h > 9.0 && h < 11.0, "{h}");
|
||||
run(&mut s, "FusionShellBodyCommand", json!({"faces": [[5, 5, 20]], "thickness": t}));
|
||||
let v_shell = volume(&mut s);
|
||||
let apex = 20.0 - h - r / a.tan() - t / a.sin();
|
||||
let big_r = r + t;
|
||||
let joint = apex + big_r / a.tan();
|
||||
let grown = PI * big_r * big_r * (20.0 - joint) + PI * big_r * big_r * (joint - apex) / 3.0;
|
||||
let cavity = 36.0 * 26.0 * 18.0 - grown;
|
||||
let want = v_body - cavity;
|
||||
assert!((v_shell - want).abs() < 2e-4 * want, "{v_shell} vs {want}");
|
||||
}
|
||||
|
||||
/// Offset Face on a cone and a sphere move them exactly.
|
||||
#[test]
|
||||
fn offset_cone_and_sphere_faces() {
|
||||
use std::f64::consts::PI;
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveSphere", json!({"center": [0, 0, 0], "radius": 10}));
|
||||
let r = run(&mut s, "FusionOffsetFacesCommand", json!({"faces": [[10, 0, 0]], "distance": 2}));
|
||||
let v = volume(&mut s);
|
||||
assert!((v - 4.0 / 3.0 * PI * 1728.0).abs() < 1e-3 * v, "{v} {r}");
|
||||
}
|
||||
|
||||
/// Offset Face on a torus changes its tube radius and keeps the major radius.
|
||||
#[test]
|
||||
fn offset_torus_face() {
|
||||
use std::f64::consts::PI;
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveTorus", json!({"major": 20, "minor": 5}));
|
||||
let v0 = volume(&mut s);
|
||||
assert!((v0 - 2.0 * PI * PI * 20.0 * 25.0).abs() < 1e-3 * v0, "{v0}");
|
||||
run(&mut s, "FusionOffsetFacesCommand", json!({"faces": [[25, 0, 0]], "distance": 1}));
|
||||
let v = volume(&mut s);
|
||||
assert!((v - 2.0 * PI * PI * 20.0 * 36.0).abs() < 1e-3 * v, "{v}");
|
||||
}
|
||||
@@ -20,6 +20,8 @@ pub(crate) mod motion;
|
||||
mod parts;
|
||||
mod section;
|
||||
pub(crate) use measure_sel::measure_items;
|
||||
#[cfg(test)]
|
||||
mod kernel_heal_tests;
|
||||
mod parameters;
|
||||
mod plastic;
|
||||
mod sheet;
|
||||
|
||||
Reference in new issue
Block a user