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
6use std::rc::Rc;
7use strum::IntoStaticStr;
8
9use crate::geo3d::*;
10
11/// 3D Geometry
12#[derive(IntoStaticStr, Clone)]
13pub enum Geometry3D {
14    /// Triangle mesh.
15    Mesh(TriangleMesh),
16    /// Manifold.
17    Manifold(Rc<Manifold>),
18    /// Collection.
19    Collection(Geometries3D),
20}
21
22impl std::fmt::Debug for Geometry3D {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        let name: &'static str = self.into();
25        write!(f, "{name}")
26    }
27}
28
29impl Geometry3D {
30    /// Return name of geometry.
31    pub fn name(&self) -> &'static str {
32        self.into()
33    }
34
35    /// Execute boolean operation.
36    pub fn boolean_op(&self, other: &Geometry3D, op: &BooleanOp) -> Option<Self> {
37        let op: manifold_rs::BooleanOp = op.into();
38        let a: Rc<Manifold> = self.clone().into();
39        let b: Rc<Manifold> = other.clone().into();
40        Some(Geometry3D::Manifold(Rc::new(a.boolean_op(&b, op))))
41    }
42
43    /// Calculate contex hull.
44    pub fn hull(&self) -> Self {
45        match &self {
46            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.to_manifold().hull().into(),
47            Geometry3D::Manifold(manifold) => manifold.hull().into(),
48            Geometry3D::Collection(collection) => {
49                TriangleMesh::from(collection).to_manifold().hull().into()
50            }
51        }
52    }
53
54    /// Return this geometry with calculated bounds.
55    pub fn with_bounds(self) -> WithBounds3D<Geometry3D> {
56        let bounds = self.calc_bounds_3d();
57        WithBounds3D {
58            bounds,
59            inner: self,
60        }
61    }
62}
63
64impl CalcBounds3D for Geometry3D {
65    fn calc_bounds_3d(&self) -> Bounds3D {
66        match self {
67            Geometry3D::Mesh(triangle_mesh) => triangle_mesh.calc_bounds_3d(),
68            Geometry3D::Manifold(manifold) => {
69                TriangleMesh::from(manifold.to_mesh()).calc_bounds_3d()
70            }
71            Geometry3D::Collection(collection) => collection.calc_bounds_3d(),
72        }
73    }
74}
75
76impl Transformed3D for Geometry3D {
77    fn transformed_3d(&self, mat: &Mat4) -> Self {
78        TriangleMesh::from(self.clone()).transformed_3d(mat).into()
79    }
80}
81
82impl From<TriangleMesh> for Geometry3D {
83    fn from(mesh: TriangleMesh) -> Self {
84        Geometry3D::Mesh(mesh)
85    }
86}
87
88impl From<Manifold> for Geometry3D {
89    fn from(manifold: Manifold) -> Self {
90        Geometry3D::Manifold(Rc::new(manifold))
91    }
92}
93
94impl From<Rc<Manifold>> for Geometry3D {
95    fn from(manifold: Rc<Manifold>) -> Self {
96        Geometry3D::Manifold(manifold)
97    }
98}
99
100impl From<Geometry3D> for Rc<Manifold> {
101    fn from(geo: Geometry3D) -> Self {
102        match geo {
103            Geometry3D::Mesh(triangle_mesh) => Rc::new(triangle_mesh.to_manifold()),
104            Geometry3D::Manifold(manifold) => manifold,
105            Geometry3D::Collection(ref collection) => {
106                Rc::new(TriangleMesh::from(collection).to_manifold())
107            }
108        }
109    }
110}