Skip to main content

egui_map/map/
objects.rs

1use egui::{Align2, Color32, FontFamily, FontId, Pos2, Stroke, Ui};
2use std::convert::{From, Into};
3use std::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub};
4use std::time::Instant;
5
6#[derive(Copy, Clone, Debug)]
7pub struct RawPoint {
8    pub components: [f32; 2],
9}
10
11impl RawPoint {
12    pub fn new(x: f32, y: f32) -> Self {
13        Self { components: [x, y] }
14    }
15}
16
17impl Default for RawPoint {
18    fn default() -> Self {
19        Self::new(0.00, 0.00)
20    }
21}
22
23impl Mul<i64> for RawPoint {
24    type Output = Self;
25
26    fn mul(self, rhs: i64) -> Self::Output {
27        Self {
28            components: [
29                self.components[0] * rhs as f32,
30                self.components[1] * rhs as f32,
31            ],
32        }
33    }
34}
35
36impl Mul<i32> for RawPoint {
37    type Output = Self;
38
39    fn mul(self, rhs: i32) -> Self::Output {
40        Self {
41            components: [
42                self.components[0] * rhs as f32,
43                self.components[1] * rhs as f32,
44            ],
45        }
46    }
47}
48
49impl Mul<u64> for RawPoint {
50    type Output = Self;
51
52    fn mul(self, rhs: u64) -> Self::Output {
53        Self {
54            components: [
55                self.components[0] * rhs as f32,
56                self.components[1] * rhs as f32,
57            ],
58        }
59    }
60}
61
62impl Mul<u32> for RawPoint {
63    type Output = Self;
64
65    fn mul(self, rhs: u32) -> Self::Output {
66        Self {
67            components: [
68                self.components[0] * rhs as f32,
69                self.components[1] * rhs as f32,
70            ],
71        }
72    }
73}
74
75impl Mul<f32> for RawPoint {
76    type Output = Self;
77
78    fn mul(self, rhs: f32) -> Self::Output {
79        Self {
80            components: [self.components[0] * rhs, self.components[1] * rhs],
81        }
82    }
83}
84
85impl MulAssign<i64> for RawPoint {
86    fn mul_assign(&mut self, rhs: i64) {
87        self.components[0] = self.components[0] * rhs as f32;
88        self.components[1] = self.components[1] * rhs as f32;
89    }
90}
91
92impl MulAssign<i32> for RawPoint {
93    fn mul_assign(&mut self, rhs: i32) {
94        self.components[0] = self.components[0] * rhs as f32;
95        self.components[1] = self.components[1] * rhs as f32;
96    }
97}
98
99impl MulAssign<u64> for RawPoint {
100    fn mul_assign(&mut self, rhs: u64) {
101        self.components[0] = self.components[0] * rhs as f32;
102        self.components[1] = self.components[1] * rhs as f32;
103    }
104}
105
106impl MulAssign<u32> for RawPoint {
107    fn mul_assign(&mut self, rhs: u32) {
108        self.components[0] = self.components[0] * rhs as f32;
109        self.components[1] = self.components[1] * rhs as f32;
110    }
111}
112
113impl MulAssign<f32> for RawPoint {
114    fn mul_assign(&mut self, rhs: f32) {
115        self.components[0] = self.components[0] * rhs;
116        self.components[1] = self.components[1] * rhs;
117    }
118}
119
120impl Div<i64> for RawPoint {
121    type Output = Self;
122
123    fn div(self, rhs: i64) -> Self::Output {
124        Self {
125            components: [
126                self.components[0] / rhs as f32,
127                self.components[1] / rhs as f32,
128            ],
129        }
130    }
131}
132
133impl Div<i32> for RawPoint {
134    type Output = Self;
135
136    fn div(self, rhs: i32) -> Self::Output {
137        Self {
138            components: [
139                self.components[0] / rhs as f32,
140                self.components[1] / rhs as f32,
141            ],
142        }
143    }
144}
145
146impl Div<u64> for RawPoint {
147    type Output = Self;
148
149    fn div(self, rhs: u64) -> Self::Output {
150        Self {
151            components: [
152                self.components[0] / rhs as f32,
153                self.components[1] / rhs as f32,
154            ],
155        }
156    }
157}
158
159impl Div<u32> for RawPoint {
160    type Output = Self;
161
162    fn div(self, rhs: u32) -> Self::Output {
163        Self {
164            components: [
165                self.components[0] / rhs as f32,
166                self.components[1] / rhs as f32,
167            ],
168        }
169    }
170}
171
172impl Div<f32> for RawPoint {
173    type Output = Self;
174
175    fn div(self, rhs: f32) -> Self::Output {
176        Self {
177            components: [self.components[0] / rhs, self.components[1] / rhs],
178        }
179    }
180}
181
182impl DivAssign<i64> for RawPoint {
183    fn div_assign(&mut self, rhs: i64) {
184        self.components[0] = self.components[0] / rhs as f32;
185        self.components[1] = self.components[1] / rhs as f32;
186    }
187}
188
189impl DivAssign<i32> for RawPoint {
190    fn div_assign(&mut self, rhs: i32) {
191        self.components[0] = self.components[0] / rhs as f32;
192        self.components[1] = self.components[1] / rhs as f32;
193    }
194}
195
196impl DivAssign<u64> for RawPoint {
197    fn div_assign(&mut self, rhs: u64) {
198        self.components[0] = self.components[0] / rhs as f32;
199        self.components[1] = self.components[1] / rhs as f32;
200    }
201}
202
203impl DivAssign<u32> for RawPoint {
204    fn div_assign(&mut self, rhs: u32) {
205        self.components[0] = self.components[0] / rhs as f32;
206        self.components[1] = self.components[1] / rhs as f32;
207    }
208}
209
210impl DivAssign<f32> for RawPoint {
211    fn div_assign(&mut self, rhs: f32) {
212        self.components[0] = self.components[0] / rhs;
213        self.components[1] = self.components[1] / rhs;
214    }
215}
216
217impl Add<RawPoint> for RawPoint {
218    type Output = RawPoint;
219    fn add(self, rhs: RawPoint) -> Self::Output {
220        Self {
221            components: [
222                self.components[0] + rhs.components[0],
223                self.components[1] + rhs.components[1],
224            ],
225        }
226    }
227}
228
229impl Sub<RawPoint> for RawPoint {
230    type Output = RawPoint;
231    fn sub(self, rhs: RawPoint) -> Self::Output {
232        Self {
233            components: [
234                self.components[0] - rhs.components[0],
235                self.components[1] - rhs.components[1],
236            ],
237        }
238    }
239}
240
241impl Add<&RawPoint> for RawPoint {
242    type Output = RawPoint;
243    fn add(self, rhs: &RawPoint) -> Self::Output {
244        Self {
245            components: [
246                self.components[0] + rhs.components[0],
247                self.components[1] + rhs.components[1],
248            ],
249        }
250    }
251}
252
253impl Sub<&RawPoint> for RawPoint {
254    type Output = RawPoint;
255    fn sub(self, rhs: &RawPoint) -> Self::Output {
256        Self {
257            components: [
258                self.components[0] - rhs.components[0],
259                self.components[1] - rhs.components[1],
260            ],
261        }
262    }
263}
264
265impl From<[f32; 2]> for RawPoint {
266    fn from(value: [f32; 2]) -> Self {
267        Self { components: value }
268    }
269}
270
271impl From<Pos2> for RawPoint {
272    fn from(value: Pos2) -> Self {
273        Self {
274            components: [value.x, value.y],
275        }
276    }
277}
278
279impl From<[i64; 2]> for RawPoint {
280    fn from(value: [i64; 2]) -> Self {
281        Self {
282            components: [value[0] as f32, value[1] as f32],
283        }
284    }
285}
286
287impl From<[i32; 2]> for RawPoint {
288    fn from(value: [i32; 2]) -> Self {
289        Self {
290            components: [value[0] as f32, value[1] as f32],
291        }
292    }
293}
294
295impl From<[i16; 2]> for RawPoint {
296    fn from(value: [i16; 2]) -> Self {
297        Self {
298            components: [value[0] as f32, value[1] as f32],
299        }
300    }
301}
302
303impl From<[i8; 2]> for RawPoint {
304    fn from(value: [i8; 2]) -> Self {
305        Self {
306            components: [value[0] as f32, value[1] as f32],
307        }
308    }
309}
310
311impl From<RawPoint> for [f32; 2] {
312    fn from(val: RawPoint) -> Self {
313        [val.components[0], val.components[1]]
314    }
315}
316
317impl From<RawPoint> for Pos2 {
318    fn from(val: RawPoint) -> Self {
319        Pos2::from(val.components)
320    }
321}
322
323#[derive(Copy, Clone, Debug)]
324pub struct RawLine {
325    pub points: [RawPoint; 2],
326}
327
328impl RawLine {
329    pub fn new(a: RawPoint, b: RawPoint) -> Self {
330        Self { points: [a, b] }
331    }
332
333    pub fn distance(self) -> f32 {
334        let x = self.points[0].components[0] - self.points[1].components[0];
335        let y = self.points[0].components[1] - self.points[1].components[1];
336        (x.powi(2) + y.powi(2)).sqrt()
337    }
338
339    pub fn midpoint(self) -> RawPoint {
340        let x = (self.points[0].components[0] + self.points[1].components[0]) / 2.0;
341        let y = (self.points[0].components[1] + self.points[1].components[1]) / 2.0;
342        RawPoint::new(x, y)
343    }
344}
345
346impl From<RawLine> for [Pos2; 2] {
347    fn from(val: RawLine) -> Self {
348        let position1 = val.points[0].into();
349        let position2 = val.points[1].into();
350        [position1, position2]
351    }
352}
353
354impl From<[[i64; 2]; 2]> for RawLine {
355    fn from(value: [[i64; 2]; 2]) -> Self {
356        Self {
357            points: [RawPoint::from(value[0]), RawPoint::from(value[1])],
358        }
359    }
360}
361
362#[derive(Clone, Debug)]
363pub struct MapStyle {
364    pub border: Option<Stroke>,
365    pub line: Option<Stroke>,
366    pub fill_color: Color32,
367    pub text_color: Color32,
368    pub font: Option<FontId>,
369    pub background_color: Color32,
370    pub alert_color: Color32,
371}
372
373impl MapStyle {
374    pub fn new() -> Self {
375        MapStyle {
376            border: None,
377            line: None,
378            fill_color: Color32::TRANSPARENT,
379            text_color: Color32::TRANSPARENT,
380            font: None,
381            background_color: Color32::TRANSPARENT,
382            alert_color: Color32::TRANSPARENT,
383        }
384    }
385}
386
387impl Default for MapStyle {
388    fn default() -> Self {
389        MapStyle::new()
390    }
391}
392
393impl Mul<i64> for MapStyle {
394    // The multiplication of rational numbers is a closed operation.
395    type Output = Self;
396
397    fn mul(mut self, rhs: i64) -> Self::Output {
398        self.border.as_mut().unwrap().width *= rhs as f32;
399        self.line.as_mut().unwrap().width *= rhs as f32;
400        self.font.as_mut().unwrap().size *= rhs as f32;
401        self
402    }
403}
404
405impl Mul<i32> for MapStyle {
406    // The multiplication of rational numbers is a closed operation.
407    type Output = Self;
408
409    fn mul(mut self, rhs: i32) -> Self::Output {
410        self.border.as_mut().unwrap().width *= rhs as f32;
411        self.line.as_mut().unwrap().width *= rhs as f32;
412        self.font.as_mut().unwrap().size *= rhs as f32;
413        self
414    }
415}
416
417impl Mul<f32> for MapStyle {
418    // The multiplication of rational numbers is a closed operation.
419    type Output = Self;
420
421    fn mul(mut self, rhs: f32) -> Self::Output {
422        self.border.as_mut().unwrap().width *= rhs;
423        self.line.as_mut().unwrap().width *= rhs;
424        self.font.as_mut().unwrap().size *= rhs;
425        self
426    }
427}
428
429impl Mul<f64> for MapStyle {
430    // The multiplication of rational numbers is a closed operation.
431    type Output = Self;
432
433    fn mul(mut self, rhs: f64) -> Self::Output {
434        self.border.as_mut().unwrap().width *= rhs as f32;
435        self.line.as_mut().unwrap().width *= rhs as f32;
436        self.font.as_mut().unwrap().size *= rhs as f32;
437        self
438    }
439}
440
441impl Div<i64> for MapStyle {
442    // The multiplication of rational numbers is a closed operation.
443    type Output = Self;
444
445    fn div(mut self, rhs: i64) -> Self::Output {
446        self.border.as_mut().unwrap().width /= rhs as f32;
447        self.line.as_mut().unwrap().width /= rhs as f32;
448        self.font.as_mut().unwrap().size /= rhs as f32;
449        self
450    }
451}
452
453impl Div<i32> for MapStyle {
454    // The multiplication of rational numbers is a closed operation.
455    type Output = Self;
456
457    fn div(mut self, rhs: i32) -> Self::Output {
458        self.border.as_mut().unwrap().width /= rhs as f32;
459        self.line.as_mut().unwrap().width /= rhs as f32;
460        self.font.as_mut().unwrap().size /= rhs as f32;
461        self
462    }
463}
464
465impl Div<f32> for MapStyle {
466    // The multiplication of rational numbers is a closed operation.
467    type Output = Self;
468
469    fn div(mut self, rhs: f32) -> Self::Output {
470        self.border.as_mut().unwrap().width /= rhs;
471        self.line.as_mut().unwrap().width /= rhs;
472        self.font.as_mut().unwrap().size /= rhs;
473        self
474    }
475}
476
477impl Div<f64> for MapStyle {
478    // The multiplication of rational numbers is a closed operation.
479    type Output = Self;
480
481    fn div(mut self, rhs: f64) -> Self::Output {
482        self.border.as_mut().unwrap().width /= rhs as f32;
483        self.line.as_mut().unwrap().width /= rhs as f32;
484        self.font.as_mut().unwrap().size /= rhs as f32;
485        self
486    }
487}
488
489#[derive(Clone, Debug)]
490pub struct MapLabel {
491    pub text: String,
492    pub center: Pos2,
493}
494
495impl Default for MapLabel {
496    fn default() -> Self {
497        MapLabel::new()
498    }
499}
500
501impl MapLabel {
502    pub fn new() -> Self {
503        MapLabel {
504            text: String::new(),
505            center: Pos2::new(0.00, 0.00),
506        }
507    }
508}
509
510#[derive(Clone, Debug)]
511pub struct MapLine {
512    pub id: Option<String>,
513    pub raw_line: RawLine,
514}
515
516impl MapLine {
517    pub fn new(point1: RawPoint, point2: RawPoint) -> Self {
518        MapLine {
519            id: None,
520            raw_line: RawLine::new(point1, point2),
521        }
522    }
523}
524
525// This can by any object or point with its associated metadata
526/// Struct that contains coordinates to help calculate nearest point in space
527#[derive(Clone, Debug)]
528pub struct MapPoint {
529    /// coordinates of the Solar System
530    pub raw_point: RawPoint,
531    /// coordinates for lines connecting this point
532    pub connections: Vec<String>,
533    /// Object Identifier for search propurses
534    id: usize,
535    /// SolarSystem Name
536    name: String,
537}
538
539impl MapPoint {
540    /// Creates a new Spatial point with an Id (solarSystemId) and the system's 3D coordinates
541    pub fn new(id: usize, coords: RawPoint) -> MapPoint {
542        MapPoint {
543            raw_point: coords,
544            id,
545            connections: Vec::new(),
546            name: String::new(),
547        }
548    }
549
550    pub fn get_id(&self) -> usize {
551        self.id
552    }
553
554    pub fn get_name(&self) -> String {
555        self.name.clone()
556    }
557
558    pub fn set_name(&mut self, value: String) {
559        self.name = value;
560    }
561}
562
563impl From<std::collections::hash_map::OccupiedEntry<'_, usize, MapPoint>> for MapPoint {
564    fn from(value: std::collections::hash_map::OccupiedEntry<'_, usize, MapPoint>) -> Self {
565        let k = value.get();
566        k.clone()
567    }
568}
569
570#[derive(Clone)]
571pub(crate) struct MapBounds {
572    pub min: RawPoint,
573    pub max: RawPoint,
574    pub pos: RawPoint,
575    pub dist: f32,
576}
577
578impl MapBounds {
579    pub fn new() -> Self {
580        MapBounds {
581            min: RawPoint::default(),
582            max: RawPoint::default(),
583            pos: RawPoint::default(),
584            dist: 0.0,
585        }
586    }
587}
588
589impl Default for MapBounds {
590    fn default() -> Self {
591        MapBounds::new()
592    }
593}
594
595pub(crate) struct TextSettings {
596    pub position: RawPoint,
597    pub anchor: Align2,
598    pub text: String,
599    pub size: f32,
600    pub family: FontFamily,
601    pub text_color: Color32,
602}
603
604#[derive(Clone, Debug)]
605pub struct MapSettings {
606    pub max_zoom: f32,
607    pub min_zoom: f32,
608    pub line_visible_zoom: f32,
609    pub label_visible_zoom: f32,
610    pub node_text_visibility: VisibilitySetting,
611    pub styles: Vec<MapStyle>,
612}
613
614impl MapSettings {
615    pub fn new() -> Self {
616        MapSettings {
617            max_zoom: 0.0,
618            min_zoom: 0.0,
619            line_visible_zoom: 0.0,
620            label_visible_zoom: 0.0,
621            node_text_visibility: VisibilitySetting::Allways,
622            styles: vec![MapStyle::new()],
623        }
624    }
625}
626
627impl Default for MapSettings {
628    fn default() -> Self {
629        let mut obj = MapSettings {
630            max_zoom: 2.0,
631            min_zoom: 0.1,
632            line_visible_zoom: 0.2,
633            label_visible_zoom: 0.58,
634            node_text_visibility: VisibilitySetting::Allways,
635            styles: Vec::new(),
636        };
637
638        // light Theme
639        obj.styles.push(MapStyle {
640            border: Some(egui::Stroke {
641                width: 2.0,
642                color: Color32::from_rgb(216, 142, 58),
643            }),
644            line: Some(egui::Stroke {
645                width: 2.0,
646                color: Color32::DARK_RED,
647            }),
648            fill_color: Color32::from_rgb(216, 142, 58),
649            text_color: Color32::DARK_GREEN,
650            font: Some(FontId::new(12.00, FontFamily::Proportional)),
651            background_color: Color32::WHITE,
652            alert_color: Color32::from_rgb(246, 30, 131),
653        });
654
655        // Dark Theme
656        obj.styles.push(MapStyle {
657            border: Some(egui::Stroke {
658                width: 2.0,
659                color: Color32::GOLD,
660            }),
661            line: Some(egui::Stroke {
662                width: 2.0,
663                color: Color32::LIGHT_RED,
664            }),
665            fill_color: Color32::GOLD,
666            text_color: Color32::LIGHT_GREEN,
667            font: Some(FontId::new(12.00, FontFamily::Proportional)),
668            background_color: Color32::DARK_GRAY,
669            alert_color: Color32::from_rgb(128, 12, 67),
670        });
671        obj
672    }
673}
674
675#[derive(Clone, Debug, PartialEq)]
676pub enum VisibilitySetting {
677    Hidden,
678    Hover,
679    Allways,
680}
681
682pub trait ContextMenuManager {
683    fn ui(&self, ui: &mut Ui);
684}
685
686pub trait NodeTemplate {
687    fn node_ui(&self, ui: &mut Ui, _viewport_point: Pos2, _zoom: f32, _system: &MapPoint);
688    fn selection_ui(&self, ui: &mut Ui, _viewport_point: Pos2, _zoom: f32);
689    fn notification_ui(
690        &self,
691        ui: &mut Ui,
692        _viewport_point: Pos2,
693        _zoom: f32,
694        initial_time: Instant,
695        color: Color32,
696    ) -> bool;
697    fn marker_ui(&self, ui: &mut Ui, _viewport_point: Pos2, _zoom: f32);
698}
699
700#[cfg(test)]
701mod tests {
702    use super::*;
703    use std::collections::HashMap;
704
705    // ---------- RawPoint ----------
706
707    #[test]
708    fn raw_point_new() {
709        let p = RawPoint::new(3.5, -2.0);
710        assert_eq!(p.components, [3.5, -2.0]);
711    }
712
713    #[test]
714    fn raw_point_default() {
715        let p = RawPoint::default();
716        assert_eq!(p.components, [0.0, 0.0]);
717    }
718
719    #[test]
720    fn raw_point_mul_i64() {
721        let p = RawPoint::new(2.0, -3.0) * 3i64;
722        assert_eq!(p.components, [6.0, -9.0]);
723    }
724
725    #[test]
726    fn raw_point_mul_i32() {
727        let p = RawPoint::new(2.0, -3.0) * 3i32;
728        assert_eq!(p.components, [6.0, -9.0]);
729    }
730
731    #[test]
732    fn raw_point_mul_u64() {
733        let p = RawPoint::new(2.0, -3.0) * 3u64;
734        assert_eq!(p.components, [6.0, -9.0]);
735    }
736
737    #[test]
738    fn raw_point_mul_u32() {
739        let p = RawPoint::new(2.0, -3.0) * 3u32;
740        assert_eq!(p.components, [6.0, -9.0]);
741    }
742
743    #[test]
744    fn raw_point_mul_f32() {
745        let p = RawPoint::new(2.0, -3.0) * 0.5f32;
746        assert_eq!(p.components, [1.0, -1.5]);
747    }
748
749    #[test]
750    fn raw_point_mul_assign_i64() {
751        let mut p = RawPoint::new(2.0, -3.0);
752        p *= 3i64;
753        assert_eq!(p.components, [6.0, -9.0]);
754    }
755
756    #[test]
757    fn raw_point_mul_assign_i32() {
758        let mut p = RawPoint::new(2.0, -3.0);
759        p *= 3i32;
760        assert_eq!(p.components, [6.0, -9.0]);
761    }
762
763    #[test]
764    fn raw_point_mul_assign_u64() {
765        let mut p = RawPoint::new(2.0, -3.0);
766        p *= 3u64;
767        assert_eq!(p.components, [6.0, -9.0]);
768    }
769
770    #[test]
771    fn raw_point_mul_assign_u32() {
772        let mut p = RawPoint::new(2.0, -3.0);
773        p *= 3u32;
774        assert_eq!(p.components, [6.0, -9.0]);
775    }
776
777    #[test]
778    fn raw_point_mul_assign_f32() {
779        let mut p = RawPoint::new(2.0, -3.0);
780        p *= 0.5f32;
781        assert_eq!(p.components, [1.0, -1.5]);
782    }
783
784    #[test]
785    fn raw_point_div_i64() {
786        let p = RawPoint::new(6.0, -9.0) / 3i64;
787        assert_eq!(p.components, [2.0, -3.0]);
788    }
789
790    #[test]
791    fn raw_point_div_i32() {
792        let p = RawPoint::new(6.0, -9.0) / 3i32;
793        assert_eq!(p.components, [2.0, -3.0]);
794    }
795
796    #[test]
797    fn raw_point_div_u64() {
798        let p = RawPoint::new(6.0, -9.0) / 3u64;
799        assert_eq!(p.components, [2.0, -3.0]);
800    }
801
802    #[test]
803    fn raw_point_div_u32() {
804        let p = RawPoint::new(6.0, -9.0) / 3u32;
805        assert_eq!(p.components, [2.0, -3.0]);
806    }
807
808    #[test]
809    fn raw_point_div_f32() {
810        let p = RawPoint::new(1.0, -1.5) / 0.5f32;
811        assert_eq!(p.components, [2.0, -3.0]);
812    }
813
814    #[test]
815    fn raw_point_div_assign_i64() {
816        let mut p = RawPoint::new(6.0, -9.0);
817        p /= 3i64;
818        assert_eq!(p.components, [2.0, -3.0]);
819    }
820
821    #[test]
822    fn raw_point_div_assign_i32() {
823        let mut p = RawPoint::new(6.0, -9.0);
824        p /= 3i32;
825        assert_eq!(p.components, [2.0, -3.0]);
826    }
827
828    #[test]
829    fn raw_point_div_assign_u64() {
830        let mut p = RawPoint::new(6.0, -9.0);
831        p /= 3u64;
832        assert_eq!(p.components, [2.0, -3.0]);
833    }
834
835    #[test]
836    fn raw_point_div_assign_u32() {
837        let mut p = RawPoint::new(6.0, -9.0);
838        p /= 3u32;
839        assert_eq!(p.components, [2.0, -3.0]);
840    }
841
842    #[test]
843    fn raw_point_div_assign_f32() {
844        let mut p = RawPoint::new(1.0, -1.5);
845        p /= 0.5f32;
846        assert_eq!(p.components, [2.0, -3.0]);
847    }
848
849    #[test]
850    fn raw_point_add() {
851        let a = RawPoint::new(1.0, 2.0);
852        let b = RawPoint::new(3.0, -4.0);
853        let c = a + b;
854        assert_eq!(c.components, [4.0, -2.0]);
855    }
856
857    #[test]
858    fn raw_point_sub() {
859        let a = RawPoint::new(1.0, 2.0);
860        let b = RawPoint::new(3.0, -4.0);
861        let c = a - b;
862        assert_eq!(c.components, [-2.0, 6.0]);
863    }
864
865    #[test]
866    fn raw_point_add_ref() {
867        let a = RawPoint::new(1.0, 2.0);
868        let b = RawPoint::new(3.0, -4.0);
869        let c = a + &b;
870        assert_eq!(c.components, [4.0, -2.0]);
871        // b sigue siendo usable tras la suma por referencia
872        assert_eq!(b.components, [3.0, -4.0]);
873    }
874
875    #[test]
876    fn raw_point_sub_ref() {
877        let a = RawPoint::new(1.0, 2.0);
878        let b = RawPoint::new(3.0, -4.0);
879        let c = a - &b;
880        assert_eq!(c.components, [-2.0, 6.0]);
881        assert_eq!(b.components, [3.0, -4.0]);
882    }
883
884    #[test]
885    fn raw_point_from_f32_array() {
886        let p = RawPoint::from([1.5f32, -2.5f32]);
887        assert_eq!(p.components, [1.5, -2.5]);
888    }
889
890    #[test]
891    fn raw_point_from_i64_array() {
892        let p = RawPoint::from([3i64, -4i64]);
893        assert_eq!(p.components, [3.0, -4.0]);
894    }
895
896    #[test]
897    fn raw_point_from_i32_array() {
898        let p = RawPoint::from([3i32, -4i32]);
899        assert_eq!(p.components, [3.0, -4.0]);
900    }
901
902    #[test]
903    fn raw_point_from_i16_array() {
904        let p = RawPoint::from([3i16, -4i16]);
905        assert_eq!(p.components, [3.0, -4.0]);
906    }
907
908    #[test]
909    fn raw_point_from_i8_array() {
910        let p = RawPoint::from([3i8, -4i8]);
911        assert_eq!(p.components, [3.0, -4.0]);
912    }
913
914    #[test]
915    fn raw_point_from_pos2() {
916        let p = RawPoint::from(Pos2::new(7.0, 8.0));
917        assert_eq!(p.components, [7.0, 8.0]);
918    }
919
920    #[test]
921    fn raw_point_into_f32_array() {
922        let arr: [f32; 2] = RawPoint::new(7.0, 8.0).into();
923        assert_eq!(arr, [7.0, 8.0]);
924    }
925
926    #[test]
927    fn raw_point_into_pos2() {
928        let pos: Pos2 = RawPoint::new(7.0, 8.0).into();
929        assert_eq!(pos, Pos2::new(7.0, 8.0));
930    }
931
932    // ---------- RawLine ----------
933
934    #[test]
935    fn raw_line_new() {
936        let a = RawPoint::new(1.0, 2.0);
937        let b = RawPoint::new(3.0, 4.0);
938        let line = RawLine::new(a, b);
939        assert_eq!(line.points[0].components, [1.0, 2.0]);
940        assert_eq!(line.points[1].components, [3.0, 4.0]);
941    }
942
943    #[test]
944    fn raw_line_distance() {
945        // triángulo 3-4-5
946        let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(3.0, 4.0));
947        assert_eq!(line.distance(), 5.0);
948    }
949
950    #[test]
951    fn raw_line_distance_zero() {
952        let line = RawLine::new(RawPoint::new(2.0, 2.0), RawPoint::new(2.0, 2.0));
953        assert_eq!(line.distance(), 0.0);
954    }
955
956    #[test]
957    fn raw_line_midpoint() {
958        let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(4.0, 6.0));
959        let mid = line.midpoint();
960        assert_eq!(mid.components, [2.0, 3.0]);
961    }
962
963    #[test]
964    fn raw_line_into_pos2_array() {
965        let line = RawLine::new(RawPoint::new(1.0, 2.0), RawPoint::new(3.0, 4.0));
966        let arr: [Pos2; 2] = line.into();
967        assert_eq!(arr, [Pos2::new(1.0, 2.0), Pos2::new(3.0, 4.0)]);
968    }
969
970    #[test]
971    fn raw_line_from_i64_arrays() {
972        let line = RawLine::from([[1i64, 2i64], [3i64, 4i64]]);
973        assert_eq!(line.points[0].components, [1.0, 2.0]);
974        assert_eq!(line.points[1].components, [3.0, 4.0]);
975    }
976
977    // ---------- MapStyle ----------
978
979    fn full_style() -> MapStyle {
980        MapStyle {
981            border: Some(Stroke::new(2.0, Color32::RED)),
982            line: Some(Stroke::new(4.0, Color32::BLUE)),
983            fill_color: Color32::GREEN,
984            text_color: Color32::WHITE,
985            font: Some(FontId::new(10.0, FontFamily::Proportional)),
986            background_color: Color32::BLACK,
987            alert_color: Color32::YELLOW,
988        }
989    }
990
991    #[test]
992    fn map_style_new() {
993        let s = MapStyle::new();
994        assert!(s.border.is_none());
995        assert!(s.line.is_none());
996        assert!(s.font.is_none());
997        assert_eq!(s.fill_color, Color32::TRANSPARENT);
998        assert_eq!(s.text_color, Color32::TRANSPARENT);
999        assert_eq!(s.background_color, Color32::TRANSPARENT);
1000        assert_eq!(s.alert_color, Color32::TRANSPARENT);
1001    }
1002
1003    #[test]
1004    fn map_style_default_equals_new() {
1005        let s = MapStyle::default();
1006        assert!(s.border.is_none());
1007        assert!(s.line.is_none());
1008        assert!(s.font.is_none());
1009    }
1010
1011    #[test]
1012    fn map_style_mul_i64() {
1013        let s = full_style() * 2i64;
1014        assert_eq!(s.border.unwrap().width, 4.0);
1015        assert_eq!(s.line.unwrap().width, 8.0);
1016        assert_eq!(s.font.unwrap().size, 20.0);
1017    }
1018
1019    #[test]
1020    fn map_style_mul_i32() {
1021        let s = full_style() * 2i32;
1022        assert_eq!(s.border.unwrap().width, 4.0);
1023        assert_eq!(s.line.unwrap().width, 8.0);
1024        assert_eq!(s.font.unwrap().size, 20.0);
1025    }
1026
1027    #[test]
1028    fn map_style_mul_f32() {
1029        let s = full_style() * 0.5f32;
1030        assert_eq!(s.border.unwrap().width, 1.0);
1031        assert_eq!(s.line.unwrap().width, 2.0);
1032        assert_eq!(s.font.unwrap().size, 5.0);
1033    }
1034
1035    #[test]
1036    fn map_style_mul_f64() {
1037        let s = full_style() * 0.5f64;
1038        assert_eq!(s.border.unwrap().width, 1.0);
1039        assert_eq!(s.line.unwrap().width, 2.0);
1040        assert_eq!(s.font.unwrap().size, 5.0);
1041    }
1042
1043    #[test]
1044    fn map_style_div_i64() {
1045        let s = full_style() / 2i64;
1046        assert_eq!(s.border.unwrap().width, 1.0);
1047        assert_eq!(s.line.unwrap().width, 2.0);
1048        assert_eq!(s.font.unwrap().size, 5.0);
1049    }
1050
1051    #[test]
1052    fn map_style_div_i32() {
1053        let s = full_style() / 2i32;
1054        assert_eq!(s.border.unwrap().width, 1.0);
1055        assert_eq!(s.line.unwrap().width, 2.0);
1056        assert_eq!(s.font.unwrap().size, 5.0);
1057    }
1058
1059    #[test]
1060    fn map_style_div_f32() {
1061        let s = full_style() / 0.5f32;
1062        assert_eq!(s.border.unwrap().width, 4.0);
1063        assert_eq!(s.line.unwrap().width, 8.0);
1064        assert_eq!(s.font.unwrap().size, 20.0);
1065    }
1066
1067    #[test]
1068    fn map_style_div_f64() {
1069        let s = full_style() / 0.5f64;
1070        assert_eq!(s.border.unwrap().width, 4.0);
1071        assert_eq!(s.line.unwrap().width, 8.0);
1072        assert_eq!(s.font.unwrap().size, 20.0);
1073    }
1074
1075    // ---------- MapLabel ----------
1076
1077    #[test]
1078    fn map_label_new() {
1079        let l = MapLabel::new();
1080        assert_eq!(l.text, String::new());
1081        assert_eq!(l.center, Pos2::new(0.0, 0.0));
1082    }
1083
1084    #[test]
1085    fn map_label_default_equals_new() {
1086        let l = MapLabel::default();
1087        assert_eq!(l.text, String::new());
1088        assert_eq!(l.center, Pos2::new(0.0, 0.0));
1089    }
1090
1091    // ---------- MapLine ----------
1092
1093    #[test]
1094    fn map_line_new() {
1095        let a = RawPoint::new(1.0, 2.0);
1096        let b = RawPoint::new(3.0, 4.0);
1097        let line = MapLine::new(a, b);
1098        assert!(line.id.is_none());
1099        assert_eq!(line.raw_line.points[0].components, [1.0, 2.0]);
1100        assert_eq!(line.raw_line.points[1].components, [3.0, 4.0]);
1101    }
1102
1103    // ---------- MapPoint ----------
1104
1105    #[test]
1106    fn map_point_new() {
1107        let p = MapPoint::new(42, RawPoint::new(1.0, 2.0));
1108        assert_eq!(p.get_id(), 42);
1109        assert_eq!(p.raw_point.components, [1.0, 2.0]);
1110        assert!(p.connections.is_empty());
1111        assert_eq!(p.get_name(), String::new());
1112    }
1113
1114    #[test]
1115    fn map_point_set_and_get_name() {
1116        let mut p = MapPoint::new(1, RawPoint::default());
1117        p.set_name("Jita".to_string());
1118        assert_eq!(p.get_name(), "Jita");
1119    }
1120
1121    #[test]
1122    fn map_point_from_occupied_entry() {
1123        let mut map: HashMap<usize, MapPoint> = HashMap::new();
1124        let mut original = MapPoint::new(7, RawPoint::new(5.0, 6.0));
1125        original.set_name("Amarr".to_string());
1126        map.insert(7, original);
1127
1128        use std::collections::hash_map::Entry;
1129        if let Entry::Occupied(entry) = map.entry(7) {
1130            let cloned = MapPoint::from(entry);
1131            assert_eq!(cloned.get_id(), 7);
1132            assert_eq!(cloned.get_name(), "Amarr");
1133            assert_eq!(cloned.raw_point.components, [5.0, 6.0]);
1134        } else {
1135            panic!("se esperaba una entrada ocupada");
1136        }
1137    }
1138
1139    // ---------- MapBounds ----------
1140
1141    #[test]
1142    fn map_bounds_new() {
1143        let b = MapBounds::new();
1144        assert_eq!(b.min.components, [0.0, 0.0]);
1145        assert_eq!(b.max.components, [0.0, 0.0]);
1146        assert_eq!(b.pos.components, [0.0, 0.0]);
1147        assert_eq!(b.dist, 0.0);
1148    }
1149
1150    #[test]
1151    fn map_bounds_default_equals_new() {
1152        let b = MapBounds::default();
1153        assert_eq!(b.dist, 0.0);
1154        assert_eq!(b.pos.components, [0.0, 0.0]);
1155    }
1156
1157    // ---------- MapSettings ----------
1158
1159    #[test]
1160    fn map_settings_new() {
1161        let s = MapSettings::new();
1162        assert_eq!(s.max_zoom, 0.0);
1163        assert_eq!(s.min_zoom, 0.0);
1164        assert_eq!(s.line_visible_zoom, 0.0);
1165        assert_eq!(s.label_visible_zoom, 0.0);
1166        assert_eq!(s.node_text_visibility, VisibilitySetting::Allways);
1167        assert_eq!(s.styles.len(), 1);
1168    }
1169
1170    #[test]
1171    fn map_settings_default() {
1172        let s = MapSettings::default();
1173        assert_eq!(s.max_zoom, 2.0);
1174        assert_eq!(s.min_zoom, 0.1);
1175        assert_eq!(s.line_visible_zoom, 0.2);
1176        assert_eq!(s.label_visible_zoom, 0.58);
1177        assert_eq!(s.node_text_visibility, VisibilitySetting::Allways);
1178        // light + dark themes
1179        assert_eq!(s.styles.len(), 2);
1180        // light theme
1181        assert_eq!(s.styles[0].background_color, Color32::WHITE);
1182        assert!(s.styles[0].border.is_some());
1183        assert!(s.styles[0].line.is_some());
1184        assert!(s.styles[0].font.is_some());
1185        // dark theme
1186        assert_eq!(s.styles[1].background_color, Color32::DARK_GRAY);
1187        assert!(s.styles[1].border.is_some());
1188        assert!(s.styles[1].line.is_some());
1189        assert!(s.styles[1].font.is_some());
1190    }
1191
1192    // ---------- VisibilitySetting ----------
1193
1194    #[test]
1195    fn visibility_setting_equality() {
1196        assert_eq!(VisibilitySetting::Hidden, VisibilitySetting::Hidden);
1197        assert_eq!(VisibilitySetting::Hover, VisibilitySetting::Hover);
1198        assert_eq!(VisibilitySetting::Allways, VisibilitySetting::Allways);
1199        assert_ne!(VisibilitySetting::Hidden, VisibilitySetting::Hover);
1200        assert_ne!(VisibilitySetting::Hover, VisibilitySetting::Allways);
1201        assert_ne!(VisibilitySetting::Hidden, VisibilitySetting::Allways);
1202    }
1203}