月(moon)の姿を描画するJavaのソースコード

   2012/11/17

来年のカレンダーの中には、月の満ち欠けが載っているものもありますね。
月の満ち欠けにあわせてスケジュールを調整すると効率が上がる
という説もあるようです。(掃除は月齢15〜29の時が良い?)

毎度、管理人イガジーです。

そんなわけで、月(moon)の姿を描画するプログラムを常備しておくと
よいことがあるかもしれません(^^)

countdownプログラムに組み込んだり壁紙にカレンダーを埋め込もうwallcale.jarに組み込むのも良いかもしれません。

という訳でソースコードを一気に公開します。(ただし無保証です)

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.GregorianCalendar;

// copyright by MLTLab

public class MoonShape implements ActionListener {
	int mr=120;
	Frame f0;
	BufferedImage bi;
	Graphics g;
	MyCanvas cv;
	TextField tf;
	String []lstr={"年","月","日","時"};
	int nn=lstr.length;
	TextField []ymdh = new TextField[nn];
	Color c0=Color.YELLOW;
	Color c1=Color.DARK_GRAY;

	MoonShape(String []as){
		f0=new Frame("Moon Shape");
		f0.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent ev) {
				System.exit(0);
			}
		});
		if (as.length>0){
			for (int i=0;i<as.length;++i) {
				char c1=as[i].charAt(0);
				if ((c1>='0')&&(c1<='9')) {
					try {
						mr=Integer.parseInt(as[i]);
					} catch (NumberFormatException e) {
						mr=120; // assume
					}
					if (mr<10) mr=10;
					if (mr>200) mr=200;
				}
			}
		}
		bi=new BufferedImage(mr*2+40,mr*2+40,BufferedImage.TYPE_INT_RGB);
		g=bi.getGraphics();
		g.setColor(c0);

		cv=new MyCanvas();
		f0.add(cv,BorderLayout.CENTER);
		Panel p0=new Panel();
		Panel p1=new Panel();
		tf=new TextField(5);
		tf.addActionListener(new DrawAge());
		p1.add(new Label("月齢"));
		p1.add(tf);

		for (int i=0;i<nn;++i) {
			if (i==0) ymdh[i]=new TextField(4);
			else ymdh[i]=new TextField(2);
			ymdh[i].addActionListener(this);
			p0.add(ymdh[i]);
			p0.add(new Label(lstr[i]));
		}
		Button bb=new Button("Set");
		bb.addActionListener(this);
		p0.add(bb);
		f0.add(p0,BorderLayout.NORTH);
		f0.add(p1,BorderLayout.SOUTH);
		f0.setSize(300,400);
		f0.setVisible(true);
	}
	public int moonage10(Calendar c) { // 月齢を10倍した値を返す
		long adj=4L;
		return (int)((((c.getTimeInMillis()/1000L)-929332980L)%2551442L)/8640L+adj);
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		int []dt=new int[nn];
		Calendar cc;
		boolean vok=true;
		for (int i=0;i<nn;++i) {
			try {
				dt[i]=Integer.parseInt(ymdh[i].getText());
			} catch (NumberFormatException e) {
				dt[i]=0;
				vok=false;
			}
		}
		if (vok) {
			cc=new GregorianCalendar(dt[0],dt[1]-1,dt[2],dt[3],0);
		}else{
			cc=new GregorianCalendar();
		}
		int yy=cc.get(Calendar.YEAR);//System.out.print("year="+yy);
		ymdh[0].setText(Integer.toString(yy));
		int mm=cc.get(Calendar.MONTH)+1;//System.out.print(" month="+mm);
		ymdh[1].setText(Integer.toString(mm));
		int dd=cc.get(Calendar.DAY_OF_MONTH);//System.out.print(" day="+dd);
		ymdh[2].setText(Integer.toString(dd));
		int hh=cc.get(Calendar.HOUR_OF_DAY);//System.out.println(" hour="+hh);
		ymdh[3].setText(Integer.toString(hh));
		int ag=moonage10(cc);
		tf.setText(Double.toString((double)ag/10.0));
		moonshape10(ag,mr);
	}

	void moonshape10(int age10,int r) {
		moonshape((double)age10/10.0,r);
	}
	public static void main(String[] args) {
		new MoonShape(args);
	}
	void moonshape(double age,int r) {
		int x0=r+20;
		int y0=r+20;
		double theta=Math.PI*age/14.765;
		for (int y=-r;y<=0;++y) {
			int x2,x1;
//			x2=(int)Math.sqrt(r*r-y*y);
			double ac=Math.acos((double)y/(double)r);
			x2=(int)((double)r*Math.sin(ac)); // 円周
			x1=(int)((double)r*Math.cos(theta)*Math.sin(ac)); // 月の形
			if ((age>1.0)&&(age<29.0)) {
				if (age<15.0) {
					g.setColor(c0);
					g.drawLine(x0+x1, y0+y, x0+x2, y0+y);
					g.drawLine(x0+x1, y0-y, x0+x2, y0-y);
					g.setColor(c1);
					g.drawLine(x0-x2, y0+y, x0+x1-1, y0+y);
					g.drawLine(x0-x2, y0-y, x0+x1-1, y0-y);
				}else{
					g.setColor(c0);
					g.drawLine(x0-x2, y0+y, x0-x1, y0+y);
					g.drawLine(x0-x2, y0-y, x0-x1, y0-y);
					g.setColor(c1);
					g.drawLine(x0-x1-1, y0+y, x0+x2, y0+y);
					g.drawLine(x0-x1-1, y0-y, x0+x2, y0-y);
				}
			}else{
				g.setColor(c1);
				g.drawLine(x0-x2, y0+y, x0+x2, y0+y);
				g.drawLine(x0-x2, y0-y, x0+x2, y0-y);
			}
		}
		cv.repaint();
	}

	class DrawAge implements ActionListener {
		private double v;
		@Override
		public void actionPerformed(ActionEvent arg0) {
			try {
				v = Double.parseDouble(tf.getText());
			} catch (NumberFormatException e) {
				//e.printStackTrace();
				v=0.0;
			}
			moonshape(v,mr);
			for (int i=0;i<lstr.length;++i) ymdh[i].setText(null);
		}
	}

	class MyCanvas extends Canvas {
		private static final long serialVersionUID = 1L;
		@Override
		public void update(Graphics g0) {
			paint(g0);
		}
		@Override
		public void paint(Graphics g0) {
			g0.drawImage(bi,0,0,null);
		}
	}
}

年月日のところに何も入力せずに[Set]を押すと
その時点での日付時刻がセットされます。

月齢の部分に数値を入れて、[Enter]を押すと、その月齢に対応した
月の姿を描画します。その時、日付時刻はクリアされます。

月齢計算は簡略計算なので、±0.5 くらいの誤差があります。
(このプログラムに限らず、月齢表示プログラムには誤差がある
ものだと思って頂いた方がよいと思います。)

プログラムに関するご質問などは、お気軽に
メールフォームから送ってください。

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)