1use crate::{
2 canvas::Paint,
3 utils::{check_zoom, mean, RsilleErr, MIN_DIFFERENCE},
4 Canvas,
5};
6
7use crate::color::Color;
8use std::collections::HashMap;
9
10#[derive(Debug, Clone)]
30pub struct Object3D {
31 origin_vertices: Vec<Point3D>,
32 zoomed_vertices: Option<Vec<Point3D>>,
33 center: Point3D,
34 sides: HashMap<(usize, usize), Color>,
35}
36
37impl Object3D {
38 pub fn new() -> Self {
40 Self {
41 origin_vertices: Vec::new(),
42 zoomed_vertices: None,
43 center: Point3D::new(0.0, 0.0, 0.0),
44 sides: HashMap::new(),
45 }
46 }
47
48 pub fn vertices(&self) -> Vec<(f64, f64, f64)> {
50 self.origin_vertices.iter().map(|p| p.get()).collect()
51 }
52
53 pub fn add_points(&mut self, points: &[(f64, f64, f64)]) {
55 for p in points {
56 self.origin_vertices.push(Point3D::from(*p));
57 }
58 self.calc_center();
59 }
60
61 pub fn sides(&self) -> Vec<(usize, usize)> {
63 self.sides.keys().cloned().collect()
64 }
65
66 pub fn add_sides(&mut self, sides: &[(usize, usize)]) -> Result<(), RsilleErr> {
73 let vn = self.origin_vertices.len();
74 for side in sides {
75 if vn <= side.0 || vn <= side.1 {
76 return Err(RsilleErr::new("wrong add sides!".to_string()));
77 }
78
79 self.sides.insert(*side, Color::Reset);
80 }
81 Ok(())
82 }
83
84 pub fn add_sides_colorful(
88 &mut self,
89 sides: &[((usize, usize), Color)],
90 ) -> Result<(), RsilleErr> {
91 let vn = self.origin_vertices.len();
92 for (side, color) in sides {
93 if vn <= side.0 || vn <= side.1 {
94 return Err(RsilleErr::new("wrong add sides!".to_string()));
95 }
96 self.sides.insert(*side, *color);
97 }
98 Ok(())
99 }
100
101 pub fn set_side_colorful(&mut self, side: (usize, usize), color: Color) {
105 if self.sides.contains_key(&side) {
106 self.sides.insert(side, color);
107 }
108 }
109
110 pub fn rotate(&mut self, angle: (f64, f64, f64)) {
115 for p in &mut self.origin_vertices {
116 p.rotate(angle);
117 }
118 }
119
120 pub fn rotate_new(&self, angle: (f64, f64, f64)) -> Self {
124 let mut obj = self.clone();
125 obj.rotate(angle);
126 obj
127 }
128
129 pub fn zoom(&mut self, factor: f64) {
136 check_zoom(factor);
137 let mut vertices = self.origin_vertices.clone();
138 vertices
139 .iter_mut()
140 .for_each(|v| v.zoom(self.center, factor));
141 self.zoomed_vertices = Some(vertices);
142 }
143
144 pub fn zoom_new(&self, factor: f64) -> Self {
151 check_zoom(factor);
152 let mut points: Vec<Point3D> = self.origin_vertices.clone();
153 points.iter_mut().for_each(|v| v.zoom(self.center, factor));
154 Self {
155 origin_vertices: points,
156 zoomed_vertices: None,
157 sides: self.sides.clone(),
158 center: self.center,
159 }
160 }
161
162 pub fn map<F>(&mut self, f: F)
164 where
165 F: Fn(f64, f64, f64) -> (f64, f64, f64),
166 {
167 for p in &mut self.origin_vertices {
168 let (x, y, z) = f(p.x, p.y, p.z);
169 p.x = x;
170 p.y = y;
171 p.z = z;
172 }
173 }
174
175 fn calc_center(&mut self) {
176 let (mut xs, mut ys, mut zs) = (Vec::new(), Vec::new(), Vec::new());
177 for p in &self.origin_vertices {
178 xs.push(p.x);
179 ys.push(p.y);
180 zs.push(p.z);
181 }
182 let (mut mx, mut my, mut mz) = (mean(&xs), mean(&ys), mean(&zs));
183
184 if (mx - self.center.x) < MIN_DIFFERENCE {
186 mx = self.center.x;
187 }
188 if (my - self.center.y) < MIN_DIFFERENCE {
189 my = self.center.y;
190 }
191 if (mz - self.center.z) < MIN_DIFFERENCE {
192 mz = self.center.z;
193 }
194 self.center = Point3D::new(mx, my, mz);
195 }
196}
197
198impl Paint for Object3D {
199 fn paint<T>(&self, canvas: &mut Canvas, x: T, y: T) -> Result<(), RsilleErr>
200 where
201 T: Into<f64>,
202 {
203 let (x, y) = (x.into(), y.into());
204 let points = if let Some(p) = &self.zoomed_vertices {
205 p
206 } else {
207 &self.origin_vertices
208 };
209
210 for (side, color) in &self.sides {
211 let (v1, v2) = (points[side.0], points[side.1]);
212 let xy1 = (x + v1.x, y + v1.z);
213 let xy2 = (x + v2.x, y + v2.z);
214 canvas.line_colorful(xy1, xy2, *color);
215 }
216
217 Ok(())
218 }
219}
220
221impl Object3D {
222 pub fn cube<T>(side_len: T) -> Object3D
224 where
225 T: Into<f64>,
226 {
227 let side_len = side_len.into();
228 let mut object = Object3D::new();
229 #[rustfmt::skip]
230 let a = [
232 (-1, -1, -1),
233 (-1, -1, 1),
234 (-1, 1, -1),
235 ( 1, -1, -1),
236 (-1, 1, 1),
237 ( 1, -1, 1),
238 ( 1, 1, -1),
239 ( 1, 1, 1),
240 ];
241 let mut points = Vec::new();
242 for i in a {
243 let x = side_len / 2.0 * i.0 as f64;
244 let y = side_len / 2.0 * i.1 as f64;
245 let z = side_len / 2.0 * i.2 as f64;
246 points.push((x, y, z));
247 }
248 object.add_points(&points);
249 object
250 .add_sides(&[
251 (0, 1),
252 (1, 4),
253 (4, 2),
254 (2, 0),
255 (3, 5),
256 (5, 7),
257 (7, 6),
258 (6, 3),
259 (1, 5),
260 (4, 7),
261 (2, 6),
262 (0, 3),
263 ])
264 .unwrap();
265 object
266 }
267}
268
269#[derive(Debug, Clone, Copy)]
273struct Point3D {
274 pub(crate) x: f64,
275 pub(crate) y: f64,
276 pub(crate) z: f64,
277}
278
279#[allow(unused)]
280impl Point3D {
281 fn new(x: f64, y: f64, z: f64) -> Self {
283 Self { x, y, z }
284 }
285
286 fn from(xyz: (f64, f64, f64)) -> Self {
288 Self {
289 x: xyz.0,
290 y: xyz.1,
291 z: xyz.2,
292 }
293 }
294
295 fn get(&self) -> (f64, f64, f64) {
297 (self.x, self.y, self.z)
298 }
299
300 fn rotate(&mut self, angle: (f64, f64, f64)) {
304 self.rotate_x(angle.0);
305 self.rotate_y(angle.1);
306 self.rotate_z(angle.2);
307
308 }
321
322 fn rotate_new(&self, angle: (f64, f64, f64)) -> Self {
326 let mut point = *self;
327 point.rotate(angle);
328 point
329 }
330
331 fn zoom(&mut self, center: Self, factor: f64) {
337 check_zoom(factor);
338 self.x = (self.x - center.x) * factor;
339 self.y = (self.y - center.y) * factor;
340 self.z = (self.z - center.z) * factor;
341 }
342
343 fn zoom_new(&self, center: Self, factor: f64) -> Point3D {
347 check_zoom(factor);
348 let dx = (self.x - center.x) * factor;
349 let dy = (self.y - center.y) * factor;
350 let dz = (self.z - center.y) * factor;
351
352 Self {
353 x: dx,
354 y: dy,
355 z: dz,
356 }
357 }
358
359 fn rotate_x(&mut self, angle: f64) {
361 let (s, c) = angle.to_radians().sin_cos();
362 let (y, z) = (self.y, self.z);
363 self.y = y * c - z * s;
364 self.z = y * s + z * c;
365 }
366
367 fn rotate_y(&mut self, angle: f64) {
369 let (s, c) = angle.to_radians().sin_cos();
370 let (x, z) = (self.x, self.z);
371 self.x = x * c + z * s;
372 self.z = -x * s + z * c;
373 }
374
375 fn rotate_z(&mut self, anlge: f64) {
377 let (s, c) = anlge.to_radians().sin_cos();
378 let (x, y) = (self.x, self.y);
379 self.x = x * c - y * s;
380 self.y = x * s + y * c;
381 }
382}