@@ -17,6 +17,8 @@ import {
1717
1818import { convertEclipticToEquatorial , convertEquatorialToHorizontal } from './coordinates'
1919
20+ import { getLunarEquatorialCoordinate } from './moon'
21+
2022import {
2123 getPlanetaryGeocentricEclipticCoordinate ,
2224 getPlanetaryPositions ,
@@ -393,3 +395,138 @@ export const findPlanetaryConjunctions = (
393395}
394396
395397/*****************************************************************************************************************/
398+
399+ /**
400+ * findConjunctions
401+ *
402+ * Finds all conjunctions of the planets, Spica, Regulus and the Moon within a given time interval,
403+ * returning only those that are inconjunction with each other (as determined by the angular
404+ * separation threshold).
405+ *
406+ * @param interval - The interval to search for the initial conjunction.
407+ * @param observer - The geographic coordinate of the observer.
408+ * @param horizon - The minimum altitude of the planets above the horizon.
409+ * @param angularSeparationThreshold - The minimum angular separation for conjunction.
410+ * @param stepMinutes - The step size in minutes for checking conjunction.
411+ * @returns An array of conjunctions found.
412+ *
413+ */
414+ export const findConjunctions = (
415+ interval : Interval ,
416+ observer : GeographicCoordinate ,
417+ params : {
418+ horizon ?: number // six degrees above the horizon
419+ angularSeparationThreshold ?: number // three degrees of separation
420+ stepMinutes ?: number // check every 1/3 hour
421+ } = {
422+ horizon : 6 ,
423+ angularSeparationThreshold : ANGULAR_SEPARATION_THRESHOLD ,
424+ stepMinutes : 20
425+ }
426+ ) : Map < string , Conjunction > => {
427+ // A conjunction is a close apparent approach of two celestial objects in the sky.
428+ const conjunctions = new Map < string , Conjunction > ( )
429+
430+ /*eslint prefer-const: ["error", {"destructuring": "all"}]*/
431+ let { from, to } = interval
432+
433+ const {
434+ horizon = 6 ,
435+ angularSeparationThreshold = ANGULAR_SEPARATION_THRESHOLD ,
436+ stepMinutes = 20
437+ } = params
438+
439+ // Spica is close to the ecliptic, so we know that we may see it close to a planet:
440+ // We are using the J2000.0 coordinates for Spica, we therefore need to convert them to the current epoch:
441+ const spica = {
442+ ra : 201.298 ,
443+ dec : - 11.1613
444+ }
445+
446+ // Regulus is close to the ecliptic, so we know that we may see it close to a planet:
447+ // We are using the J2000.0 coordinates for Regulus, we therefore need to convert them to the current epoch:
448+ const regulus = {
449+ ra : 152.093 ,
450+ dec : 11.9672
451+ }
452+
453+ while ( from <= to ) {
454+ const moon = getLunarEquatorialCoordinate ( from )
455+
456+ // Collate the positions of all planets other than Earth and those below the horizon in the sky:
457+ // N.B. They may be in conjunction, but they won't be visible to our local observer if they are
458+ // below the horizon.
459+ const positions = [
460+ ...getPlanetaryPositions ( from , observer ) ,
461+ {
462+ name : 'Moon' ,
463+ ...moon ,
464+ ...convertEquatorialToHorizontal ( from , observer , moon )
465+ } ,
466+ {
467+ name : 'Spica' ,
468+ ...spica ,
469+ ...convertEquatorialToHorizontal ( from , observer , spica )
470+ } ,
471+ {
472+ name : 'Regulus' ,
473+ ...regulus ,
474+ ...convertEquatorialToHorizontal ( from , observer , regulus )
475+ }
476+ ]
477+
478+ // Loop over all pairs of planets and check for conjunctions:
479+ for ( let i = 0 ; i < positions . length ; i ++ ) {
480+ for ( let j = i + 1 ; j < positions . length ; j ++ ) {
481+ // If either of the planets is below the horizon, skip this pair:
482+ if ( positions [ i ] . alt < horizon || positions [ j ] . alt < horizon ) continue
483+
484+ // Get the positions of the two planets:
485+ const alterior = positions [ i ]
486+ const ulterior = positions [ j ]
487+
488+ // Create a unique key for the conjunction between the two planets, sorted by name:
489+ const key = [ alterior . name , ulterior . name ] . sort ( ) . join ( '-' )
490+
491+ // Check for a conjunction between the two planets by comparing their angular separation:
492+ const separation = getAngularSeparation (
493+ {
494+ θ : positions [ i ] . alt ,
495+ φ : positions [ i ] . az
496+ } ,
497+ {
498+ θ : positions [ j ] . alt ,
499+ φ : positions [ j ] . az
500+ }
501+ )
502+
503+ // Update the conjunction if the angular separation is less than the threshold,
504+ // and the conjunction is the closest one found so far:
505+ if (
506+ isConjunction ( from , [ alterior , ulterior ] , {
507+ horizon,
508+ angularSeparationThreshold
509+ } ) &&
510+ ( ! conjunctions . has ( key ) || conjunctions . get ( key ) ! . angularSeparation > separation )
511+ ) {
512+ const conjunction : Conjunction = {
513+ datetime : from ,
514+ targets : [ alterior , ulterior ] ,
515+ angularSeparation : separation ,
516+ ra : ( alterior . ra + ulterior . ra ) / 2 ,
517+ dec : ( alterior . dec + ulterior . dec ) / 2
518+ }
519+
520+ conjunctions . set ( key , conjunction )
521+ }
522+ }
523+ }
524+
525+ // Increment the from date by the step size:
526+ from = new Date ( from . getTime ( ) + stepMinutes * 60000 )
527+ }
528+
529+ return conjunctions
530+ }
531+
532+ /*****************************************************************************************************************/
0 commit comments