円に沿ってオブジェクトを配置する

特定のライブラリや Web だけの技術にとどまらず、プログラムで動くものを作る際に幅広い表現ができるようになるための練習をしていきます。


円形配置

円形配置配置が完成した時のスクリーンショット

今回はあるオブジェクトを円に沿うように配置したい時にどのような計算を行えばいいのかを解説します。


下のデモでは描画を行うことに重点を置き、コードを極力シンプルに書くことができる Processing をベースにより Web と親和性を高めたライブラリ p5.js を利用しています。

p5.js は描画に Canvas を利用するので、このデモも Canvas で描画しています。

また、プログラム中で利用している変数を GUI で操作することができるライブラリ dat.GUI も併せて利用しています。

この記事中ではそれぞれのライブラリについて詳しく解説していませんので、メソッドなどの詳細な解説はそれぞれのドキュメントを参照してみてください。


作ろうとしているもの

  • 円状に特定のオブジェクトを等間隔に配置する
  • オブジェクトの数がいくつ増えても等間隔で配置する
  • 円の位置を変えてもオブジェクトの配置の状態を維持する
  • 円自体を回転させることもできるようにする

完成 DEMO

See the Pen 円状配置 by turusuke (@turusuke) on CodePen.

この完成したデモ中で使われているコードを元に、 各オブジェクトをどのように配置すればよいかを説明していきます。

個々のオブジェクトの座標を求める

今回の目的を達成するためには1つ1つのオブジェクトを Canvas 上のどこに置けばよいのかを求めなければいけません。 ここでは三角関数を使って座標を求めます。 デモ中では 29行目から34行目で座標を求めています。

  [...new Array(setting.cricleNum)].forEach((_, i) => {
    const _rad = i / setting.cricleNum * PI * 2 + setting.angle; //  現在の円のインデックス / 円の総数 * 2π + 円全体の角度
    const x = setting.h * cos(_rad) + setting.cx; // x座標を求める
    const y = setting.h * sin(_rad) + setting.cy; // y座標を求める
    ellipse(x, y, 10, 10); // 円を描画する
  })
}

このコードを解説していきます。

配置するオブジェクトの数だけループさせる

[...new Array(setting.cricleNum)].forEach((_, i) => {
// ~~略~~
}

ここでは円の周りに配置するオブジェクトの数(setting.CirclesNum)だけループを回しています。 この中でオブジェクト個々の座標を求めています。

各オブジェクトが全体の何%にあたる位置なのかを計算する

const r = i / setting.circlesNum * PI * 2 + setting.angle;

円の中心座標とオブジェクトが作りだす直角三角形の内角を求めています。 一度にたくさん計算をしているので少し分解して見ていきます。

i / setting.circlesNum = オブジェクトのインデックス番号 / オブジェクト全体の個数

式の最初の i / setting.CirclesNum の部分を見てみます。 ここではループ中で定義されてインクリメントされている 変数 i , つまりオブジェクトのインデックスをオブジェクト全体の個数で割っています。

この計算によって、i番目のオブジェクト が全体を 100% と見た時に全体の何 % にあたるのかがわかります。


中心座標とオブジェクトが作り出す角度を求める

次にこの値に 円1周の角度を示す 2πを乗算することで円の中点からオブジェクトが作り出す直角三角形の内角が導けます。

(全体の何%にあたる部分にいるのか) * 2π = 円の中点からオブジェクトが作り出す直角三角形の内角

最後に setting.angle を足しています。この値は円自体の角度です。この値を足すことで個々のオブジェクトの角度が setting.angle 分ずれるので、結果的に円全体を回転させることができます。

const _rad = (円の角度が 0 度の時のオブジェクトの内角) + setting.angle;

角度がわかれば三角関数を使い、オブジェクトの座標を求められます。

const x = setting.h * cos(_rad);
const y = setting.h * sin(_rad);

setting.h は円の半径の大きさです。cos(_rad), sin(_rad) で半径が 1の時の角度 _rad の座標が求められます。

これに半径をかけることで円の半径が setting.h の時のオブジェクトの x,y 座標を導くことができます。

円の中心座標をずらす

今のままでは円の中心座標が (x=0,y=0) なので、予め値を設定しておいた setting.cx, setting.cy を足すことで円の中心座標をずらすことができます。

x + setting.cx;
y + setting.cy;

cx,cy の値を dat.GUI で変化させてみると円がどう動くかを見てみる

これで各オブジェクトの座標を求めることができました。後はこの値を使って何かしらの方法で画面上に描画してあげれば完成です。

ellipse(x, y, 10, 10); // 円を描画する