PHPで月の満ち欠けを描画

(1/1)
PHP で日出没・月出没・月齢を計算」で月齢を求めるプログラムを紹介した。今回は、月齢を入力すると、月の満ち欠けの様子を画像として表示する PHP プログラムをつくってみることにする。

サンプル・プログラム

サンプル・プログラムの実行例

PHPで月の満ち欠けを描画

サンプル・プログラムの解説:準備

0026: //満月の画像
0027: // PNG形式限定
0028: // 正方形で,領域いっぱいに真円の満月が描かれていること.
0029: // 背景は透明であること.
0030: define('FULLMOON', 'fullmoon.png');
0031: 
0032: //影の透明度(0~127):0 は完全に不透明な状態。 127 は完全に透明な状態
0033: define('ALPHA', 30);
0034: 
0035: //明部分を白色で塗るかどうか
0036: define('MOON_BRIGHT', FALSE);
0037: 
0038: //画像を保存するフォルダ
0039: define('SAVE_PATH', './');

満月の写真があれば、それを定数 FULLMOON に指定する。
ただし、写真は PNG 形式限定。大きさの制限はないが、正方形で、領域いっぱいに真円の満月が描かれていること。また、背景は透明であることが望ましい。

今回は、影の部分だけ半透明の黒で塗りつぶすだけだが、もし太陽光の当たっている明部分を白で塗りたければ、定数 MOON_BRIGHT を TRUE にする。

影や明部分の透明度を制御するアルファチャネルの値は定数 ALPHA に指定する。0 は完全に不透明な状態、127 は完全に透明な状態となる。

月齢ごとの満ち欠け画像を保存するフォルダを、定数 SAVE_PATH に指定する。

サンプル・プログラムの解説:月の満ち欠けを描く

0124: /**
0125:  * 月の満ち欠けを描く
0126:  * @param double $age 月齢
0127:  * @return object GDリソース
0128: */
0129: function draw_moonage($age) {
0130:     if ($age < 0 || $age > 30)      $age = 0;
0131: 
0132:     //満月画像がなければ円を描画
0133:     if (! file_exists(FULLMOON)) {
0134:         $dd = 500;           //直径
0135:         $rr = $dd / 2;       //半径
0136:         $image = imagecreatetruecolor($dd$dd);
0137:         //背景透明化
0138:         $bgcolor = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);//背景色セット
0139:         imagefill($image, 0, 0, $bgcolor);
0140:         imagecolortransparent($image$bgcolor);
0141:         //円を描画
0142:         $color = imagecolorallocate($image, 0xFF, 0xFF, 0x7F);
0143:         imagefilledarc($image$rr$rr$dd$dd, 0, 360, $color, IMG_ARC_PIE);
0144: 
0145:     //満月画像の読み込み
0146:     } else {
0147:         if (($arr = getimagesize(FULLMOON)) == FALSE)   return FALSE;
0148:         $dd = $arr[0];       //直径
0149:         $rr = $dd / 2;       //半径
0150:         //画像読み込み
0151:         $image = imagecreatefrompng(FULLMOON);
0152:     }
0153: 
0154:     //完全なアルファチャネル情報を保存するフラグをonにする
0155:     imagesavealpha($imageTRUE);
0156:     //カラー設定
0157:     $black = imagecolorallocatealpha($image, 0x00, 0x00, 0x00, ALPHA);
0158:     $white = imagecolorallocatealpha($image, 0xFF, 0xFF, 0xFF, ALPHA);
0159: 
0160:     //影を描く
0161:     $x0 = $rr;
0162:     $y0 = $rr;
0163:     $th = $age / 14.765 * pi();
0164:     for ($y = -$rr$y <= 0; $y++) {
0165:         $ac = acos($y / $rr);
0166:         $x2 = $rr * sin($ac);                // 円周
0167:         $x1 = $rr * cos($th) * sin($ac); // 月の形
0168:         if (($age > 0.5) && ($age < 29.5)) {
0169:             if ($age < 15.0) {
0170:                 $x3 = $x0 + $x1;
0171:                 $x4 = $x0 + $x2;
0172:                 $x5 = $x0 - $x2;
0173:                 $y3 = $y0 + $y;
0174:                 $y4 = $y0 - $y;
0175:             } else {
0176:                 $x3 = $x0 - $x1;
0177:                 $x4 = $x0 - $x2;
0178:                 $x5 = $x0 + $x2;
0179:                 $y3 = $y0 + $y;
0180:                 $y4 = $y0 - $y;
0181:             }
0182:             imageline($image$x3$y3$x5$y3$black);
0183:             if (MOON_BRIGHT)    imageline($image$x3$y3$x4$y3$white);
0184:             if ($y != 0) {
0185:                 imageline($image$x3$y4$x5$y4$black);
0186:                 if (MOON_BRIGHT)    imageline($image$x3$y4$x4$y4$white);
0187:             }
0188:         } else {
0189:             $x3 = $x0 - $x2;
0190:             $x4 = $x0 + $x2;
0191:             $y3 = $y0 + $y;
0192:             $y4 = $y0 - $y;
0193:             imageline($image$x3$y3$x4$y3$black);
0194:             if ($y != 0) {
0195:                 imageline($image$x3$y4$x4$y4$black);
0196:             }
0197:         }
0198:     }
0199:     return $image;
0200: }

月の満ち欠けを描くのがユーザー関数 draw_moonage である。
冒頭で、 file_exists  を使い、満月画像 FULLMOON を探す。なければ円を描画する。

後半では、満月画像を読み込んで、影の部分を描画関数  imageline  を使って 1 ラインずつ塗りつぶしていく。
PHPで月の満ち欠けを描画
図 1 は、月の軌道と満ち欠けを示したものである。
遠方からやってくる太陽光線は直線になっているものと仮定する。ここで、太陽-地球-月のなす角をθとする。

このときの月を拡大したのが図 2 である。
月の中心を O とすると、地球から観たときに明部分となっているのは、AC の部分である。
地球の中心を E とすると、∠AEC=θ=∠AOC となる。
ここで、R=OA=OC であるので、 mimetex  と計算できる。

R は、両極(緯度 90°)で 0、赤道(緯度 0°)で月の半径と等しくなる。
月は真円であるので、月の緯度をγとすると R は  mimetex  で計算できる。

以上のことから、月の明部分の長さは  mimetex  で計算できる。これを月の半径から減じたものが影の部分の長さになる。
θは月齢と同じ意味である。θ=180°(月齢15)を境界条件とし、月の南北で影の長さが同じであることから計算量を減らしたのがユーザー関数 draw_moonage の肝の部分となる。

参考サイト

(この項おわり)
header