1
- import * as Physic from "./physic"
2
1
import * as Newton from "./newton"
3
-
4
- /**
5
- * `OrbitalBody` defines data representing information about an orbiting body of the solar system.
6
- *
7
- * This can be referred to a planet orbiting around a star, or a satellite orbiting a planet.
8
- */
9
- interface OrbitalBody {
10
- mass : number /// The orbital body mass in Kg.
11
- rotation : number /// The rotation period in seconds.
12
- orbit : OrbitalParameters /// The orbital parameters.
13
- axial_tilt ?: number /// Axial tilt for the body rotation wrt the orbital plane.
14
- }
2
+ import { OrbitalBody , orbital_period , secondsToDays , eccentricity } from "./physic" ;
15
3
16
4
/**
17
5
* `SystemParameters` describes the parameters for a planet in star system.
18
6
*
19
7
* It includes the star mass, and the planet and satellites orbital information.
20
8
*/
21
9
interface SystemParameters {
22
- planet : OrbitalBody /// The planet.
23
- star_mass : number /// The orbiting star mass in Kg.
24
- satellites : Array < OrbitalBody > /// A list of satellites.
10
+ readonly planet : OrbitalBody /// The planet.
11
+ readonly satellites : ReadonlyArray < OrbitalBody > /// A list of satellites.
25
12
}
26
13
27
14
/**
28
- * Define the orbital parameters for an orbital body .
15
+ * The output data for the actual calendar .
29
16
*/
30
- interface OrbitalParameters {
31
- periapsis : number /// The celestial body orbit periapsis in meters.
32
- apoapsis : number /// The celestial body orbit apopasis in meters.
33
- inclination ?: number /// The inclination of the orbital plane respect to the system reference plane.
17
+ interface CalendarParameters {
18
+ readonly days_per_year : number /// Number of days in a year.
19
+ readonly moon_day_period : number /// Number of days in a principal moon revolution.
20
+ readonly months_per_year : number /// How many moon revolutions there are in a year.
21
+ readonly base_days_per_month : number /// Number of days in a principal moon revolution (floored). // TODO: This is probably superfluous.
22
+ readonly leap : LeapYearData /// Information about leap days.
34
23
}
35
24
36
25
/**
37
- * The output data for the actual calendar.
26
+ * Store information on the lunar phases of a single moon.
27
+ *
28
+ * All time correspond to the FIRST occurrence from time zero.
29
+ * Values are expressed in seconds.
38
30
*/
39
- interface CalendarParameters {
40
- days_per_year : number /// Number of days in a year.
41
- moon_day_period : number /// Number of days in a principal moon revolution.
42
- months_per_year : number /// How many moon revolutions there are in a year.
43
- base_days_per_month : number /// Number of days in a principal moon revolution (floored). // TODO: This is probably superfluous.
44
- leap : LeapYearData /// Information about leap days.
31
+ export interface LunarPhases {
32
+ readonly full_moon : number
33
+ readonly new_moon : number
34
+ readonly third_quart : number
35
+ readonly first_quart : number
45
36
}
46
37
47
38
/**
@@ -53,25 +44,26 @@ interface LeapYearData { leap_total_days: number, leap_period: number }
53
44
* Output of the calendar generator. // TODO: Probably superfluous.
54
45
*/
55
46
export interface CalendarGeneratorOutput {
56
- calendar_parameters : CalendarParameters
47
+ readonly calendar_parameters : CalendarParameters
57
48
}
58
49
59
50
/**
60
51
* Computed astronomical season-related events.
61
52
*/
62
53
export interface SeasonsParameters {
63
- spring_equinox : number , /// Time in seconds for the first equinox.
64
- summer_solstice : number ,
65
- autumn_equinox : number ,
66
- winter_solstice : number
54
+ readonly spring_equinox : number , /// Time in seconds for the first equinox.
55
+ readonly summer_solstice : number ,
56
+ readonly autumn_equinox : number ,
57
+ readonly winter_solstice : number
67
58
}
68
59
69
60
/**
70
61
* Encapsulate the global generator output.
71
62
*/
72
63
export interface GeneratorOutput {
73
- calendar : CalendarGeneratorOutput ,
74
- seasons : SeasonsParameters
64
+ readonly calendar : CalendarGeneratorOutput ,
65
+ readonly seasons : SeasonsParameters ,
66
+ readonly lunar_phases : LunarPhases
75
67
}
76
68
77
69
/**
@@ -80,31 +72,25 @@ export interface GeneratorOutput {
80
72
* @returns An instance of a generated calendar for the planet.
81
73
*/
82
74
export function generateCalendarFromOrbit ( system_data : SystemParameters ) : GeneratorOutput {
83
- const planet_apoapsis = system_data . planet . orbit . apoapsis ;
84
- const planet_periapsis = system_data . planet . orbit . periapsis ;
85
- const planet_axis_major = ( planet_apoapsis + planet_periapsis ) / 2 ;
86
- const planet_mass = system_data . planet . mass ;
87
75
const planet_day_duration = system_data . planet . rotation ;
88
- const eccentricity = ( planet_apoapsis - planet_periapsis ) / ( planet_apoapsis + planet_periapsis ) ;
89
76
90
77
// Compute planet orbital period.
91
- let planet_year = Physic . orbital_period ( system_data . star_mass , planet_axis_major , planet_mass ) ;
78
+ let planet_year = orbital_period ( system_data . planet ) ;
92
79
93
80
let moon_periods : Array < number > = [ ] ;
94
81
// Compute moon periods.
95
82
for ( let moon of system_data . satellites ) {
96
- let moon_axis_major = ( moon . orbit . periapsis + moon . orbit . apoapsis ) / 2 ;
97
- moon_periods . push ( Physic . orbital_period ( planet_mass , moon_axis_major , moon . mass ) ) ;
83
+ moon_periods . push ( orbital_period ( moon ) ) ;
98
84
}
99
85
100
- const seasons = computeSeasons ( 0 , 6 , 4 , eccentricity , planet_year ) ;
86
+ const seasons = compute_seasons ( system_data . planet , 6 , 4 ) ;
101
87
const calendar = generateCalendarFromPeriod ( planet_year , moon_periods , planet_day_duration ) ;
102
- //instantiateCalendar(calendar, 7, seasons );
103
- return { calendar, seasons } ;
88
+ const lunar_phases = computeLunarPhases ( system_data . planet , system_data . satellites [ 0 ] , calendar ) ;
89
+ return { calendar, seasons, lunar_phases } ;
104
90
}
105
91
106
92
function generateCalendarFromPeriod ( planet_period : number , moon_periods : Array < number > , planet_day_duration : number = 86400 ) : CalendarGeneratorOutput {
107
- let year_days_full = Physic . secondsToDays ( planet_period , planet_day_duration ) ;
93
+ let year_days_full = secondsToDays ( planet_period , planet_day_duration ) ;
108
94
let year_days = Math . floor ( year_days_full ) ;
109
95
110
96
// Compute Leap Years.
@@ -121,10 +107,10 @@ function generateCalendarFromPeriod(planet_period: number, moon_periods: Array<n
121
107
122
108
if ( moon_periods . length > 0 ) {
123
109
// TODO: For now, there is only one moon. In the future we may support multiple moons.
124
- let moon_day_period = Physic . secondsToDays ( moon_periods [ 0 ] , planet_day_duration ) ;
125
- let month_days = Math . floor ( Physic . secondsToDays ( moon_periods [ 0 ] , planet_day_duration ) ) ;
110
+ let moon_day_period = secondsToDays ( moon_periods [ 0 ] , planet_day_duration ) ;
111
+ let month_days = Math . floor ( secondsToDays ( moon_periods [ 0 ] , planet_day_duration ) ) ;
126
112
let lunar_months = Math . floor ( year_days / month_days ) ;
127
- let days_remainder = year_days - lunar_months * month_days ;
113
+ // let days_remainder = year_days - lunar_months * month_days;
128
114
129
115
output_parameters = {
130
116
days_per_year : year_days ,
@@ -204,20 +190,54 @@ function thirdOrderConvergent(cf: Array<number>): [number, number] {
204
190
}
205
191
206
192
// SEASONS
207
-
208
- export function computeSeasons ( axial_tilt : number , A : number , B : number , eccentricity : number , period : number ) : SeasonsParameters {
193
+ export function compute_seasons ( body : OrbitalBody , A : number , B : number ) : SeasonsParameters {
194
+ const e = eccentricity ( body . orbit ) ;
195
+ const period = orbital_period ( body ) ;
209
196
let E = Newton . NewtonRoot (
210
- ( x ) => ( B * ( Math . cos ( x ) - eccentricity ) - A * ( Math . sqrt ( 1 - eccentricity * eccentricity ) * Math . sin ( x ) ) ) ,
211
- ( x ) => - ( B * Math . sin ( x ) + A * ( Math . sqrt ( 1 - eccentricity * eccentricity ) ) * Math . cos ( x ) ) ,
197
+ ( x ) => ( B * ( Math . cos ( x ) - e ) - A * ( Math . sqrt ( 1 - e * e ) * Math . sin ( x ) ) ) ,
198
+ ( x ) => - ( B * Math . sin ( x ) + A * ( Math . sqrt ( 1 - e * e ) ) * Math . cos ( x ) ) ,
212
199
1 , 0.01 ) ;
213
200
let E2 = E + Math . PI / 2 ;
214
201
let E3 = E + Math . PI ;
215
202
let E4 = E + ( 3 / 2 ) * Math . PI ;
216
203
return {
217
- spring_equinox : ( period / ( 2 * Math . PI ) ) * ( E - eccentricity * Math . sin ( E ) ) ,
218
- summer_solstice : ( period / ( 2 * Math . PI ) ) * ( E2 - eccentricity * Math . sin ( E2 ) ) ,
219
- autumn_equinox : ( period / ( 2 * Math . PI ) ) * ( E3 - eccentricity * Math . sin ( E3 ) ) ,
220
- winter_solstice : ( period / ( 2 * Math . PI ) ) * ( E4 - eccentricity * Math . sin ( E4 ) )
204
+ spring_equinox : ( period / ( 2 * Math . PI ) ) * ( E - e * Math . sin ( E ) ) ,
205
+ summer_solstice : ( period / ( 2 * Math . PI ) ) * ( E2 - e * Math . sin ( E2 ) ) ,
206
+ autumn_equinox : ( period / ( 2 * Math . PI ) ) * ( E3 - e * Math . sin ( E3 ) ) ,
207
+ winter_solstice : ( period / ( 2 * Math . PI ) ) * ( E4 - e * Math . sin ( E4 ) )
221
208
} ;
222
209
210
+ }
211
+
212
+ // LUNAR PHASES
213
+ export function computeLunarPhases ( planet : OrbitalBody , moon : OrbitalBody , calendar : CalendarGeneratorOutput ) : LunarPhases {
214
+ const moon_period = calendar . calendar_parameters . moon_day_period ;
215
+ // Compute first full moon.
216
+ // Full moons occurs when the moon is aligned with the SUN-PLANET axis.
217
+ // This is equivalent of saying that the full moon occurs when the true anomaly of the moon orbit is 0.
218
+ // FM = kP (where P is the orbital period and k is an integer)
219
+ const full_moon_time = 0 ;
220
+ // Compute first new moon.
221
+ // This occurs when the moon is in opposition to the SUN-PLANET axis.
222
+ // This is equivalent of saying that the new moon occurs when the true anomaly of the moon orbit is PI.
223
+ // NM = P/2 + kP
224
+ // (Note that Mean Anomaly, Eccentric Anomaly and True Anomaly are equivalent on 0 and PI)
225
+ const new_moon_time = Math . floor ( moon_period / 2 ) ;
226
+ // Compute the third quart.
227
+ // this occur when MOON-PLANET axis is perpendicular to the SUN-PLANET orbit.
228
+ // This is equivalent of saying that the third quarter occurs when the true anomaly of the moon orbit is PI/2.
229
+ // In this case MA, EA, and TA **do not match**. The formula is more complex.
230
+ const moon_apoapsis = moon . orbit . apoapsis ;
231
+ const moon_periapsis = moon . orbit . periapsis ;
232
+ const e = ( moon_apoapsis - moon_periapsis ) / ( moon_apoapsis + moon_periapsis ) ;
233
+ const gamma = Math . sqrt ( ( 1 + e ) / ( 1 - e ) ) ;
234
+ const third_quart_time = Math . floor ( moon_period * ( 1 / Math . PI ) * Math . atan ( 1 / gamma ) - e * ( ( 2 * gamma ) / ( gamma * gamma ) + 1 ) ) ;
235
+ // Compute the first quart.
236
+ // this occur when MOON-PLANET axis is anti-perpendicular to the SUN-PLANET orbit.
237
+ // This is equivalent of saying that the third quarter occurs when the true anomaly of the moon orbit is -PI/2.
238
+ // In this case MA, EA, and TA **do not match**. The formula is more complex.
239
+ const first_quart_time = Math . floor ( - third_quart_time + moon_period ) ; // TODO: Check this.
240
+
241
+ return { full_moon : full_moon_time , new_moon : new_moon_time , first_quart : first_quart_time , third_quart : third_quart_time } ;
242
+
223
243
}
0 commit comments