Celestia/Celx Scripting/Q&A/Angles

Finding the angles between two objects is a handy thing to be able to do in a script. It would mostly be useful for finding angular separations and phase angles (illustrated below) which can be used for a variety of other purposes.



The angular separation between two objects seen is a measure of how far apart they are in the sky as seen by the observer.

The phase angle is usually described for non-emissive objects orbiting stars (e.g. planets, asteroids, comets, moons, etc.) and is the angle of illumination of the object seen by an observer. It is the angle between the Star-Target line and the Target-Observer line. Using the image as an example, a phase angle of 0 degrees means that the observer is directly between the star and the planet - thus, the star is behind the observer, and the planet would appear "Full" to the viewer. A phase angle of 90 or 270 degrees means that the observer is over the terminator of the planet (the line dividing day and night), so he would see a 'Half-Full" planet. A phase angle of 180 degrees means that the planet is directly between the observer and the star, so the observer is in the planet's shadow and would see a "New" planet. At intermediate phase angles the observer would see a crescent or gibbous planet.

Theory
Celestia stores the positions of objects as a table consisting of an x-coordinate, y-coordinate, and z-coordinate. The line connecting two points is known as a vector, so basically we're finding the angle between two vectors. First we have to calculate each of the vectors. To do this we find the positions of the objects at either end of the line, and then simply subtract one from the other. So in order to calculate a Phase Angle, the vector of the Star-Planet line is (position of the planet - position of the star), and the vector of the Observer-Planet line is (position of the planet - position of the observer).

Once we have these vectors, we need to use a special mathematical function used for vectors called the Dot Product. This is reproduced below:


 * $$ \mathbf{a} \cdot \mathbf{b} = a \, b \cos \theta \;$$

We'd refer to this as "a dot b", where a and b are the vectors involved. The ab on the right-hand-side of the equation are the lengths of the two vectors multiplied together, and the angle theta is the angle between the two vectors. In this case, Celestia already knows what the vectors are (and how long they are and what the angle is between them) and so can calculate the dot product - we just need to extract the information we want in a script. We can also normalise the vectors so that the lengths equal 1 - this makes the calculation a little simpler (and conveniently enough there's a 'normalize' script command that does this). This reduces the equation we need in the script to:


 * $$ \theta = \arccos (\mathbf{a} \cdot \mathbf{b}) \;$$

The script below illustrates how to perform this calculation in Celx.

Download the script
This is a complete script that you can run as-is to display the phase angle to a target in the solar system. The target must already be selected before the script is run.

camera = celestia:getobserver			-- set camera object target = celestia:getselection	 		-- set target object sunpos = celestia:find("Sol"):getposition		-- find sun position campos = camera:getposition				-- find camera position planpos = target:getposition				-- find target position sun_target_vector = planpos - sunpos			-- determine sun-target vector obs_target_vector = planpos - campos			-- determine observer-target vector phase_angle = math.acos(sun_target_vector:normalize * obs_target_vector:normalize)	-- find phase angle (in radians) celestia:flash("Phase angle to target is "..string.format("%.2f", math.deg(phase_angle)).." degrees\n") wait(2)