Draw phases of the moon On a form

ddanbe 1 Tallied Votes 2K Views Share

Lately, I was reading this snippet by vegaseat. I thought, why not do it in C#? But I would also like to add lattitude and logitude in the celestial calculations and draw a picture of the moon at that moment and location. Now the calculations can get a bit involved but are doable. So first I did a little try out about the drawing of a moon phase picture. Code for the main drawing method is given here. Just call it from a Paint event. A litte project file for a test app is included in a zip file as is a picture of how it looks.

using System;
using System.Drawing;

namespace MoonPhases
{
    public enum Phase
    {
        new_moon, waxing_crescent, first_quarter, waxing_gibbous, 
        full_moon, waning_gibbous, third_quarter, waning_crescent
    }

    class Moon
    {
        private const float ArcLength = 180; //from north to south pole
        private float penthickness = 2f;    //2 to get a better overlap of pixels

        public int DrawSize { get; set; }

        public Point DrawPosition { get; set; }

        public Moon()
        {
            DrawSize = 200; //default values
            DrawPosition = new Point(100, 100);
        }

        public Moon(int drawsize)
        {
            DrawSize = drawsize;
            if (drawsize < 50) penthickness = 1f;
            else penthickness = 2f;
            DrawPosition = new Point(100, 100);
        }
        /// <summary>
        /// "Main" method of this class
        /// </summary>
        /// <param name="a Graphics object"></param>
        /// <param name="angle should be -90"></param>
        /// <param name="phase see the Pase enum"></param>
        public void DrawMoonPhase(Graphics G, float angle, Phase phase)
        {
            bool blackcoloring = true;
            Brush BR;
            Pen P = new Pen(Color.Black, penthickness);
            
            int moonphase = GetMoonPhasenumber(phase, out blackcoloring);
            if (blackcoloring) // reverse color depending on what phase we are in
            {
                BR = Brushes.Black; P.Color = Color.Wheat; 
            }
            else
            {
                BR = Brushes.Wheat; P.Color = Color.Black; 
            }
            G.FillEllipse(BR, DrawPosition.X, DrawPosition.Y, DrawSize, DrawSize);
            if (moonphase <= DrawSize / 2)
            {
                DrawRightMoonPart(G, angle, P, moonphase);
            }
            else
            {
                DrawRightMoonPart(G, angle, P, DrawSize / 2);
                DrawLeftMoonPart(G, angle, P, moonphase - DrawSize / 2);
            }
        }

        private void DrawLeftMoonPart(Graphics G, float angle, Pen P, int moonphase)
        {
            for (int i = 0; i < moonphase; i++)
            {
                // Increase rect size to draw arc in
                G.DrawArc(P,
                    new RectangleF(DrawPosition.X + DrawSize / 2 - i, DrawPosition.Y, 0.1f + 2 * i, DrawSize), angle + ArcLength, ArcLength);
            }
        }

        private void DrawRightMoonPart(Graphics G, float angle, Pen P, int moonphase)
        {
            for (int i = 0; i < moonphase; i++)
            {
                // Decrease rect size to draw arc in
                G.DrawArc(P, 
                    new RectangleF(DrawPosition.X + i, DrawPosition.Y, DrawSize - 2 * i, DrawSize), angle, ArcLength);
            }
        }

        //return the number of pixels, to indicate sunlight on the moon
        private int GetMoonPhasenumber(Phase P, out Boolean colorblack)
        {
            int phasenumber = 0;
            Boolean cb = true;

            switch (P)
            {
                case Phase.new_moon: 
                    phasenumber = 0;
                    cb = true;
                    break;
                case Phase.waxing_crescent:
                    phasenumber = DrawSize / 4;
                    cb = true;
                    break;
                case Phase.first_quarter:
                    phasenumber = DrawSize / 2;
                    cb = true;
                    break;
                case Phase.waxing_gibbous:
                    phasenumber = 3 * DrawSize / 4;
                    cb = true;
                    break;
                case Phase.full_moon:
                    phasenumber = 0;
                    cb = false;
                    break;
                case Phase.waning_gibbous:
                    phasenumber = DrawSize / 4;
                    cb = false;
                    break;
                case Phase.third_quarter:
                    phasenumber = DrawSize / 2;
                    cb = false;
                    break;
                case Phase.waning_crescent:
                    phasenumber = 3 * DrawSize / 4;
                    cb = false;
                    break;
                default:
                    break;
            }
            colorblack = cb;
            return phasenumber;
        }
    }
}