1use std::fmt;
26
27use crate::*;
28
29#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Hash)]
32pub struct Polygon3D<P>
34where
35 P: Is3D,
36{
37 pc: PointCloud3D<P>,
38}
39
40impl<P> IsPolygon<P> for Polygon3D<P>
41where
42 P: Is3D + Clone,
43{
44 fn num_segments(&self) -> usize {
45 self.pc.len()
46 }
47
48 fn segment_vertex_ids(&self, segmentid: SId) -> Result<(VId, VId)> {
49 if segmentid.val >= self.pc.len() {
50 Err(ErrorKind::IncorrectSegmentID)
51 } else if segmentid.val == self.pc.len() - 1 {
52 Ok((VId { val: segmentid.val }, VId { val: 0 }))
53 } else {
54 Ok((
55 VId { val: segmentid.val },
56 VId {
57 val: segmentid.val + 1,
58 },
59 ))
60 }
61 }
62
63 fn segment_vertices(&self, segmentid: SId) -> Result<(P, P)> {
64 let (vid1, vid2) = self.segment_vertex_ids(segmentid)?;
65 Ok((self.pc[vid1.val].clone(), self.pc[vid2.val].clone()))
66 }
67
68 fn vertex(&self, vertexid: VId) -> Result<P> {
69 if vertexid.val >= self.pc.len() {
70 Err(ErrorKind::IncorrectVertexID)
71 } else {
72 Ok(self.pc[vertexid.val].clone())
73 }
74 }
75}
76
77impl<P> IsEditablePolygon<P> for Polygon3D<P>
78where
79 P: Is3D + Clone,
80{
81 fn add_vertex(&mut self, vertex: P) -> VId {
82 self.pc.data.push(vertex);
83 VId {
84 val: self.pc.len() - 1,
85 }
86 }
87
88 fn change_vertex(&mut self, vertexid: VId, vertex: P) -> Result<()> {
89 if vertexid.val >= self.pc.len() {
90 return Err(ErrorKind::IncorrectVertexID);
91 }
92
93 self.pc[vertexid.val] = vertex;
94 Ok(())
95 }
96}
97
98impl<P> IsMovable3D for Polygon3D<P>
99where
100 P: Is3D + IsMovable3D,
101{
102 fn move_by(&mut self, x: f64, y: f64, z: f64) {
103 self.pc.move_by(x, y, z)
104 }
105}
106
107impl<P> HasBoundingBox3DMaybe for Polygon3D<P>
108where
109 P: Is3D,
110{
111 fn bounding_box_maybe(&self) -> Result<BoundingBox3D> {
112 self.pc.bounding_box_maybe()
113 }
114}
115
116impl<P> HasCenterOfGravity3D for Polygon3D<P>
117where
118 P: Is3D,
119{
120 fn center_of_gravity(&self) -> Result<Point3D> {
121 self.pc.center_of_gravity()
122 }
123}
124
125impl<P> HasLength for Polygon3D<P>
126where
127 P: Is3D,
128{
129 fn length(&self) -> f64 {
130 let mut length = self.pc.length();
131
132 if self.pc.data.len() > 0 {
133 length += dist_3d(&self.pc.data[self.pc.data.len() - 1], &self.pc.data[0]);
134 }
135
136 length
137 }
138}
139
140impl<P> IsScalable for Polygon3D<P>
141where
142 P: IsEditable3D,
143{
144 fn scale(&mut self, factor: Positive) {
145 self.pc.scale(factor)
146 }
147}
148
149impl<P> IsMatrix4Transformable for Polygon3D<P>
150where
151 P: Is3D + IsMatrix4Transformable + Clone,
152{
153 fn transformed(&self, m: &Matrix4) -> Self {
154 let mut new = self.clone();
155 new.transform(m);
156 new
157 }
158
159 fn transform(&mut self, m: &Matrix4) {
160 self.pc.transform(m);
161 }
162}
163
164impl<P> Default for Polygon3D<P>
165where
166 P: Is3D,
168{
169 fn default() -> Self {
170 let pc = PointCloud3D::default();
171 Polygon3D { pc }
172 }
173}
174
175impl<P> fmt::Display for Polygon3D<P>
176where
177 P: Is3D + fmt::Display,
178{
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 self.pc.fmt(f)
181 }
182}
183
184impl<P> From<PointCloud3D<P>> for Polygon3D<P>
185where
186 P: Is3D,
187{
188 fn from(pc: PointCloud3D<P>) -> Self {
189 Polygon3D { pc }
190 }
191}