rust_3d/
mesh_3d.rs

1/*
2Copyright 2016 Martin Buck
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation the
7rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the Software
9is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall
12be included all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21*/
22
23//! Mesh3D, a mesh with tri-faces within 3D space
24
25use crate::*;
26
27use std::marker::PhantomData;
28
29//------------------------------------------------------------------------------
30
31#[derive(Default, Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Hash)]
32/// Mesh3D, a mesh with tri-faces within 3D space
33pub struct Mesh3D<P, ID, IC>
34where
35    P: Is3D,
36    ID: IsDataContainer<P>,
37    IC: IsIndexContainer,
38{
39    pc: ID,
40    topology: IC,
41    _phantom: PhantomData<P>,
42}
43
44impl<P, ID, IC> IsMesh<P, Face3> for Mesh3D<P, ID, IC>
45where
46    P: Is3D + Clone,
47    ID: IsDataContainer<P>,
48    IC: IsIndexContainer,
49{
50    fn num_faces(&self) -> usize {
51        self.topology.len() / 3
52    }
53
54    fn num_vertices(&self) -> usize {
55        self.pc.len_d()
56    }
57
58    fn face_vertex_ids(&self, faceid: FId) -> Result<Face3> {
59        let id1 = 3 * faceid.val + 0;
60        let id2 = 3 * faceid.val + 1;
61        let id3 = 3 * faceid.val + 2;
62
63        if id3 >= self.topology.len() {
64            return Err(ErrorKind::IncorrectFaceID);
65        }
66
67        Ok(Face3::new(
68            VId {
69                val: self.topology.get(id1),
70            },
71            VId {
72                val: self.topology.get(id2),
73            },
74            VId {
75                val: self.topology.get(id3),
76            },
77        ))
78    }
79
80    fn face_vertices(&self, faceid: FId) -> Result<[P; 3]> {
81        let face = self.face_vertex_ids(faceid)?;
82        if let (Ok(v1), Ok(v2), Ok(v3)) = (
83            self.vertex(face.a),
84            self.vertex(face.b),
85            self.vertex(face.c),
86        ) {
87            return Ok([v1, v2, v3]);
88        }
89        Err(ErrorKind::IncorrectVertexID)
90    }
91
92    fn vertex(&self, vertexid: VId) -> Result<P> {
93        if vertexid.val >= self.pc.len_d() {
94            return Err(ErrorKind::IncorrectVertexID);
95        }
96        Ok(self.pc.get_d(vertexid.val))
97    }
98}
99
100impl<P, ID, IC> IsFaceEditableMesh<P, Face3> for Mesh3D<P, ID, IC>
101where
102    P: IsEditable3D + IsBuildable3D + Clone,
103    ID: IsDataContainer<P>,
104    IC: IsIndexContainer,
105{
106    fn add_face(&mut self, v1: P, v2: P, v3: P) -> FId {
107        let vid1 = self.add_vertex(v1);
108        let vid2 = self.add_vertex(v2);
109        let vid3 = self.add_vertex(v3);
110        self.topology.push(vid1.val);
111        self.topology.push(vid2.val);
112        self.topology.push(vid3.val);
113        FId {
114            val: self.topology.len() / 3 - 1,
115        }
116    }
117
118    fn try_add_connection(&mut self, vid1: VId, vid2: VId, vid3: VId) -> Result<FId> {
119        if vid1.val >= self.pc.len_d()
120            || vid2.val >= self.pc.len_d()
121            || vid3.val >= self.pc.len_d()
122            || vid1 == vid2
123            || vid1 == vid3
124            || vid2 == vid3
125        {
126            return Err(ErrorKind::IncorrectVertexID);
127        }
128        self.topology.push(vid1.val);
129        self.topology.push(vid2.val);
130        self.topology.push(vid3.val);
131        Ok(FId {
132            val: self.topology.len() / 3 - 1,
133        })
134    }
135
136    fn reserve_faces(&mut self, n: usize) {
137        self.topology.reserve(3 * n)
138    }
139}
140
141impl<P, ID, IC> IsVertexEditableMesh<P, Face3> for Mesh3D<P, ID, IC>
142where
143    P: IsEditable3D + IsBuildable3D + Clone,
144    ID: IsDataContainer<P>,
145    IC: IsIndexContainer,
146{
147    fn add_vertex(&mut self, vertex: P) -> VId {
148        self.pc.push_d(vertex);
149        VId {
150            val: self.pc.len_d() - 1,
151        }
152    }
153
154    fn change_vertex(&mut self, vid: VId, vertex: P) -> Result<()> {
155        if vid.val < self.pc.len_d() {
156            self.pc.set_d(vid.val, vertex);
157            Ok(())
158        } else {
159            Err(ErrorKind::IncorrectVertexID)
160        }
161    }
162
163    fn reserve_vertices(&mut self, n: usize) {
164        self.pc.reserve_d(n)
165    }
166}
167
168impl<P, ID, IC> HasBoundingBox3DMaybe for Mesh3D<P, ID, IC>
169where
170    P: Is3D,
171    ID: IsDataContainer<P> + HasBoundingBox3DMaybe,
172    IC: IsIndexContainer,
173{
174    fn bounding_box_maybe(&self) -> Result<BoundingBox3D> {
175        self.pc.bounding_box_maybe()
176    }
177}
178
179impl<P, ID, IC> HasCenterOfGravity3D for Mesh3D<P, ID, IC>
180where
181    P: Is3D,
182    ID: IsDataContainer<P> + HasCenterOfGravity3D,
183    IC: IsIndexContainer,
184{
185    fn center_of_gravity(&self) -> Result<Point3D> {
186        self.pc.center_of_gravity()
187    }
188}
189
190impl<P, ID, IC> IsScalable for Mesh3D<P, ID, IC>
191where
192    P: IsEditable3D,
193    ID: IsDataContainer<P> + IsScalable,
194    IC: IsIndexContainer,
195{
196    fn scale(&mut self, factor: Positive) {
197        self.pc.scale(factor);
198    }
199}
200
201impl<P, ID, IC> IsMatrix4Transformable for Mesh3D<P, ID, IC>
202where
203    P: Is3D + IsMatrix4Transformable + Clone,
204    ID: IsDataContainer<P> + IsMatrix4Transformable + Clone,
205    IC: IsIndexContainer,
206{
207    fn transformed(&self, m: &Matrix4) -> Self {
208        let mut new = self.clone();
209        new.transform(m);
210        new
211    }
212
213    fn transform(&mut self, m: &Matrix4) {
214        self.pc.transform(m);
215    }
216}
217
218impl<P, ID, IC> IsMovable3D for Mesh3D<P, ID, IC>
219where
220    P: Is3D + IsMovable3D,
221    ID: IsDataContainer<P> + IsMovable3D,
222    IC: IsIndexContainer,
223{
224    fn move_by(&mut self, x: f64, y: f64, z: f64) {
225        self.pc.move_by(x, y, z)
226    }
227}
228
229impl<P, ID, IC> From<(ID, IC)> for Mesh3D<P, ID, IC>
230where
231    P: Is3D,
232    ID: IsDataContainer<P>,
233    IC: IsIndexContainer,
234{
235    fn from(pt: (ID, IC)) -> Self {
236        Self {
237            pc: pt.0,
238            topology: pt.1,
239            _phantom: PhantomData::default(),
240        }
241    }
242}
243
244impl<P, ID, IC> Into<(ID, IC)> for Mesh3D<P, ID, IC>
245where
246    P: Is3D,
247    ID: IsDataContainer<P>,
248    IC: IsIndexContainer,
249{
250    fn into(self) -> (ID, IC) {
251        (self.pc, self.topology)
252    }
253}