1219235567 開発言語は問いませんが、グラフィックのことで教えてください。


大きめの正円の線上に小さな正円をならべたいと思っています。どのようなアルゴリズムでプログラミングすればいいのでしょうか?


イメージ画像を添付します。

よろしくお願いします。

回答の条件
  • URL必須
  • 1人3回まで
  • 登録:2008/08/20 21:32:54
  • 終了:2008/08/27 21:35:02

回答(5件)

id:yo-kun No.1

yo-kun回答回数220ベストアンサー獲得回数302008/08/20 21:41:00

ポイント20pt

大円に内接する正多角形の頂点上に、

直径が正多角形の辺の長さに等しい小円を置いていけばいいと思います。


URLはダミーです

http://q.hatena.ne.jp/

id:pahoo No.3

pahoo回答回数5960ベストアンサー獲得回数6332008/08/20 22:28:07

ポイント20pt

小円の数を N 個とすると、N が十分に大きくないと、小円同士が重なってしまうのではないかと思うのですが――きちんと証明できないのですが、そんな気がします。


で、Nが十分に大きいと仮定すれば、大円の中心から小円1つあたりの半径と中心座標を三角関数で求めることができます。

PHPによるソースコードは下記の通り。

//大円の中心座標
$x0 = 150;
$y0 = 150;
//大円の半径
$r0 = 100;
//小円の数
$n = 20;

$t0 = 2.0 * pi() / $n;		//大円の中心から見た小円1つあたりの角度
$r1 = sin($t0) * $r0 / 2;	//小円の半径

//小円1つ1つの中心座標を配列に格納していく
for ($i = 0; $i < $n; $i++) {
    $x1[$i] = cos($t0 * $i) * $r0 + $x0;
    $y1[$i] = sin($t0 * $i) * $r0 + $y0;
}

もし gd ライブラリが利用できるようでしたら、下記のコードを付加することで円を描いていきます。

$image = imagecreatetruecolor(500, 500);
$bg = imagecolorallocate($image, 0, 0, 0);
$col_ellipse = imagecolorallocate($image, 255, 255, 255);
imageellipse($image, $x0, $y0, $r0 * 2, $r0 * 2, $col_ellipse);

for ($i = 0; $i < $n; $i++) {
    imageellipse($image, $x1[$i], $y1[$i], $r1 * 2, $r1 * 2, $col_ellipse);
}

header("Content-type: image/png");
imagepng($image);
id:Mook No.4

Mook回答回数1312ベストアンサー獲得回数3912008/08/20 22:47:25

ポイント20pt

手軽なところで EXCEL を使用した例ですが、VBAでの実装例です。

'-------------------------------------------------
Sub myDrow()
'-------------------------------------------------
    Const numOfCirclse = 10# '--- 円の個数
    Const radius = 200#      '--- 大きい円の半径
    Const centerX = 300#     '--- 円の中心のX座標
    Const centerY = 300#     '--- 円の中心のY座標
    Const PI = 3.14159265358979
    drowCircle centerX, centerY, radius
    
    Dim xx#, yy#, rr#
    rr = radius * Sin(PI / numOfCirclse)
    For i = 1 To numOfCirclse
        xx = centerX + radius * Cos(2 * PI * CDbl(i) / numOfCirclse)
        yy = centerY + radius * Sin(2 * PI * CDbl(i) / numOfCirclse)
        drowCircle xx, yy, rr
    Next
    
End Sub
'-------------------------------------------------
Sub drowCircle(cx#, cy#, r#)
'-------------------------------------------------
' Shape で、中心 (cx、cy) 半径 r の円を描画する
'-------------------------------------------------
    Dim tshape As Shape
    Set tshape = ActiveSheet.Shapes.AddShape(Type:=msoShapeOval, Left:=cx - r, Top:=cy - r, Width:=2 * r, Height:=2 * r)
    tshape.Fill.Visible = msoFalse
End Sub

http://www.feedsoft.net/excel/tips/shape/shp_84.html

id:Mook No.5

Mook回答回数1312ベストアンサー獲得回数3912008/08/21 23:31:24

ポイント20pt

yo-kun さんのコメントを見て気がつきましたが、大きい円の円周上に

小さい円どうしの接点と中心が両方のることはありえないのですね。


先の回答(他の回答者の回答も含めて)は、円周上の円の中心がのる場合のケースでした。

しかし、どちらかというと質問者さんは接点が円周上にあることをイメージしていた

でしょうか。


その場合、仮想的に中心がのる円の半径に置き換えることで、簡単に実現できると思います。

下記は、その場合の実装例です。

'-------------------------------------------------
Sub myDrow2()
'-------------------------------------------------
    Const numOfCircle = 8# '--- 円の個数
    Const radius = 100#      '--- 大きい円の半径
    Const centerX = 300#     '--- 円の中心のX座標
    Const centerY = 300#     '--- 円の中心のY座標
    Const PI = 3.14159265358979
    drowCircle centerX, centerY, radius

    Dim vRadius#
    vRadius = radius / Cos(PI / numOfCircle) '--- 仮想的な中心の乗る円の半径

    Dim xx#, yy#, rr#
    rr = vRadius * Sin(PI / numOfCircle)
    For i = 1 To numOfCircle
        xx = centerX + vRadius * Cos(2 * PI * CDbl(i) / numOfCircle)
        yy = centerY + vRadius * Sin(2 * PI * CDbl(i) / numOfCircle)
        drowCircle xx, yy, rr
    Next
End Sub
'-------------------------------------------------
Sub drowCircle(cx#, cy#, r#)
'-------------------------------------------------
' Shape で、中心 (cx、cy) 半径 r の円を描画する
'-------------------------------------------------
    Dim tshape As Shape
    Set tshape = ActiveSheet.Shapes.AddShape(Type:=msoShapeOval, Left:=cx - r, Top:=cy - r, Width:=2 * r, Height:=2 * r)
    tshape.Fill.Visible = msoFalse
End Sub

仮想円の半径は、正弦定理から簡単に求めることができます。

http://ja.wikipedia.org/wiki/%E6%AD%A3%E5%BC%A6%E5%AE%9A%E7%90%8...

  • id:yo-kun
    さすがに簡潔すぎましたのでフォローをば。

    大円の中心が原点にある時、半径をR、小円の数をnとすれば
    小円の中心座標はそれぞれ
    ( Rcos(2πi/n), Rsin(2πi/n) )となると思います。
    内接n角形の一辺の長さは2Rsin(π/n)ですので、

    for( i = 1 ; i <= n ; ++i ) {
    // 中心( Rcos(2πi/n), Rsin(2πi/n) )に半径2Rsin(π/n)の円を書く
    }

    という感じになると思います。
  • id:zzz_1980
    n個の小円を置くなら yo-kun さんの
    「内接正n角形の頂点に直径が正多角形の辺の長さに等しい小円を置く。」
    ではなく、
    「内接正2n角形の頂点ひとつおきに『半径が』正2n多角形の辺の長さに等しい小円を置く。」
    と小円の中心が大円上にあるだけでなく隣り合う小円と大円の交点が1点に集まりますので、
    こちらのほうがいいかなと思ったのですが、確実に隣り合う小円が重なってしまいます。
    (大円上に小円を3個置く場合を考えてみてください。)
  • id:yo-kun
    もし「小円同士が接する位置が大円の円周上」になるように配置したいのであれば
    大円の外接n角形の頂点に…小円を配置すればよいのですけどね。

    ただ、この場合は小円の中心が大円の中心上にはなりませんが。

    >質問者様
    すでに開かれている回答がご要望に合わないならば
    コメントなどに正確な条件を追記されたほうがよろしいかと。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません