BASIC 《 プログラミング言語 《 大系彷徨の神殿
『スピログラフ』

第2回 サイクロイド

Part 2. Cycloid
2006.11.11-2006.12.25

今回はサイクロイドを描きます。

サイクロイドが描ければ、スピログラフはほとんど描けたようなものです。

  1. サイクロイド
    1. サイクロイドの式
      1. θ
      2. 中心C
      3. 中心Cから見た点Pの座標
      4. 点Pの座標
    2. サイクロイドを描く
      1. とりあえず描く
      2. ゆっくり描く
    3. サイクロイドの描画アニメーション
      1. 動円を描く
      2. 点Pも描く
  2. 外サイクロイド
    1. 外サイクロイドの式
      1. θ
      2. 動円の中心C
      3. 中心Cから見た点Pの座標
      4. 点Pの座標
    2. 外サイクロイドを描く
      1. とりあえず描く
      2. 描画アニメーション
  3. 内サイクロイド
    1. 内サイクロイドの式
      1. θ
      2. 動円の中心C
      3. 中心Cから見た点Pの座標
      4. 点Pの座標
    2. 内サイクロイドの描画

1. サイクロイド

サイクロイド(cycloid、あえて日本語に訳すなら、「転がってる感じ」というところでしょうか。

円をコロコロ転がしてできる図形です。

1.1. サイクロイドの式

図1*1. サイクロイド

図1のように、半径rの円(動円)を、X軸に沿って転がすことを考えます。

サイクロイドとは、この動円の円周上の一点Pが描く軌跡です。

図1では、最初に原点にある点Pが、動円が転がることによって描く軌跡を示しています。

1.1.1. θ

ここでは、図1のように「動円が回転した角度」θ とします。

点Pは、 θ=0° の時に原点からスタートし、 θ=180°で頂点に達し、 θ=360° で一周してX軸上に戻ってきます。

サイクロイドの式は、このθパラメータとして、つまり、θを0°から増やしていく形で、考えていきます。

1.1.2. 中心C

θをパラメータにしたので、回転角がθの時の中心Cの座標を考えます。

まず、Y座標は、θに関係なく常に r です。

次に、X座標に関しては、図1に緑で示したように、転がった長さ、つまりは中心角θに対する弧の長さ rθ になります。

というわけで、

(1)
C=(rθ,r)

となります(θはラジアンで計算します)。

1.1.3. 中心Cから見た点Pの座標

図1a*5. サイクロイドのCP

中心Cを基準として、そこから点Pの座標をどう表せるかを、図1aを眺めながら考えます。

まずX座標は、中心Cの座標から r sinθ を引いた値になります。

次にY座標は、中心Cの座標から r cosθ を引いた値になります。

θ=0°,90°,180° 等の時を当てはめてみれば、確認できます。

よって、中心Cから見た点Pの座標は、

(2)
CP=(-r sinθ,-r cosθ)

となります。

1.1.4. 点Pの座標

(1)(2)から、点Pの座標は、

(3)
P=(rθ-r sinθ,r-r cosθ)

と表せます。

1.2. サイクロイドを描く

1.2.1. とりあえず描く

とりあえず、サイクロイドを描いてみます。

リスト1. cycloid0.bas
!
! サイクロイドを描く
!      Copyright(c) カイン Cain 2006
!
LET r = 1 ! 半径
WHEN EXCEPTION IN
   INPUT r
USE
END WHEN
LET r = ABS( r )
LET rounds = 1.7 ! 周回数
WHEN EXCEPTION IN
   INPUT rounds
USE
END WHEN
LET rounds = ABS( rounds )
!
SET WINDOW -r * 1.2, r * ( 2 * PI * rounds + 1.2 ), &
&  r - ( 2 * PI * rounds + 2.4 ) / 2, r + ( 2 * PI * rounds + 2.4 ) / 2
DRAW grid
!
! サイクロイド描画
! 関数定義
DEF xp(t) = r * ( t - SIN( t ) )
DEF yp(t) = r * ( 1 - COS( t ) )
!
LET div = 36 ! 360°を分割する数
!
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   PLOT LINES : xp(t), yp(t);
NEXT t
END

実行すると、まず半径 r の入力を求められ(初期値1)、続いて周回数 rounds の入力も求められます(初期値1.7)。

周回数は、 θ=0°~360°を一周と考えて、何周分描くか、を指定します。

グラフィックスウィンドウの大きさを、 SET WINDOW で、 rrounds を元に軌跡がウィンドウ内に収まるように設定するので、あまり rounds を大きくしない方がいいでしょう。…どうせ同じ曲線の繰り返しですし。

デフォルト値のままで描くと、次のような軌跡が描かれます。

rrounds の入力
rrounds の入力については、前回やった通り、初期値を設定し、例外も受け止め、絶対値を取っています。
行継続
JIS Full BASICでは、基本的には一行一命令なのですが、命令文を複数の行に分けることもできます。
リスト1では、 SET WINDOW 文が長くなったので二行にわけ、その行末と行頭をアンド記号( & )でつないでいます。
今回は、ブラウザ上で表示するために行継続を使いましたが、普段は特に使う必要はありません。
括弧
JIS Full BASICでは、数学と同様、括弧() )で括った部分が先に計算されます。
r * ( 2 * PI * rounds + 1.2 ) は、まず先に 2 * PI * rounds + 1.2 が計算され、それに r が掛けられます。
ただし、数学では丸括弧( () )の外側では波括弧( {} )で括ったりしますが、JIS Full BASICでは丸括弧のみが使われ、丸括弧の外側でも丸括弧で括ります。
関数
JIS Full BASICでは、関数(functionを次のように定義します。
DEF 関数名(引数1,引数2,) = 
こうして定義した関数は、組み込み関数の SINCOSABS 等と同じ感覚で使うことができます。
リスト1では、(3)を元に、点 P の座標(xP(θ),yP(θ))を
DEF xp(t) = r * ( t - SIN( t ) )
DEF yp(t) = r * ( 1 - COS( t ) )
と定義しています。
この時、半径を表す変数 r は、メインプログラムの変数 r がそのまま使われますが、引数として受け取っている、回転角θを表す変数 t の方は、関数定義内でのみ使えるローカル変数になります
変数 r は、プログラムの前半で設定されて以降は値が変わらないために、このような形で関数 xpypを定義しています。

そして、θである変数 t を0から2π×(周回数)まで変化させ、 関数 xp(t)yp(t) によって点 P の座標を得て、サイクロイドを描いています。

1.2.2. ゆっくり描く

軌跡が描かれた結果だけではなく、軌跡が描かれる経過を表現することを考えます。

リスト2. cycloid1.bas

LET div = 36 ! 360°を分割する数
LET round_time = 2 ! t=0~2π を描くのにウェイトをかける秒数
!
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   PLOT LINES : xp(t), yp(t);
   WAIT DELAY round_time / div
NEXT t
END

リスト2では、主にリスト1からの変更箇所を表示しています。

実行すると、リスト1と同じ軌跡がゆっくり描かれます。

ウェイト
WAIT DELAY 待ち時間
WAIT DELAY 文を使うことで、指定した時間(秒単位、小数可)だけウェイト(=待ち時間)を入れることが出来ます((仮称)十進BASIC独自の拡張)。
リスト2では、線を一つ引くごとに round_time/div 秒のウェイトを入れています。
つまり、リスト2の実行時間は、リスト1に比べて ( round_time / div ) × div × rounds 秒ほど余計にかかります。

ウェイトを入れることで、描画の様子をアニメーションさせるための下準備ができました。

1.3. サイクロイドの描画アニメーション

ここまでは点Pの軌跡だけを描いてきましたが、動円が回転する様子も描くことを考えます。

1.3.1. 動円を描く

まずは動円を描きます。

リスト3. cycloid2.bas
!
! サイクロイドを描く
!      Copyright(c) カイン Cain 2006
!
DECLARE EXTERNAL PICTURE circle
!
LET r = 1 ! 半径

LET round_time = 2 ! t=0~2π を描くのにウェイトをかける秒数
!
LET prev_xp = xp(0) ! 1つ前の点
LET prev_yp = yp(0)
!
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   ! 軌跡描画
   SET LINE COLOR 4
   PLOT LINES : prev_xp, prev_yp ; xp(t), yp(t)
   LET prev_xp = xp(t)
   LET prev_yp = yp(t)
   ! 動円描画
   SET DRAW MODE NOTXOR
      SET LINE COLOR 2
      DRAW circle( r * t, r, r )
      WAIT DELAY round_time / div
      DRAW circle( r * t, r, r )
   SET DRAW MODE OVERWRITE
NEXT t
END
!
! (擬似)円描画ルーチン
!
EXTERNAL PICTURE circle( xc, yc, r )
   LET div = 90
   !
   FOR t=0 TO 2 * PI STEP 2 * PI / div
      PLOT LINES : xc + r * COS( t ), yc + r * SIN( t );
   NEXT t
END PICTURE

リスト3では、主にリスト2からの変更箇所を表示しています。

(擬似)円描画ルーチンは、第1回のリスト6からコピーしています。

実行すると、次のように描画途中の動円も描かれます。

prev_xprev_y
第1回のリスト4でしたように、軌跡を描く際に、一つ前の点の座標を prev_xprev_y に記憶して線を引いています。
これは、軌跡を描く途中に動円を描くと、
PLOT LINES X座標, Y座標;
と末尾にセミコロンを置いても、動円を描く(擬似)円描画ルーチン中にも PLOT LINES 文があって、線がつながらないためです。
こういう場合、一つ前の点の座標を記憶するやり方の方が応用が利きます。
線の色
SET LINE COLOR 色番号
とすることで、描かれる線の色を変えることができます。
カラーインデックスは、0が白、1が黒、2が青、3が緑、4が赤…と、255まで使えます。
リスト3では、軌跡を色番号4の赤、動円を色番号2の青で描いています。
より細かい色の指定もできますが、今回は取り上げません。
描画モード
アニメーションするためには、一度描いた動円を消す必要があります。
しかし、動円を消す時に、既に描いた点Pの軌跡まで消えてしまっては困ります。
そんな時、描画モードNOTXORを使います。
なぜNOTXORなのかは、一応コラムに書いておきました。
NOTXORモードへは、
SET DRAW MODE NOTXOR
で移行します。
NOTXORモードでは、次のような動作をします。
  • 白地には、描こうとする色そのままの色で描かれる。
  • 白地以外のところには、描こうとする色とは異なる色で描かれる。
  • 白地であっても白地でなくても、同じ色で二度描けば、そこの色は元に戻る=消える
「二度描くと消える」というのがミソです。
これにより、アニメーションが実現できます。
リスト3では、
  1. DRAW circle(...) で動円を描く。
  2. WAIT DELAY ... でちょっと待つ。
  3. DRAW circle(...) で動円を描く=消す。
とすることで、動円のアニメーションを実現しています。
通常の上書きモードへは、
SET DRAW MODE OVERWRITE
で戻ります。

動円を動かすことで、サイクロイドがより実感できるようになりました。

描画モードNOTXOR

なぜNOTXORだと二度描いたら消えるのか、について、ざっと書いておきます。

ただ、これを理解するためには論理演算を理解しておく必要があるのですが、それをここで一から書くのは難しいので、論理演算の基礎を前提として書きます。

別に、分からなくても困ることはありません。

以下、話は0と1のみの場合で進めていきます。

論理演算NOT XOR

NOT XOR、つまり排他的論理和(exclusive or)の否定は、次のようになります。

XYX NOT XOR Y
001
010
100
111
真っ白な背景に描くとそのままの色になる

背景色Bは、白の時1であるとします。

白い背景色B=1に、ある色CでNOT XORで描くと、次のようになります。

BCB NOT XOR C=C'
100
111

実際に描かれた色をC'としています。

NOTXORで色Cで描くと、白い背景には色Cがそのまま出ていますね。

真っ白な背景でない時は?

背景色B=0の時は、次のようになります。

BCB NOT XOR C=C'
001
010

Cとは異なる色で描かれます。

赤い点Pの軌跡と青い動円が交差するところを拡大すると、色が緑になっています。

もう一度NOT XORで描くと…

Bに一度色CでNOT XORで描いてC'になったところに、もう一度色CでNOT XORで描くと、次のようになります。

BCB NOT XOR C=C'CC' NOT XOR C
10001
11111
00100
01010

C' NOT XOR C=Bになりました。

つまり、NOT XORで白地に色Cで描くと色Cになり、もう一度NOT XORで色Cで描くと、白地でもそうでなくても、元の色に戻る=消せる、ということです。

これにより、「アニメーションのための一時的な描画」が実現できます。

1.3.2. 点Pも描く

点Pの位置を、もう少し分かりやすく描きたいと思います。

リスト4. cycloid3.bas

LET prev_yp = yp(0)
!
SET POINT STYLE 5 ! 描画ポイントを示す
SET POINT COLOR 2
!
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   
      DRAW circle( r * t, r, r )
      PLOT LINES : r * t, r ; xp(t), yp(t)
      PLOT POINTS: xp(t), yp(t)
      WAIT DELAY round_time / div
      PLOT POINTS: xp(t), yp(t)
      PLOT LINES : r * t, r ; xp(t), yp(t)
      DRAW circle( r * t, r, r )
   SET DRAW MODE OVERWRITE
NEXT t

リスト4では、主にリスト3からの変更箇所を示しています。

実行すると、次のように、中心Cと点Pをつなぐ半径と、分かりにくいですが点Pのところに一応点を打っています。

点のスタイルと色
線の色は SET LINE COLOR で変えましたが、同じように点のスタイルと色は、
SET POINT STYLE スタイル番号
SET POINT COLOR 色番号
で変えます。
点のスタイルというのは、打つ点ので、JIS Full BASICでは、1:・、2:+、3:*、4:○、5:×、となります(初期値3)。
たぶん、グラフに印をつけるような用途を想定しているために、記号で点を打つ仕様になっているのだと思われます。
の方は、線の時と同じように色番号で指定しますが、線の描画色とは別に管理されます。
つまり、点の色を変えても線の色は変わりません。
中心の座標
リスト4では、
PLOT LINES : r * t, r ; xp(t), yp(t)
として、中心Cから点Pに線を引いています。
r*t,r というのは、(1)の (rθ,r) です。

アニメーションさせることで、描かれ方がだいぶ分かりやすくなりましたが、直線上を転がすだけのサイクロイドでは、さほど変化のある図形は描けませんね。

2. 外サイクロイド

外サイクロイド(epicycloid、epi-は「外」とか「上」とかの意味で、この場合は「円の外」を指します。

円の外をコロコロ転がしてできる図形です。

2.1. 外サイクロイドの式

図2*2. 外サイクロイド

図2のように、半径r2の円(動円)を、原点を中心とする半径r1の円(定円)の外側で転がすことを考えます。

外サイクロイドとは、サイクロイドと同じように、この動円の円周上の一点Pが描く軌跡です。

動円は、まずは定円の右側に接する形でスタートし、この時、点Pは定円と接する(r1,0)にあることにします。

2.1.1. θ

ここでは、図2のように、「定円から動円を見た角度」θ としています。

定円の中心と動円の中心を結んだ線とX軸がなす角、とも言えます。

図1では、θは「動円の回転角」でしたが、図2ではθは定円側にあります。

外サイクロイドの式は、このθパラメータとして、つまり、θを0°から増やしていく形で、考えていきます。

2.1.2. 動円の中心C

θをパラメータにしたので、θに対する動円の中心Cの座標を考えます。

図2を見れば、原点から見た動円の中心Cの角度は、θです。というか、それをθということにしました。

原点から動円の中心Cまでの距離は、定円の外側に動円がくっついているのだから、r1+r2になります。

というわけで、動円の中心Cの座標は、

(4)
C=((r1+r2)cosθ,(r1+r2)sinθ)

となります。

2.1.3. 中心Cから見た点Pの座標

動円の側のθ

図2のように、動円の中心CからX軸に平行に引いた線と、原点と中心Cを結んだ線も、角度θをなします。

角度φと置く

原点と中心Cを結んだ線と、中心Cと点Pを結ぶ線のなす角をφとします。

φの大きさ

サイクロイドについて、動円の中心Cの座標を考えた時のように、動円が定円上を転がった長さを考えます。

動円が0°からθまで転がる間に定円と接した部分は、図2に緑で示した部分になります。

この部分の長さは、定円側の弧についてはr1θ動円側の弧についてはr2φになります。

この2つの弧の長さは同じ長さになるので、

r1θ=r2φ

が成り立ちます。

よって、φの大きさは、

(5)
φ=(r1/r2)θ

となります。

つまり、半径r1の定円の方が半径r2の動円より大きければ、動円は小さい分より多く回転しなければならないため、φはθより大きくなります。

中心Cから見た点Pの座標
図2a*6. 外サイクロイドのCP

図2aを眺めながら、中心Cから見た点Pの座標θ+φを使って考えると、

CP=(-r2 cos(θ+φ),-r2 sin(θ+φ))

と表せます。

これに(5)を代入して

(6)
CP=(-r2 cos(θ+(r1/r2)θ),-r2 sin(θ+(r1/r2)θ))=(-r2 cos((r1+r2)/r2)θ,-r2 sin((r1+r2)/r2)θ)

が得られます。

半径r2で、θより余計に回転している、という式ですね。

2.1.4. 点Pの座標

(4)(6)から、点Pの座標は、

(7)
P=C+CP=((r1+r2)cosθ-r2 cos((r1+r2)/r2)θ,(r1+r2)sinθ-r2 sin((r1+r2)/r2)θ)

と表せます。

一見ややこしく見えますが、「中心Cの座標」の項と「中心Cから見たP」の項に分けて考えれば、それほど複雑でもありません。

2.2. 外サイクロイドを描く

2.2.1. とりあえず描く

(7)を元に、とりあえず外サイクロイドを描きます。

リスト5. epicycloid0.bas
!
! 外サイクロイドを描く
!      Copyright(c) カイン Cain 2006
!
DECLARE EXTERNAL PICTURE circle
!
! 定数設定
!  半径
LET r1 = 3 ! 定円半径
LET r2 = 1 ! 動円半径
LET prompt$="半径r1,r2を入力(デフォルト値 " &
&        & STR$(r1) & "," & STR$(r2) & ")"
WHEN EXCEPTION IN
   INPUT PROMPT prompt$ : r1,r2
USE
END WHEN
LET r1 = ABS( r1 )
LET r2 = ABS( r2 )
!  周回数
LET rounds = 5
LET prompt$="周回数を入力(デフォルト値 " & STR$(rounds) & ")"
WHEN EXCEPTION IN
   INPUT PROMPT prompt$: rounds
USE
END WHEN
LET rounds = ABS( rounds )
!
SET WINDOW - ( r1 + r2 * 2 ) * 1.2, ( r1 + r2 * 2 ) * 1.2, &
& - ( r1 + r2 * 2 ) * 1.2, ( r1 + r2 * 2 ) * 1.2
DRAW grid
!
! 定円描画
DRAW circle( 0, 0, r1 )
!
! 外サイクロイド描画
! 関数定義
DEF xp(t) = ( r1 + r2 ) * COS( t ) - r2 * COS( ( r1 + r2 ) / r2 * t )
DEF yp(t) = ( r1 + r2 ) * SIN( t ) - r2 * SIN( ( r1 + r2 ) / r2 * t )
!
LET div = 90 ! 360°を分割する数
!
! 描画
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   SET LINE COLOR 4
   PLOT LINES : xp(t), yp(t);
NEXT t
END
!
! (擬似)円描画ルーチン
!
EXTERNAL PICTURE circle( xc, yc, r )
   LET div = 90
   !
   FOR t=0 TO 2 * PI STEP 2 * PI / div
      PLOT LINES : xc + r * COS( t ), yc + r * SIN( t );
   NEXT t
END PICTURE

やや長く見えますが、これまでのプログラムと基本的な作りは同じです。

リスト5では、まだ描画アニメーションは行っていません。定円軌跡を描いているだけです。

実行すると、まずは r1,r2 の入力を求められます。入力する半径は2つになりました。

そして周回数の入力も求められ、パラメータを初期値のままにすれば、次のような図形が描かれます。

文字列変数
文字列(stringは、文字通り、「文字を並べたもの」です。
今まで扱ってきた「数値」とは、また別の種類()のデータです。
そして、その文字列を記憶する変数が文字列変数で、末尾にドル記号( $ )をつけて区別します。
リスト5では、
LET prompt$=
として、文字列変数 prompt$ への代入を行っています。
文字列定数
文字列定数(string literalというのは、プログラム中に直接かかれた文字列で、ダブルクォーテーション( " ;double quotation marksで囲みます。
"文字列定数"
リスト5では、 "半径r1,r2を入力(デフォルト値 " などの文字列定数を使っています。
ちなみに、リテラル(literalというのは、プログラム中に直接かかれたデータを指します。
英和辞典を引いた感じでは、「文字通り」とかの意味のようです。
式を計算して得られるデータではなく、プログラム中でそのまま「文字通りに」解釈されるデータ、といったところでしょうか。
今まであえて定義はしてきませんでしたが、文字列と同じように、プログラム中に直接かかれた数値(1.5とか2とか)を数値リテラル(numerical literalと言います。
STR$ 関数:数値→文字列の変換
STR$(数値)
で、数値を文字列に変換できます。
数値を表示したい時などに使います。
文字列の連結
2つの文字列をつなげて一つの文字列にしたい時は、
文字列1 & 文字列2
と、アンド記号( & )でつなげます。
リスト5では、
LET prompt$="半径r1,r2を入力(デフォルト値 " & STR$(r1) & "," & STR$(r2) & ")"
として、文字列定数と STR$ 関数の戻り値(=関数を呼び出して得られた結果)を連結しています。
INPUT PROMPT 文:入力時にメッセージも表示
INPUT PROMPT メッセージ : 変数1,変数2,…
と、 INPUT PROMPT 文を使うことで、入力時にメッセージを表示することができます。
リスト5では、 r1,r2 の入力の際に、
と、デフォルト値を表示しています。
外サイクロイドの式
リスト5
DEF xp(t) = ( r1 + r2 ) * COS( t ) - r2 * COS( ( r1 + r2 ) / r2 * t )
DEF yp(t) = ( r1 + r2 ) * SIN( t ) - r2 * SIN( ( r1 + r2 ) / r2 * t )
は、(7)をそのまま関数にしたものです。

例えば、 r1,r2 として 8,5 を入力すると、次のような図形が描かれます。

ただのサイクロイドに比べて、外サイクロイドでは、だいぶ複雑な図形が描けるようになりました。

2.2.2. 描画アニメーション

前節と同じように、外サイクロイドの描画の様子をアニメーションで描くようにします。

リスト6. epicycloid1.bas

LET div = 90 ! 360°を分割する数
LET round_time = 1 ! t=0~2π を描くのにウェイトをかける秒数
!
LET prev_xp = xp(0) ! 1つ前の点
LET prev_yp = yp(0)
!
SET POINT STYLE 5 ! 描画ポイントを示す
SET POINT COLOR 2
!
! 描画
FOR t = 0 TO 2 * PI * rounds STEP 2 * PI / div
   SET LINE COLOR 4
   PLOT LINES : prev_xp, prev_yp ; xp(t), yp(t)
   LET prev_xp = xp(t)
   LET prev_yp = yp(t)
   ! 動円描画
   SET DRAW MODE NOTXOR
      SET LINE COLOR 2
      DRAW circle( ( r1 + r2 ) * COS( t ) , ( r1 + r2 ) * SIN( t ), r2 )
      PLOT LINES : &
&        ( r1 + r2 ) * COS( t ) , ( r1 + r2 ) * SIN( t ) ; xp(t), yp(t)
      PLOT POINTS: xp(t), yp(t)
      WAIT DELAY round_time / div
      PLOT POINTS: xp(t), yp(t)
      PLOT LINES : &
&        ( r1 + r2 ) * COS( t ) , ( r1 + r2 ) * SIN( t ) ; xp(t), yp(t)
      DRAW circle( ( r1 + r2 ) * COS( t ) , ( r1 + r2 ) * SIN( t ), r2 )
   SET DRAW MODE OVERWRITE
NEXT t
END

リスト6では、主にリスト5からの変更箇所を示しています。

リスト6を実行すると、次のように描画の様子が描かれます。

prev_xprev_y に一つ前の値を記憶し、 WAIT DELAY で待ち時間を入れつつ、描画モード NOTXOR で動円を一時的に描画する、と、これまでやってきた通りです。

動円は、中心の座標は(4)、半径は r2 です。

3. 内サイクロイド

内サイクロイド(hypocycloid、hypo-はepi-の反対、「内」とか「下」とかの意味で、この場合は「円の内側」を指します。

円の内側をコロコロ転がしてできる図形です。

3.1. 内サイクロイドの式

図3*3. 内サイクロイド

図3のように、半径r2の動円を、原点を中心とする半径r1の定円の内側で転がすことを考えます。

内サイクロイドとは、サイクロイド、外サイクロイドと同じように、この動円の円周上の一点Pが描く軌跡です。

動円は、まずは定円の右側に接する形でスタートし、この時、点Pは定円と接する(r1,0)にあることにします。

3.1.1. θ

外サイクロイドの時と同じく図3のように、「定円から動円を見た角度」θ としています。

定円の中心と動円の中心を結んだ線とX軸がなす角、とも言えます。

内サイクロイドの式は、このθパラメータとして、つまり、θを0°から増やしていく形で、考えていきます。

3.1.2. 動円の中心C

θをパラメータにしたので、θに対する動円の中心Cの座標を考えます。

図3を見れば、原点から見た動円の中心Cは、角度θ、距離r1-r2になります。

というわけで、動円の中心Cの座標は、

(8)
C=((r1-r2)cosθ,(r1-r2)sinθ)

となります。

3.1.3. 中心Cから見た点Pの座標

動円の側のθ

図3のように、動円の中心CからX軸に平行に引いた線と、原点と中心Cを結んだ線も、角度θをなします。

角度φと置く

原点と中心Cを結んだ線と、中心Cと点Pを結ぶ線のなす角をφとします。

φの大きさ

外サイクロイドの時と同じように、動円が0°からθまで転がる間に定円と接した部分は、図3に緑で示した部分になり、この2つの弧の長さは同じ長さになるので、

r1θ=r2φ

が成り立ちます。

よって、φの大きさは、

(9)
φ=(r1/r2)θ

となります。

中心Cから見た点Pの座標
図3a*7. 内サイクロイドのCP

図3aを眺めながら、中心Cから見た点Pの座標φ-θを使って考えると、

(12)
CP=(r2 cos(φ-θ),-r2 sin(φ-θ))

と表せます。

これに(9)を代入して

(10)
CP=(r2 cos(θ-(r1/r2)θ),-r2 sin((r1/r2)θ-θ))=(r2 cos((r1-r2)/r2)θ,-r2 sin((r1-r2)/r2)θ)

が得られます。

3.1.4. 点Pの座標

(8)(10)から、点Pの座標は、

(11)
P=C+CP=((r1-r2)cosθ+r2 cos((r1-r2)/r2)θ,(r1-r2)sinθ-r2 sin((r1-r2)/r2)θ)

と表せます。

外サイクロイドの(7)と、よく似た形の式です。

3.2. 内サイクロイドの描画

リスト6を元に、内サイクロイドを描きます。

リスト7. hypocycloid0.bas
!
! サイクロイドを描く

LET rounds = ABS( rounds )
!
IF r1 > r2 THEN
   SET WINDOW - r1 * 1.2, r1 * 1.2, - r1 * 1.2, r1 * 1.2
ELSE
   SET WINDOW - ( r2 + ( r2 - r1 ) ) * 1.2, ( r2 + ( r2 - r1 ) ) * 1.2, &
&   - ( r2 + ( r2 - r1 ) ) * 1.2, ( r2 + ( r2 - r1 ) ) * 1.2
END IF
DRAW grid
!
! サイクロイド描画
! 関数定義
DEF xp(t) = ( r1 - r2 ) * COS( t ) + r2 * COS( ( r1 - r2 ) / r2 * t )
DEF yp(t) = ( r1 - r2 ) * SIN( t ) - r2 * SIN( ( r1 - r2 ) / r2 * t )

      DRAW circle( ( r1 - r2 ) * COS( t ) , ( r1 - r2 ) * SIN( t ), r2 )
      PLOT LINES : &
&        ( r1 - r2 ) * COS( t ) , ( r1 - r2 ) * SIN( t ) ; xp(t), yp(t)
      PLOT POINTS: xp(t), yp(t)
      WAIT DELAY round_time / div
      PLOT POINTS: xp(t), yp(t)
      PLOT LINES : &
&        ( r1 - r2 ) * COS( t ) , ( r1 - r2 ) * SIN( t ) ; xp(t), yp(t)
      DRAW circle( ( r1 - r2 ) * COS( t ) , ( r1 - r2 ) * SIN( t ), r2 )

リスト7では、主にリスト6からの変更箇所を示しています。

書き換わっているのは、グラフィックウィンドウの設定、関数xpとyp、中心Cの座標、といったところです。

リスト7を実行すると、次のように描かれていきます。

IF
条件付けをして処理を分けたい時には、 IF 文を使います。
IF 条件 THEN
   条件が「真(true)」の時に実行されるプログラム
ELSE
   条件が「偽(false)」の時に実行されるプログラム
END IF
という構文になります。
条件が「偽(false)」の場合に何もしないのであれば、 ELSE 以下を省略して
IF 条件 THEN
   条件が「真(True)」の時に実行されるプログラム
END IF
とも書けます。
条件
条件は、結果が真(true偽(falseのどちらかになる式で書かれます。それ以外の結果にはなりません(例外の発生を除く)。
「真」か「偽」か、なんてのは、日常生活ではあまり使わない表現ですが、条件付け自体は、日常の中で常に行っています。YES/NOと読み替えても構いません。
例えば、日常生活の中では、次のような条件付けを行うこともあるでしょう。
IF 炊飯器のスイッチは入っている THEN
   おかずを調理する ! 炊飯器のスイッチが入っている場合
ELSE
   あわてて炊飯器のスイッチを入れる ! 炊飯器のスイッチが入っていない場合
END IF
そういう判断を、プログラムの中で行います。
このような、「真」か「偽」かの演算を、論理演算(logical operationあるいはブール演算(boolean operationと言います。
「ブール」は、数学者の名前です。
関係演算
関係演算(relational operationは、2つの式の大小関係を表すもので、つまりは数学で使う等号や不等号のことです。
仮に
LET a = 5
としたものとして、見ていきます。
関係演算には、次のものがあります。
  • = :等しい。数学の=と同じ。「 a=5 」は真、「 a=7 」は偽。代入文に出てくる = とは別物。
  • <> :等しくない。数学の≠と同じ。「 a<>8 」は真、「 a<>5 」は偽。
  • < :小なり。数学の<と同じ。「 a<8 」は真、「 a<3 」も「 a<5 」も偽。
  • > :大なり。数学の>と同じ。「 a>3 」は真、「 a>8 」も「 a>5 」も偽。
  • <= :小なりイコール。数学の≦と同じ。「 a<=8 」も「 a<=5 」も真、「 a<=3 」は偽。
  • >= :大なりイコール。数学の≧と同じ。「 a>=3 」も「 a>=5 」も真、「 a>=8 」は偽。
リスト7IF
リスト7IF 文を見てみます。
IF r1 > r2 THEN
   SET WINDOW - r1 * 1.2, r1 * 1.2, - r1 * 1.2, r1 * 1.2
ELSE
   SET WINDOW - ( r2 + ( r2 - r1 ) ) * 1.2, ( r2 + ( r2 - r1 ) ) * 1.2, &
&   - ( r2 + ( r2 - r1 ) ) * 1.2, ( r2 + ( r2 - r1 ) ) * 1.2
END IF
まず、 r1 > r2 で、定円の半径 r1 の方が大きい場合そうでない場合に分けています。
定円の方が大きければ、内サイクロイドは定円の中に収まるので、グラフィックウィンドウの大きさは r1 のみで決めています。
定円の方が小さい時(例えば、 r1,r21,3 )は下の図のようになるので、ウィンドウサイズの基準を±(r2+(r2-r1))としています。
実際の定規等であれば、「動円が定円より大きい内サイクロイド」を描くのは難しいのですが、これはプログラムなので、そういったものも自由に描けます。*4

例えば、 r1,r28,5 とすると、次のような図形が描かれます。

かなり色々描けるようになったところで、今回はここまで。

もうちょっとで、スピログラフに辿り着きます。

あと、外サイクロイド・内サイクロイド共に、何周かすれば点Pは最初の位置に戻るわけですが、それに必要な周回数には、一応それなりの法則があります。これについても、また次回。

たとえば…
サイクロイド

リスト4を、中心CのX座標 xc についてループを組むようにすると、どう書けるでしょうか。

ただし、(1)から、xc=rθ、つまりθ=xc/rです。

外サイクロイド

リスト6を、θではなくφについてループを組むようにすると、どう書けるでしょうか。

(5)を逆にして(6)に代入すれば、必要な式を求めることができます。

内サイクロイド

リスト7を、やはりθではなくφについてループを組むようにすると、どう書けるでしょうか。

内サイクロイドの性質

内サイクロイドでは、 r1=5,r2=3r1=5,r2=2 は同じ形の曲線になります。

片方を(11)に代入し、θ=ほにゃららθ' と置けば、もう一方と同じ形の式が得られます。

このことから、一般に、内サイクロイドの形とr1、r2について、どのような性質が予想できるでしょうか。(参考文献[3]に出ています。)

またこの時、θとθ'はどのような関係になるでしょうか。

ただし、cos(-θ)=cosθ、sin(-θ)=-sinθです。

あえて「予想できるでしょうか」と書いたのは、こういうのって、いきなり論理的に導き出せるものではないからです。
いろいろやっていく中で、「あれ?」という「引っかかり」から発見は生まれ、発見から理論が生まれます。
そういう、いろいろやっていく「遊び」の部分って、大事だと思います。
外サイクロイドと内サイクロイド

r1=5,r2=3,rounds=3で描いた外サイクロイドと、r1=5,r2=8,rounds=8で描いた内サイクロイドは、同じ図形になります。

(7)(11)にそれぞれ代入すれば、確認できます。

このことから、一般に、外サイクロイドと内サイクロイドが同じ図形になる条件は、どう予想できるでしょうか。

またこの時、同じ座標の点Pに対する外サイクロイドのθ(θeと置きます)と内サイクロイドのθ(θhと置きます)の間には、どのような関係があるでしょうか。

『スピログラフ』 第2回 サイクロイド (続く…)
【まとめ】
  1. ファイル庫/Spiro/figure/fig-cycloid.odg(OpenOffice.org Draw)にて出力。
  2. ファイル庫/Spiro/figure/fig-epicycloid.odg(OpenOffice.org Draw)にて出力。
  3. ファイル庫/Spiro/figure/fig-hypocycloid.odg(OpenOffice.org Draw)にて出力。
  4. 普通、内サイクロイドと言えば r1>r2 なのかもしれませんが、ここではあえて r1<r2 もあり得ることにしています。その方が、ちょっとだけ面白そうだからです。
  5. ファイル庫/Spiro/figure/fig-cycloid-sincos.odg(OpenOffice.org Draw)にて出力。
  6. ファイル庫/Spiro/figure/fig-epicycloid-sincos.odg(OpenOffice.org Draw)にて出力。
  7. ファイル庫/Spiro/figure/fig-hypocycloid-sincos.odg(OpenOffice.org Draw)にて出力。
参考文献
[1]. (仮称)十進BASIC オンラインヘルプ
[2]. Wikipedia「サイクロイド」項目
[3]. サイクロイドとスピログラフ(http://www.geocities.jp/sgwr0/sp/sp.html)
inserted by FC2 system