1use rstar::{AABB, PointDistance, RTreeObject};
2
3pub use nms_core::system::SystemId;
5
6#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct SystemPoint {
9 pub id: SystemId,
10 pub point: [f64; 3],
11}
12
13impl SystemPoint {
14 pub fn new(id: SystemId, x: f64, y: f64, z: f64) -> Self {
15 Self {
16 id,
17 point: [x, y, z],
18 }
19 }
20
21 pub fn from_address(addr: &nms_core::address::GalacticAddress) -> Self {
23 let id = SystemId::from_address(addr);
24 Self::new(
25 id,
26 addr.voxel_x() as f64,
27 addr.voxel_y() as f64,
28 addr.voxel_z() as f64,
29 )
30 }
31}
32
33impl RTreeObject for SystemPoint {
34 type Envelope = AABB<[f64; 3]>;
35
36 fn envelope(&self) -> Self::Envelope {
37 AABB::from_point(self.point)
38 }
39}
40
41impl PointDistance for SystemPoint {
42 fn distance_2(&self, point: &[f64; 3]) -> f64 {
43 let dx = self.point[0] - point[0];
44 let dy = self.point[1] - point[1];
45 let dz = self.point[2] - point[2];
46 dx * dx + dy * dy + dz * dz
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use nms_core::address::GalacticAddress;
54
55 #[test]
56 fn test_system_id_from_address_zeroes_planet() {
57 let addr1 = GalacticAddress::new(100, 50, 200, 0x123, 0, 0);
58 let addr2 = GalacticAddress::new(100, 50, 200, 0x123, 5, 0);
59 assert_eq!(
60 SystemId::from_address(&addr1),
61 SystemId::from_address(&addr2)
62 );
63 }
64
65 #[test]
66 fn test_system_id_different_ssi_differs() {
67 let addr1 = GalacticAddress::new(100, 50, 200, 0x123, 0, 0);
68 let addr2 = GalacticAddress::new(100, 50, 200, 0x456, 0, 0);
69 assert_ne!(
70 SystemId::from_address(&addr1),
71 SystemId::from_address(&addr2)
72 );
73 }
74
75 #[test]
76 fn test_system_point_from_address_coordinates() {
77 let addr = GalacticAddress::new(100, -50, 200, 0x123, 3, 0);
78 let point = SystemPoint::from_address(&addr);
79 assert_eq!(point.point, [100.0, -50.0, 200.0]);
80 }
81
82 #[test]
83 fn test_system_point_distance_squared() {
84 use rstar::PointDistance;
85 let p = SystemPoint::new(SystemId(0), 0.0, 0.0, 0.0);
86 let target = [3.0, 4.0, 0.0];
87 assert!((p.distance_2(&target) - 25.0).abs() < 1e-10);
88 }
89
90 #[test]
91 fn test_rtree_nearest_neighbor() {
92 use rstar::RTree;
93 let points = vec![
94 SystemPoint::new(SystemId(1), 0.0, 0.0, 0.0),
95 SystemPoint::new(SystemId(2), 10.0, 0.0, 0.0),
96 SystemPoint::new(SystemId(3), 100.0, 0.0, 0.0),
97 ];
98 let tree = RTree::bulk_load(points);
99 let nearest = tree.nearest_neighbor(&[1.0, 0.0, 0.0]).unwrap();
100 assert_eq!(nearest.id, SystemId(1));
101 }
102
103 #[test]
104 fn test_rtree_bulk_load_size() {
105 use rstar::RTree;
106 let points = vec![
107 SystemPoint::new(SystemId(1), 0.0, 0.0, 0.0),
108 SystemPoint::new(SystemId(2), 5.0, 5.0, 5.0),
109 ];
110 let tree = RTree::bulk_load(points);
111 assert_eq!(tree.size(), 2);
112 }
113
114 #[test]
115 fn test_system_point_envelope() {
116 use rstar::RTreeObject;
117 let p = SystemPoint::new(SystemId(1), 3.0, 4.0, 5.0);
118 let env = p.envelope();
119 assert_eq!(env.lower(), [3.0, 4.0, 5.0]);
120 assert_eq!(env.upper(), [3.0, 4.0, 5.0]);
121 }
122}