こんにちは。株式会社リンクネット ソリューション事業部の吉川です。
最近はお仕事でよくCreateJSを触っています。
星は何かと使う図形だと思うのですが、山が5つでない星を描こうとしたときに意外と悩んでしまいました。
最終的には欲しいものを描けるようになったので、考えていたことをまとめようと思います。
最終的には以下のようなコードになりました。
nの部分を何かしらのUIで変更することで任意の山の数の星を描画できます。
const stage = new createjs.Stage('canvas');
const star = new createjs.Shape;
const shape = new createjs.Shape;
// スタイルの設定
shape.graphics.setStrokeStyle(1).beginStroke('#000').beginFill('DeepSkyBlue');
// ここで描画
const n = 5; // 山の数
const alpha = Math.PI / n;
const pointSize = 1 - Math.cos(alpha) + Math.sin(alpha) * Math.tan(alpha);
shape.graphics.drawPolyStar(150, 150, 100, n, pointSize, -90);
// 描画ここまで
stage.addChild(shape);
stage.update();
以降は描画する部分のコードのみ記載します。
CreateJSにはdrawPolyStar
というメソッドがあります。
ドキュメントに山が5つの星を描くサンプルがあったので描いてみます。
shape.graphics.drawPolyStar(150, 150, 100, 5, 0.6, -90);
簡単にきれいな星が描けました。
ここで、第4引数が山の数、第5引数が山の尖り具合(谷の深さ)を表しているそうです。
次に、山が6つできれいな星を描くとき、第5引数はどんな値が良いでしょうか。
shape.graphics.drawPolyStar(150, 150, 100, 6, 0.42, -90);
適当に数値を変えてみた結果、0.42辺りがきれいな形でした。
谷の深さは山の数が増えるほど浅くなるので、数値も小さくなっています。
では、一般に山が個の星をきれいに描くときの谷の深さはどうすればよいでしょうか。
これまで"きれいな星"と言っていました。
以降では、"きれいな星"は正多角形の頂点を1つ飛ばして結んだ図形の輪郭線のこととします。
山が5つの星を例に挙げて考えると、星を描くための五角形(青)と内側にできる五角形(赤)ができます。
それらの外接円について、外側の半径を、内側の半径をとします。
すると、谷の深さは外側の半径に対する半径の差の比と考えられそうです。
この比をの式で表すために試行錯誤した結果、以下のようになりました。
これをソースコードに起こしてみます。
const n = 5; // 山の数
const alpha = Math.PI / n;
const pointSize = 1 - Math.cos(alpha) + Math.sin(alpha) * Math.tan(alpha);
shape.graphics.drawPolyStar(150, 150, 100, n, pointSize, -90);
思っていた通りの星を描くことができました。
サンプルで描いた星と見比べると、こちらの方が整った形をしていると思います。
上の式で計算すると、のときのpointSize
は0.618...となり、0.6では深さが足りなかったのです。
今回の谷の深さの考え方だと、pointSize
が0となるときは2つの外接円が重なり、であれば正十角形となりそうです。
しかし、実際に試してみるとドキュメントにも描いてある通り正五角形が描画されます。
0に近い小数を渡してみると正十角形に近い形が描画されるため、0の時は特別な処理が入っているようです。
shape.graphics.drawPolyStar(150, 150, 100, 5, 0.001, -90);
今回は頂点を1つ飛ばしで結んだ星を考えましたが、
山の数が7つ以上であれば2つ飛ばしで結んだ星も考えられます。
そういった星の描き方を考えるのも楽しいですね!
以上です。どなたかの参考になれば幸いです。