STEP export: shelled revolved bodies export instead of panicking (#1496)
A scale across a revolution's axis keeps the face a surface of revolution and is written as one; any other refusal from the writer is an export error, not a panic.
This commit is contained in:
1 parent
d188eea1f4
commit
63accec16e
5 files changed
+161
-13
No files matched your search
@@ -74,10 +74,25 @@ pub(crate) fn truck_step(bodies: &[&Body], system: &str) -> Result<String> {
|
||||
let cs: Vec<_> = bodies.iter().map(|b| plain_curves(b).map(|solid| solid.compress())).collect::<Result<_>>()?;
|
||||
let models: out::StepModels<_, _, _> = cs.iter().collect();
|
||||
let header = out::StepHeaderDescriptor { organization_system: system.to_owned(), ..Default::default() };
|
||||
Ok(out::CompleteStepDisplay::new(models, header).to_string())
|
||||
written(&out::CompleteStepDisplay::new(models, header))
|
||||
})
|
||||
}
|
||||
|
||||
/// The text of truck's STEP writer, or an error. The writer refuses some geometry by returning
|
||||
/// `fmt::Error` after a line saying why; `to_string` would turn that into a panic (caught by
|
||||
/// `guard` on the desktop, but the browser build aborts on any panic).
|
||||
fn written(display: &impl std::fmt::Display) -> Result<String> {
|
||||
use std::fmt::Write;
|
||||
let mut text = String::new();
|
||||
match write!(text, "{display}") {
|
||||
Ok(()) => Ok(text),
|
||||
Err(_) => {
|
||||
let why = text.lines().last().map(str::trim).filter(|l| !l.is_empty() && !l.starts_with('#')).unwrap_or("unsupported geometry");
|
||||
Err(KernelError::Failed(format!("not supported yet: STEP export of this body ({why})")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// STEP (ISO 10303-21, AP242) text for the given bodies as one part (`Body1`…, with the
|
||||
/// bodies' colours).
|
||||
pub fn step_export(bodies: &[&Body], system: &str) -> Result<String> {
|
||||
|
||||
@@ -1202,3 +1202,42 @@ fn large_imports_are_freed_with_their_last_user() {
|
||||
drop((first, again));
|
||||
assert!(weak.upgrade().is_none(), "the cache must not keep a large import alive after its design is gone");
|
||||
}
|
||||
|
||||
/// A three-quarter turn of a rectangle about Z: planar end caps, revolved cylinders and annuli.
|
||||
fn three_quarter_ring() -> Body {
|
||||
let rect =
|
||||
Region2 { outer: Loop2::polygon(&[Vec2::new(5.0, 0.0), Vec2::new(25.0, 0.0), Vec2::new(25.0, 5.0), Vec2::new(5.0, 5.0)]), holes: vec![] };
|
||||
revolve(&Plane::XZ, &[rect], Vec2::ZERO, Vec2::Y, 1.5 * std::f64::consts::PI).unwrap().pop().unwrap()
|
||||
}
|
||||
|
||||
fn scaled(b: &Body, x: f64, y: f64, z: f64) -> Body {
|
||||
crate::transform_matrix(b, [[x, 0.0, 0.0, 0.0], [0.0, y, 0.0, 0.0], [0.0, 0.0, z, 0.0], [0.0, 0.0, 0.0, 1.0]]).unwrap()
|
||||
}
|
||||
|
||||
/// A scale across the revolution axis that differs from the scale along it (how a shell or an
|
||||
/// offset moves a revolved face) keeps the faces surfaces of revolution. The writer refused it
|
||||
/// ("non-uniform scale"), and the refusal surfaced as a panic in export (robustness seeds 19, 24).
|
||||
#[test]
|
||||
fn revolved_faces_scaled_across_the_axis_round_trip() {
|
||||
let ring = three_quarter_ring();
|
||||
let v0 = measure(&ring).unwrap().volume;
|
||||
let b = scaled(&ring, 1.5, 1.5, 0.5);
|
||||
assert!(rel(measure(&b).unwrap().volume, v0 * 1.5 * 1.5 * 0.5) < 1e-3);
|
||||
round_trip(&b);
|
||||
}
|
||||
|
||||
/// A transform that does not keep the faces surfaces of revolution: export may refuse the body,
|
||||
/// but with an error, never a panic (the browser build aborts on any panic), and anything it does
|
||||
/// write must read back as the same solid.
|
||||
#[test]
|
||||
fn revolved_faces_skewed_never_panic_on_export() {
|
||||
let b = scaled(&three_quarter_ring(), 1.5, 1.0, 1.0);
|
||||
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| step_export(&[&b], "t")));
|
||||
let Ok(r) = r else { panic!("STEP export panicked") };
|
||||
match r {
|
||||
Err(e) => assert!(e.to_string().contains("not supported yet"), "{e}"),
|
||||
Ok(_) => {
|
||||
round_trip(&b);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user