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