ログ日記

作業ログと日記とメモ

TCPDFで円とベジェ曲線で図形を描く

TCPDFでちょっとした図形を入れたい場合、画像を使わずに直接PDFに出力してしまう方法がある。
TCPDFのソースとマニュアルを見ていたらベジエ曲線が簡単に描けるようなのでやってみた。
ベジェ曲線?どっち?昔聞いたときはベジエ曲線と発音されていたような気がする。)


まずは円弧を描く。

<?php
// (snip)
    $x = $pdf->GetX();
    $y = $pdf->GetY();
    $w = 20;
    $h = 20;

    $cx = $x + $w / 2;
    $cy = $y + $h / 2;
    $cw = $w / 2;

    $start = 0;
    $end = $start + 255;

    $pdf->Circle($cx, $cy, $cw, $start, $end, 'D');

角度は右が0度で半時計回りに指定するようだ。
これで右から255度分の円弧を描ける。

ベジエ曲線は、開始座標+3座標を指定する。

<?php
// (snip)
    $ax = $cx + $cw * cos(deg2rad($end));
    $ay = $cy - $cw * sin(deg2rad($end));
    $aw = $x + $w - $ax;

    $ax1 = $ax + $aw / 2 * $sign;
    $ax2 = $ax + $aw * $sign;
    $ax3 = $ax + $aw * $sign;
    $ay1 = $ay;
    $ay2 = $ay + $w / 3;
    $ay3 = $ay + $w / 2.5;
    $p1 = [$ax1, $ay1, $ax2, $ay2, $ax3, $ay3];

    $pdf->Polycurve($ax, $ay, [$p1], 'D');

円弧の端の座標をsinとcosで求める。
角度は$endをラジアンに変換する。deg2radっていう組み込み関数があったんだね。

そこからなめらかになるように、座標を配列で指定して Polycurve 関数で出力する。[$p1]となっているところは、複数繋げると複雑な曲線が描ける。

tcpdf-bezier

こんな感じに線を引けた。

中を塗る場合は、反転したベジエ曲線切らずに繋げて空白を埋めるように工夫する必要がある。

<?php

require_once 'vendor/autoload.php';


function drawCircle($pdf, $reverse)
{
    $x = $pdf->GetX();
    $y = $pdf->GetY();
    $w = 20;
    $h = 20;

    $cx = $x + $w / 2;
    $cy = $y + $h / 2;
    $cw = $w / 2;

    $start = 0;
    $end = $start + 255;

    $pdf->Circle($cx, $cy, $cw, $start, $end, 'D');
}

function drawBezier($pdf, $reverse)
{
    $x = $pdf->GetX();
    $y = $pdf->GetY();
    $w = 20;
    $h = 20;

    $cx = $x + $w / 2;
    $cy = $y + $h / 2;
    $cw = $w / 2;

    if (!$reverse){
        $start = 0;
        $end = $start + 255;
    }else{
        $start = 285;
        $end = 180 + 360;
    }

    if (!$reverse){
        $sign = 1;
        $point = $end;
    }else{
        $sign = -1;
        $point = $start;
    }

    $ax = $cx + $cw * cos(deg2rad($point));
    $ay = $cy - $cw * sin(deg2rad($point));


    if (!$reverse)
        $aw = $x + $w - $ax;
    else
        $aw = $ax - $x;
    $ax1 = $ax + $aw / 2 * $sign;
    $ax2 = $ax + $aw * $sign;
    $ax3 = $ax + $aw * $sign;
    $ay1 = $ay;
    $ay2 = $ay + $w / 3;
    $ay3 = $ay + $w / 2.5;
    $p1 = [$ax1, $ay1, $ax2, $ay2, $ax3, $ay3];

    $pdf->Polycurve($ax, $ay, [$p1], 'D');
}

$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('genshingothic', '', 8);

$color = [255,100,100];

$pdf->SetFillColor(...$color);
$pdf->SetDrawColor(...$color);

$pdf->Cell(0, 0, '円弧を描く', 0, 1);
drawCircle($pdf, false);

$pdf->SetY($pdf->GetY() + 30);

$pdf->Cell(0, 0, '円弧を反転してもう一つ描く', 0, 1);
drawCircle($pdf, false);
$pdf->SetX($pdf->GetX() + 20);
drawCircle($pdf, true);

$pdf->SetY($pdf->GetY() + 30);
$pdf->Cell(0, 0, 'ベジエ曲線を描く', 0, 1);
drawCircle($pdf, false);
drawBezier($pdf, false);

$pdf->SetY($pdf->GetY() + 30);
$pdf->Cell(0, 0, '円弧とベジエ曲線を反転して描く', 0, 1);
drawCircle($pdf, false);
drawBezier($pdf, false);
$pdf->SetX($pdf->GetX() + 20);
drawCircle($pdf, true);
drawBezier($pdf, true);



$pdf->Output();