Mind Render上でミッキーマウスの輪郭を描く数式アートを描いた話

Mind Render上で数式を使ってミッキーマウスの輪郭を描く数式アートを描くプログラムを作成した話に関する記事となります。
作成したプログラムを実行すると、下の数式アートが描かれます。

https://twitter.com/miya00907380/status/1645909595800457218

![mickyMouse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633154/c15b1ae0-4a56-9d01-75f7-7c8580069c00.png "Mind Render上で描いたミッキーマウスの輪郭")

# 本記事の作成目的
1. 下記の対象読者の知的好奇心を満たすこと
2. 本件に関して学んだ知識を著者が定着させること


# 対象読者
1. Mind Renderに興味がある人
2. 数式アートに興味がある人


# Mind Renderとは？

Scratchのようなブロックベースのゲーム開発ツールとなります。2D、3Dゲームの開発やムービーの作成、物理エンジンを利用したシミュレーションなどを行うことができます。

https://mindrender.jp

# 数式アートとは？
数式を使って描かれた図形です。DesmosやGeoGebraなどの数学ソフトウェアを使用して作成されることが多いようです。

# 使用数式
下のミッキーマウスの輪郭の数式を利用しました。

```math
\min(x^{2}+y^{2}-1,(\left|x\right|-0.8)^{2}+(y-0.8)^{2}-0.55^{2})=0 \tag{1}
```
https://www.desmos.com/calculator/w9rgzlekc7

```math
{(1)式のDesmos上での描画結果}
```


# 作成プログラム
![qiitaJoin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633154/7cc2ba8c-df50-46b3-e71a-eb7716ebbc71.png)


上の画像が作成したプログラムとなります（一部画像を加工しています）。[こちら](https://share.mindrender.app/locker.html?key=8b6h754MFsQVCeJVNHDNoU7eHseGeN7JKfVbq5Chz4dYn6pik1vzynxJW0sUCgF9tBWHc0O)に作成プログラムを公開しています(閲覧するためには、Mind Renderのインストールが必要です)。

| 種別 | 名称 | 定義 | 
| :-- | :-: | :-: | 
| 変数 | x | 現在のx座標の値 |	
| 変数 | y | 現在のy座標の値 |	
| 定数 | Tx | x軸方向の間隔 |	
| 定数 | Ty | y軸方向の間隔 |	
| 定数 | Xs | 最初のx座標の値 |	
| 定数 | Ys | 最初のy座標の値 |	
| 定数 | Xe | 最後のx座標の値 |	
| 定数 | Ye | 最後のy座標の値 |	
| 定数 | W | \|Xe - Xs\| |	
| 定数 | H | \|Ye - Ys\| |	
| 定数 | Epsilon | 0より大きい非常に小さな値 |	
| 定数 | Ixmax | x軸方向の繰り返し回数 |	
| 定数 | Iymax | y軸方向の繰り返し回数 |	
| 変数 | tmp | 数式(1)のmin()内の左項目$(x^2 + y^2 - 1)$の値 |	
| 変数 | tmp7 | 数式(1)のmin()内の右項目$((\|x\|−0.8)^2 + (y−0.8)^2 − 0.55^2)$の値 |
| 変数 | tmp2〜tmp6 | tmp7の計算過程で一時的に格納する値 |	
| マクロ | min | 2つの入力値のうち、小さい方を返すマクロ |	
| 変数 | returnValue | マクロminの出力結果を格納する値 |	
| オブジェクト | 自分 | オレンジ色の球体のオブジェクトであり、本プログラムを実行します. |	
```math
本プログラムの各変数、定数、マクロ、オブジェクトの定義一覧
```



概要ですが、ある座標(x, y)に対して数式(1)が満たされるかどうか確認して、満たされた場合に、その座標に自分（オレンジ球体オブジェクト）を表示させるという処理を各座標に対して行うというプログラムになります。

具体的には、(x, y)の初期値を左上の座標(Xs, Ys)とします。その後、ラスタ走査のように右水平方向に向かってxをTxの間隔で変化させていき、その行の最後に到達したら次の下の行の先頭(Xs, Ys - Ty)に移動して続けるという方法で座標を変化させていきます。その度に、各座標に対して(1)式が満たされるかどうか、すなわち(1)式の左辺 &asymp; 0 かどうか調査して、満たされた場合に球体をその座標に表示する処理を行います。



# 課題

描画に5分くらいの長い時間がかかる点が課題と言えます。

この原因として、球体を表示させない多くの座標に対しても、(1)式が成り立つかどうかを計算していることが考えられます。例えば左上の開始地点(Xs, Ys)は明らかに球体を表示させない座標ですが、この座標に対しても計算を行っているため、これは無駄だと言えます。

上記プログラムの時間計算量は、(1)式の1回の計算を1ステップと仮定した場合、
```math
O(Ixmax * Iymax) = O(280 * 250) = O(70000) {\tag9}
```
であり非常に大きいといえるかもしれません。

解決策として、(1)式を変形し、y=f(x)の形にして、xを一定間隔で変化させ、各xに対応するyの値を計算して、その座標(x, y)に対してのみ球体を表示させる方法が挙げられます。この方法を採用することで、表示させる座標に対してのみ計算を行わせることができ、より効率的になる可能性があります。

具体的には、(1)式は以下の(2)-(8)の式に分解できます（MicrosoftのMath Solverを使用して求めました）。

```math
y=\sqrt{1-x^{2}}\left\{\left|x\right|\le.274\ \right\}{\tag2}
```
```math
y=\sqrt{1-x^{2}}\left\{\left|x\right|\ge.962\right\}{\tag3}
```
```math
y=-\sqrt{1-x^{2}}{\tag4}
```
```math
y=-\frac{\sqrt{-400x^{2}-640x-135}}{20}+\frac{4}{5}\left\{x\le-.964\right\}{\tag5}
```
```math
y=\frac{\sqrt{-400x^{2}-640x-135}}{20}+\frac{4}{5}\left\{x\le-.274\right\}
{\tag6}
```
```math
y=-\frac{\sqrt{-400x^{2}+640x-135}}{20}+\frac{4}{5}\left\{x\ge.964\right\}
{\tag7}
```
```math
y=\frac{\sqrt{-400x^{2}+640x-135}}{20}+\frac{4}{5}\left\{x\ge.274\right\}
{\tag8}
```

https://www.desmos.com/calculator/xp6lnv1dhn?lang=ja
```math
{(2)-(8)式のDesmos上での描画結果}
```
これらの式を使用して本アイディアを実装したプログラムの時間計算量は、これら7つの式に対してyの値を多めに各1000回計算してかつ1回の計算がすべて1ステップであると仮定すると、

```math
O(1000 * 7) = O(7000) 
```
となり、(9)式と比較して小さくなります。ただし、現在、1回の計算が全ての式で1ステップで行えると仮定しているため、時間計算量が小さくても実際の実行時間が小さくなるとは限りませんが、そうなる可能性はあるとは思います。

本記事では、このアイディアの実装結果について取り上げません。余力があれば別記事で詳しく取り上げたいと思います。


# 参考URL
ミッキーマウスの数式
https://corollary2525.hatenablog.com/entry/2019/12/11/224546

MindRender上で描いたコウモリの数式アート
https://www.youtube.com/watch?v=fodyto4HlBc

MindRender公式ページ
https://mindrender.jp

Desmos
https://www.desmos.com/?lang=ja