@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). }