1use egui::{Align2, Color32, FontFamily, FontId, Pos2, Stroke, Ui};
9use rstar::AABB;
10use std::convert::{From, Into};
11use std::ops::{Add, Div, DivAssign, Mul, MulAssign, Sub};
12use std::time::Instant;
13
14#[derive(Copy, Clone, Debug, PartialEq)]
33pub struct RawPoint {
34 pub components: [f32; 2],
36}
37
38impl RawPoint {
39 pub fn new(x: f32, y: f32) -> Self {
41 Self { components: [x, y] }
42 }
43}
44
45impl rstar::Point for RawPoint {
46 type Scalar = f32;
47 const DIMENSIONS: usize = 2;
48
49 fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
50 let mut components = [0.0; 2];
51 for (i, component) in components.iter_mut().enumerate() {
52 *component = generator(i);
53 }
54 Self { components }
55 }
56
57 fn nth(&self, index: usize) -> Self::Scalar {
58 self.components[index]
59 }
60
61 fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
62 &mut self.components[index]
63 }
64}
65
66impl Default for RawPoint {
67 fn default() -> Self {
68 Self::new(0.00, 0.00)
69 }
70}
71
72impl Mul<i64> for RawPoint {
73 type Output = Self;
74
75 fn mul(self, rhs: i64) -> Self::Output {
76 Self {
77 components: [
78 self.components[0] * rhs as f32,
79 self.components[1] * rhs as f32,
80 ],
81 }
82 }
83}
84
85impl Mul<i32> for RawPoint {
86 type Output = Self;
87
88 fn mul(self, rhs: i32) -> Self::Output {
89 Self {
90 components: [
91 self.components[0] * rhs as f32,
92 self.components[1] * rhs as f32,
93 ],
94 }
95 }
96}
97
98impl Mul<u64> for RawPoint {
99 type Output = Self;
100
101 fn mul(self, rhs: u64) -> Self::Output {
102 Self {
103 components: [
104 self.components[0] * rhs as f32,
105 self.components[1] * rhs as f32,
106 ],
107 }
108 }
109}
110
111impl Mul<u32> for RawPoint {
112 type Output = Self;
113
114 fn mul(self, rhs: u32) -> Self::Output {
115 Self {
116 components: [
117 self.components[0] * rhs as f32,
118 self.components[1] * rhs as f32,
119 ],
120 }
121 }
122}
123
124impl Mul<f32> for RawPoint {
125 type Output = Self;
126
127 fn mul(self, rhs: f32) -> Self::Output {
128 Self {
129 components: [self.components[0] * rhs, self.components[1] * rhs],
130 }
131 }
132}
133
134impl MulAssign<i64> for RawPoint {
135 fn mul_assign(&mut self, rhs: i64) {
136 self.components[0] = self.components[0] * rhs as f32;
137 self.components[1] = self.components[1] * rhs as f32;
138 }
139}
140
141impl MulAssign<i32> for RawPoint {
142 fn mul_assign(&mut self, rhs: i32) {
143 self.components[0] = self.components[0] * rhs as f32;
144 self.components[1] = self.components[1] * rhs as f32;
145 }
146}
147
148impl MulAssign<u64> for RawPoint {
149 fn mul_assign(&mut self, rhs: u64) {
150 self.components[0] = self.components[0] * rhs as f32;
151 self.components[1] = self.components[1] * rhs as f32;
152 }
153}
154
155impl MulAssign<u32> for RawPoint {
156 fn mul_assign(&mut self, rhs: u32) {
157 self.components[0] = self.components[0] * rhs as f32;
158 self.components[1] = self.components[1] * rhs as f32;
159 }
160}
161
162impl MulAssign<f32> for RawPoint {
163 fn mul_assign(&mut self, rhs: f32) {
164 self.components[0] = self.components[0] * rhs;
165 self.components[1] = self.components[1] * rhs;
166 }
167}
168
169impl Div<i64> for RawPoint {
170 type Output = Self;
171
172 fn div(self, rhs: i64) -> Self::Output {
173 Self {
174 components: [
175 self.components[0] / rhs as f32,
176 self.components[1] / rhs as f32,
177 ],
178 }
179 }
180}
181
182impl Div<i32> for RawPoint {
183 type Output = Self;
184
185 fn div(self, rhs: i32) -> Self::Output {
186 Self {
187 components: [
188 self.components[0] / rhs as f32,
189 self.components[1] / rhs as f32,
190 ],
191 }
192 }
193}
194
195impl Div<u64> for RawPoint {
196 type Output = Self;
197
198 fn div(self, rhs: u64) -> Self::Output {
199 Self {
200 components: [
201 self.components[0] / rhs as f32,
202 self.components[1] / rhs as f32,
203 ],
204 }
205 }
206}
207
208impl Div<u32> for RawPoint {
209 type Output = Self;
210
211 fn div(self, rhs: u32) -> Self::Output {
212 Self {
213 components: [
214 self.components[0] / rhs as f32,
215 self.components[1] / rhs as f32,
216 ],
217 }
218 }
219}
220
221impl Div<f32> for RawPoint {
222 type Output = Self;
223
224 fn div(self, rhs: f32) -> Self::Output {
225 Self {
226 components: [self.components[0] / rhs, self.components[1] / rhs],
227 }
228 }
229}
230
231impl DivAssign<i64> for RawPoint {
232 fn div_assign(&mut self, rhs: i64) {
233 self.components[0] = self.components[0] / rhs as f32;
234 self.components[1] = self.components[1] / rhs as f32;
235 }
236}
237
238impl DivAssign<i32> for RawPoint {
239 fn div_assign(&mut self, rhs: i32) {
240 self.components[0] = self.components[0] / rhs as f32;
241 self.components[1] = self.components[1] / rhs as f32;
242 }
243}
244
245impl DivAssign<u64> for RawPoint {
246 fn div_assign(&mut self, rhs: u64) {
247 self.components[0] = self.components[0] / rhs as f32;
248 self.components[1] = self.components[1] / rhs as f32;
249 }
250}
251
252impl DivAssign<u32> for RawPoint {
253 fn div_assign(&mut self, rhs: u32) {
254 self.components[0] = self.components[0] / rhs as f32;
255 self.components[1] = self.components[1] / rhs as f32;
256 }
257}
258
259impl DivAssign<f32> for RawPoint {
260 fn div_assign(&mut self, rhs: f32) {
261 self.components[0] = self.components[0] / rhs;
262 self.components[1] = self.components[1] / rhs;
263 }
264}
265
266impl Add<RawPoint> for RawPoint {
267 type Output = RawPoint;
268 fn add(self, rhs: RawPoint) -> Self::Output {
269 Self {
270 components: [
271 self.components[0] + rhs.components[0],
272 self.components[1] + rhs.components[1],
273 ],
274 }
275 }
276}
277
278impl Sub<RawPoint> for RawPoint {
279 type Output = RawPoint;
280 fn sub(self, rhs: RawPoint) -> Self::Output {
281 Self {
282 components: [
283 self.components[0] - rhs.components[0],
284 self.components[1] - rhs.components[1],
285 ],
286 }
287 }
288}
289
290impl Add<&RawPoint> for RawPoint {
291 type Output = RawPoint;
292 fn add(self, rhs: &RawPoint) -> Self::Output {
293 Self {
294 components: [
295 self.components[0] + rhs.components[0],
296 self.components[1] + rhs.components[1],
297 ],
298 }
299 }
300}
301
302impl Sub<&RawPoint> for RawPoint {
303 type Output = RawPoint;
304 fn sub(self, rhs: &RawPoint) -> Self::Output {
305 Self {
306 components: [
307 self.components[0] - rhs.components[0],
308 self.components[1] - rhs.components[1],
309 ],
310 }
311 }
312}
313
314impl From<[f32; 2]> for RawPoint {
315 fn from(value: [f32; 2]) -> Self {
316 Self { components: value }
317 }
318}
319
320impl From<Pos2> for RawPoint {
321 fn from(value: Pos2) -> Self {
322 Self {
323 components: [value.x, value.y],
324 }
325 }
326}
327
328impl From<[i64; 2]> for RawPoint {
329 fn from(value: [i64; 2]) -> Self {
330 Self {
331 components: [value[0] as f32, value[1] as f32],
332 }
333 }
334}
335
336impl From<[i32; 2]> for RawPoint {
337 fn from(value: [i32; 2]) -> Self {
338 Self {
339 components: [value[0] as f32, value[1] as f32],
340 }
341 }
342}
343
344impl From<[i16; 2]> for RawPoint {
345 fn from(value: [i16; 2]) -> Self {
346 Self {
347 components: [value[0] as f32, value[1] as f32],
348 }
349 }
350}
351
352impl From<[i8; 2]> for RawPoint {
353 fn from(value: [i8; 2]) -> Self {
354 Self {
355 components: [value[0] as f32, value[1] as f32],
356 }
357 }
358}
359
360impl From<RawPoint> for [f32; 2] {
361 fn from(val: RawPoint) -> Self {
362 [val.components[0], val.components[1]]
363 }
364}
365
366impl From<RawPoint> for Pos2 {
367 fn from(val: RawPoint) -> Self {
368 Pos2::from(val.components)
369 }
370}
371
372#[derive(Copy, Clone, Debug)]
374pub struct RawLine {
375 pub points: [RawPoint; 2],
377}
378
379impl RawLine {
380 pub fn new(a: RawPoint, b: RawPoint) -> Self {
382 Self { points: [a, b] }
383 }
384
385 pub fn distance(self) -> f32 {
387 let x = self.points[0].components[0] - self.points[1].components[0];
388 let y = self.points[0].components[1] - self.points[1].components[1];
389 (x.powi(2) + y.powi(2)).sqrt()
390 }
391
392 pub fn midpoint(self) -> RawPoint {
394 let x = (self.points[0].components[0] + self.points[1].components[0]) / 2.0;
395 let y = (self.points[0].components[1] + self.points[1].components[1]) / 2.0;
396 RawPoint::new(x, y)
397 }
398
399 pub fn distance_to_point(self, point: RawPoint) -> f32 {
417 let [a, b] = self.points;
418 let ab = b - a;
419 let ap = point - a;
420 let len_sq = ab.components[0].powi(2) + ab.components[1].powi(2);
421 if len_sq == 0.0 {
422 return (ap.components[0].powi(2) + ap.components[1].powi(2)).sqrt();
424 }
425 let t = ((ap.components[0] * ab.components[0] + ap.components[1] * ab.components[1])
426 / len_sq)
427 .clamp(0.0, 1.0);
428 let closest = a + ab * t;
429 let d = point - closest;
430 (d.components[0].powi(2) + d.components[1].powi(2)).sqrt()
431 }
432}
433
434impl From<RawLine> for [Pos2; 2] {
435 fn from(val: RawLine) -> Self {
436 let position1 = val.points[0].into();
437 let position2 = val.points[1].into();
438 [position1, position2]
439 }
440}
441
442impl From<[[i64; 2]; 2]> for RawLine {
443 fn from(value: [[i64; 2]; 2]) -> Self {
444 Self {
445 points: [RawPoint::from(value[0]), RawPoint::from(value[1])],
446 }
447 }
448}
449
450#[derive(Clone, Debug)]
457pub struct MapStyle {
458 pub border: Option<Stroke>,
460 pub line: Option<Stroke>,
462 pub fill_color: Color32,
464 pub text_color: Color32,
466 pub font: Option<FontId>,
468 pub background_color: Color32,
470 pub alert_color: Color32,
472}
473
474impl MapStyle {
475 pub fn new() -> Self {
477 MapStyle {
478 border: None,
479 line: None,
480 fill_color: Color32::TRANSPARENT,
481 text_color: Color32::TRANSPARENT,
482 font: None,
483 background_color: Color32::TRANSPARENT,
484 alert_color: Color32::TRANSPARENT,
485 }
486 }
487}
488
489impl Default for MapStyle {
490 fn default() -> Self {
491 MapStyle::new()
492 }
493}
494
495impl MapStyle {
496 fn scaled(mut self, factor: f32) -> Self {
499 if let Some(border) = self.border.as_mut() {
500 border.width *= factor;
501 }
502 if let Some(line) = self.line.as_mut() {
503 line.width *= factor;
504 }
505 if let Some(font) = self.font.as_mut() {
506 font.size *= factor;
507 }
508 self
509 }
510}
511
512impl Mul<i64> for MapStyle {
513 type Output = Self;
514
515 fn mul(self, rhs: i64) -> Self::Output {
516 self.scaled(rhs as f32)
517 }
518}
519
520impl Mul<i32> for MapStyle {
521 type Output = Self;
522
523 fn mul(self, rhs: i32) -> Self::Output {
524 self.scaled(rhs as f32)
525 }
526}
527
528impl Mul<f32> for MapStyle {
529 type Output = Self;
530
531 fn mul(self, rhs: f32) -> Self::Output {
532 self.scaled(rhs)
533 }
534}
535
536impl Mul<f64> for MapStyle {
537 type Output = Self;
538
539 fn mul(self, rhs: f64) -> Self::Output {
540 self.scaled(rhs as f32)
541 }
542}
543
544impl Div<i64> for MapStyle {
545 type Output = Self;
546
547 fn div(self, rhs: i64) -> Self::Output {
548 self.scaled(1.0 / rhs as f32)
549 }
550}
551
552impl Div<i32> for MapStyle {
553 type Output = Self;
554
555 fn div(self, rhs: i32) -> Self::Output {
556 self.scaled(1.0 / rhs as f32)
557 }
558}
559
560impl Div<f32> for MapStyle {
561 type Output = Self;
562
563 fn div(self, rhs: f32) -> Self::Output {
564 self.scaled(1.0 / rhs)
565 }
566}
567
568impl Div<f64> for MapStyle {
569 type Output = Self;
570
571 fn div(self, rhs: f64) -> Self::Output {
572 self.scaled(1.0 / rhs as f32)
573 }
574}
575
576#[derive(Clone, Debug)]
580pub struct MapLabel {
581 pub text: String,
583 pub center: Pos2,
585}
586
587impl Default for MapLabel {
588 fn default() -> Self {
589 MapLabel::new()
590 }
591}
592
593impl MapLabel {
594 pub fn new() -> Self {
596 MapLabel {
597 text: String::new(),
598 center: Pos2::new(0.00, 0.00),
599 }
600 }
601}
602
603#[derive(Clone, Copy, Debug, PartialEq)]
619pub struct MapSegment {
620 pub id: (usize, usize),
623 pub point1: [f32; 2],
625 pub point2: [f32; 2],
627}
628
629impl MapSegment {
630 pub fn new(id: (usize, usize), point1: [f32; 2], point2: [f32; 2]) -> Self {
632 Self { id, point1, point2 }
633 }
634
635 pub(crate) fn raw_line(&self) -> RawLine {
638 RawLine::new(RawPoint::from(self.point1), RawPoint::from(self.point2))
639 }
640}
641
642impl rstar::RTreeObject for MapSegment {
643 type Envelope = AABB<[f32; 2]>;
644
645 fn envelope(&self) -> Self::Envelope {
646 AABB::from_corners(
647 [
648 self.point1[0].min(self.point2[0]),
649 self.point1[1].min(self.point2[1]),
650 ],
651 [
652 self.point1[0].max(self.point2[0]),
653 self.point1[1].max(self.point2[1]),
654 ],
655 )
656 }
657}
658
659#[derive(Clone, Debug, PartialEq)]
682pub struct MapPoint {
683 pub coords: [f32; 2],
685 pub id: usize,
687 pub name: Option<String>,
689 pub connections: Vec<(usize, usize)>,
699 pub color: Option<Color32>,
708}
709
710impl MapPoint {
711 pub fn new(id: usize, coords: [f32; 2]) -> MapPoint {
713 MapPoint {
714 coords,
715 id,
716 connections: Vec::new(),
717 name: None,
718 color: None,
719 }
720 }
721
722 pub fn get_id(&self) -> usize {
724 self.id
725 }
726
727 pub fn get_name(&self) -> String {
729 self.name.clone().unwrap_or_default()
730 }
731
732 pub fn set_name(&mut self, value: String) {
734 self.name = Some(value);
735 }
736}
737
738impl From<std::collections::hash_map::OccupiedEntry<'_, usize, MapPoint>> for MapPoint {
739 fn from(value: std::collections::hash_map::OccupiedEntry<'_, usize, MapPoint>) -> Self {
740 let k = value.get();
741 k.clone()
742 }
743}
744
745#[derive(Clone)]
746pub(crate) struct MapBounds {
747 pub min: RawPoint,
748 pub max: RawPoint,
749 pub pos: RawPoint,
750 pub dist: f32,
751}
752
753impl MapBounds {
754 pub fn new() -> Self {
755 MapBounds {
756 min: RawPoint::default(),
757 max: RawPoint::default(),
758 pos: RawPoint::default(),
759 dist: 0.0,
760 }
761 }
762}
763
764impl Default for MapBounds {
765 fn default() -> Self {
766 MapBounds::new()
767 }
768}
769
770pub(crate) struct TextSettings {
771 pub position: RawPoint,
772 pub anchor: Align2,
773 pub text: String,
774 pub size: f32,
775 pub family: FontFamily,
776 pub text_color: Color32,
777}
778
779#[derive(Clone, Debug)]
786pub struct MapSettings {
787 pub max_zoom: f32,
789 pub min_zoom: f32,
791 pub line_visible_zoom: f32,
793 pub label_visible_zoom: f32,
797 pub node_text_visibility: VisibilitySetting,
799 pub marker_animation: SteadyAnimation,
808 pub node_text_size: f32,
819 pub label_text_size: f32,
823 pub styles: Vec<MapStyle>,
826}
827
828impl MapSettings {
829 pub fn new() -> Self {
835 MapSettings {
836 max_zoom: 0.0,
837 min_zoom: 0.0,
838 line_visible_zoom: 0.0,
839 label_visible_zoom: 0.0,
840 node_text_visibility: VisibilitySetting::Always,
841 marker_animation: SteadyAnimation::Blink,
842 node_text_size: 12.0,
843 label_text_size: 24.0,
844 styles: vec![MapStyle::new()],
845 }
846 }
847}
848
849impl Default for MapSettings {
850 fn default() -> Self {
854 let mut obj = MapSettings {
855 max_zoom: 2.0,
856 min_zoom: 0.1,
857 line_visible_zoom: 0.2,
858 label_visible_zoom: 0.58,
859 node_text_visibility: VisibilitySetting::Always,
860 marker_animation: SteadyAnimation::Blink,
861 node_text_size: 12.0,
862 label_text_size: 24.0,
863 styles: Vec::new(),
864 };
865
866 obj.styles.push(MapStyle {
868 border: Some(egui::Stroke {
869 width: 2.0,
870 color: Color32::from_rgb(216, 142, 58),
871 }),
872 line: Some(egui::Stroke {
873 width: 2.0,
874 color: Color32::DARK_RED,
875 }),
876 fill_color: Color32::from_rgb(216, 142, 58),
877 text_color: Color32::DARK_GREEN,
878 font: Some(FontId::new(12.00, FontFamily::Proportional)),
879 background_color: Color32::WHITE,
880 alert_color: Color32::from_rgb(246, 30, 131),
881 });
882
883 obj.styles.push(MapStyle {
885 border: Some(egui::Stroke {
886 width: 2.0,
887 color: Color32::GOLD,
888 }),
889 line: Some(egui::Stroke {
890 width: 2.0,
891 color: Color32::LIGHT_RED,
892 }),
893 fill_color: Color32::GOLD,
894 text_color: Color32::LIGHT_GREEN,
895 font: Some(FontId::new(12.00, FontFamily::Proportional)),
896 background_color: Color32::DARK_GRAY,
897 alert_color: Color32::from_rgb(128, 12, 67),
898 });
899 obj
900 }
901}
902
903#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
915pub enum NodeAnimation {
916 #[default]
918 Pulse,
919 Ripple,
921 CountdownArc,
923 ScaleIn,
925 Crosshair,
927}
928
929#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
941pub enum SteadyAnimation {
942 #[default]
944 Blink,
945 Halo,
947 Orbit,
949}
950
951#[derive(Clone, Debug, PartialEq)]
953pub enum VisibilitySetting {
954 Hidden,
956 Hover,
958 Always,
960}
961
962pub trait ContextMenuManager {
981 fn ui(&self, ui: &mut Ui);
983}
984
985pub trait NodeTemplate {
1081 fn node_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32, _point: &MapPoint);
1087
1088 fn selection_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32);
1093
1094 fn notification_ui(
1102 &self,
1103 ui: &mut Ui,
1104 _viewport_position: Pos2,
1105 _zoom: f32,
1106 initial_time: Instant,
1107 color: Color32,
1108 ) -> bool;
1109
1110 fn marker_ui(&self, ui: &mut Ui, _viewport_position: Pos2, _zoom: f32);
1117}
1118
1119#[cfg(test)]
1120mod tests {
1121 use super::*;
1122 use std::collections::HashMap;
1123
1124 #[test]
1127 fn raw_point_new() {
1128 let p = RawPoint::new(3.5, -2.0);
1129 assert_eq!(p.components, [3.5, -2.0]);
1130 }
1131
1132 #[test]
1135 fn map_segment_new_computes_tight_aabb() {
1136 let seg = MapSegment::new((1, 2), [10.0, -5.0], [-2.0, 7.0]);
1137 assert_eq!(seg.id, (1, 2));
1138 let envelope: AABB<[f32; 2]> = rstar::RTreeObject::envelope(&seg);
1139 assert_eq!(envelope.lower(), [-2.0, -5.0]);
1140 assert_eq!(envelope.upper(), [10.0, 7.0]);
1141 assert_eq!(seg.raw_line().points[0].components, [10.0, -5.0]);
1142 assert_eq!(seg.raw_line().points[1].components, [-2.0, 7.0]);
1143 }
1144
1145 #[test]
1146 fn map_segment_envelope_returns_its_aabb() {
1147 let seg = MapSegment::new((1, 2), [0.0, 0.0], [4.0, 2.0]);
1148 let envelope: AABB<[f32; 2]> = rstar::RTreeObject::envelope(&seg);
1149 assert_eq!(envelope.lower(), [0.0, 0.0]);
1150 assert_eq!(envelope.upper(), [4.0, 2.0]);
1151 }
1152
1153 #[test]
1154 fn map_segment_degenerate_line_has_point_aabb() {
1155 let seg = MapSegment::new((1, 2), [3.0, 3.0], [3.0, 3.0]);
1157 let envelope: AABB<[f32; 2]> = rstar::RTreeObject::envelope(&seg);
1158 assert_eq!(envelope.lower(), [3.0, 3.0]);
1159 assert_eq!(envelope.upper(), [3.0, 3.0]);
1160 }
1161
1162 #[test]
1163 fn raw_point_default() {
1164 let p = RawPoint::default();
1165 assert_eq!(p.components, [0.0, 0.0]);
1166 }
1167
1168 #[test]
1169 fn raw_point_mul_i64() {
1170 let p = RawPoint::new(2.0, -3.0) * 3i64;
1171 assert_eq!(p.components, [6.0, -9.0]);
1172 }
1173
1174 #[test]
1175 fn raw_point_mul_i32() {
1176 let p = RawPoint::new(2.0, -3.0) * 3i32;
1177 assert_eq!(p.components, [6.0, -9.0]);
1178 }
1179
1180 #[test]
1181 fn raw_point_mul_u64() {
1182 let p = RawPoint::new(2.0, -3.0) * 3u64;
1183 assert_eq!(p.components, [6.0, -9.0]);
1184 }
1185
1186 #[test]
1187 fn raw_point_mul_u32() {
1188 let p = RawPoint::new(2.0, -3.0) * 3u32;
1189 assert_eq!(p.components, [6.0, -9.0]);
1190 }
1191
1192 #[test]
1193 fn raw_point_mul_f32() {
1194 let p = RawPoint::new(2.0, -3.0) * 0.5f32;
1195 assert_eq!(p.components, [1.0, -1.5]);
1196 }
1197
1198 #[test]
1199 fn raw_point_mul_assign_i64() {
1200 let mut p = RawPoint::new(2.0, -3.0);
1201 p *= 3i64;
1202 assert_eq!(p.components, [6.0, -9.0]);
1203 }
1204
1205 #[test]
1206 fn raw_point_mul_assign_i32() {
1207 let mut p = RawPoint::new(2.0, -3.0);
1208 p *= 3i32;
1209 assert_eq!(p.components, [6.0, -9.0]);
1210 }
1211
1212 #[test]
1213 fn raw_point_mul_assign_u64() {
1214 let mut p = RawPoint::new(2.0, -3.0);
1215 p *= 3u64;
1216 assert_eq!(p.components, [6.0, -9.0]);
1217 }
1218
1219 #[test]
1220 fn raw_point_mul_assign_u32() {
1221 let mut p = RawPoint::new(2.0, -3.0);
1222 p *= 3u32;
1223 assert_eq!(p.components, [6.0, -9.0]);
1224 }
1225
1226 #[test]
1227 fn raw_point_mul_assign_f32() {
1228 let mut p = RawPoint::new(2.0, -3.0);
1229 p *= 0.5f32;
1230 assert_eq!(p.components, [1.0, -1.5]);
1231 }
1232
1233 #[test]
1234 fn raw_point_div_i64() {
1235 let p = RawPoint::new(6.0, -9.0) / 3i64;
1236 assert_eq!(p.components, [2.0, -3.0]);
1237 }
1238
1239 #[test]
1240 fn raw_point_div_i32() {
1241 let p = RawPoint::new(6.0, -9.0) / 3i32;
1242 assert_eq!(p.components, [2.0, -3.0]);
1243 }
1244
1245 #[test]
1246 fn raw_point_div_u64() {
1247 let p = RawPoint::new(6.0, -9.0) / 3u64;
1248 assert_eq!(p.components, [2.0, -3.0]);
1249 }
1250
1251 #[test]
1252 fn raw_point_div_u32() {
1253 let p = RawPoint::new(6.0, -9.0) / 3u32;
1254 assert_eq!(p.components, [2.0, -3.0]);
1255 }
1256
1257 #[test]
1258 fn raw_point_div_f32() {
1259 let p = RawPoint::new(1.0, -1.5) / 0.5f32;
1260 assert_eq!(p.components, [2.0, -3.0]);
1261 }
1262
1263 #[test]
1264 fn raw_point_div_assign_i64() {
1265 let mut p = RawPoint::new(6.0, -9.0);
1266 p /= 3i64;
1267 assert_eq!(p.components, [2.0, -3.0]);
1268 }
1269
1270 #[test]
1271 fn raw_point_div_assign_i32() {
1272 let mut p = RawPoint::new(6.0, -9.0);
1273 p /= 3i32;
1274 assert_eq!(p.components, [2.0, -3.0]);
1275 }
1276
1277 #[test]
1278 fn raw_point_div_assign_u64() {
1279 let mut p = RawPoint::new(6.0, -9.0);
1280 p /= 3u64;
1281 assert_eq!(p.components, [2.0, -3.0]);
1282 }
1283
1284 #[test]
1285 fn raw_point_div_assign_u32() {
1286 let mut p = RawPoint::new(6.0, -9.0);
1287 p /= 3u32;
1288 assert_eq!(p.components, [2.0, -3.0]);
1289 }
1290
1291 #[test]
1292 fn raw_point_div_assign_f32() {
1293 let mut p = RawPoint::new(1.0, -1.5);
1294 p /= 0.5f32;
1295 assert_eq!(p.components, [2.0, -3.0]);
1296 }
1297
1298 #[test]
1299 fn raw_point_add() {
1300 let a = RawPoint::new(1.0, 2.0);
1301 let b = RawPoint::new(3.0, -4.0);
1302 let c = a + b;
1303 assert_eq!(c.components, [4.0, -2.0]);
1304 }
1305
1306 #[test]
1307 fn raw_point_sub() {
1308 let a = RawPoint::new(1.0, 2.0);
1309 let b = RawPoint::new(3.0, -4.0);
1310 let c = a - b;
1311 assert_eq!(c.components, [-2.0, 6.0]);
1312 }
1313
1314 #[test]
1315 #[allow(clippy::op_ref)] fn raw_point_add_ref() {
1317 let a = RawPoint::new(1.0, 2.0);
1318 let b = RawPoint::new(3.0, -4.0);
1319 let c = a + &b;
1320 assert_eq!(c.components, [4.0, -2.0]);
1321 assert_eq!(b.components, [3.0, -4.0]);
1323 }
1324
1325 #[test]
1326 #[allow(clippy::op_ref)] fn raw_point_sub_ref() {
1328 let a = RawPoint::new(1.0, 2.0);
1329 let b = RawPoint::new(3.0, -4.0);
1330 let c = a - &b;
1331 assert_eq!(c.components, [-2.0, 6.0]);
1332 assert_eq!(b.components, [3.0, -4.0]);
1333 }
1334
1335 #[test]
1336 fn raw_point_from_f32_array() {
1337 let p = RawPoint::from([1.5f32, -2.5f32]);
1338 assert_eq!(p.components, [1.5, -2.5]);
1339 }
1340
1341 #[test]
1342 fn raw_point_from_i64_array() {
1343 let p = RawPoint::from([3i64, -4i64]);
1344 assert_eq!(p.components, [3.0, -4.0]);
1345 }
1346
1347 #[test]
1348 fn raw_point_from_i32_array() {
1349 let p = RawPoint::from([3i32, -4i32]);
1350 assert_eq!(p.components, [3.0, -4.0]);
1351 }
1352
1353 #[test]
1354 fn raw_point_from_i16_array() {
1355 let p = RawPoint::from([3i16, -4i16]);
1356 assert_eq!(p.components, [3.0, -4.0]);
1357 }
1358
1359 #[test]
1360 fn raw_point_from_i8_array() {
1361 let p = RawPoint::from([3i8, -4i8]);
1362 assert_eq!(p.components, [3.0, -4.0]);
1363 }
1364
1365 #[test]
1366 fn raw_point_from_pos2() {
1367 let p = RawPoint::from(Pos2::new(7.0, 8.0));
1368 assert_eq!(p.components, [7.0, 8.0]);
1369 }
1370
1371 #[test]
1372 fn raw_point_into_f32_array() {
1373 let arr: [f32; 2] = RawPoint::new(7.0, 8.0).into();
1374 assert_eq!(arr, [7.0, 8.0]);
1375 }
1376
1377 #[test]
1378 fn raw_point_into_pos2() {
1379 let pos: Pos2 = RawPoint::new(7.0, 8.0).into();
1380 assert_eq!(pos, Pos2::new(7.0, 8.0));
1381 }
1382
1383 #[test]
1386 fn raw_line_new() {
1387 let a = RawPoint::new(1.0, 2.0);
1388 let b = RawPoint::new(3.0, 4.0);
1389 let line = RawLine::new(a, b);
1390 assert_eq!(line.points[0].components, [1.0, 2.0]);
1391 assert_eq!(line.points[1].components, [3.0, 4.0]);
1392 }
1393
1394 #[test]
1395 fn raw_line_distance() {
1396 let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(3.0, 4.0));
1398 assert_eq!(line.distance(), 5.0);
1399 }
1400
1401 #[test]
1402 fn raw_line_distance_zero() {
1403 let line = RawLine::new(RawPoint::new(2.0, 2.0), RawPoint::new(2.0, 2.0));
1404 assert_eq!(line.distance(), 0.0);
1405 }
1406
1407 #[test]
1408 fn raw_line_midpoint() {
1409 let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(4.0, 6.0));
1410 let mid = line.midpoint();
1411 assert_eq!(mid.components, [2.0, 3.0]);
1412 }
1413
1414 #[test]
1415 fn raw_line_distance_to_point_on_segment() {
1416 let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(10.0, 0.0));
1417 assert_eq!(line.distance_to_point(RawPoint::new(5.0, 3.0)), 3.0);
1418 assert_eq!(line.distance_to_point(RawPoint::new(5.0, 0.0)), 0.0);
1419 }
1420
1421 #[test]
1422 fn raw_line_distance_to_point_beyond_endpoints() {
1423 let line = RawLine::new(RawPoint::new(0.0, 0.0), RawPoint::new(10.0, 0.0));
1424 assert_eq!(line.distance_to_point(RawPoint::new(14.0, 0.0)), 4.0);
1426 assert_eq!(line.distance_to_point(RawPoint::new(-3.0, -4.0)), 5.0);
1427 }
1428
1429 #[test]
1430 fn raw_line_distance_to_point_degenerate_segment() {
1431 let line = RawLine::new(RawPoint::new(1.0, 1.0), RawPoint::new(1.0, 1.0));
1432 assert_eq!(line.distance_to_point(RawPoint::new(4.0, 5.0)), 5.0);
1433 }
1434
1435 #[test]
1436 fn raw_line_into_pos2_array() {
1437 let line = RawLine::new(RawPoint::new(1.0, 2.0), RawPoint::new(3.0, 4.0));
1438 let arr: [Pos2; 2] = line.into();
1439 assert_eq!(arr, [Pos2::new(1.0, 2.0), Pos2::new(3.0, 4.0)]);
1440 }
1441
1442 #[test]
1443 fn raw_line_from_i64_arrays() {
1444 let line = RawLine::from([[1i64, 2i64], [3i64, 4i64]]);
1445 assert_eq!(line.points[0].components, [1.0, 2.0]);
1446 assert_eq!(line.points[1].components, [3.0, 4.0]);
1447 }
1448
1449 fn full_style() -> MapStyle {
1452 MapStyle {
1453 border: Some(Stroke::new(2.0, Color32::RED)),
1454 line: Some(Stroke::new(4.0, Color32::BLUE)),
1455 fill_color: Color32::GREEN,
1456 text_color: Color32::WHITE,
1457 font: Some(FontId::new(10.0, FontFamily::Proportional)),
1458 background_color: Color32::BLACK,
1459 alert_color: Color32::YELLOW,
1460 }
1461 }
1462
1463 #[test]
1464 fn map_style_new() {
1465 let s = MapStyle::new();
1466 assert!(s.border.is_none());
1467 assert!(s.line.is_none());
1468 assert!(s.font.is_none());
1469 assert_eq!(s.fill_color, Color32::TRANSPARENT);
1470 assert_eq!(s.text_color, Color32::TRANSPARENT);
1471 assert_eq!(s.background_color, Color32::TRANSPARENT);
1472 assert_eq!(s.alert_color, Color32::TRANSPARENT);
1473 }
1474
1475 #[test]
1476 fn map_style_default_equals_new() {
1477 let s = MapStyle::default();
1478 assert!(s.border.is_none());
1479 assert!(s.line.is_none());
1480 assert!(s.font.is_none());
1481 }
1482
1483 #[test]
1484 fn map_style_mul_i64() {
1485 let s = full_style() * 2i64;
1486 assert_eq!(s.border.unwrap().width, 4.0);
1487 assert_eq!(s.line.unwrap().width, 8.0);
1488 assert_eq!(s.font.unwrap().size, 20.0);
1489 }
1490
1491 #[test]
1492 fn map_style_mul_i32() {
1493 let s = full_style() * 2i32;
1494 assert_eq!(s.border.unwrap().width, 4.0);
1495 assert_eq!(s.line.unwrap().width, 8.0);
1496 assert_eq!(s.font.unwrap().size, 20.0);
1497 }
1498
1499 #[test]
1500 fn map_style_mul_f32() {
1501 let s = full_style() * 0.5f32;
1502 assert_eq!(s.border.unwrap().width, 1.0);
1503 assert_eq!(s.line.unwrap().width, 2.0);
1504 assert_eq!(s.font.unwrap().size, 5.0);
1505 }
1506
1507 #[test]
1508 fn map_style_mul_f64() {
1509 let s = full_style() * 0.5f64;
1510 assert_eq!(s.border.unwrap().width, 1.0);
1511 assert_eq!(s.line.unwrap().width, 2.0);
1512 assert_eq!(s.font.unwrap().size, 5.0);
1513 }
1514
1515 #[test]
1516 fn map_style_div_i64() {
1517 let s = full_style() / 2i64;
1518 assert_eq!(s.border.unwrap().width, 1.0);
1519 assert_eq!(s.line.unwrap().width, 2.0);
1520 assert_eq!(s.font.unwrap().size, 5.0);
1521 }
1522
1523 #[test]
1524 fn map_style_div_i32() {
1525 let s = full_style() / 2i32;
1526 assert_eq!(s.border.unwrap().width, 1.0);
1527 assert_eq!(s.line.unwrap().width, 2.0);
1528 assert_eq!(s.font.unwrap().size, 5.0);
1529 }
1530
1531 #[test]
1532 fn map_style_div_f32() {
1533 let s = full_style() / 0.5f32;
1534 assert_eq!(s.border.unwrap().width, 4.0);
1535 assert_eq!(s.line.unwrap().width, 8.0);
1536 assert_eq!(s.font.unwrap().size, 20.0);
1537 }
1538
1539 #[test]
1540 fn map_style_div_f64() {
1541 let s = full_style() / 0.5f64;
1542 assert_eq!(s.border.unwrap().width, 4.0);
1543 assert_eq!(s.line.unwrap().width, 8.0);
1544 assert_eq!(s.font.unwrap().size, 20.0);
1545 }
1546
1547 #[test]
1550 fn map_label_new() {
1551 let l = MapLabel::new();
1552 assert_eq!(l.text, String::new());
1553 assert_eq!(l.center, Pos2::new(0.0, 0.0));
1554 }
1555
1556 #[test]
1557 fn map_label_default_equals_new() {
1558 let l = MapLabel::default();
1559 assert_eq!(l.text, String::new());
1560 assert_eq!(l.center, Pos2::new(0.0, 0.0));
1561 }
1562
1563 #[test]
1566 fn map_point_new() {
1567 let p = MapPoint::new(42, [1.0, 2.0]);
1568 assert_eq!(p.get_id(), 42);
1569 assert_eq!(p.coords, [1.0, 2.0]);
1570 assert!(p.connections.is_empty());
1571 assert_eq!(p.name, None);
1572 assert_eq!(p.get_name(), String::new());
1573 }
1574
1575 #[test]
1576 fn map_point_set_and_get_name() {
1577 let mut p = MapPoint::new(1, [0.0, 0.0]);
1578 p.set_name("Jita".to_string());
1579 assert_eq!(p.name, Some("Jita".to_string()));
1580 assert_eq!(p.get_name(), "Jita");
1581 }
1582
1583 #[test]
1584 fn map_point_from_occupied_entry() {
1585 let mut map: HashMap<usize, MapPoint> = HashMap::new();
1586 let mut original = MapPoint::new(7, [5.0, 6.0]);
1587 original.set_name("Amarr".to_string());
1588 map.insert(7, original);
1589
1590 use std::collections::hash_map::Entry;
1591 if let Entry::Occupied(entry) = map.entry(7) {
1592 let cloned = MapPoint::from(entry);
1593 assert_eq!(cloned.get_id(), 7);
1594 assert_eq!(cloned.get_name(), "Amarr");
1595 assert_eq!(cloned.coords, [5.0, 6.0]);
1596 } else {
1597 panic!("se esperaba una entrada ocupada");
1598 }
1599 }
1600
1601 #[test]
1604 fn map_bounds_new() {
1605 let b = MapBounds::new();
1606 assert_eq!(b.min.components, [0.0, 0.0]);
1607 assert_eq!(b.max.components, [0.0, 0.0]);
1608 assert_eq!(b.pos.components, [0.0, 0.0]);
1609 assert_eq!(b.dist, 0.0);
1610 }
1611
1612 #[test]
1613 fn map_bounds_default_equals_new() {
1614 let b = MapBounds::default();
1615 assert_eq!(b.dist, 0.0);
1616 assert_eq!(b.pos.components, [0.0, 0.0]);
1617 }
1618
1619 #[test]
1622 fn map_settings_new() {
1623 let s = MapSettings::new();
1624 assert_eq!(s.max_zoom, 0.0);
1625 assert_eq!(s.min_zoom, 0.0);
1626 assert_eq!(s.line_visible_zoom, 0.0);
1627 assert_eq!(s.label_visible_zoom, 0.0);
1628 assert_eq!(s.node_text_visibility, VisibilitySetting::Always);
1629 assert_eq!(s.marker_animation, SteadyAnimation::Blink);
1630 assert_eq!(s.node_text_size, 12.0);
1631 assert_eq!(s.label_text_size, 24.0);
1632 assert_eq!(s.styles.len(), 1);
1633 }
1634
1635 #[test]
1636 fn map_settings_default() {
1637 let s = MapSettings::default();
1638 assert_eq!(s.max_zoom, 2.0);
1639 assert_eq!(s.min_zoom, 0.1);
1640 assert_eq!(s.line_visible_zoom, 0.2);
1641 assert_eq!(s.label_visible_zoom, 0.58);
1642 assert_eq!(s.node_text_visibility, VisibilitySetting::Always);
1643 assert_eq!(s.marker_animation, SteadyAnimation::Blink);
1644 assert_eq!(s.node_text_size, 12.0);
1645 assert_eq!(s.label_text_size, 24.0);
1646 assert_eq!(s.styles.len(), 2);
1648 assert_eq!(s.styles[0].background_color, Color32::WHITE);
1650 assert!(s.styles[0].border.is_some());
1651 assert!(s.styles[0].line.is_some());
1652 assert!(s.styles[0].font.is_some());
1653 assert_eq!(s.styles[1].background_color, Color32::DARK_GRAY);
1655 assert!(s.styles[1].border.is_some());
1656 assert!(s.styles[1].line.is_some());
1657 assert!(s.styles[1].font.is_some());
1658 }
1659
1660 #[test]
1663 fn visibility_setting_equality() {
1664 assert_eq!(VisibilitySetting::Hidden, VisibilitySetting::Hidden);
1665 assert_eq!(VisibilitySetting::Hover, VisibilitySetting::Hover);
1666 assert_eq!(VisibilitySetting::Always, VisibilitySetting::Always);
1667 assert_ne!(VisibilitySetting::Hidden, VisibilitySetting::Hover);
1668 assert_ne!(VisibilitySetting::Hover, VisibilitySetting::Always);
1669 assert_ne!(VisibilitySetting::Hidden, VisibilitySetting::Always);
1670 }
1671}