111 lines
4.7 KiB
Plaintext
111 lines
4.7 KiB
Plaintext
@lazyglobal off.
|
|
|
|
global moonmath is lex(
|
|
"calculate_launch", calculate_launch@,
|
|
"position", moon_position_at_time@
|
|
).
|
|
|
|
local function calculate_launch {
|
|
parameter target_inclination, azimuth, target_alt.
|
|
|
|
|
|
local time_fudge is 0.
|
|
|
|
local wait_time is 0.
|
|
local orbit_time is 0.
|
|
local burn_ra is 0.
|
|
local tt is hohmann_transfer_time(earth, target_alt, moon:obt:semimajoraxis).
|
|
print "Initial moon distance: " + moon:obt:semimajoraxis.
|
|
print "Initial travel time: " + tt.
|
|
local moon_vec is moon_position_at_time(time:seconds + tt + time_fudge).
|
|
local iterations is 0.
|
|
until iterations > 10 {
|
|
local next_tt is hohmann_transfer_time(earth, target_alt, moon_vec:mag - earth:radius).
|
|
print "Updated moon distance: " + (moon_vec:mag - earth:radius).
|
|
print "Updated travel time: " + next_tt.
|
|
local next_moon_vec is moon_position_at_time(time:seconds + next_tt + wait_time + orbit_time+time_fudge).
|
|
local err is abs((next_moon_vec - moon_vec):mag).
|
|
print "Position Error " + iterations + ": " + err.
|
|
set moon_vec to next_moon_vec.
|
|
set tt to next_tt.
|
|
set iterations to iterations + 1.
|
|
|
|
local rm is moon_vec:normalized.
|
|
local rt is(-1) * rm.
|
|
|
|
set burn_ra to mod(arctan2(rt:y,rt:x) + 360, 360).
|
|
|
|
|
|
// `w` is the unit vector normal to the launch orbital plane
|
|
local w_z is cos(target_inclination).
|
|
local w_y_1 is (0 - w_z*rm:y*rm:z + rm:x*sqrt(1 - rm:z*rm:z - w_z*w_z)) / (rm:x*rm:x + rm:y*rm:y).
|
|
local w_y_2 is (0 - w_z*rm:y*rm:z - rm:x*sqrt(1 - rm:z*rm:z - w_z*w_z)) / (rm:x*rm:x + rm:y*rm:y).
|
|
local w_x_1 is (0 - w_y_1*rm:y - w_z*rm:z)/rm:x.
|
|
local w_x_2 is (0 - w_y_2*rm:y - w_z*rm:z)/rm:x.
|
|
|
|
|
|
local launch_ra_1_cos is (w_z*w_x_1*sin(ship:latitude) + w_y_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
|
|
local launch_ra_2_cos is (w_z*w_x_2*sin(ship:latitude) + w_y_2*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
|
|
local launch_ra_1_sin is (w_z*w_y_1*sin(ship:latitude) - w_x_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
|
|
local launch_ra_2_sin is (w_z*w_y_2*sin(ship:latitude) - w_x_1*cos(ship:latitude)*cos(azimuth)) / (w_z*w_z-1)*cos(ship:latitude).
|
|
|
|
local launch_right_ascension_1 is arctan2(launch_ra_1_sin, launch_ra_1_cos).
|
|
local launch_right_ascension_2 is arctan2(launch_ra_2_sin, launch_ra_2_cos).
|
|
|
|
local current_right_ascension is earth:rotationangle + ship:longitude.
|
|
local wait_angle_1 is mod(360 + launch_right_ascension_1 - current_right_ascension, 360).
|
|
local wait_angle_2 is mod(360 + launch_right_ascension_2 - current_right_ascension, 360).
|
|
print "Need to rotate " + wait_angle_1 + " or " + wait_angle_2 + " degrees.".
|
|
local wait_angle is min(wait_angle_1, wait_angle_2).
|
|
print "Choosing " + wait_angle.
|
|
set wait_time to body:rotationperiod * wait_angle / 360.
|
|
print "That will take " + wait_time + " seconds.".
|
|
|
|
local launch_ra is wait_angle + earth:rotationangle + ship:longitude.
|
|
local orbit_angle is mod(burn_ra - launch_ra + 360, 360).
|
|
local orbit_frac is orbit_angle / 360.
|
|
set orbit_time to orbit_frac * 90 * 60.
|
|
|
|
if err < (moon:radius / 100) {
|
|
break.
|
|
}
|
|
}
|
|
|
|
return lex(
|
|
"launch_time", time:seconds + wait_time,
|
|
"moon_altitude", moon_vec:mag - earth:radius,
|
|
"burn_longitude", burn_ra
|
|
).
|
|
}
|
|
|
|
local function moon_position_at_time {
|
|
parameter t.
|
|
return position_at_time(moon, t).
|
|
}
|
|
|
|
global function position_at_time {
|
|
parameter bod, t.
|
|
local bod_orbit is bod:obt.
|
|
local delta_t is t - bod_orbit:epoch.
|
|
local revolutions is delta_t / bod_orbit:period.
|
|
local mean_anomaly is mod(revolutions * 360 + bod_orbit:meananomalyatepoch, 360).
|
|
local e is bod_orbit:eccentricity.
|
|
local e2 is e*e.
|
|
local e3 is e2*e.
|
|
local true_anomaly is mean_anomaly + (2*e - e3/4)*sin(mean_anomaly) + 5/4*e2*sin(2*mean_anomaly)+13/12*e3*sin(3*mean_anomaly).
|
|
local radius is bod_orbit:semimajoraxis * (1 - e2) / (1 + e*cos(true_anomaly)).
|
|
|
|
local sin_lan is sin(bod_orbit:longitudeofascendingnode).
|
|
local cos_lan is cos(bod_orbit:longitudeofascendingnode).
|
|
local sin_inc is sin(bod_orbit:inclination).
|
|
local cos_inc is cos(bod_orbit:inclination).
|
|
local sin_anom is sin(bod_orbit:argumentofperiapsis + true_anomaly).
|
|
local cos_anom is cos(bod_orbit:argumentofperiapsis + true_anomaly).
|
|
|
|
local x is radius * (cos_lan*cos_anom - sin_lan*sin_anom*cos_inc).
|
|
local y is radius * (sin_lan*cos_anom + cos_lan*sin_anom*cos_inc).
|
|
local z is radius * sin_inc * sin_anom.
|
|
|
|
return V(x, y, z).
|
|
}
|