PHPで月の満ち欠けを描画

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

(2023年1月16日)現在の月齢をデフォルト値にする

目次

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

PHPで月の満ち欠けを描画

サンプル・プログラム

圧縮ファイルの内容
moonage.phpサンプル・プログラム本体。
fullmoon.png満月画像。
pahooCalendar.php暦・潮位計算クラス pahooCalendar。
暦・潮位計算クラスの使い方は「PHPで二十四節気・七十二候一覧を作成」「PHPで月齢を計算」「PHPで日出没・月出没・月齢・潮を計算」「PHPで潮位を計算する」などを参照。include_path が通ったディレクトリに配置すること。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「PHPでGET/POSTでフォームから値を受け取る」「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
tripleCalendar.php 更新履歴
バージョン 更新日 内容
2.0.2 2023/10/06 bugfix:makeCalendar() -- 祝日をredに
2.0.1 2023/01/18 bug-fix
2.0.0 2023/01/14 土用の二の丑の日、天赦日を追加
1.9 2022/06/05 pahooInputData.php分離,カレンダー作成期間追加,タイトル変更
1.8 2022/05/27 2033年問題解決案を追加;定数 RESOLVE2033
pahooCalendar.php 更新履歴
バージョン 更新日 内容
4.5.0 2024/03/17 ヒジュラ暦メソッドを追加
4.4.1 2024/03/17 getCabinetOfficeHolidayTable() -- bug-fix
4.4.0 2024/02/25 内閣府の祝日表を参照できるようにした
4.3.2 2023/02/11 getSolarTerm72() 表記改訂:水澤腹堅→水沢腹堅
4.3.1 2023/02/03 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.5.0 2024/01/28 exitIfExceedVersion() 追加
1.4.2 2024/01/28 exitIfLessVersion() メッセージ修正
1.4.1 2023/09/30 コメントの訂正
1.4.0 2023/09/09 $_GET, $_POST参照をfilter_input()関数に置換
1.3.0 2023/07/11 roundFloat() 追加

準備:初期値など

  38: //満月の画像
  39: // PNG形式限定
  40: // 正方形で,領域いっぱいに真円の満月が描かれていること.
  41: // 背景は透明であること.
  42: define('FULLMOON', 'fullmoon.png');
  43: 
  44: //影の透明度(0~127):0 は完全に不透明な状態。 127 は完全に透明な状態
  45: define('ALPHA', 30);
  46: 
  47: //明部分を白色で塗るかどうか
  48: define('MOON_BRIGHT', FALSE);
  49: 
  50: //画像データ保存機能を使うかどうか TRUE:使う,FALSE:使わない
  51: define('ISSAVE', FALSE);
  52: 
  53: //画像を保存するフォルダ
  54: define('SAVE_PATH', './');
  55: 
  56: //表示幅(ピクセル)
  57: define('WIDTH', 600);
  58: 
  59: //表示言語(jp:日本語, en:英語, en3:英語略記)
  60: define('LANGUAGE', 'jp');
  61: 
  62: //世界時からの時差(日本標準時)
  63: define('UTCDIFF', +9.0);
  64: 
  65: //require_once()で呼ぶファイルはinclude_pathが通っているフォルダに配置すること。
  66: //暦計算クラス
  67: require_once('pahooCalendar.php');
  68: 
  69: //データ入力に関わる関数群
  70: require_once('pahooInputData.php');

各種定数は変更可能である。

満月の写真があれば、それを定数 FULLMOON に指定する。
ただし、写真はPNG形式限定。大きさの制限はないが、正方形で、領域いっぱいに真円の満月が描かれていること。また、背景は透明であることが望ましい。
今回は、影の部分だけ半透明の黒で塗りつぶすだけだが、もし太陽光の当たっている明部分を白で塗りたければ、定数 MOON_BRIGHT を TRUE にする。
影や明部分の透明度を制御するアルファチャネルの値は定数 ALPHA に指定する。0 は完全に不透明な状態、127 は完全に透明な状態となる。

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

データ入力に関わる関数群は別ファイル "pahooInputData.php" に分離しており、include_path が通ったディレクトリに配置すること。
また、暦計算クラス・ファイル "pahooCalendar.php" もinclude_pathが通ったディレクトリに配置すること。

解説:指定した月齢の月の満ち欠けを描く

 156: /**
 157:  * 指定した月齢の月の満ち欠けを描く.
 158:  * @param   double $age 月齢
 159:  * @return  object GDリソース
 160: */
 161: function drawMissingMoon($age) {
 162:     if ($age < 0 || $age > 30)       $age = 0;
 163: 
 164:     //満月画像がなければ円を描画
 165:     if (! file_exists(FULLMOON)) {
 166:         $dd = 500;          //直径
 167:         $rr = $dd / 2;      //半径
 168:         $image = imagecreatetruecolor($dd, $dd);
 169:         //背景透明化
 170:         $bgcolor = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);//背景色セット
 171:         imagefill($image, 0, 0, $bgcolor);
 172:         imagecolortransparent($image, $bgcolor);
 173:         //円を描画
 174:         $color = imagecolorallocate($image, 0xFF, 0xFF, 0x7F);
 175:         imagefilledarc($image, $rr, $rr, $dd, $dd, 0, 360, $color, IMG_ARC_PIE);
 176: 
 177:     //満月画像の読み込み
 178:     } else {
 179:         if (($arr = getimagesize(FULLMOON)) == FALSE)   return FALSE;
 180:         $dd = $arr[0];      //直径
 181:         $rr = $dd / 2;      //半径
 182:         //画像読み込み
 183:         $image = imagecreatefrompng(FULLMOON);
 184:     }
 185: 
 186:     //完全なアルファチャネル情報を保存するフラグをonにする
 187:     imagesavealpha($image, TRUE);
 188:     //カラー設定
 189:     $black = imagecolorallocatealpha($image, 0x00, 0x00, 0x00, ALPHA);
 190:     $white = imagecolorallocatealpha($image, 0xFF, 0xFF, 0xFF, ALPHA);
 191: 
 192:     //影を描く
 193:     $x0 = $rr;
 194:     $y0 = $rr;
 195:     $th = $age / 14.765 * pi();
 196:     for ($y = -$rr$y <0$y++) {
 197:         $ac = acos($y / $rr);
 198:         $x2 = $rr * sin($ac);               // 円周
 199:         $x1 = $rr * cos($th* sin($ac);    // 月の形
 200:         if (($age > 0.5&& ($age < 29.5)) {
 201:             if ($age < 15.0) {
 202:                 $x3i = round($x0 + $x1);
 203:                 $x4i = round($x0 + $x2);
 204:                 $x5i = round($x0 - $x2);
 205:                 $y3i = round($y0 + $y);
 206:                 $y4i = round($y0 - $y);
 207:             } else {
 208:                 $x3i = round($x0 - $x1);
 209:                 $x4i = round($x0 - $x2);
 210:                 $x5i = round($x0 + $x2);
 211:                 $y3i = round($y0 + $y);
 212:                 $y4i = round($y0 - $y);
 213:             }
 214:             imageline($image, $x3i, $y3i, $x5i, $y3i, $black);
 215:             if (MOON_BRIGHT)    imageline($image, $x3i, $y3i, $x4i, $y3i, $white);
 216:             if ($y !0) {
 217:                 imageline($image, $x3i, $y4i, $x5i, $y4i, $black);
 218:                 if (MOON_BRIGHT) {
 219:                     imageline($image, $x3i, $y4i, $x4i, $y4i, $white);
 220:                 }
 221:             }
 222:         } else {
 223:             $x3i = round($x0 - $x2);
 224:             $x4i = round($x0 + $x2);
 225:             $y3i = round($y0 + $y);
 226:             $y4i = round($y0 - $y);
 227:             imageline($image, $x3i, $y3i, $x4i, $y3i, $black);
 228:             if ($y !0) {
 229:                 imageline($image, $x3i, $y4i, $x4i, $y4i, $black);
 230:             }
 231:         }
 232:     }
 233:     return $image;
 234: }

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

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

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

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

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

参考サイト

(この項おわり)
header