10
$\begingroup$

Given that that n% of the moon is illuminated. I want to (approximately, but more or less correctly) draw the the terminator line on the circle (that represents the moon). Orientation is not the case here, just the crescent shape.

What is the best/correct way to determine/calculate/approximate the shape of the terminator line? Is this line actually a chord of a circle, or it is something different?

$\endgroup$
1
  • 1
    $\begingroup$ Pedantry: 50% of the moon is illuminated, except during lunar eclipse; we just can't see all of it. I'll get me coat... $\endgroup$ Jan 26 at 7:12

3 Answers 3

16
$\begingroup$

The line is a semi-ellipse. It is formed by projecting the great circle on the moon formed by the terminator to the plane perpendicular to a line going from the observer to the moon. Projecting a circle to a plane results in an ellipse.

These pictures show simulations of a "thin crescent" or "nearly full gibbous" and "near half moon" (depending on which part you consider to be lit).

enter image description here enter image description here

$\endgroup$
1
11
$\begingroup$

Edit: created a new Codepen that shows the terminator as a gradient, which eliminates the hard line.

enter image description here

Rigorous:

For those not wanting to settle for an approximation, rendering a photorealistic, properly shaded (with mountains and craters having shadows) image is pretty easy with existing tools like Blender, and NASA's CGI Moon Kit. Since that's a solved problem, and this question is specifically looking for an approximation, I'll focus on that. But an example using ThreeJS is here, and a tutorial using Blender is here.

Approximate:

An approximate method is to imagine a plane intersecting the center of the Moon, perpendicular to the direction of the Sun. As the phase changes, the plane is rotated about the Y axis. To keep things simple, we can ignore any perspective distortion (e.g. ignore the Z coordinate), the Y coordinate won't change, leaving only the X coordinate to be computed, and the rotation matrix simplifies to:

$$ x= radius * \cos(phase) $$

Where $phase$ is the phase from 0° (new moon) to 360°, and $radius$ is the radius of the full sphere.

The JavaScript code below expects HTML with a canvas with an ID of "canvas", and a moon image with ID of "moon". Here is a demo in CodePen. It generates the polygon necessary to fill in the dark side of a full moon image, and renders the moon as it would be seen from the Northern hemisphere.

This generates a pretty harsh edge. Since the Sun has an apparent size of about 0.5°, it will produce a gradient of that angular size on the Moon. So it would produce a better result to compute two arcs, one +0.25° of the current phase, and one -0.25° and fill a linear gradient in between.

Here is an example produced by the code below:

enter image description here

const rad=Math.PI/180;

const canvas = document.getElementById("canvas");
const w=canvas.width;
const h=canvas.height;
const ctx = canvas.getContext("2d");
const r=w/2*.91;

function drawPhase(phase){
    //A rotation matrix, ignoring the Z result, and with Z=0 initially simplifies to cos(phase*360)
    const f=Math.cos(phase*rad);

    ctx.lineWidth=1;
    ctx.beginPath();
    let x=f*r*Math.cos(0)+w/2;
    let y=r*Math.sin(0)+h/2;
    ctx.moveTo(x,y);

    if(phase<=180){
        for(let i=0;i<=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi>0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    } else {
        for(let i=0;i<=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi<0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    }

    ctx.closePath();
    ctx.fill();
}

function display(){
    ctx.fillStyle="#000000cc";
    ctx.drawImage(document.getElementById("moon"), 0, 0);
    
    phase=(phase+1)%360;

    drawPhase(phase);
    window.setTimeout(()=>{
        display();
    },10);
}

let phase=0;
display();
$\endgroup$
3
  • $\begingroup$ That's pretty cool! How is the amount of earthlight computed? $\endgroup$ Jan 26 at 7:50
  • 2
    $\begingroup$ No attempt is made to compute the amount of light from Earth, the question asked for an approximate solution that looks right. $\endgroup$ Jan 26 at 14:39
  • 1
    $\begingroup$ It looks like the earthlight is simply setting the brightness to 20%: ctx.fillStyle="#000000cc" $\endgroup$ Jan 26 at 19:04
9
$\begingroup$

enter image description here

You must draw a semicircle of radius R and a semi-ellipse of semi-major axis "R" and semi-minor axis "b". To calculate "b" knowing the illuminated ratio "n":

$$n=\dfrac{\dfrac{\pi R^2}2+\dfrac{\pi R b}2}{\pi R^2}$$

Simplifying:

$$\boxed{b=(2 n - 1) \ R}$$

If "$n_{pc}$" is expressed in %

$$b=(2 n_{pc} - 100) R$$

With the values of "R" and "b" it is easy to draw the semi-ellipse of the terminator using, for example, rectangular coordinates:

$$\boxed{y=\dfrac b R \sqrt{R^2-x^2}}$$

$\endgroup$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .