manifold_rs/
lib.rs

1// Copyright © 2024 The µCAD authors <info@ucad.xyz>
2// SPDX-License-Identifier: Apache-2.0
3
4//! Rust integration of C++ library *Manifold* for geometric operations
5
6#[cfg(feature = "output")]
7pub mod output;
8
9#[cxx::bridge(namespace = "manifold_rs")]
10mod ffi {
11    // C++ types and signatures exposed to Rust.
12    unsafe extern "C++" {
13        include!("manifold_rs.h");
14
15        type Polygons;
16
17        /// Get the number of polygons.
18        fn size(self: &Polygons) -> usize;
19
20        /// Get the number of vertices in a polygon.
21        fn get_as_slice(self: &Polygons, i: usize) -> &[f64];
22
23        /// Manifold object, wrapper for C++ manifold object.
24        type Manifold;
25
26        fn is_empty(self: &Manifold) -> bool;
27
28        /// Slice the manifold into a set of polygons.
29        fn slice(self: &Manifold, height: f64) -> UniquePtr<Polygons>;
30
31        /// Project the manifold onto a plane and return the resulting polygons.
32        fn project(self: &Manifold) -> UniquePtr<Polygons>;
33
34        /// Create an empty manifold.
35        fn empty() -> UniquePtr<Manifold>;
36
37        /// Create a tetrahedron.
38        fn tetrahedron() -> UniquePtr<Manifold>;
39
40        /// Create a sphere manifold.
41        fn sphere(radius: f64, segments: u32) -> UniquePtr<Manifold>;
42
43        /// Create a cube manifold.
44        fn cube(x_size: f64, y_size: f64, z_size: f64) -> UniquePtr<Manifold>;
45
46        /// Create a cylinder manifold.
47        fn cylinder(
48            radius_low: f64,
49            radius_high: f64,
50            height: f64,
51            segments: u32,
52        ) -> UniquePtr<Manifold>;
53
54        /// Get the union of two manifolds.
55        fn union_(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
56
57        /// Get the intersection of two manifolds.
58        fn intersection(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
59
60        /// Get the difference of two manifolds.
61        fn difference(a: &Manifold, b: &Manifold) -> UniquePtr<Manifold>;
62
63        /// Trim by a plane.
64        fn trim_by_plane(
65            self: &Manifold,
66            x: f64,
67            y: f64,
68            z: f64,
69            offset: f64,
70        ) -> UniquePtr<Manifold>;
71
72        /// Convex hull.
73        fn hull(self: &Manifold) -> UniquePtr<Manifold>;
74
75        /// Translate the manifold.
76        fn translate(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
77
78        /// Scale the manifold.
79        fn scale(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
80
81        /// Rotate the manifold.
82        fn rotate(self: &Manifold, x: f64, y: f64, z: f64) -> UniquePtr<Manifold>;
83
84        /// Extrude a polygon to create a manifold.
85        fn extrude(
86            multi_polygon_data: &[&[f64]],
87            height: f64,
88            n_divisions: u32,
89            twist_degrees: f64,
90            scale_top_x: f64,
91            scale_top_y: f64,
92        ) -> UniquePtr<Manifold>;
93
94        /// Revolve a polygon to create a manifold.
95        fn revolve(
96            multi_polygon_data: &[&[f64]],
97            circular_segments: u32,
98            revolve_degrees: f64,
99        ) -> UniquePtr<Manifold>;
100
101        /// Refine manifold.
102        fn refine(self: &Manifold, n: i32) -> UniquePtr<Manifold>;
103
104        /// Refine manifold to Length.
105        fn refine_to_length(self: &Manifold, t: f64) -> UniquePtr<Manifold>;
106
107        /// Refine to tolerance.
108        fn refine_to_tolerance(self: &Manifold, t: f64) -> UniquePtr<Manifold>;
109
110        /// Smooth by normals.
111        fn smooth_by_normals(self: &Manifold, normal_idx: i32) -> UniquePtr<Manifold>;
112
113        /// Smooth out.
114        fn smooth_out(
115            self: &Manifold,
116            min_sharp_angle: f64,
117            min_smoothness: f64,
118        ) -> UniquePtr<Manifold>;
119
120        /// Calculate normals for the manifold and return a new one.
121        fn calculate_normals(
122            self: &Manifold,
123            normal_idx: i32,
124            min_sharp_angle: f64,
125        ) -> UniquePtr<Manifold>;
126
127        /// Manifold object, wrapper for C++ mesh object.
128        type Mesh;
129
130        /// Get the number of vertex properties of a mesh.
131        fn num_props(self: &Mesh) -> u32;
132
133        /// Get the vertices of the mesh.
134        fn vertices(self: &Mesh) -> UniquePtr<CxxVector<f32>>;
135
136        /// Get the indices of the mesh.
137        fn indices(self: &Mesh) -> UniquePtr<CxxVector<u32>>;
138
139        /// Create a mesh from a manifold.
140        fn mesh_from_manifold(manifold: &Manifold) -> UniquePtr<Mesh>;
141
142        /// Create a manifold from a mesh.
143        fn manifold_from_mesh(mesh: &Mesh) -> UniquePtr<Manifold>;
144
145        /// Create a mesh from vertices and indices.
146        ///
147        /// The vertices are a flat array of floats containing the x, y, z coordinates of each vertex.
148        /// The indices are a flat array of unsigned integers containing the indices of the vertices.
149        fn mesh_from_vertices(vertices: &[f32], indices: &[u32]) -> UniquePtr<Mesh>;
150    }
151}
152
153/// Boolean operation on manifolds.
154pub enum BooleanOp {
155    /// Union of two manifolds.
156    Union,
157    /// Intersection of two manifolds.
158    Intersection,
159    /// Difference of two manifolds.
160    Difference,
161}
162
163/// Manifold rust wrapper for C++ polygons object.
164pub struct Polygons(cxx::UniquePtr<ffi::Polygons>);
165
166impl Polygons {
167    /// Get the number of polygons.
168    pub fn size(&self) -> usize {
169        self.0.size()
170    }
171
172    /// Get the number of vertices in a polygon.
173    pub fn get_as_slice(&self, i: usize) -> &[f64] {
174        self.0.get_as_slice(i)
175    }
176}
177
178/// Manifold rust wrapper for C++ manifold object.
179pub struct Manifold(cxx::UniquePtr<ffi::Manifold>);
180
181impl Manifold {
182    /// Does [`Manifold`] contain triangles?
183    pub fn is_empty(&self) -> bool {
184        self.0.is_empty()
185    }
186
187    /// Slice the manifold into a set of polygons.
188    pub fn slice(&self, height: f64) -> Polygons {
189        Polygons(self.0.slice(height))
190    }
191
192    /// Project the manifold onto a plane and return the resulting polygons.
193    pub fn project(&self) -> Polygons {
194        Polygons(self.0.project())
195    }
196
197    /// Trim by a plane.
198    pub fn trim_by_plane(&self, x: f64, y: f64, z: f64, offset: f64) -> Self {
199        Self(self.0.trim_by_plane(x, y, z, offset))
200    }
201
202    /// Convex hull.
203    pub fn hull(&self) -> Self {
204        Self(self.0.hull())
205    }
206
207    /// Translate the manifold.
208    pub fn translate(&self, x: f64, y: f64, z: f64) -> Self {
209        Self(self.0.translate(x, y, z))
210    }
211
212    /// Scale the manifold.
213    pub fn scale(&self, x: f64, y: f64, z: f64) -> Self {
214        Self(self.0.scale(x, y, z))
215    }
216
217    /// Rotate the manifold.
218    pub fn rotate(&self, x: f64, y: f64, z: f64) -> Self {
219        Self(self.0.rotate(x, y, z))
220    }
221
222    /// Create empty manifold.
223    pub fn empty() -> Self {
224        Self(ffi::empty())
225    }
226
227    /// Create tetrahedron manifold.
228    pub fn tetrahedron() -> Self {
229        Self(ffi::tetrahedron())
230    }
231
232    /// Create a sphere manifold.
233    pub fn sphere(radius: f64, segments: u32) -> Self {
234        Self(ffi::sphere(radius, segments))
235    }
236
237    /// Create a cube manifold.
238    pub fn cube(x_size: f64, y_size: f64, z_size: f64) -> Self {
239        Self(ffi::cube(x_size, y_size, z_size))
240    }
241
242    /// Create a cylinder manifold.
243    pub fn cylinder(radius_low: f64, radius_high: f64, height: f64, segments: u32) -> Self {
244        Self(ffi::cylinder(radius_low, radius_high, height, segments))
245    }
246
247    /// Get the union of two manifolds.
248    pub fn union(&self, b: &Self) -> Self {
249        Self(ffi::union_(self.inner(), b.inner()))
250    }
251
252    /// Get the intersection of two manifolds.
253    pub fn intersection(&self, b: &Self) -> Self {
254        Self(ffi::intersection(self.inner(), b.inner()))
255    }
256
257    /// Get the difference of two manifolds.
258    pub fn difference(&self, b: &Self) -> Self {
259        Self(ffi::difference(self.inner(), b.inner()))
260    }
261
262    /// Boolean operation on manifolds.
263    pub fn boolean_op(&self, b: &Self, op: crate::BooleanOp) -> Self {
264        match op {
265            crate::BooleanOp::Union => self.union(b),
266            crate::BooleanOp::Intersection => self.intersection(b),
267            crate::BooleanOp::Difference => self.difference(b),
268        }
269    }
270
271    /// Extrude a polygon to create a manifold.
272    pub fn extrude(
273        multi_polygon_data: &[&[f64]],
274        height: f64,
275        n_divisions: u32,
276        twist_degrees: f64,
277        scale_top_x: f64,
278        scale_top_y: f64,
279    ) -> Self {
280        Self(ffi::extrude(
281            multi_polygon_data,
282            height,
283            n_divisions,
284            twist_degrees,
285            scale_top_x,
286            scale_top_y,
287        ))
288    }
289
290    /// Revolve a polygon to create a manifold.
291    pub fn revolve(
292        multi_polygon_data: &[&[f64]],
293        circular_segments: u32,
294        revolve_degrees: f64,
295    ) -> Self {
296        Self(ffi::revolve(
297            multi_polygon_data,
298            circular_segments,
299            revolve_degrees,
300        ))
301    }
302
303    /// Refine manifold.
304    pub fn refine(self: &Manifold, n: i32) -> Self {
305        Self(self.0.refine(n))
306    }
307
308    /// Refine manifold to Length.
309    pub fn refine_to_length(self: &Manifold, t: f64) -> Self {
310        Self(self.0.refine_to_length(t))
311    }
312
313    /// Refine to tolerance.
314    pub fn refine_to_tolerance(self: &Manifold, t: f64) -> Self {
315        Self(self.0.refine_to_tolerance(t))
316    }
317
318    /// Smooth by normals.
319    pub fn smooth_by_normals(self: &Manifold, normal_idx: i32) -> Self {
320        Self(self.0.smooth_by_normals(normal_idx))
321    }
322
323    /// Smooth out.
324    pub fn smooth_out(self: &Manifold, min_sharp_angle: f64, min_smoothness: f64) -> Self {
325        Self(self.0.smooth_out(min_sharp_angle, min_smoothness))
326    }
327
328    /// Calculate normals for the manifold and return a new one.
329    pub fn calculate_normals(self: &Manifold, normal_idx: i32, min_sharp_angle: f64) -> Self {
330        Self(self.0.calculate_normals(normal_idx, min_sharp_angle))
331    }
332
333    /// Get the mesh representation of the manifold.
334    pub fn to_mesh(&self) -> Mesh {
335        Mesh(ffi::mesh_from_manifold(&self.0))
336    }
337
338    /// Create a manifold from a mesh.
339    pub fn from_mesh(mesh: Mesh) -> Self {
340        mesh.into()
341    }
342
343    /// Get the inner C++ manifold object.
344    fn inner(&self) -> &ffi::Manifold {
345        self.0.as_ref().unwrap()
346    }
347}
348
349/// Wrapper around a C++ mesh object.
350pub struct Mesh(cxx::UniquePtr<ffi::Mesh>);
351
352/// Implementations for the Mesh struct.
353impl Mesh {
354    /// Create a new mesh from vertices and indices.
355    pub fn new(vertices: &[f32], indices: &[u32]) -> Self {
356        let mesh = ffi::mesh_from_vertices(vertices, indices);
357        Self(mesh)
358    }
359
360    /// Number of properties per vertex
361    pub fn num_props(&self) -> u32 {
362        self.0.num_props()
363    }
364
365    /// Get the vertices of the mesh.
366    pub fn vertices(&self) -> Vec<f32> {
367        let vertices_binding = self.0.vertices();
368        let vertices = vertices_binding.as_ref().unwrap().as_slice();
369        vertices.to_vec()
370    }
371
372    /// Get the indices of the mesh.
373    pub fn indices(&self) -> Vec<u32> {
374        let indices_binding = self.0.indices();
375        let indices = indices_binding.as_ref().unwrap().as_slice();
376        indices.to_vec()
377    }
378
379    /// Get the manifold representation of the mesh.
380    pub fn to_manifold(&self) -> Manifold {
381        let manifold = ffi::manifold_from_mesh(&self.0);
382        Manifold(manifold)
383    }
384}
385
386/// Convert Mesh to Manifold struct
387impl From<Mesh> for Manifold {
388    fn from(mesh: Mesh) -> Self {
389        mesh.to_manifold()
390    }
391}
392
393/// Convert Manifold to Mesh struct
394impl From<Manifold> for Mesh {
395    fn from(manifold: Manifold) -> Self {
396        manifold.to_mesh()
397    }
398}
399
400#[test]
401fn test_manifold_ffi() {
402    let sphere = ffi::sphere(1.0, 32);
403
404    let mesh = ffi::mesh_from_manifold(&sphere);
405
406    let vertices_binding = mesh.vertices();
407    let vertices = vertices_binding.as_ref().unwrap().as_slice();
408    assert!(!vertices.is_empty());
409
410    let indices_binding = mesh.indices();
411    let indices = indices_binding.as_ref().unwrap().as_slice();
412    assert!(!indices.is_empty());
413}