dotbim_rust/
element.rs

1use std::collections::HashMap;
2use serde::{Deserialize, Serialize};
3use crate::color::Color;
4use crate::rotation::Rotation;
5use crate::vector::Vector;
6
7/// Represents a mesh object in three-dimensional space.
8#[derive(Deserialize, Serialize)]
9pub struct Element {
10    /// The identifier of the mesh associated with the element.
11    pub mesh_id: i32,
12    /// The position of the element.
13    pub vector: Vector,
14    /// The rotation of the element.
15    pub rotation: Rotation,
16    /// The globally unique identifier for the element.
17    pub guid: String,
18    /// The type of the element.
19    #[serde(rename(serialize = "type", deserialize = "type"))]
20    pub element_type: String,
21    /// The color of the element.
22    pub color: Color,
23    /// The list of integers, that determine face colors of a mesh.
24    /// They should be organized like this: [r1, g1, b1, a1, r2, g2, b2, a2, r3, g3, b3, a3, ... rn, gn, bn, an]
25    /// E.g. list like: [255, 0, 0, 255, 135, 206, 235, 255, 255, 255, 255, 255]
26    /// means first triangle should be colored as red (255,0,0,255),
27    /// second as skyblue (135,206,235,255),
28    /// third as white (255,255,255,255).
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub face_colors: Option<Vec<i32>>,
31    /// Additional information about the element.
32    pub info: HashMap<String, String>
33}
34
35impl PartialEq for Element {
36    fn eq(&self, other: &Self) -> bool {
37        if self.mesh_id != other.mesh_id {
38            return false;
39        }
40        if self.vector != other.vector {
41            return false;
42        }
43        if self.rotation != other.rotation {
44            return false;
45        }
46        if self.guid != other.guid {
47            return false;
48        }
49        if self.element_type != other.element_type {
50            return false;
51        }
52        if self.color != other.color {
53            return false;
54        }
55        if self.face_colors.is_none() && other.face_colors.is_none() {
56
57        } else {
58            if self.face_colors.is_some() && other.face_colors.is_some() {
59                let self_face_colors_unpacked = self.face_colors.as_ref().unwrap();
60                let other_face_colors_unpacked = other.face_colors.as_ref().unwrap();
61                if self_face_colors_unpacked.len() != other_face_colors_unpacked.len() {
62                    return false;
63                }
64                for i in 0..self_face_colors_unpacked.len() {
65                    if self_face_colors_unpacked[i] != other_face_colors_unpacked[i] {
66                        return false;
67                    }
68                }
69            } else {
70                return false;
71            }
72        }
73
74        if !self.info.eq(&other.info) {
75            return false;
76        }
77
78        true
79    }
80}
81
82impl Element {
83    /// Returns a new Element
84    pub fn new(mesh_id: i32, vector: Vector, rotation: Rotation, guid: String, element_type: String,
85               color: Color, face_colors: Option<Vec<i32>>, info: HashMap<String, String>)
86        -> Element { Element { mesh_id, vector, rotation, guid, element_type, color, face_colors, info } }
87}
88
89#[cfg(test)]
90mod tests {
91    use serde_json::to_string;
92    use serde_json::from_str;
93    use super::*;
94
95    fn get_blue_test_element() -> Element {
96        let mut info: HashMap<String, String> = HashMap::new();
97        info.insert(String::from("Key"), String::from("Value"));
98
99        Element::new(
100            4,
101            Vector::new(0.2, 0.3, 0.4),
102            Rotation::new(1.0, 1.5, 2.0, 2.5),
103            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
104            String::from("Plate"),
105            Color::new(0,0,255,0),
106            None,
107            info.clone(),
108        )
109    }
110
111    fn get_face_colored_test_element() -> Element {
112        let mut info: HashMap<String, String> = HashMap::new();
113        info.insert(String::from("Key"), String::from("Value"));
114
115        Element::new(
116            0,
117            Vector::new(0.0, 0.0, 0.0),
118            Rotation::new(0.0, 0.0, 0.0, 1.0),
119            String::from("3028896f-cd51-4b3a-be54-08841b4e9081"),
120            String::from("Cube"),
121            Color::new(0,0,255,0),
122            Some(vec![
123                // Front side
124                255, 105, 180, 150, // Hot pink with transparency
125                255, 192, 203, 255, // Pink
126
127                // Bottom side
128                53, 57, 53, 255, // Onyx
129                0, 0, 0, 255, // Black
130
131                // Left side
132                243, 229, 171, 255, // Vanilla
133                255, 255, 0, 255, // Yellow
134
135                // Right side
136                9, 121, 105, 255, // Cadmium Green
137                0, 128, 0, 255, // Green
138
139                // Top side
140                0, 255, 255, 255, // Cyan
141                0, 0, 255, 255, // Blue
142
143                // Back side
144                226, 223, 210, 255, // Pearl
145                255, 255, 255, 255, // White
146            ]),
147            info.clone(),
148        )
149    }
150
151    #[test]
152    fn test_new_without_face_colors() {
153        let mut info: HashMap<String, String> = HashMap::new();
154        info.insert(String::from("Key"), String::from("Value"));
155
156        let result = get_blue_test_element();
157
158        assert_eq!(result.mesh_id, 4);
159        assert_eq!(Vector::new(0.2, 0.3, 0.4).eq(&result.vector), true);
160        assert_eq!(Rotation::new(1.0, 1.5, 2.0, 2.5).eq(&result.rotation), true);
161        assert_eq!(String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353").eq(&result.guid), true);
162        assert_eq!(String::from("Plate").eq(&result.element_type), true);
163        assert_eq!(Color::new(0,0,255,0).eq(&result.color), true);
164        assert_eq!(result.face_colors.is_none(), true);
165        assert_eq!(result.face_colors.is_some(), false);
166        assert_eq!(info.eq(&result.info), true);
167    }
168
169    #[test]
170    fn test_new_with_face_colors() {
171        let mut info: HashMap<String, String> = HashMap::new();
172        info.insert(String::from("Key"), String::from("Value"));
173        let expected_face_colors = vec![
174            // Front side
175            255, 105, 180, 150, // Hot pink with transparency
176            255, 192, 203, 255, // Pink
177
178            // Bottom side
179            53, 57, 53, 255, // Onyx
180            0, 0, 0, 255, // Black
181
182            // Left side
183            243, 229, 171, 255, // Vanilla
184            255, 255, 0, 255, // Yellow
185
186            // Right side
187            9, 121, 105, 255, // Cadmium Green
188            0, 128, 0, 255, // Green
189
190            // Top side
191            0, 255, 255, 255, // Cyan
192            0, 0, 255, 255, // Blue
193
194            // Back side
195            226, 223, 210, 255, // Pearl
196            255, 255, 255, 255, // White
197        ];
198
199        let result = get_face_colored_test_element();
200
201        assert_eq!(result.mesh_id, 0);
202        assert_eq!(Vector::new(0.0, 0.0, 0.0).eq(&result.vector), true);
203        assert_eq!(Rotation::new(0.0, 0.0, 0.0, 1.0).eq(&result.rotation), true);
204        assert_eq!(String::from("3028896f-cd51-4b3a-be54-08841b4e9081").eq(&result.guid), true);
205        assert_eq!(String::from("Cube").eq(&result.element_type), true);
206        assert_eq!(Color::new(0,0,255,0).eq(&result.color), true);
207        assert_eq!(result.face_colors.is_none(), false);
208        assert_eq!(result.face_colors.is_some(), true);
209        let face_colors_unpacked = result.face_colors.as_ref().unwrap();
210        assert_eq!(face_colors_unpacked.len(), expected_face_colors.len());
211        for i in 0..face_colors_unpacked.len() {
212            assert_eq!(face_colors_unpacked[i], expected_face_colors[i]);
213        }
214        assert_eq!(info.eq(&result.info), true);
215    }
216
217    #[test]
218    fn test_partial_eq_without_face_colors_true(){
219        let a = get_blue_test_element();
220        let b = get_blue_test_element();
221        assert_eq!(a.eq(&b), true);
222        assert_eq!(b.eq(&a), true);
223    }
224
225    #[test]
226    fn test_partial_eq_without_face_colors_different_mesh_id(){
227        let a = get_blue_test_element();
228
229        let mut info: HashMap<String, String> = HashMap::new();
230        info.insert(String::from("Key"), String::from("Value"));
231
232        let b = Element::new(
233            3, // different
234            Vector::new(0.2, 0.3, 0.4),
235            Rotation::new(1.0, 1.5, 2.0, 2.5),
236            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
237            String::from("Plate"),
238            Color::new(0,0,255,0),
239            None,
240            info.clone(),
241        );
242
243        assert_eq!(a.eq(&b), false);
244        assert_eq!(b.eq(&a), false);
245    }
246
247    #[test]
248    fn test_partial_eq_without_face_colors_different_vector(){
249        let a = get_blue_test_element();
250
251        let mut info: HashMap<String, String> = HashMap::new();
252        info.insert(String::from("Key"), String::from("Value"));
253
254        let b = Element::new(
255            4,
256            Vector::new(0.1, 0.3, 0.4), // different
257            Rotation::new(1.0, 1.5, 2.0, 2.5),
258            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
259            String::from("Plate"),
260            Color::new(0,0,255,0),
261            None,
262            info.clone(),
263        );
264
265        assert_eq!(a.eq(&b), false);
266        assert_eq!(b.eq(&a), false);
267    }
268
269    #[test]
270    fn test_partial_eq_without_face_colors_different_rotation(){
271        let a = get_blue_test_element();
272
273        let mut info: HashMap<String, String> = HashMap::new();
274        info.insert(String::from("Key"), String::from("Value"));
275
276        let b = Element::new(
277            4,
278            Vector::new(0.2, 0.3, 0.4),
279            Rotation::new(1.0, -0.5, 2.0, 2.5), // different
280            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
281            String::from("Plate"),
282            Color::new(0,0,255,0),
283            None,
284            info.clone(),
285        );
286
287        assert_eq!(a.eq(&b), false);
288        assert_eq!(b.eq(&a), false);
289    }
290
291    #[test]
292    fn test_partial_eq_without_face_colors_different_guid(){
293        let a = get_blue_test_element();
294
295        let mut info: HashMap<String, String> = HashMap::new();
296        info.insert(String::from("Key"), String::from("Value"));
297
298        let b = Element::new(
299            4,
300            Vector::new(0.2, 0.3, 0.4),
301            Rotation::new(1.0, 1.5, 2.0, 2.5),
302            String::from("b34a1674-e680-40f2-baa9-0e9b017bea14"), // different
303            String::from("Plate"),
304            Color::new(0,0,255,0),
305            None,
306            info.clone(),
307        );
308
309        assert_eq!(a.eq(&b), false);
310        assert_eq!(b.eq(&a), false);
311    }
312
313    #[test]
314    fn test_partial_eq_without_face_colors_different_type(){
315        let a = get_blue_test_element();
316
317        let mut info: HashMap<String, String> = HashMap::new();
318        info.insert(String::from("Key"), String::from("Value"));
319
320        let b = Element::new(
321            4,
322            Vector::new(0.2, 0.3, 0.4),
323            Rotation::new(1.0, 1.5, 2.0, 2.5),
324            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
325            String::from("Another one"), // different
326            Color::new(0,0,255,0),
327            None,
328            info.clone(),
329        );
330
331        assert_eq!(a.eq(&b), false);
332        assert_eq!(b.eq(&a), false);
333    }
334
335    #[test]
336    fn test_partial_eq_without_face_colors_different_color(){
337        let a = get_blue_test_element();
338
339        let mut info: HashMap<String, String> = HashMap::new();
340        info.insert(String::from("Key"), String::from("Value"));
341
342        let b = Element::new(
343            4,
344            Vector::new(0.2, 0.3, 0.4),
345            Rotation::new(1.0, 1.5, 2.0, 2.5),
346            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
347            String::from("Plate"),
348            Color::new(55,0,255,0), // different
349            None,
350            info.clone(),
351        );
352
353        assert_eq!(a.eq(&b), false);
354        assert_eq!(b.eq(&a), false);
355    }
356
357    #[test]
358    fn test_partial_eq_without_face_colors_existing_face_colors(){
359        let a = get_blue_test_element();
360
361        let mut info: HashMap<String, String> = HashMap::new();
362        info.insert(String::from("Key"), String::from("Value"));
363
364        let b = Element::new(
365            4,
366            Vector::new(0.2, 0.3, 0.4),
367            Rotation::new(1.0, 1.5, 2.0, 2.5),
368            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
369            String::from("Plate"),
370            Color::new(0,0,255,0),
371            Some(vec![255, 0, 0, 0]), // different
372            info.clone(),
373        );
374
375        assert_eq!(a.eq(&b), false);
376        assert_eq!(b.eq(&a), false);
377    }
378
379    #[test]
380    fn test_partial_eq_without_face_colors_different_face_colors(){
381        let a = get_face_colored_test_element();
382
383        let mut info: HashMap<String, String> = HashMap::new();
384        info.insert(String::from("Key"), String::from("Value"));
385
386        let b = Element::new(
387            0,
388            Vector::new(0.0, 0.0, 0.0),
389            Rotation::new(0.0, 0.0, 0.0, 1.0),
390            String::from("3028896f-cd51-4b3a-be54-08841b4e9081"),
391            String::from("Cube"),
392            Color::new(0,0,255,0),
393            Some(vec![
394                // Front side
395                255, 105, 180, 150, // Hot pink with transparency
396                255, 192, 203, 255, // Pink
397
398                // Bottom side
399                53, 57, 53, 255, // Onyx
400                1, 0, 0, 255, // Black <- Different
401
402                // Left side
403                243, 229, 171, 255, // Vanilla
404                255, 255, 0, 255, // Yellow
405
406                // Right side
407                9, 121, 105, 255, // Cadmium Green
408                0, 128, 0, 255, // Green
409
410                // Top side
411                0, 255, 255, 255, // Cyan
412                0, 0, 255, 255, // Blue
413
414                // Back side
415                226, 223, 210, 255, // Pearl
416                255, 255, 255, 255, // White
417            ]),
418            info.clone(),
419        );
420
421        assert_eq!(a.eq(&b), false);
422        assert_eq!(b.eq(&a), false);
423    }
424
425    #[test]
426    fn test_partial_eq_without_face_colors_different_face_colors_count(){
427        let a = get_face_colored_test_element();
428
429        let mut info: HashMap<String, String> = HashMap::new();
430        info.insert(String::from("Key"), String::from("Value"));
431
432        let b = Element::new(
433            0,
434            Vector::new(0.0, 0.0, 0.0),
435            Rotation::new(0.0, 0.0, 0.0, 1.0),
436            String::from("3028896f-cd51-4b3a-be54-08841b4e9081"),
437            String::from("Cube"),
438            Color::new(0,0,255,0),
439            Some(vec![
440                // Front side
441                255, 105, 180, 150, // Hot pink with transparency
442                255, 192, 203, 255, // Pink
443
444                // Bottom side
445                53, 57, 53, 255, // Onyx
446                1, 0, 0, 255, // Black <- Different
447
448                // Left side
449                243, 229, 171, 255, // Vanilla
450                255, 255, 0, 255, // Yellow
451
452                // Right side
453                9, 121, 105, 255, // Cadmium Green
454                0, 128, 0, 255, // Green
455
456                // Top side
457                0, 255, 255, 255, // Cyan
458                0, 0, 255, 255, // Blue
459
460                // Back side
461                226, 223, 210, 255, // Pearl
462                255, 255, 255, //255, // White <- different
463            ]),
464            info.clone(),
465        );
466
467        assert_eq!(a.eq(&b), false);
468        assert_eq!(b.eq(&a), false);
469    }
470
471    #[test]
472    fn test_partial_eq_without_face_colors_different_info_value(){
473        let a = get_blue_test_element();
474
475        let mut info: HashMap<String, String> = HashMap::new();
476        info.insert(String::from("Key"), String::from("Another value")); // different
477
478        let b = Element::new(
479            4,
480            Vector::new(0.2, 0.3, 0.4),
481            Rotation::new(1.0, 1.5, 2.0, 2.5),
482            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
483            String::from("Plate"),
484            Color::new(0,0,255,0),
485            None,
486            info.clone(),
487        );
488
489        assert_eq!(a.eq(&b), false);
490        assert_eq!(b.eq(&a), false);
491    }
492
493    #[test]
494    fn test_partial_eq_without_face_colors_different_info_key(){
495        let a = get_blue_test_element();
496
497        let mut info: HashMap<String, String> = HashMap::new();
498        info.insert(String::from("Another key"), String::from("Value")); // different
499
500        let b = Element::new(
501            4,
502            Vector::new(0.2, 0.3, 0.4),
503            Rotation::new(1.0, 1.5, 2.0, 2.5),
504            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
505            String::from("Plate"),
506            Color::new(0,0,255,0),
507            None,
508            info.clone(),
509        );
510
511        assert_eq!(a.eq(&b), false);
512        assert_eq!(b.eq(&a), false);
513    }
514
515    #[test]
516    fn test_partial_eq_without_face_colors_different_info_length(){
517        let a = get_blue_test_element();
518
519        let mut info: HashMap<String, String> = HashMap::new();
520        info.insert(String::from("Key"), String::from("Value"));
521        info.insert(String::from("Another key"), String::from("Another value")); // different
522
523        let b = Element::new(
524            4,
525            Vector::new(0.2, 0.3, 0.4),
526            Rotation::new(1.0, 1.5, 2.0, 2.5),
527            String::from("b8a7a2ed-0c30-4c20-867e-baa1ef7b8353"),
528            String::from("Plate"),
529            Color::new(0,0,255,0),
530            None,
531            info.clone(),
532        );
533
534        assert_eq!(a.eq(&b), false);
535        assert_eq!(b.eq(&a), false);
536    }
537
538    #[test]
539    fn test_partial_eq_with_face_colors_true(){
540        let a = get_face_colored_test_element();
541        let b = get_face_colored_test_element();
542        assert_eq!(a.eq(&b), true);
543        assert_eq!(b.eq(&a), true);
544    }
545
546    #[test]
547    fn test_to_json_without_face_colors() {
548        let input = get_blue_test_element();
549        let input_serialized = to_string(&input);
550        assert_eq!(input_serialized.is_ok(), true);
551        let input_serialized_string = input_serialized.ok().unwrap();
552        assert_eq!(input_serialized_string, "{\"mesh_id\":4,\"vector\":{\"x\":0.2,\"y\":0.3,\"z\":0.4},\"rotation\":{\"qx\":1.0,\"qy\":1.5,\"qz\":2.0,\"qw\":2.5},\"guid\":\"b8a7a2ed-0c30-4c20-867e-baa1ef7b8353\",\"type\":\"Plate\",\"color\":{\"r\":0,\"g\":0,\"b\":255,\"a\":0},\"info\":{\"Key\":\"Value\"}}");
553    }
554
555    #[test]
556    fn test_from_json_without_face_colors() {
557        let json = "{\"mesh_id\":4,\"vector\":{\"x\":0.2,\"y\":0.3,\"z\":0.4},\"rotation\":{\"qx\":1.0,\"qy\":1.5,\"qz\":2.0,\"qw\":2.5},\"guid\":\"b8a7a2ed-0c30-4c20-867e-baa1ef7b8353\",\"type\":\"Plate\",\"color\":{\"r\":0,\"g\":0,\"b\":255,\"a\":0},\"info\":{\"Key\":\"Value\"}}";
558        let actual_result = from_str::<Element>(json);
559        // println!("{}", actual_result.err().unwrap());
560        assert_eq!(actual_result.is_ok(), true);
561        let actual = actual_result.ok().unwrap();
562        let expected = get_blue_test_element();
563        assert_eq!(expected.eq(&actual), true);
564    }
565
566    #[test]
567    fn test_to_json_with_face_colors() {
568        let input = get_face_colored_test_element();
569        let input_serialized = to_string(&input);
570        assert_eq!(input_serialized.is_ok(), true);
571        let input_serialized_string = input_serialized.ok().unwrap();
572        assert_eq!(input_serialized_string, "{\"mesh_id\":0,\"vector\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"rotation\":{\"qx\":0.0,\"qy\":0.0,\"qz\":0.0,\"qw\":1.0},\"guid\":\"3028896f-cd51-4b3a-be54-08841b4e9081\",\"type\":\"Cube\",\"color\":{\"r\":0,\"g\":0,\"b\":255,\"a\":0},\"face_colors\":[255,105,180,150,255,192,203,255,53,57,53,255,0,0,0,255,243,229,171,255,255,255,0,255,9,121,105,255,0,128,0,255,0,255,255,255,0,0,255,255,226,223,210,255,255,255,255,255],\"info\":{\"Key\":\"Value\"}}");
573    }
574
575    #[test]
576    fn test_from_json_with_face_colors() {
577        let json = "{\"mesh_id\":0,\"vector\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"rotation\":{\"qx\":0.0,\"qy\":0.0,\"qz\":0.0,\"qw\":1.0},\"guid\":\"3028896f-cd51-4b3a-be54-08841b4e9081\",\"type\":\"Cube\",\"color\":{\"r\":0,\"g\":0,\"b\":255,\"a\":0},\"face_colors\":[255,105,180,150,255,192,203,255,53,57,53,255,0,0,0,255,243,229,171,255,255,255,0,255,9,121,105,255,0,128,0,255,0,255,255,255,0,0,255,255,226,223,210,255,255,255,255,255],\"info\":{\"Key\":\"Value\"}}";
578        let actual_result = from_str::<Element>(json);
579        // println!("{}", actual_result.err().unwrap());
580        assert_eq!(actual_result.is_ok(), true);
581        let actual = actual_result.ok().unwrap();
582        let expected = get_face_colored_test_element();
583        assert_eq!(expected.eq(&actual), true);
584    }
585}