Skip to content

Commit 1485e83

Browse files
committed
implement From for Mesh and BMesh
1 parent 6230d43 commit 1485e83

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

src/bmesh/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use boolmesh::{
1717

1818
use nalgebra::{Matrix4, Point3};
1919
use std::{fmt::Debug, sync::OnceLock};
20+
use crate::mesh::Mesh;
2021

2122
/// A solid represented by boolmesh’s `Manifold`, wired into csgrs’ `CSG` trait.
2223
///
@@ -247,3 +248,47 @@ impl<S: Clone + Send + Sync + Debug> CSG for BMesh<S> {
247248
}
248249
}
249250

251+
impl<S: Clone + Send + Sync + Debug> From<Mesh<S>> for BMesh<S> {
252+
fn from(mesh: Mesh<S>) -> Self {
253+
// Keep the metadata from the original mesh
254+
let metadata = mesh.metadata.clone();
255+
256+
// Triangulate the mesh (this also fixes T-junctions etc. via your existing code)
257+
let tri_mesh = mesh.triangulate();
258+
259+
// Extract vertices and triangle indices from the triangulated mesh
260+
let (vertices, indices) = tri_mesh.get_vertices_and_indices();
261+
262+
// Flatten vertices into boolmesh's `Vec<Real>` layout: [x0, y0, z0, x1, y1, z1, ...]
263+
let mut pos_bool: Vec<boolmesh::Real> = Vec::with_capacity(vertices.len() * 3);
264+
for v in &vertices {
265+
pos_bool.push(v.x as boolmesh::Real);
266+
pos_bool.push(v.y as boolmesh::Real);
267+
pos_bool.push(v.z as boolmesh::Real);
268+
}
269+
270+
// Flatten triangle indices into `Vec<usize>`
271+
let mut idx_bool: Vec<usize> = Vec::with_capacity(indices.len() * 3);
272+
for tri in &indices {
273+
idx_bool.push(tri[0] as usize);
274+
idx_bool.push(tri[1] as usize);
275+
idx_bool.push(tri[2] as usize);
276+
}
277+
278+
// If there are no triangles, treat as empty BMesh
279+
let manifold = if idx_bool.is_empty() {
280+
None
281+
} else {
282+
Some(
283+
Manifold::new(&pos_bool, &idx_bool)
284+
.expect("boolmesh::Manifold::new failed when converting from Mesh"),
285+
)
286+
};
287+
288+
BMesh {
289+
manifold,
290+
bounding_box: OnceLock::new(),
291+
metadata,
292+
}
293+
}
294+
}

src/mesh/mod.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use std::{
2626
num::NonZeroU32,
2727
sync::OnceLock,
2828
};
29+
use crate::bmesh::BMesh;
2930

3031
#[cfg(feature = "parallel")]
3132
use rayon::{iter::IntoParallelRefIterator, prelude::*};
@@ -1169,3 +1170,52 @@ impl<S: Clone + Send + Sync + Debug> From<Sketch<S>> for Mesh<S> {
11691170
}
11701171
}
11711172
}
1173+
1174+
impl<S: Clone + Send + Sync + Debug> From<BMesh<S>> for Mesh<S> {
1175+
fn from(bmesh: BMesh<S>) -> Self {
1176+
// Empty BMesh -> empty Mesh
1177+
let Some(manifold) = bmesh.manifold else {
1178+
return Mesh::<S>::new();
1179+
};
1180+
1181+
// Convert boolmesh vertices (glam) into nalgebra points
1182+
let mut points: Vec<Point3<Real>> = Vec::with_capacity(manifold.ps.len());
1183+
for p in &manifold.ps {
1184+
points.push(Point3::new(p.x as Real, p.y as Real, p.z as Real));
1185+
}
1186+
1187+
// Each 3 half-edges in hs correspond to 1 triangle face
1188+
let mut polygons: Vec<Polygon<S>> = Vec::with_capacity(manifold.hs.len() / 3);
1189+
1190+
for halfs in manifold.hs.chunks_exact(3) {
1191+
let i0 = halfs[0].tail;
1192+
let i1 = halfs[1].tail;
1193+
let i2 = halfs[2].tail;
1194+
1195+
// Safeguard against invalid indices
1196+
if i0 >= points.len() || i1 >= points.len() || i2 >= points.len() {
1197+
continue;
1198+
}
1199+
1200+
let p0 = points[i0];
1201+
let p1 = points[i1];
1202+
let p2 = points[i2];
1203+
1204+
// Compute triangle normal
1205+
let e1: Vector3<Real> = p1 - p0;
1206+
let e2: Vector3<Real> = p2 - p0;
1207+
let mut n = e1.cross(&e2);
1208+
if let Some(unit) = n.try_normalize(1e-12) {
1209+
n = unit;
1210+
}
1211+
1212+
let v0 = Vertex::new(p0, n);
1213+
let v1 = Vertex::new(p1, n);
1214+
let v2 = Vertex::new(p2, n);
1215+
1216+
polygons.push(Polygon::new(vec![v0, v1, v2], bmesh.metadata.clone()));
1217+
}
1218+
1219+
Mesh::from_polygons(&polygons, bmesh.metadata.clone())
1220+
}
1221+
}

0 commit comments

Comments
 (0)