Adobe Illustratorで関数曲線
Illustratorで数学の曲線を描く。
・2017年6月/全面的に加筆修正。
・2020年5月/JSの書き方を修正。(CC 2020での動作確認済み)
参考文献:
JavaScript (のやや古いバージョン)で書いたらいいらしい。下に載っけてるコードをエディタとかメモ帳で拡張子「.js」をつけて保存し、イラレの「ファイル>スクリプト>その他のスクリプト」から選択すれば、実行されてパスが表示される。離散化された点を線で結んだだけだから近似曲線になるけど、十分な点数を用意すればまあ問題ないかと。(やっていて分かったけど、どうも900点を超えてくるとエラーを吐くっぽい。カクカクが気になるのであれば、パスの単純化で一応なめらかにはなるのでお試しを。)
1. 放物線(二次関数)
const start = -50; //スタート
const end = 50; //エンド
const step = 0.5; //描画ステップ
var anchorpoint = [];
for (var x = start; x <= end; x += step) {
var y = 0.05 * Math.pow(x, 2);
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
n次関数ならMath.pow(x,2) ⇒ Math.pow(x,n)
2. 三角関数
const start = 0; //最初の角度(度数法)
const end = 360; //最後の角度(度数法)
const step = 1; //描画ステップ
var anchorpoint = [];
for (var theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var y = 100 * Math.sin(theta_rad);
anchorpoint.push([theta, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
ここではとりあえずsin(x)を。cos(x)ならMath.sin() ⇒ Math.cos()に変更。同じノリでtanをやっちゃうと、発散してキャンバスからめちゃくちゃはみ出るので注意。極は除きましょう。ちなみにイラレの「効果>パスの変形>ジグザグ(なめらか)」で直線をうにゃらせたやつは正弦波とは全くの別物なので、正弦波のノリで使わないように…!
3. 波数k1のsin波を波数k2のsin波でAM変調させた波
const start = 0; //最初の角度(度数法)
const end = 360; //最後の角度(度数法)
const step = 1; //描画ステップ
const k1 = 1; //波数1
const k2 = 10; //波数2
var anchorpoint = [];
for (theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var y = 100 * Math.sin(k1 * theta_rad) * Math.sin(k2 * theta_rad);
anchorpoint.push([theta, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
4. 指数関数的に減衰する振動
const start = 0; //最初の角度(度数法)
const end = 360; //最後の角度(度数法)
const step = 1; //描画ステップ
const k = 5; //波数
var anchorpoint = [];
for (theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var y = 100 * Math.cos(k * theta_rad) * Math.exp(-0.01 * theta);
anchorpoint.push([theta, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
5. 指数関数的に減衰する歳差運動
const start = 0; //最初の角度(度数法)
const end = 3600; //最後の角度(度数法)
const step = 5; //描画ステップ
var anchorpoint = [];
for (var theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var x = 100 * Math.exp(-0.1 * theta_rad) * Math.sin(theta_rad);
var y = 100 * Math.exp(-0.1 * theta_rad) * Math.cos(theta_rad);
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
6. アルキメデスの螺旋
const start = 0; //最初の角度(度数法)
const end = 3600; //最後の角度(度数法)
const step = 5; //描画ステップ
var anchorpoint = [];
for (var theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var x = Math.cos(theta_rad) * theta_rad;
var y = Math.sin(theta_rad) * theta_rad;
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
この螺旋は蚊取り線香を描くときに使えそう。見てると目が回る。
c.f. その他の螺旋の方程式(放物螺旋とか描いてみるとモアレが出て楽しい。)
7. ガウシアン(Gaussian, 正規分布)
const start = -100; //スタート
const end = 100; //エンド
const step = 1; //描画ステップ
var anchorpoint = [];
for (var x = start; x <= end; x += step) {
var y = 100 * Math.exp(-(x * x) / (20 * 20));
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
8. ローレンチアン(Lorentzian, コーシー分布)
const start = -100; //スタート
const end = 100; //エンド
const step = 1; //描画ステップ
var anchorpoint = [];
for (var x = start; x <= end; x += step) {
y = 10000 / (100 + x * x);
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
9. サイクロイド曲線(cycloid)
const start = 0; //最初の角度(度数法)
const end = 360; //最後の角度(度数法)
const step = 1; //描画ステップ
var anchorpoint = [];
for (var theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var x = 50 * (theta_rad - Math.sin(theta_rad));
var y = 50 * (1 - Math.cos(theta_rad));
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
c.f. 媒介変数表示された有名な曲線7つ
他の有名な媒介変数表示された曲線も、上で関数だけ書き換えれば描ける。
10. フレネル積分(Fresnel integrals)
var x = 0 //x初期値
const dt = 0.01; //描画ステップ
const hScale = 20; //横スケール
const vScale = 100; //縦スケール
function func1(t) {
return Math.cos(t * t);
}
var anchorpoint = [];
for (var t = 0; t <= 8; t += dt) {
var dx = dt * func1(t);
x += dx;
anchorpoint.push([hScale * t, vScale * x]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
sinの方も同じ感じで作れる。雑な解説は下のクロソイドのところで。
11. クロソイド曲線(clothoid, フレネル積分, コルニュ螺旋)
var x = 0.0; //x初期値
var y = 0.0; //y初期値
const dt = 0.01; //描画ステップ
const scale = 100; //スケール
function func1(t) {
return Math.cos(t * t);
}
function func2(t) {
return Math.sin(t * t);
}
var anchorpoint = [];
for (var t = 0; t <= 8; t += dt) {
var dx = dt * func1(t);
var dy = dt * func2(t);
x += dx;
y += dy;
anchorpoint.push([scale * x, scale * y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = false; //塗りなし
pObj.stroked = true; //線あり
pObj.strokeWidth = 1; //線幅1pt
クロソイド曲線は一般に媒介変数表示で、 \begin{align} x(l) &= \int_{0}^{l}\cos(t^2)dt \nonumber\\ y(l) &= \int_{0}^{l}\sin(t^2)dt \nonumber \end{align} のフレネル積分になっている。なので、ここでは微分方程式 \begin{align} \frac{dx}{dt} &= \cos(t^2) \nonumber\\ \frac{dy}{dt} &= \sin(t^2) \nonumber \end{align} をオイラー法で解いて表示している。
マイナス側も必要だったらfor文のところ、for (t=-4.5; t<=4.5; t+=dt)で。(ただ、点数を増やすなら片側描いて反転でくっつけた方がいいかも)
12. おまけ。 MONTBLANCのロゴみたいなの(中の星部分)
媒介変数表示した円の半径をcosで変調させてる。(ここでは狙って6周期)
const start = 0; //最初の角度(度数法)
const end = 360; //最後の角度(度数法)
const step = 1; //描画ステップ
var anchorpoint = [];
for (var theta = start; theta <= end; theta += step) {
var theta_rad = theta * Math.PI / 180;
var R = 50 + 8 * Math.cos(6 * theta_rad);
var x = R * Math.sin(theta_rad);
var y = R * Math.cos(theta_rad);
anchorpoint.push([x, y]);
}
const docObj = activeDocument;
var pObj = docObj.pathItems.add();
pObj.setEntirePath(anchorpoint);
pObj.filled = true; //塗りあり
pObj.stroked = false; //線なし
pObj.strokeWidth = 1; //線幅1pt
こんな感じでデザインされたのかなと思ってやってみたけど、比べると若干ずれがあった。cosの係数次第でもう少し寄せられるかもしれない。
余談になるけど、ガウシアン、ローレンチアンは拡大縮小で任意のガウシアン、ローレンチアンに変形できる。だから、例えばどんな強度、分散を持つガウシアンであっても、上記コードを実行して出てきたガウシアンのパスを適当に縦横拡大縮小すればそれを再現できる。(言うまでもなく、放物線や三角関数もそう。)
例えばガウシアンの場合、もともとの関数形は \begin{align} y = a\exp\left\{-\frac{(x-b)^2}{2c^2}\right\} \end{align} $b$ は $x$ 軸方向の平行移動なので無視するとして、パラメータ $a, c$ がそれぞれ $a', c'$ 倍されても \begin{align} y &= a'a\exp\left\{-\frac{x^2}{2(c'c)^2}\right\}\\ \frac{y}{a'} &= a\exp\left\{-\frac{(x/c')^2}{2c^2}\right\}\\ \end{align} ここで、$y' = y/a'$, $x' = x/c'$ と変数変換すれば、 \begin{align} y' = a\exp\left\{-\frac{x'^2}{2c^2}\right\} \end{align} となり、これは元の関数形($b$ を無視した場合)と同じである。ということで結局、$a$ を $a'$ 倍、$c$ を $c'$ 倍したところで、それは結局、元のガウシアンを縦方向に $a'$ 倍、横方向に $c'$ 倍したものにすぎない。
あと諸々の複雑な関数(ガンマ関数とかベッセル関数とか)になるとjsじゃ少なくとも簡単には書けないので、素直にグラフソフト(gnuplotとかPythonのMatplotlib)で描いてpdfなりepsなりで吐き出したものを読み込むのがいいと思う。
Adobe Illustratorで関数曲線
Reviewed by mug
on
10/30/2016
Rating:
0 件のコメント: