2018年12月18日(火) 03:57 JST

掃引体 -GDLメモ vol.2

  • 2010年7月 2日(金) 14:30 JST
  • 投稿者:

GDLはBASICに似た言語で、比較的簡単に使えるようになりますが、すこし複雑なことをしようとすると返って難しくなることもあります。前回、メビウスの輪を紹介しましたが、これに厚みを持たせようとするとプログラムはすぐに複雑になってしまいます。

厚みを持たせるGDLの書き方は、GDL講習会のこのあたりを参考にしてください。おそらくこの方法でメビウスの輪にも厚みを与えることはできるでしょう。この記事では別の方法でメビウスの輪に厚みを持たせてみようと思います。

掃引という手法があります。用語としてはスイープの方が馴染みがあるかもしれません。GDLにもSWEEPコマンドは用意されていますが、これはXY平面においた図形に掃引するパスを与えることで掃引体を作ります。これを使ってメビウスの輪ができればいいのですが、掃引パスを予め別の場所で計算しておいて、コマンドの引数としてソースにペーストしなければなりません。これは面倒です。GDLのコマンドはこのタイプのものが多く、せっかく便利な機能であってもパラメトリックに取り扱いたいところで使えないことがおおいようです。たとえば、掃引パスの分割を増減して微調整するだけの簡単なこともできません。

そこで、SWEEPコマンドを使わないでメビウスの輪に厚みを持たせる方法を考えてみたいと思います。

次のような手順でメビウスの輪を作ります。

  1. 掃引する元の図形としてXZ平面の長方形を設定する
  2. 長方形の中心はXY平面上の原点中心半径rの円上を通る
  3. 長方形が円周上を一周して元の位置に戻ってくるまでに180°回転する

たったこれだけですからすぐにでもプログラムは書けそうですが、意外と難しいのです。どう書けばいいのか一番難しいのは「3.パス中心に回転」の部分でしょう。クオータニオンとか便利なアルゴリズムを使えばいいわけですが、ここではもっと泥臭く考えます。

  1. 長方形の中心が原点中心にあるとしてXZ平面内で回転移動する
  2. 回転移動後の長方形を半径r分だけX軸方向に平行移動する
  3. 平行移動後の長方形をZ軸中心に回転移動する

右の図ですと、赤、青、黄の順番で図形を移動して長方形の頂点座標を分割数(都合により+1)だけ計算していき配列に格納します。その後、これらの頂点座標をつなぐ形でメビウスの輪を描画します。ソース例のワイヤーフレームの表示では、ポリゴン頂点を結んだ線とせずに、掃引された長方形を描画するようにしています。

以上をプログラムすると下のコードになります。毎度の言い訳になりますが、これが唯一のコードでもないし、最良のコードでもありません。冒頭の8の字形の掃引パスの図形も同じ方法で作成しています。中央部で交差していない点に注目してください。掃引パスをZ方向にも変化をつけてこのような微妙な3次元形状を作っています。


DIM x0[], y0[], z0[]
DIM x1[], y1[], z1[]
DIM x2[], y2[], z2[]
DIM x3[], y3[], z3[]
DIM x4[], y4[], z4[]

n = 60    !! 分割数
r = 100   !! 半径
w = 20    !! 長方形横
h = 10    !! 長方形縦

th = 360  !! 1周360°
ro = 180  !! で半ひねり

!! スイープパスの生成
FOR i=1 to n+1
  x0[i] = r * COS( (th/n) * (i-1))
  y0[i] = r * SIN( (th/n) * (i-1)) 
  z0[i] = 0
NEXT i

!! ①
xx1 =  w
yy1 =  0
zz1 =  h
!! ②
xx2 = -w
yy2 =  0
zz2 =  h
!! ③
xx3 = -w
yy3 =  0
zz3 = -h
!! ④
xx4 = w
yy4 = 0
zz4 = -h

FOR i=1 to n+1
    ! ①
    l = COS((ro/n)*(i-1)) * xx1 - SIN((ro/n)*(i-1)) * zz1
    z = SIN((ro/n) * (i-1)) * xx1 + COS((ro/n) * (i-1)) * zz1
    y = (l+r) * SIN((th/n)*(i-1))
    x = (l+r) * COS((th/n)*(i-1))
    z1[i] = z + z0[i]
    x1[i] = x 
    y1[i] = y
    ! ②
    l = COS((ro/n)*(i-1)) * xx2 - SIN((ro/n)*(i-1)) * zz2
    z = SIN((ro/n) * (i-1)) * xx2 + COS((ro/n) * (i-1)) * zz2
    y = (l+r) * SIN((th/n)*(i-1))
    x = (l+r) * COS((th/n)*(i-1))
    z2[i] = z + z0[i]
    x2[i] = x
    y2[i] = y
    ! ③
    l = COS((ro/n)*(i-1)) * xx3 - SIN((ro/n)*(i-1)) * zz3
    z = SIN((ro/n) * (i-1)) * xx3 + COS((ro/n) * (i-1)) * zz3
    y = (l+r) * SIN((th/n)*(i-1))
    x = (l+r) * COS((th/n)*(i-1))
    z3[i] = z + z0[i]
    x3[i] = x 
    y3[i] = y
    ! ④
    l = COS((ro/n)*(i-1)) * xx4 - SIN((ro/n)*(i-1)) * zz4
    z = SIN((ro/n) * (i-1)) * xx4 + COS((ro/n) * (i-1)) * zz4
    y = (l+r) * SIN((th/n)*(i-1))
    x = (l+r) * COS((th/n)*(i-1))
    z4[i] = z + z0[i]
    x4[i] = x
    y4[i] = y
NEXT i

FOR i=1 to n
!! ワイヤーフレームでの表示はこちらを生かしてください
!   LIN_ x1[i], y1[i],z1[i], x2[i], y2[i],z2[i]
!   LIN_ x2[i], y2[i],z2[i], x3[i], y3[i],z3[i]
!   LIN_ x3[i], y3[i],z3[i], x4[i], y4[i],z4[i]
!   LIN_ x4[i], y4[i],z4[i], x1[i], y1[i],z1[i]
   PLANE 3, x1[i], y1[i], z1[i], x4[i], y4[i], z4[i], x1[i+1], y1[i+1], z1[i+1]
   PLANE 3, x4[i], y4[i], z4[i], x4[i+1], y4[i+1], z4[i+1], x1[i+1], y1[i+1], z1[i+1]
   PLANE 3, x2[i], y2[i], z2[i], x3[i], y3[i], z3[i], x2[i+1], y2[i+1], z2[i+1]
   PLANE 3, x3[i], y3[i], z3[i], x3[i+1], y3[i+1], z3[i+1], x2[i+1], y2[i+1], z2[i+1]
   PLANE 3, x2[i], y2[i], z2[i], x1[i], y1[i], z1[i], x2[i+1], y2[i+1], z2[i+1]
   PLANE 3, x1[i], y1[i], z1[i], x2[i+1], y2[i+1], z2[i+1], x1[i+1], y1[i+1], z1[i+1]
   PLANE 3, x4[i], y4[i], z4[i], x3[i], y3[i], z3[i], x4[i+1], y4[i+1], z4[i+1]
   PLANE 3, x3[i], y3[i], z3[i], x4[i+1], y4[i+1], z4[i+1], x3[i+1], y3[i+1], z3[i+1]
NEXT i

以下のコメントは、その投稿者が所有するものでサイト管理者はコメントに関する責任を負いません。