Skip to main content

leodos_protocols/network/isl/routing/algorithm/
distance_minimizing.rs

1//! Distance Minimizing (Physics Aware) Routing Strategy
2
3use core::f32::consts::PI;
4
5use crate::network::isl::address::Address;
6use crate::network::isl::routing::algorithm::RoutingAlgorithm;
7use crate::network::isl::routing::algorithm::gateway::GatewayTable;
8use crate::network::isl::shell::Shell;
9use crate::network::isl::torus::{Direction, Hop};
10use crate::network::isl::torus::Point;
11
12/// Physics-aware routing that considers orbital mechanics to
13/// minimize ISL distance. Prefers cross-plane hops when the
14/// satellite is near the poles (where planes converge).
15pub struct DistanceMinimizing<const N: usize> {
16    shell: Shell,
17    gateway_table: GatewayTable<N>,
18}
19
20impl<const N: usize> DistanceMinimizing<N> {
21    /// Creates a new distance-minimizing router.
22    pub fn new(
23        shell: Shell,
24        gateway_table: GatewayTable<N>,
25    ) -> Self {
26        Self { shell, gateway_table }
27    }
28
29    /// Relative cross-plane distance factor at a given
30    /// effective anomaly angle.
31    ///
32    /// Minimum at the poles, maximum at the equator.
33    fn cross_plane_factor(&self, anomaly: f32) -> f32 {
34        let cos_theta = libm::cosf(anomaly);
35        let sin_theta = libm::sinf(anomaly);
36        let cos_inc = libm::cosf(self.shell.inclination_rad);
37        libm::sqrtf(
38            cos_theta * cos_theta
39                + cos_inc * cos_inc * sin_theta * sin_theta,
40        )
41    }
42
43    /// Computes the effective anomaly for a satellite at grid
44    /// position `orb`, accounting for orbital motion over time.
45    fn effective_anomaly(
46        &self,
47        orb: u8,
48        time_s: u32,
49    ) -> f32 {
50        let num_orbs = self.shell.torus.num_orbs as f32;
51        let base = 2.0 * PI * (orb as f32) / num_orbs;
52        base + 2.0 * PI * time_s as f32
53            / self.shell.orbital_period_s()
54    }
55
56    fn route_to_point(
57        &self,
58        current: Point,
59        target: Point,
60        time_s: u32,
61    ) -> Direction {
62        let torus = &self.shell.torus;
63
64        if current.orb == target.orb {
65            return torus.direction_to_sat(
66                current, target,
67            );
68        }
69
70        if current.sat == target.sat {
71            return torus.direction_to_orb(
72                current, target,
73            );
74        }
75
76        let v_dir =
77            torus.direction_to_orb(current, target);
78        let toward_orb = match v_dir {
79            Direction::East => torus.next_orb(current),
80            _ => torus.prev_orb(current),
81        };
82
83        let curr_anomaly =
84            self.effective_anomaly(current.orb, time_s);
85        let toward_anomaly =
86            self.effective_anomaly(toward_orb, time_s);
87
88        let curr_factor = self.cross_plane_factor(curr_anomaly);
89        let toward_factor =
90            self.cross_plane_factor(toward_anomaly);
91
92        if toward_factor < curr_factor {
93            v_dir
94        } else {
95            torus.direction_to_sat(current, target)
96        }
97    }
98}
99
100impl<const N: usize> RoutingAlgorithm for DistanceMinimizing<N> {
101    fn route(
102        &self,
103        current: Point,
104        target: Address,
105        time_s: u32,
106    ) -> Hop {
107        let (target_point, local_hop) = match target {
108            Address::Satellite(p) => (p, Hop::Local),
109            Address::Ground { station } => {
110                let gw = self
111                    .gateway_table
112                    .gateway(&self.shell, station, time_s)
113                    .unwrap_or(Point {
114                        orb: 0,
115                        sat: station,
116                    });
117                (gw, Hop::Ground)
118            }
119            Address::ServiceArea { orb } => (
120                Point { orb: current.orb, sat: orb },
121                Hop::Local,
122            ),
123        };
124        if current == target_point {
125            return local_hop;
126        }
127        Hop::Isl(self.route_to_point(current, target_point, time_s))
128    }
129}