2014/12/15

ジバニャン方程式の作り方 #vgadvent2014  



※この記事はVOYAGE GROUP エンジニアブログ : Advent Calendar 2014の16日目の記事として書かれています。

11月にジバニャン方程式発見のツイートをして9000以上のRTをいただきました。




このエントリーではこのジバニャン方程式をどうやって作ったのかを紹介します。
実際には試行錯誤をしながら道具や環境を整えて行ったのでこの順番に作ったわけでは無いのですが、説明しやすい順番で書きますね。

0. 自分のモチベーションと目的を確認する。



仕事じゃないんだからモチベーションとか目的とか言わなくていいでしょ、と思うでしょう。私もそう思います!
でも、自分の趣味とはいえ何日も何週間もやっているとそうも言っていられなくなるんですよね。
ジバニャン方程式は、構想を含めなければ10月22日から手をつけたようで、発表が11月12日なので、3週間くらいやっていたひとりプロジェクトでした。
3週間!!!
ふりかえって見ると長いですね。

途中で何度か目的を見失って、このままだと完成しないなーと感じることがありました。
そういうときはたいてい、こだわりすぎて作業が前進しないときなので、何をしたかったのか自分に問いかけてこだわりを割り切ったりしました。

【やりたかったこと】
・ジバニャンを方程式で書く(以前やったアンパンマン方程式の続編)
・その方程式はTeXでかっこいい数式にする
・方程式は1個にする。(別で定義した式を使わない)

【割り切って捨てたこと】
・かっこいいDSL
・正確なジバニャンの描画(口とか、目のまわりとか)
・maxとminは使いたくなかったけど、使うことにした。(元々は四則演算とn乗と絶対値だけのつもりでした)

そして今思えば、TeXにするのは余分なこだわりだったかなと思っています。

1. 方程式の見える化の環境を作る。



方程式は文字列なので、目に見えるグラフのようなものにしておかないとお絵描きすることはできません。今回は言語としてRを選択したので等高線を書くcontourを使いました。
例えば

$$ 0 = 1 - \left(\frac{x-119}{103} \right)^2 - \left(\frac{y-56}{86} \right)^2 $$

この楕円の方程式であれば、

クリックすると元のサイズで表示します

こんな風に表示できます。

$x$,$y$の2変数の方程式なので、 $z=f(x,y)$ の形の3次元空間内の曲面とみなすこともできて、その方が考えやすいときもあります。
rglを使って3次元の状態を見られるようにもしておきましょう。
ここに貼っているのは画像ですが、Rで実行するとマウスでぐりぐり動かせる3Dモデルになります。

クリックすると元のサイズで表示します

実際には $z=f(x,y)$ ではなく $z=-log(-min(f(x,y),0)+1)$ という変換をしています。$z=0$ と言う平面との交わりを見るためと、$z$方向が大きすぎたり小さすぎたりすると、縦横に比べて高さが大きくなりすぎて、見にくくなってしまうので、それを防ぐための工夫です。
(3次元空間で表現するのは@kohskeさんのアイデアをいただきました。)

function_viewer.r

2. DSLを作る。



いきなりDSL作るのか!と思うかも知れませんが、何度も方程式を書き換えていると面倒な作業が多くなってきて、それを軽減するために作るという感じです。
DSL(ドメイン固有言語:domain-specific language)と言っても、楕円の方定式を作る、ミラー、ユニオン、インターセクション、補集合、などの7つ程度です。

方程式は最終的には文字列にしたいので、上記のDSLも方程式文字列を受け取って新しい方程式文字列を返すという関数の形をしています。

function_dsl.r

いくつか解説しますね。

【楕円を書く】

たとえば

ellipse(119,56,103,86)

と書くと楕円を書きます。端が欠けているのは領域をはみ出しているからです。

クリックすると元のサイズで表示します

【インターセクション】

二項演算子 %I% を使うとインターセクションを書いてくれます。
曲線の内側の領域に注目してインターセクションと呼んでいます。
下の画像は、2つの楕円のインターセクションです。

クリックすると元のサイズで表示します

【ミラー】

ジバニャンはほぼ左右対称なので、ミラー関数mirrorを作りました。

クリックすると元のサイズで表示します

【ユニオン】

二つの領域をくっつけるのがユニオンです。union関数にしました。
最初は %U% という二項演算子だったのですが、2個だけじゃなくて複数のユニオンを取ることが多かったので可変長引数の関数にしてあります。

クリックすると元のサイズで表示します

【カット】

余分な部分を消すのがカットです。二項演算子の %C% です。
インターセクションと似ていますね。実は %C% の実装には %I% を使っています。
%I% を使うよりわかりやすいので作りました。 ( %I% を使った方がわかりやすい時もあるので両方残してあります。)

この画像は、上の例の下半分をカットしています。

クリックすると元のサイズで表示します

こんな風にDSLを活用してジバニャンを作り上げていくのです。

3. ひたすら書く。



まず輪郭をつくっておきます。

クリックすると元のサイズで表示します

つぎに顔の内側を作ります。

クリックすると元のサイズで表示します

おでこのぐにゃぐにゃした模様は、楕円の組み合わせでは難しそうだったので、特別に関数を作りました。
登別の温泉に入りながらひらめいた関数です。

$$ 1 - \left|\frac{x}{51}+\frac{10}{51} sin \left( \frac{7}{2} \pi \left|\frac{y}{1.2*51}\right|^{1.2} \right) \right|^\frac{2}{3} - \left|\frac{y}{1.2*51}\right|^{\frac{2}{3}} $$


クリックすると元のサイズで表示します

これを顔の内側の部分からカットします。

クリックすると元のサイズで表示します

顔の内側ができたので、輪郭と合わせます。

クリックすると元のサイズで表示します

目、鼻、口をつけて出来上がり。

クリックすると元のサイズで表示します

クリックすると元のサイズで表示します

これで完成です。
この後、DSLで構成した方程式が余計な記述があったりするので(2重のカッコとか、2重のマイナスとか、絶対値を2乗しているので絶対値不要とか)、手作業で直しておしまいです。

jibanyan_edit.r

まとめ



こうやってみるとドローツールでジバニャンを描いているだけにも見えますね。
おでこの模様は楕円じゃなくて、実は内心自慢のポイントです。

妖怪ウォッチが大好きな娘に見せたら、口が変、と言われました。
口、最後に作ったし、本気で作ると細かいパーツが多くて大変だったから、さぼったのだけど、一瞬でバレました。さすがのドメイン知識です。

明日のVOYAGE GROUP エンジニアブログ : Advent Calendar 2014は、@co3kです!
0



コメントを書く


名前
メールアドレス
コメント本文(1000文字まで)
URL




teacup.ブログ “AutoPage”
AutoPage最新お知らせ