How to draw a crescent

Hello friends,
I would like to depict moon phases by laying a dark crescent shape over an image of the moon. I’m able to create a crescent shape using beginShape()/endShape() and generating lots of vertices inside a couple for-loops. However, this seems rather clumsy and perhaps computationally inefficient. Is there an easier way to draw a crescent shape? I essentially want to shade a region inside a circle but outside an ellipse, and I can’t seem to find a way to do this. Thanks, in advance, for pointing me in the right direction.

1 Like

Hello!
I just did a quick search for “moon” on openprocessing.org and this popped up. As you can see it’s processing NOT p5.js. Code runs perfectly and looks like it would be easy to convert.
There may be other sketches in p5.js but I didn’t look any further after this one. :slight_smile:

////////////////////////////////////////////////////////////////////////////////////////

Credit: Moon Phases by Salam on openprocessing.org

void setup(){
  size(715, 300);
  background(0);
  smooth();
  stroke(0);
}
 
void draw(){ 
  float k = 0;
  for(int i = 60; i < 600; i=i+500){
    
    pushMatrix();
    
      fill(255);
      translate(i, height/2);
      rotate(-PI/2);
      
      arc(0, 0, 75, 75, 0, PI*4);
      fill(0);
      k=k+5;
      arc(k, k, 75, 75, 0, PI*4);
      
    popMatrix();
  }
  
  fill(255);
  translate(660, height/2);
  rotate(-PI/2);
  arc(0, 0, 75, 75, 0, PI*4);
}
1 Like

Thanks debxyz. This does indeed produce nice crescent shapes. But it seems to use a circle/ellipse portion to cover up a circle. The problem here for me is that the second circle portion will also cover up my moon image underneath. (I hope that makes sense.) I’d like to do something just like this, but I want an ellipse portion to “erase” the portion it overlaps with the circle, rather than covering it up.

Oh. :upside_down_face:
Well, I think there were some other examples that popped up. Maybe take a look? Make sure the search parameter is set for “all time” so that you filter for more than the past 30 days, etc.
:nerd_face:

Oh, I’ll take a look. Thanks!

It would be interesting to see a sample of your use case. There’s probably a solution that uses a separate p5.Graphics object and then draws it to your main canvas with image().

Additionally, since ellipses are drawn as Bézier curves under the hood, in theory you could generate Bézier curves for the results of the boolean subtraction that makes a crescent. However the code necessary for implementing this in the general cases is a bit daunting:

https://losingfight.com/blog/2011/07/07/how-to-implement-boolean-operations-on-bezier-paths-part-1/
https://losingfight.com/blog/2011/07/08/how-to-implement-boolean-operations-on-bezier-paths-part-2/
https://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/

I wouldn’t be surprised if there’s a special case shortcut for computing a Bézier curve for arbitrary crescents though.

1 Like

Oh, maybe Bézier curves are the way to go. I will take a look. Thanks for the links!

And one way or another I’ll post an example of what I’m going for so people can make suggestions for improvements.

So, I was able to create a function that draws crescent shapes well enough for me to depict moon phases. Maybe (probably?) there is something more elegant than this, but it seems to be easy enough for me to use. You can check out my code and use case here: p5.js Web Editor

Thanks so much to both of you for your help. From debxyz’s link I learned there isn’t an obvious crescent drawing method I was missing, as everyone seemed to be overlaying one circle on another and that sort of thing. And from KumuPaul I learned of the existence of Boolean subtraction with Bezier curves. Very interesting!

4 Likes

WOW!! Those are beautiful crescent shapes!! And great to see the code behind them!
:nerd_face:

Thanks! The curves took me a few tries to get right. Among other difficulties, I seem to never keep straight that the vertical coordinate increases downward. So many years of doing it the other way around I guess. :slight_smile:

Regarding Y axis orientation, you can always add this to the top of your draw function:

  scale(1, -1);
  translate(0, -height);
1 Like

Hello Dan,

I came across your question about generating a moon crescent. Shown below is a program that generates the part of the crescent ellipse for any value (k) of illumination. k lies between 0.0 and 1.0 and at those extremes the ellipse becomes a semi-circle. When k=0.5 the ellipse becomes a straight line. This ellipse is rotated by the angle theta. This angle (theta) changes as the moon goes from new moon to full moon and back again. The argument n is the number of points to be generated.

Example:

Generate a crescent ellipse with 25 points and rotated (from moon north in an easterly direction) by 213.0 degrees where 74% of the moon is illuminated
The ellipse minor axes have unit length i.e. this ellipse will fit in a circle of unit radius.

moon_crescent_points = moon_crescent(0.74, 213, 25)

The the output file (moon_crescent_points) is an array (2 x n) where row 1 is the x-axis values and row 2 is the y-axis values.

Moon Crescent Program :-

EXPORT moon_crescent(k,θ,n)
BEGIN
//
//Generate the crescent ellipse
//
LOCAL cres_data,npoints,r:= 1.0; 
LOCAL step, j, x, y, rot_θ;
//
npoints:= n ;
cres_data:= matrix(2,npoints+1);
    rot_θ:= matrix(2,2);
//Rotation Matrix
rot_θ(1,1):= COS(θ); rot_θ(1,2):= SIN(θ);
rot_θ(2,1):=-SIN(θ); rot_θ(2,2):= COS(θ);
//
step:= r/npoints;
FOR j FROM 1 TO npoints+1 
 DO
x:= 2.0*(step*(j-1))-1.0;
      cres_data(1,j):=  x;
y:= (2.0*k-1.0)*√(r^2-x^2);
       cres_data(2,j):= y;
 END;
cres_data:= ROUND(rot_θ * cres_data,3);
RETURN(cres_data);
END;

This program generates the ellipse crescent (very accurately) on my HP calculator program called moon_now. The picture below shows the calculator screen - the middle picture represents the moon and crescent. The moon is upside down because I am in the southern hemisphere.

Regards,

Jeremy!

moon_now|238x500

2 Likes

Thanks Jeremy! Your plot looks very nice. I was able to get something OK working using beginShape() … endShape() as in my link above. I used it to depict the current moon phase on part of a clock. I didn’t incorporate a rotation as you did. This would be better for sure, but it would depend on the viewer’s latitude (I think) and I didn’t want my page asking the viewer to enable location services or something like that. Also, it was just a small part of the clock, so I guess I got lazy about adding more detail to it. :slight_smile:

Thanks again for your code. Programming for calculators looks fun.

Dan

1 Like

Sorry guys… couldn’t resist suggesting this cheeky option. Why not simulate an actual sphere and light to get the crescent as close as possible? Also I know you’re working in p5.js and I’m not, but had to make a little sketch:

PImage moonImg;
PGraphics moonPG;

void settings()
{
  moonImg = loadImage("https://astronomy.com/~/media/3B700E883696431CA4097FC0DEB600CA.jpg");
  size(moonImg.width, moonImg.height, P3D);
}

void setup()
{
  frameRate(60);
  moonPG = createGraphics(width, height, P3D);
}

void draw()
{
  background(moonImg);

  moonPG.beginDraw();
  moonPG.translate(width/2, height/2);
  moonPG.directionalLight(255, 255, 255, cos(frameCount/100.f), 0, sin(frameCount/100.f));
  moonPG.noStroke();
  moonPG.sphereDetail(90);
  moonPG.sphere(365);
  moonPG.endDraw();

  blendMode(MULTIPLY);
  image(moonPG, 0, 0);
}
3 Likes

Ha! I love that idea Tiemen! I take it this written in Processing? I haven’t used that. Can you post an image of the result? (I suppose I could also install Processing and try your code.) Anyway, thanks for suggesting this very realistic approach.

Yeah this was written in processing, though I thought p5js and processing should be fairly similar?

2 Likes

Oh wow! Yeah, that looks just amazing.
Right, processing and p5.ha should be similar enough, so maybe I can try your approach.
Thanks for the inspiration to try something new.

You made me make my first p5js sketch! That web editor is kinda cool. Does this work? https://editor.p5js.org/rapatski/sketches/GeTl8coHG

It seems to work, except for the light animating by means of frameCount… which is puzzling, but you were possibly going to do it a different way anyway…?

2 Likes

Ha! Thanks for translating this for me! I’ve never done any of this WebGL stuff with p5.js, and now I have your example to work from. :+1:

1 Like

Greetings Dan,
I programmed in the calculators’ native language (Pascal like !!) because I use it in my moon observations. The code is easy to understand and may be easily translated to Octave or Matlab. There are two rotation angles:

  1. Position angle determined by the position of the moon and sun.
  2. The Parallactic Angle that is determined by ones location (lat and lon) and the time of day.
    Using both these angles gives one an accurate view of the crescent. The changes of the position is quite complex and varies with the season.

Here is a reference fyi : en:start [Virtual Moon Atlas Version 8.2].

Jeremy.

2 Likes