STEP export: pieces of a plane or extruded cylinder written as one face
Fusion round trip WARNs on face counts:
- 48: the pulley's annular end faces arrived as 240° and 120° sectors.
- 54: the side faces and holes of a body glued to its mirror image came
in halves.
Changes:
- Planes merge: PLANE faces and flat B-spline sheets, as well as revolved
planes. A plane keeps several loops (an annulus, a face with holes), no
seam. Flat B-spline sheets are written as PLANE.
- Pieces of an extruded cylinder (B-spline sheets) merge when their edges
are circles square to the axis. The merged face is written as a
CYLINDRICAL_SURFACE, with its parameter seam on the face's seam edge.
- A full turn's loop is built explicitly: ring, seam, other ring (or the
apex on the axis), seam back. Before, it depended on edge order, and
after 81c85b5 the pulley's last pieces no longer merged.
- The read-back check moved to the whole file. If the merged file reads
with warnings and the unmerged one does not, the unmerged one is
written.
Results: 48 has 12 faces (Fusion 12), 54 has 12 (Fusion 12). Oracle
results are unchanged (73 PASS) and the STEP corpus passes 76/76. New
test: a plate with a hole glued to its mirror exports 8 faces, all
planes and cylinders, and round-trips.
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
c009bb2c2a
commit
0a1b6f0fff
6 files changed
+396
-163
No files matched your search
@@ -692,7 +692,7 @@ fn revolved_oriented(curve: mt::Curve, o: mt::Point3, axis: mt::Vector3, u: f64,
|
||||
revolved(curve, o, -axis)
|
||||
}
|
||||
|
||||
fn bspline_surface(cx: &Ctx, e: &Entity) -> R<mt::Surface> {
|
||||
pub(crate) fn bspline_surface(cx: &Ctx, e: &Entity) -> R<mt::Surface> {
|
||||
let (base, knots, kind): (Vec<Param>, Option<[Option<&Param>; 4]>, &str) = if e.is_complex() {
|
||||
let b = e.record("B_SPLINE_SURFACE").ok_or("complex surface without B_SPLINE_SURFACE")?;
|
||||
let mut base = vec![Param::Str(String::new())];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use solvecraft_geom::{Loop2, Plane, Region2, Vec2, Vec3};
|
||||
|
||||
use super::*;
|
||||
use crate::{BoolOp, boolean, box_solid, cylinder, fillet, measure, revolve, sphere, step_export, torus};
|
||||
use crate::{BoolOp, boolean, box_solid, cylinder, extrude, fillet, measure, revolve, sphere, step_export, torus};
|
||||
|
||||
fn rel(a: f64, b: f64) -> f64 {
|
||||
(a - b).abs() / b.abs().max(1e-9)
|
||||
@@ -502,3 +502,23 @@ fn tee_fillet_exports_byte_identical() {
|
||||
assert!(export() == first, "export differs between runs");
|
||||
}
|
||||
}
|
||||
|
||||
/// A plate with a hole glued to its mirror image: the faces split at the mirror plane and the
|
||||
/// hole's B-spline halves are written as one plane or one cylinder each, as other systems
|
||||
/// count them.
|
||||
#[test]
|
||||
fn glued_halves_export_as_whole_faces() {
|
||||
let half = Region2 {
|
||||
outer: Loop2::polygon(&[Vec2::new(0.0, 0.0), Vec2::new(30.0, 0.0), Vec2::new(30.0, 40.0), Vec2::new(0.0, 40.0)]),
|
||||
holes: vec![Loop2::circle(Vec2::new(15.0, 20.0), 4.0).reversed()],
|
||||
};
|
||||
let right = extrude(&Plane::XY, &[half], 0.0, 10.0).unwrap().pop().unwrap();
|
||||
let left = crate::transform_matrix(&right, [[-1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]).unwrap();
|
||||
let b = boolean(&right, &left, BoolOp::Union).unwrap().unwrap();
|
||||
let text = step_export(&[&b], "t").unwrap();
|
||||
assert!(!text.contains("B_SPLINE_SURFACE"), "{text}");
|
||||
assert_eq!(text.matches("CYLINDRICAL_SURFACE(").count(), 2);
|
||||
let imp = round_trip(&b);
|
||||
// Box sides and caps (6) and two holes.
|
||||
assert_eq!(imp.bodies[0].file_faces, 8);
|
||||
}
|
||||
Reference in new issue
Block a user