読者です 読者をやめる 読者になる 読者になる

LaTeX + 数値計算パッケージでフラクタル図形

はじめに

LTで発表することになったので再帰マクロを使ったフラクタル図形描画マクロを作ろうと思いました.

何を作ったのか

今回はフラクタル図形を描画できる再帰マクロを作りました.

フラクタル図形とは

幾何学の概念であり,図形の一部が全体の形と同じ形(=自己相似形)になっているような図形のことをいいます.

実装する

数値計算のパッケージを使った

気がついたらLTの準備期間が1週間しかなかったので, TeXオンリーではなくTeX+LaTeX+数値計算パッケージを使いました. 今回,実装する上で試したパッケージは以下の3つです.

  • FPパッケージ
  • calculatorパッケージ
  • PGFパッケージ

私が今回採用したのはPGFパッケージです. なぜこのパッケージを採用したのかを説明する為にも それぞれのパッケージのメリット,デメリットについて紹介していきます.

FPパッケージ

固定小数点演算ができるパッケージで,三角関数なども実装されているので 今回,フラクタル図形を生成するには実装上問題ないはずでした.しかし,以下のメリット,デメリットの為にあえなく断念しました.

  • TeXレジスタに依存しない巨大小数点の演算が可能
  • \FPevalで数式の解釈が可能
  • 演算が極めて遅い

前回,モンテカルロ積分を実装した時に使ったパッケージなので 今回も使おうと思いましたが再帰的に大量の計算を行う今回のケースには不向きでした.そもそもそこまで巨大な数を扱う予定もありません.

calculatorパッケージ

次に目を付けたのはこのパッケージです.このパッケージは固定小数点演算ができ,TeXレジスタに依存していて\pm 16383.99999の範囲の小数点のみ扱うので計算はFPパッケージよりも速いです.しかし,このパッケージも使うのは断念しました.

  • FPパッケージよりは計算が速い
  • 可読性が低い
    • マクロ名が全て大文字
    • 数式の評価ができない
    • 一つの演算に一つのマクロ

PGFパッケージ

今回使ったパッケージです.このパッケージも固定小数点演算ができます.採用した理由は以下の通りです.

  • 数式が解釈できる
  • 演算がFPパッケージより速い

PGFパッケージを使って描いたフラクタル図形を紹介します. 画像は実際に描画したPDFをjpgにしたものです.

円のフラクタル図形

図形はここを参考にしました. f:id:muscle_keisuke:20170422173321j:plain マクロのソースは以下のようになっていて再帰になっているのが分かります.

\newcounter{deep}
\def\circleR#1#2#3#4{{
  \pgfmathsetmacro{\xA}{#1}
  \pgfmathsetmacro{\yA}{#2}
  \pgfmathsetmacro{\R}{#3}
  \setcounter{deep}{#4}

  \draw[ultra thin] (\xA, \yA) circle (\R);

  \pgfmathsetmacro{\newR}{\R/2}

  \ifnum \value{deep}=1
  \else
    \circleR{\xA - \newR}{\yA}{\newR}{#4-1}
    \circleR{\xA + \newR}{\yA}{\newR}{#4-1}
  \fi
}}

コッホ曲線

f:id:muscle_keisuke:20170422173328j:plain

シェルピンスキーのギャスケット

f:id:muscle_keisuke:20170422173332j:plain

木も生やしてみた

f:id:muscle_keisuke:20170422180248j:plain 木はそのまま自己相似形にすると自然ではないので枝分かれの角度を乱数によって決めています. また,枝が分かれるほど線を細く描画するようにしています.

\def\Tree#1#2#3#4#5{{%
  \pgfmathsetmacro{\xA}{#1}
  \pgfmathsetmacro{\yA}{#2}
  \pgfmathsetmacro{\R}{#3}
  \pgfmathsetmacro{\Degree}{#4}
  \setcounter{deep}{#5}
  \setlength{\treeBold}{\value{deep} pt}

  \pgfmathsetmacro{\xB}{\xA - \R*cos(\Degree)}
  \pgfmathsetmacro{\yB}{\yA + \R*sin(\Degree)}
  \draw[line width=\treeBold] (\xA, \yA) -- (\xB, \yB);
  \ifnum \value{deep}=1
  \else
    \pgfmathsetmacro{\newR}{0.8*\R}
    \pgfmathrandominteger{\a}{0}{60}
    \pgfmathsetmacro{\newAngleLeft}{\Degree+\a}
    \pgfmathrandominteger{\a}{0}{60}
    \pgfmathsetmacro{\newAngleRight}{\Degree-\a}
    \Tree{\xB}{\yB}{\newR}{\newAngleLeft}{#5-1}
    \Tree{\xB}{\yB}{\newR}{\newAngleRight}{#5-1}
  \fi
}}

最後に

今回,作成したフラクタル図形のソースは以下に載せておきます.

フラクタル図形を描画するfractal.sty