1#![allow(non_snake_case)]
2
3#[cfg(test)]
4mod tests;
5
6mod newton;
7use newton::LambertError;
8
9const Z_SERIES_THRESHOLD: f64 = 1.0e-3;
10
11const fn factorial(num: u64) -> u64 {
12 match num {
13 0 => 1,
14 1.. => num * factorial(num-1),
15 }
16}
17fn dot(v1: [f64; 3], v2: [f64; 3]) -> f64 {
18 v1[0]*v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
19}
20
21pub fn get_velocities(r1: [f64; 3], r2: [f64; 3], tof: f64, mu: f64, short: bool,
54 eps: f64, max_iter: usize) -> Result<([f64; 3], [f64; 3]), LambertError> {
55 let r1_mag = dot(r1, r1).sqrt();
56 let r2_mag = dot(r2, r2).sqrt();
57 let A = f64::sqrt(r1_mag * r2_mag + dot(r1, r2)) * (if short {1.0} else {-1.0});
58
59 let best_z = newton::find_root(|z| -> f64 {
60 let S = get_S(z);
61 let C = get_C(z);
62 let y = r1_mag + r2_mag - A * (1.0 - z * S) / C.sqrt(); let x = f64::sqrt(y / C); let t = (x * x * x * S + A * y.sqrt()) / mu.sqrt();t / tof - 1.0
66 }, |z| -> f64 {
67 let S = get_S(z);
68 let dS_dz = get_dS_dz(z);
69 let C = get_C(z);
70 let dC_dz = get_dC_dz(z);
71 let y = r1_mag + r2_mag - A * (1.0 - z * S) / C.sqrt();
72 let x = f64::sqrt(y / C);
73 (x * x * x * (dS_dz - 3.0 * S * dC_dz / (2.0 * C))
74 + A / 8.0 * (3.0 * S * y.sqrt() / C + A / x)) / mu.sqrt() / tof
75 }, eps, max_iter)?;
76
77 let S = get_S(best_z);
78 let C = get_C(best_z);
79 let y = r1_mag + r2_mag - A * (1.0 - best_z * S) / C.sqrt();
80 let f = 1.0 - y / r1_mag; let g = A * f64::sqrt(y / mu); let g_dot = 1.0 - y / r2_mag; let v1 = [
85 (r2[0] - f * r1[0]) / g,
86 (r2[1] - f * r1[1]) / g,
87 (r2[2] - f * r1[2]) / g,
88 ]; let v2 = [
90 (g_dot * r2[0] - r1[0]) / g,
91 (g_dot * r2[1] - r1[1]) / g,
92 (g_dot * r2[2] - r1[2]) / g,
93 ]; Ok((v1, v2))
96}
97
98fn get_S(z: f64) -> f64 { if z.abs() < Z_SERIES_THRESHOLD {
101 1.0 / factorial(3) as f64
102 - z / factorial(5) as f64
103 + z * z / factorial(7) as f64
104 - z * z * z / factorial(9) as f64
105 + z * z * z * z / factorial(11) as f64
106 } else {
107 if z > 0.0 {
108 let z_sqrt = z.sqrt();
109 (z_sqrt - z_sqrt.sin()) / (z * z_sqrt)
110 } else {
111 let z_sqrt = (-z).sqrt();
112 (z_sqrt.sinh() - z_sqrt) / (-z * z_sqrt)
113 }
114 }
115}
116
117fn get_C(z: f64) -> f64 { if z.abs() < Z_SERIES_THRESHOLD {
120 1.0 / factorial(2) as f64
121 - z / factorial(4) as f64
122 + z * z / factorial(6) as f64
123 - z * z * z / factorial(8) as f64
124 + z * z * z * z / factorial(10) as f64
125 } else {
126 if z > 0.0 {
127 (1.0 - z.sqrt().cos()) / z
128 } else {
129 (1.0 - (-z).sqrt().cosh()) / z
130 }
131 }
132}
133
134fn get_dS_dz(z: f64) -> f64 { if z.abs() < Z_SERIES_THRESHOLD {
137 - 1.0 / factorial(5) as f64
138 + 2.0 * z / factorial(7) as f64
139 - 3.0 * z * z / factorial(9) as f64
140 + 4.0 * z * z * z / factorial(11) as f64
141 - 5.0 * z * z * z * z / factorial(13) as f64
142 } else {
143 if z > 0.0 {
144 let sqrt_z = z.sqrt();
145 - 0.5 / (z * z) * (2.0 + sqrt_z.cos()
146 - 3.0 * sqrt_z.sin() / sqrt_z)
147 } else {
148 let sqrt_z = (-z).sqrt();
149 - 0.5 / (z * z) * (2.0 + sqrt_z.cosh()
150 - 3.0 * sqrt_z.sinh() / sqrt_z)
151 }
152 }
153}
154
155fn get_dC_dz(z: f64) -> f64 { if z.abs() < Z_SERIES_THRESHOLD {
158 - 1.0 / factorial(4) as f64
159 + 2.0 * z / factorial(6) as f64
160 - 3.0 * z * z / factorial(8) as f64
161 + 4.0 * z * z * z / factorial(10) as f64
162 - 5.0 * z * z * z * z / factorial(10) as f64
163 } else {
164 if z > 0.0 {
165 let sqrt_z = z.sqrt();
166 - 0.5 / (z * z) * (2.0 - 2.0 * sqrt_z.cos()
167 - sqrt_z.sin() * sqrt_z)
168 } else {
169 let sqrt_z = (-z).sqrt();
170 - 0.5 / (z * z) * (2.0 - 2.0 * sqrt_z.cosh()
171 + sqrt_z.sinh() * sqrt_z)
172 }
173 }
174}