microcad_core/geo3d/
geometry.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use crate::{
5    traits::{Center, TotalMemory, VertexCount},
6    *,
7};
8
9use derive_more::From;
10use std::rc::Rc;
11use strum::IntoStaticStr;
12
13use crate::geo3d::*;
14
15/// 3D Geometry
16#[derive(IntoStaticStr, From, Clone)]
17pub enum Geometry3D {
18    /// Triangle mesh.
19    Mesh(TriangleMesh),
20    /// Manifold.
21    Manifold(Rc<Manifold>),
22    /// Collection.
23    Collection(Geometries3D),
24}
25
26impl std::fmt::Debug for Geometry3D {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        let name: &'static str = self.into();
29        write!(f, "{name}")
30    }
31}
32
33impl Geometry3D {
34    /// Return name of geometry.
35    pub fn name(&self) -> &'static str {
36        self.into()
37    }
38
39    /// Execute boolean operation.
40    pub fn boolean_op(&self, other: &Geometry3D, op: &BooleanOp) -> Option<Self> {
41        let op: manifold_rs::BooleanOp = op.into();
42        let a: Rc<Manifold> = self.clone().into();
43        let b: Rc<Manifold> = other.clone().into();
44        Some(Geometry3D::Manifold(Rc::new(a.boolean_op(&b, op))))
45    }
46
47    /// Calculate contex hull.
48    pub fn hull(&self) -> Self {
49        match &self {
50            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.to_manifold().hull().into(),
51            Geometry3D::Manifold(manifold) => manifold.hull().into(),
52            Geometry3D::Collection(collection) => {
53                TriangleMesh::from(collection).to_manifold().hull().into()
54            }
55        }
56    }
57
58    /// Return this geometry with calculated bounds.
59    pub fn with_bounds(self) -> WithBounds3D<Geometry3D> {
60        let bounds = self.calc_bounds_3d();
61        WithBounds3D {
62            bounds,
63            inner: self,
64        }
65    }
66}
67
68impl CalcBounds3D for Geometry3D {
69    fn calc_bounds_3d(&self) -> Bounds3D {
70        match self {
71            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.calc_bounds_3d(),
72            Geometry3D::Manifold(manifold) => {
73                TriangleMesh::from(manifold.to_mesh()).calc_bounds_3d()
74            }
75            Geometry3D::Collection(collection) => collection.calc_bounds_3d(),
76        }
77    }
78}
79
80impl Transformed3D for Geometry3D {
81    fn transformed_3d(&self, mat: &Mat4) -> Self {
82        TriangleMesh::from(self.clone()).transformed_3d(mat).into()
83    }
84}
85
86impl Center for Geometry3D {
87    fn center(&self) -> Self {
88        let d: Vec3 = self.calc_bounds_3d().center();
89        self.transformed_3d(&Mat4::from_translation(-d))
90    }
91}
92
93impl From<Manifold> for Geometry3D {
94    fn from(manifold: Manifold) -> Self {
95        Geometry3D::Manifold(Rc::new(manifold))
96    }
97}
98
99impl From<Geometry3D> for Rc<Manifold> {
100    fn from(geo: Geometry3D) -> Self {
101        match geo {
102            Geometry3D::Mesh(triangle_mesh) => Rc::new(triangle_mesh.to_manifold()),
103            Geometry3D::Manifold(manifold) => manifold,
104            Geometry3D::Collection(ref collection) => {
105                Rc::new(TriangleMesh::from(collection).to_manifold())
106            }
107        }
108    }
109}
110
111impl TotalMemory for Rc<Manifold> {} // TODO: Get estimation of total memory of Manifold via C++ API.
112
113impl TotalMemory for Geometry3D {
114    fn heap_memory(&self) -> usize {
115        match &self {
116            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.heap_memory(),
117            Geometry3D::Manifold(manifold) => manifold.heap_memory(),
118            Geometry3D::Collection(collection) => collection.heap_memory(),
119        }
120    }
121}
122
123impl VertexCount for Rc<Manifold> {
124    fn vertex_count(&self) -> usize {
125        0 // TODO: Get number of vertices for Manifold via C++ API
126    }
127}
128
129impl VertexCount for Geometry3D {
130    fn vertex_count(&self) -> usize {
131        match &self {
132            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.vertex_count(),
133            Geometry3D::Manifold(manifold) => manifold.vertex_count(),
134            Geometry3D::Collection(collection) => collection.vertex_count(),
135        }
136    }
137}