【PHP実践|実務向け】PHPのGDライブラリで実現する「座標回転」の基礎と実務への応用

導入

Webシステム開発において、動的なグラフ生成や簡易的な画像加工が必要になるケースは少なくありません。特に、レーダーチャートやアナログ時計のような描画を行う際、中心点から特定の角度に向けて線を引く「座標回転」のロジックは不可欠です。本記事では、PHPの標準画像処理ライブラリであるGDを活用し、三角関数を用いた座標回転の仕組みと、実務で役立つ実装方法を解説します。

基礎知識

コンピュータグラフィックスにおいて、ある点を中心として回転した座標を求めるには「三角関数(sin/cos)」を利用します。
PHPには度数法(0〜360度)を弧度法(ラジアン)に変換する deg2rad() 関数が用意されています。
回転後の相対座標(x, y)は以下の数式で算出可能です。

・x = 半径 cos(ラジアン)
・y = 半径 sin(ラジアン)

注意点として、数学的な座標系と画像処理(GD)の座標系はY軸の向きが逆になる場合があります。また、0度は通常「右方向(3時)」を指すため、時計のように「真上(12時)」から始めたい場合は、計算結果から90度分を調整する工夫が必要です。

実装/解決策

中心座標(cx, cy)から、半径(r)の線を指定した角度(angle)で引くための関数を作成します。ポイントは、計算した相対座標を「中心座標」に加算することです。これにより、画像上のどの位置からでも正確に線を描画できます。

サンプルプログラム

  • 指定した角度と長さから座標を算出する関数
  • @param int $r 線分の長さ
  • @param float $angle 角度(度数法)
  • @return array [x, y] の相対座標
  • /
    function getRotatedPoint($r, $angle) {
    // PHPの三角関数はラジアンを要求するため変換
    $radian = deg2rad($angle);

    // 座標計算(数学の単位円の考え方)
    $x = $r cos($radian);
    $y = $r sin($radian);

    return [round($x), round($y)];
    }

    // キャンバス設定
    $width = 300;
    $height = 300;
    $centerX = $width / 2;
    $centerY = $height / 2;

    $image = imagecreatetruecolor($width, $height);
    $white = imagecolorallocate($image, 255, 255, 255);
    $red = imagecolorallocate($image, 255, 0, 0);

    // 例:中心から長さ100px、角度45度で線を引く
    $radius = 100;
    $angle = 45;

    list($dx, $dy) = getRotatedPoint($radius, $angle);

    // 終点座標は中心座標 + 相対座標
    imageline($image, $centerX, $centerY, $centerX + $dx, $centerY + $dy, $red);

    // 画像出力
    header(‘Content-Type: image/png’);
    imagepng($image);
    imagedestroy($image);
    ?>

    応用・注意点

    1. 座標系の調整: サンプルコードでは0度が右方向を指します。もし12時方向をスタート地点にしたい場合は、角度から90度を引くか、sinとcosを入れ替える調整を行ってください。
    2. ピクセル単位のズレ: 座標計算には浮動小数点数が絡むため、最終的な座標は必ず round() や floor() で整数化してください。これを怠ると、imagelineで意図しないピクセルに描画される原因となります。
    3. パフォーマンス: 多数の線を描画する場合(円グラフなど)、ループ内で毎回 deg2rad() を実行するとオーバーヘッドが生じます。定数化や計算の事前キャッシュを検討し、高負荷な処理を避けるよう心がけましょう。

    このロジックを理解すれば、レーダーチャートの頂点算出や、動的なゲージ生成など、表現の幅が大きく広がります。ぜひ実務のツールとして活用してみてください。

    タイトルとURLをコピーしました