Display tessellation plans (3/4): display meshes from plans, GPU evaluation in the viewport (#805)
Display meshes are built from tessellation plans, with GPU evaluation in the viewport.
This commit is contained in:
1 parent
534393ed5a
commit
ff7a347013
19 files changed
+1474
-77
No files matched your search
@@ -1093,9 +1093,21 @@ impl Body {
|
||||
has.iter().filter(|h| !**h).count()
|
||||
}
|
||||
|
||||
/// Display mesh: like [`Body::tessellate`], with seam edges flagged.
|
||||
/// Display mesh: like [`Body::tessellate`], with seam edges flagged. Meshed from the
|
||||
/// body's [`Body::display_plan`] (shared edge nodes, structured grids), or the way
|
||||
/// [`Body::tessellate`] meshes when no plan can be made.
|
||||
pub fn display_mesh(&self, tol: f64) -> Result<Mesh> {
|
||||
self.flagged(self.tessellate(tol)?)
|
||||
if self.is_mesh() {
|
||||
return self.flagged(self.tessellate(tol)?);
|
||||
}
|
||||
let m = match self.display_plan(tol) {
|
||||
Ok(plan) => plan.evaluate(),
|
||||
Err(e) => {
|
||||
log::debug!("display mesh: {e}; meshing the reference way");
|
||||
self.tessellate(tol)?
|
||||
}
|
||||
};
|
||||
self.flagged(m)
|
||||
}
|
||||
|
||||
/// Display mesh whose curved faces and edges look curved whatever the body's size: like
|
||||
@@ -1104,6 +1116,30 @@ impl Body {
|
||||
/// sagitta of a small radius on a large body (a sheet-metal bend, a small hole), which the
|
||||
/// tolerance alone leaves as one flat facet.
|
||||
pub fn display_mesh_angular(&self, tol: f64, angle: f64) -> Result<Mesh> {
|
||||
if self.is_mesh() {
|
||||
return self.flagged(self.tessellate(tol)?);
|
||||
}
|
||||
match self.display_plan_angular(tol, angle) {
|
||||
Ok(plan) => self.display_mesh_of(&plan),
|
||||
Err(e) => {
|
||||
log::debug!("display mesh: {e}; meshing the reference way");
|
||||
self.reference_display_mesh_angular(tol, angle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The display mesh of a plan made from this body ([`Body::display_plan`],
|
||||
/// [`Body::display_plan_angular`]): evaluated on the CPU, with its edges flagged.
|
||||
pub fn display_mesh_of(&self, plan: &solidcraft_geom::tess::TessPlan) -> Result<Mesh> {
|
||||
self.flagged(plan.evaluate())
|
||||
}
|
||||
|
||||
/// The reference mesher's angular display mesh: what [`Body::display_mesh_angular`] falls
|
||||
/// back to when no plan can be made.
|
||||
pub fn reference_display_mesh_angular(&self, tol: f64, angle: f64) -> Result<Mesh> {
|
||||
if self.is_mesh() {
|
||||
return self.flagged(self.tessellate(tol)?);
|
||||
}
|
||||
self.flagged(self.tessellate_within(tol, angle, false)?)
|
||||
}
|
||||
|
||||
|
||||
@@ -406,7 +406,9 @@ mod tests {
|
||||
assert!(display.contains(Vec3::new(width / 2. - thickness / 2., 0., thickness / 2.)));
|
||||
assert!(display.contains(Vec3::new(width / 2. - thickness / 2., 0., 15.)));
|
||||
assert!(!display.contains(Vec3::new(0., 0., 15.)));
|
||||
assert_eq!(raw.measure().volume, display.measure().volume);
|
||||
// Different meshers (the display plan and the reference), both within 0.01 mm.
|
||||
let (rv, dv) = (raw.measure().volume, display.measure().volume);
|
||||
assert!((rv - dv).abs() <= raw.measure().area * 0.01, "display volume {dv} vs {rv}");
|
||||
let expected = (width * 60. - (4. - std::f64::consts::PI) * 36.) * 30.
|
||||
- ((width - 2. * thickness) * (60. - 2. * thickness) - (4. - std::f64::consts::PI) * (6. - thickness).powi(2)) * (30. - thickness);
|
||||
assert!((cup.tessellate(1e-4).unwrap().measure().volume - expected).abs() < 0.2);
|
||||
@@ -549,7 +551,8 @@ mod tests {
|
||||
assert!(!display.contains(Vec3::new(0., 0., 5.)));
|
||||
assert!(display.contains(Vec3::new(28., 0., 5.)));
|
||||
assert!((display.measure().volume - (60. * 54. * 10. - 4. * x * y * 9.)).abs() < 1e-7);
|
||||
assert_eq!(raw.measure().volume, display.measure().volume);
|
||||
// Different triangulations of the same polyhedron: equal up to rounding.
|
||||
assert!((raw.measure().volume - display.measure().volume).abs() < 1e-9 * raw.measure().volume);
|
||||
let imported = crate::step_import(&crate::step_export(&[&pocket], "regularized pocket").unwrap()).unwrap();
|
||||
assert!(imported.warnings.is_empty());
|
||||
let copy = &imported.bodies[0].body;
|
||||
|
||||
@@ -256,13 +256,15 @@ mod tests {
|
||||
assert!(mesh.shaded_edge_visible(index));
|
||||
}
|
||||
}
|
||||
// Smoothing flags are display-only: the edges and faces keep the body's identities.
|
||||
let raw = body.tessellate(0.02).unwrap();
|
||||
assert_eq!(mesh.edges, raw.edges);
|
||||
assert_eq!(mesh.edges.len(), raw.edges.len());
|
||||
assert_eq!(mesh.edge_faces, raw.edge_faces);
|
||||
assert_eq!(mesh.tri_face, raw.tri_face);
|
||||
assert_eq!(mesh.triangles, raw.triangles);
|
||||
assert_eq!(mesh.positions, raw.positions);
|
||||
assert_eq!(mesh.normals, raw.normals);
|
||||
for (a, b) in mesh.edges.iter().zip(&raw.edges) {
|
||||
assert_eq!((a.first(), a.last()), (b.first(), b.last()));
|
||||
}
|
||||
let faces = |m: &Mesh| m.tri_face.iter().copied().collect::<std::collections::BTreeSet<u32>>();
|
||||
assert_eq!(faces(&mesh), faces(&raw));
|
||||
let moved = crate::transform_matrix(&body, [[1., 0., 0., 0.], [0., 0., 1., 0.], [0., -1., 0., 0.], [30., 20., 10., 1.]]).unwrap();
|
||||
assert_eq!(moved.display_mesh(0.02).unwrap().smooth_edges.iter().filter(|f| **f).count(), 512);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user