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.

Celx angles.jpg

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.


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:


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:


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

Download the scriptEdit

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")