STEP import: a ball bounded only by its seam comes in whole (#1742)
Thanks @onembyte.
This commit is contained in:
1 parent
6bde126a5c
commit
fbc00bb2c4
3 files changed
+226
-44
No files matched your search
+49
-44
@@ -2063,6 +2063,15 @@ pub fn sphere_patches_rotated(center: Vec3, radius: f64, rot: [Vec3; 3]) -> Resu
|
||||
|
||||
/// [`sphere_patches_rotated`], every patch swept from profile segments `arcs`.
|
||||
fn sphere_solid(center: Vec3, radius: f64, rot: [Vec3; 3], arcs: &[usize]) -> Result<Body> {
|
||||
guard("sphere", || {
|
||||
let shell: mt::Shell = sphere_patch_faces(center, radius, rot)?.into();
|
||||
let solid = Solid::try_new(vec![shell]).map_err(|e| KernelError::Failed(format!("sphere: {e}")))?;
|
||||
record::attach(Body::new(solid)?, &[], Some(vec![record::profile(arcs); 6]), Default::default())
|
||||
})
|
||||
}
|
||||
|
||||
/// The six outward patch faces of [`sphere_patches_rotated`]; truck calls, so callers guard them.
|
||||
pub(crate) fn sphere_patch_faces(center: Vec3, radius: f64, rot: [Vec3; 3]) -> Result<Vec<mt::Face>> {
|
||||
let radius = finite(radius, "radius")?;
|
||||
let turn = |v: Vec3| rot[0] * v.x + rot[1] * v.y + rot[2] * v.z;
|
||||
if radius <= 1e-6 || !center.is_finite() {
|
||||
@@ -2080,50 +2089,46 @@ fn sphere_solid(center: Vec3, radius: f64, rot: [Vec3; 3], arcs: &[usize]) -> Re
|
||||
(Vec3::Z, Vec3::X, [[-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, 1.0, 1.0]]),
|
||||
(-Vec3::Z, Vec3::X, [[-1.0, 1.0, -1.0], [1.0, 1.0, -1.0], [1.0, -1.0, -1.0], [-1.0, -1.0, -1.0]]),
|
||||
];
|
||||
guard("sphere", || {
|
||||
let key = |s: [f64; 3]| ((s[0] > 0.0) as usize) | (((s[1] > 0.0) as usize) << 1) | (((s[2] > 0.0) as usize) << 2);
|
||||
let mut verts: std::collections::HashMap<usize, mt::Vertex> = std::collections::HashMap::new();
|
||||
let mut vert = |s: [f64; 3]| verts.entry(key(s)).or_insert_with(|| builder::vertex(p3(corner(s[0], s[1], s[2])))).clone();
|
||||
let mut edges: std::collections::HashMap<(usize, usize), mt::Edge> = std::collections::HashMap::new();
|
||||
let mut out: Vec<mt::Face> = Vec::new();
|
||||
for (dir, axis, cs) in faces {
|
||||
let (dir, axis) = (turn(dir), turn(axis));
|
||||
let mut wire: Vec<mt::Edge> = Vec::new();
|
||||
for i in 0..4 {
|
||||
let (a, b) = (cs[i], cs[(i + 1) % 4]);
|
||||
let (ka, kb) = (key(a), key(b));
|
||||
let e = match edges.get(&(ka.min(kb), ka.max(kb))) {
|
||||
Some(e) => e.clone(),
|
||||
None => {
|
||||
let (lo, hi) = if ka < kb { (a, b) } else { (b, a) };
|
||||
let (va, vb) = (vert(lo), vert(hi));
|
||||
let mid = (corner(lo[0], lo[1], lo[2]) + corner(hi[0], hi[1], hi[2])) * 0.5 - center;
|
||||
let transit = center + mid.normalized().unwrap_or(dir) * radius;
|
||||
let e = builder::circle_arc(&va, &vb, p3(transit));
|
||||
edges.insert((ka.min(kb), ka.max(kb)), e.clone());
|
||||
e
|
||||
}
|
||||
};
|
||||
wire.push(if ka < kb { e } else { e.inverse() });
|
||||
}
|
||||
// The meridian runs pole to pole through the side away from the patch.
|
||||
let (np, sp, back) = (center + axis * radius, center - axis * radius, center - dir * radius);
|
||||
let meridian = builder::circle_arc(&builder::vertex(p3(np)), &builder::vertex(p3(sp)), p3(back));
|
||||
let mut surface =
|
||||
mt::Surface::RevolutedCurve(mt::Processor::new(mt::RevolutedCurve::by_revolution(meridian.oriented_curve(), p3(center), v3(axis))));
|
||||
// Outward normal at the patch centre.
|
||||
let probe = p3(center + dir * radius);
|
||||
use mt::{ParametricSurface3D, SearchParameter};
|
||||
if let Some((u, v)) = surface.search_parameter(probe, mt::SPHint2D::None, 100) {
|
||||
let n = surface.normal(u, v);
|
||||
if mt::InnerSpace::dot(n, v3(dir)) < 0.0 {
|
||||
mt::Invertible::invert(&mut surface);
|
||||
let key = |s: [f64; 3]| ((s[0] > 0.0) as usize) | (((s[1] > 0.0) as usize) << 1) | (((s[2] > 0.0) as usize) << 2);
|
||||
let mut verts: std::collections::HashMap<usize, mt::Vertex> = std::collections::HashMap::new();
|
||||
let mut vert = |s: [f64; 3]| verts.entry(key(s)).or_insert_with(|| builder::vertex(p3(corner(s[0], s[1], s[2])))).clone();
|
||||
let mut edges: std::collections::HashMap<(usize, usize), mt::Edge> = std::collections::HashMap::new();
|
||||
let mut out: Vec<mt::Face> = Vec::new();
|
||||
for (dir, axis, cs) in faces {
|
||||
let (dir, axis) = (turn(dir), turn(axis));
|
||||
let mut wire: Vec<mt::Edge> = Vec::new();
|
||||
for i in 0..4 {
|
||||
let (a, b) = (cs[i], cs[(i + 1) % 4]);
|
||||
let (ka, kb) = (key(a), key(b));
|
||||
let e = match edges.get(&(ka.min(kb), ka.max(kb))) {
|
||||
Some(e) => e.clone(),
|
||||
None => {
|
||||
let (lo, hi) = if ka < kb { (a, b) } else { (b, a) };
|
||||
let (va, vb) = (vert(lo), vert(hi));
|
||||
let mid = (corner(lo[0], lo[1], lo[2]) + corner(hi[0], hi[1], hi[2])) * 0.5 - center;
|
||||
let transit = center + mid.normalized().unwrap_or(dir) * radius;
|
||||
let e = builder::circle_arc(&va, &vb, p3(transit));
|
||||
edges.insert((ka.min(kb), ka.max(kb)), e.clone());
|
||||
e
|
||||
}
|
||||
}
|
||||
out.push(mt::Face::new(vec![wire.into()], surface));
|
||||
};
|
||||
wire.push(if ka < kb { e } else { e.inverse() });
|
||||
}
|
||||
let shell: mt::Shell = out.into();
|
||||
let solid = Solid::try_new(vec![shell]).map_err(|e| KernelError::Failed(format!("sphere: {e}")))?;
|
||||
record::attach(Body::new(solid)?, &[], Some(vec![record::profile(arcs); 6]), Default::default())
|
||||
})
|
||||
// The meridian runs pole to pole through the side away from the patch.
|
||||
let (np, sp, back) = (center + axis * radius, center - axis * radius, center - dir * radius);
|
||||
let meridian = builder::circle_arc(&builder::vertex(p3(np)), &builder::vertex(p3(sp)), p3(back));
|
||||
let mut surface =
|
||||
mt::Surface::RevolutedCurve(mt::Processor::new(mt::RevolutedCurve::by_revolution(meridian.oriented_curve(), p3(center), v3(axis))));
|
||||
// Outward normal at the patch centre.
|
||||
let probe = p3(center + dir * radius);
|
||||
use mt::{ParametricSurface3D, SearchParameter};
|
||||
if let Some((u, v)) = surface.search_parameter(probe, mt::SPHint2D::None, 100) {
|
||||
let n = surface.normal(u, v);
|
||||
if mt::InnerSpace::dot(n, v3(dir)) < 0.0 {
|
||||
mt::Invertible::invert(&mut surface);
|
||||
}
|
||||
}
|
||||
out.push(mt::Face::new(vec![wire.into()], surface));
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
Reference in new issue
Block a user