Find next nearest separation script

This Stellarium script will find the next time two celestial objects are closest together. It is useful for finding when two planets conjunct or when a planet is close to a celestial object. If two planets are selected, and one of them starts retrograding before their conjunction, that will be the point of closest separation.

// ******************************************************************************************
// Stellarium script to find the next nearest time two objects are closest to each other.
// The time can be in the past or future, depending on whether they are initially moving
// away from each other.
//
// Created by David O'Neil, Aug, 2019. Released to the public domain, for anyone interested.
// Just leave this 'created by' (or 'originally created by') verbage in the derived work.
//
// To use:
//   * Set the 'obj1' and 'obj2' variables to whatever you want.
//   * Set the date via Stellarium's user interface close to a time you are looking for them
//     to come together.
//     (The date must be 1/2 year or so of a conjunction, to overcome the difficulty of
//     taking retrograde motions into account.)
//   * Run the script. It will find the next point of nearness that is closest to that date,
//     whether that is in the future or the past.
// ******************************************************************************************

pi = Math.PI;
degToRad = pi/180;

obj1 = "Jupiter";
obj2 = "Saturn";

core.selectObjectByName(obj1, true);
StelMovementMgr.setFlagTracking(true);

justFindSeparation = false;
if (justFindSeparation) {
   d = getRadiansBetweenObjects();
   d = d/degToRad;
   core.debug(d);
   degrees = Math.floor(d);
   minutes = d - degrees;
   minutes = minutes * 60;
   seconds = minutes - Math.floor(minutes);
   core.debug(degrees + " " + Math.floor(minutes) + " " + seconds*60);
   }
else findClosestConjunction();
core.debug(d / degToRad);


function findClosestConjunction() {
   core.selectObjectByName("obj1", true);
   core.setTimeRate(0); //Lock the sky in place, so we can see it unmoving!

   //Get the initial 2 points:
   a1 = getRadiansBetweenObjects();

   //Do initial iteration in 1-day increment:
   a2 = getTheAngleAfter("+1 days");

   direction = "+";
   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 days");
      a2 = getTheAngleAfter("-1 days");   //Don't know why can't use "-2 days" reliably!
      }
      
   timeStepString = direction + "1 days";

   //Iterate:
   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }
      
   //Assume we've gone through several days, and have passed the last good one,
   //so step back (or forward) a day to fix the overstep:
   if (direction == "+") {
      a1 = getTheAngleAfter("-1 days");
      }
   else {
      a1 = getTheAngleAfter("+1 days");
      }
      
      
   //Now we are doing it by the hours. As before, we must check whether we need to
   //go back or forward.

   //Now determine whether to go forward or back:
   a2 = getTheAngleAfter("+1 hour");

   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 hours");
      a2 = getTheAngleAfter("-1 hours");  //As before, don't know why can't just -2 this.
      }

   timeStepString = direction + "1 hour";

   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }

   //Assume we've gone through several hours, and have passed the last good one,
   //so step back (or forward) an hour to fix the overstep:
   if (direction == "+") {
      a1 = getTheAngleAfter("-1 hours");
      }
   else {
      a1 = getTheAngleAfter("+1 hours");
      }
      

   //And finally, for the minutes:
   //First, set a1 to a2, as a2 was last measurement taken at current time:
   a1 = a2;
   a2 = getTheAngleAfter("+1 minute");

   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 minutes");
      a2 = getTheAngleAfter("-1 minutes");
      }

   timeStepString = direction + "1 minute";

   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }
      
   core.debug("Finished! Separation = " + a1 + ", " + a2);

   core.setTimeRate(0); //Lock the sky in place, so we can see it unmoving!
   }


function getTheAngleAfter(timeStep) {
   obj2Azi = core.getObjectInfo(obj2).azimuth;
   core.setDate(timeStep);
   //The following was an attempt to leave the wait time at 0.01, and loop wait until
   //Stellarium got things caught up, but it never worked, and I had to change the
   //wait time to 0.05 many times, instead of 0.03.
   while (core.getObjectInfo(obj2).azimuth == obj2Azi) {
      core.wait(0.01);
      }
   angleDiff = getRadiansBetweenObjects();
   return angleDiff;
   }


function getRadiansBetweenObjects() {
   obj2Azi = core.getObjectInfo(obj2).elong;
   obj2Azi = obj2Azi * degToRad;
   obj2Alt = core.getObjectInfo(obj2).elat;
   obj2Alt = obj2Alt * degToRad;

   obj1Azi = core.getObjectInfo(obj1).elong;
   obj1Azi = obj1Azi * degToRad;
   obj1Alt = core.getObjectInfo(obj1).elat;
   obj1Alt = obj1Alt * degToRad;


   d = Math.acos(Math.sin(obj2Alt)*Math.sin(obj1Alt)+Math.cos(obj2Alt)*Math.cos(obj1Alt)*Math.cos(obj2Azi-obj1Azi));
   
   //The following formula is for when the objects are very close together, or very close to 180 degrees apart:
   //I may have Azi and Alt mixed up.
   
   // delAzi = obj1Azi - obj2Azi;
   // delAlt = obj1Alt - obj2Alt;

   //d = sqrt ( (cos(aziA-aziB) * (altA-altB)) ^2 + (aziA-aziB)^2 )
   //d = Math.sqrt ( Math.cos(delAzi)*(delAlt) * Math.cos(delAzi)*(delAlt) + (delAzi)*(delAzi) );
   
   return d;   //In radians
   }

Leave a Reply

Your email address will not be published. Required fields are marked *