计算和绘制月相






4.88/5 (29投票s)
计算月球的年龄并在任意给定日期绘制月相。
引言
许多社区除了阳历之外还非常关注农历,所以我查阅了许多网站来了解如何在任何给定日期计算月龄。我发现许多网站提供了不同的方法,我结合了这些方法以获得更接近真实的结果。
我注意到大多数网站都同意使用儒略日期,但在计算月龄上存在分歧,这些网站之间的差异高达一天,当月龄为 30 天时,某些网站的结果为零。
在这个程序中,我计算了月龄的近似天数,没有考虑小时和分钟的小数部分。
为了使程序更有用,我添加了一个PictureBox
控件来显示月亮被照亮的部分和黑暗的部分,与月龄相对应。

背景
我创建了两个项目,一个用 C# (2003) 编写,另一个用 VB.NET (2003) 编写。
MoonPhase
项目包含一个窗体 (frmMoon
),其中包含以下控件
MonthCalendar
控件 (MyCalendar
)Button
控件 (btnToDay
)Button
控件 (btnClose
)PictureBox
控件 (PicMoon
)Label
控件 (lblAge
)
关于代码
将日期转换为儒略日期
private int JulianDate(int d, int m, int y)
{
int mm, yy;
int k1, k2, k3;
int j;
yy = y - (int)((12 - m) / 10);
mm = m + 9;
if (mm >= 12)
{
mm = mm - 12;
}
k1 = (int)(365.25 * (yy + 4712));
k2 = (int)(30.6001 * mm + 0.5);
k3 = (int)((int)((yy / 100) + 49) * 0.75) - 38;
// 'j' for dates in Julian calendar:
j = k1 + k2 + d + 59;
if (j > 2299160)
{
// For Gregorian calendar:
j = j - k3; // 'j' is the Julian date at 12h UT (Universal Time)
}
return j;
}
计算月龄的近似天数
private double MoonAge(int d, int m, int y)
{
int j = JulianDate(d, m, y);
//Calculate the approximate phase of the moon
ip = (j + 4.867) / 29.53059;
ip = ip - Math.Floor(ip);
//After several trials I've seen to add the following lines,
//which gave the result was not bad
if(ip < 0.5)
ag = ip * 29.53059 + 29.53059 / 2;
else
ag = ip * 29.53059 - 29.53059 / 2;
// Moon's age in days
ag = Math.Floor(ag) + 1;
return ag;
}
绘制月亮
private void DrawMoon()
{
int Xpos, Ypos, Rpos;
int Xpos1, Xpos2;
double Phase;
Phase = ip;
// Width of 'ImageToDraw' Object = Width of 'PicMoon' control
int PageWidth = PicMoon.Width;
// Height of 'ImageToDraw' Object = Height of 'PicMoon' control
int PageHeight = PicMoon.Height;
// Initiate 'ImageToDraw' Object with size = size of control 'PicMoon' control
Bitmap ImageToDraw = new Bitmap(PageWidth, PageHeight);
// Create graphics object for alteration.
Graphics newGraphics = Graphics.FromImage(ImageToDraw);
Pen PenB = new Pen(Color.Black); // For darkness part of the moon
Pen PenW = new Pen(Color.White); // For the lighted part of the moon
for (Ypos=0; Ypos<= 45; Ypos++)
{
Xpos = (int)(Math.Sqrt(45*45 - Ypos*Ypos));
// Draw darkness part of the moon
Point pB1 = new Point(90-Xpos, Ypos+90);
Point pB2 = new Point(Xpos+90, Ypos+90);
Point pB3 = new Point(90-Xpos, 90-Ypos);
Point pB4 = new Point(Xpos+90, 90-Ypos);
newGraphics.DrawLine(PenB, pB1, pB2);
newGraphics.DrawLine(PenB, pB3, pB4);
// Determine the edges of the lighted part of the moon
Rpos = 2 * Xpos;
if (Phase < 0.5)
{
Xpos1 = - Xpos;
Xpos2 = (int)(Rpos - 2*Phase*Rpos - Xpos);
}
else
{
Xpos1 = Xpos;
Xpos2 = (int)(Xpos - 2*Phase*Rpos + Rpos);
}
// Draw the lighted part of the moon
Point pW1 = new Point(Xpos1+90, 90-Ypos);
Point pW2 = new Point(Xpos2+90, 90-Ypos);
Point pW3 = new Point(Xpos1+90, Ypos+90);
Point pW4 = new Point(Xpos2+90, Ypos+90);
newGraphics.DrawLine(PenW, pW1, pW2);
newGraphics.DrawLine(PenW, pW3, pW4);
}
// Display the bitmap in the picture box.
PicMoon.Image = ImageToDraw;
// Release graphics object
PenB.Dispose();
PenW.Dispose();
newGraphics.Dispose();
ImageToDraw = null;
}
您可以在解压缩Moon_VB.zip文件后返回源代码文件以阅读 VB.NET 代码。
结束语
如果您有任何想法或找到另一种计算月龄的代码,请告诉我。感谢 Code Project 以及所有人的帮助。
Mostafa Kaisoun
m_kaisoun@hotmail.com