見出し画像

プログラミング:正方形を回転する

学年末試験の作成やら,友人が出した課題で,Pythonはちょっとおやすみ。

友人が出した課題とは,

正方形を直線上をコロコロ転がして、その1つの頂点の軌跡を求める問題がありますが、これをスライダーとかアニメとかで、わかりやすく表現できるソフト(アプリ)って、ありましたっけ?
 あるいは、作るとしたら、どんなツールや言語が便利でしょうかね?
 白板ソフト、Cinderella、Geogebra、スクラッチ、Unity、Javascript、Lazarus、10進Basic、Ruby/Tk・・・
 三角形や円などのいろんな図形、あるいは自分で描いた図形で、好きな点を動点にして、それをスライダーなどで動かせたら最高ですが、そこまで行かなくても大丈夫です。
 良いアイデアあれば、お願いします。

これに応募して,早速マイクロワールドEXでアニメーションを作った人がいた。
それならば,というわけで,手慣れたCinderellaでスライダ版を作成。

まず,作図ツールでスライダを作る。線分を1本描き,その上に点を乗せると,この点は線分上だけを動かすことができる。

画像1

これを使って回転角を取得し,図を描く。まずこの図。

画像2

軌跡は円の一部。正方形は複素数を使えば簡単に描ける。あとのことを考えて,軌跡を描くものと,正方形を描くものは関数にしておく。

// [p1,0]を中心に時計回りにth回転した1辺rの正方形を描く
// 戻り値は回転した点の座標
box(th):=(
    z1 = complex([no*r,0]);
    z2 = z1+r*(cos(pi-th)+i*sin(pi-th));
    z3 = z2+(z1-z2)*i;
    z4 = z1-(z2-z1)*i;
    p1 = gauss(z1);
    p2 = gauss(z2);
    p3 = gauss(z3);
    p4 = gauss(z4);
    drawpoly([p1,p2,p3,p4]);
    p2;
);
// 点の軌跡を描く
locus1(px,rd,th):=(
    end = pi;
    st = pi - th;
    plot([rd*cos(t)+px,rd*sin(t)],start->st,stop->end,steps->100,size->2);
);
// スライダから角を取得して図を描く
theta = |A,C|/r*pi/2;
if(theta<=pi/2,
    locus1(r,r,theta);
    P.xy = box(theta);
);

次はこの図。

画像3

こんどは,円の半径がルート2倍になる。点の位置は,書き初めの頂点p1から数えるとp3になる。
そこで,box() 関数に引数:何番目の図かを追加し,戻り値をそれに応じて変えるように修正する。

 といった調子で書いていく。できあがった「ベタ」のプログラムはこうなった。

r = 4;   // 一辺の長さ
// [p1,0]を中心に時計回りにth回転した1辺rの正方形を描く
// 戻り値は回転した点の座標
box(no,th):=(
    z1 = complex([no*r,0]);
    if(no == 1,th = theta);
    if(no == 2,th = theta-pi/2);
    if(no == 3,th = theta-pi);
    z2 = z1+r*(cos(pi-th)+i*sin(pi-th));
    z3 = z2+(z1-z2)*i;
    z4 = z1-(z2-z1)*i;
    p1 = gauss(z1);
    p2 = gauss(z2);
    p3 = gauss(z3);
    p4 = gauss(z4);
    drawpoly([p1,p2,p3,p4]);
    if(no==1,ret=p2);
    if(no==2,ret=p3);
    if(no==3,ret=p4);
    if(no==4,ret=p1);
    ret;
);
locus1(px,rd,th):=(
    end = pi;
    st = pi - th;
    plot([rd*cos(t)+px,rd*sin(t)],start->st,stop->end,steps->100,size->2);
);
locus2(px,rd,th):=(
    end = pi*3/4;
    st = pi*5/4 - th;
    plot([rd*cos(t)+px,rd*sin(t)],start->st,stop->end,steps->100,size->2);
);
locus3(px,rd,th):=(
    end = pi/2;
    st = 3*pi/2 -th;
    plot([rd*cos(t)+px,rd*sin(t)],start->st,stop->end,steps->100,size->2);
);
// ここから,角の取得と描画
theta = |A,C|/r*pi/2;
if(theta<=pi/2,
    locus1(r,r,theta);
    P.xy = box(1,theta);
);
    if(pi/2<theta & theta<=pi,
    locus1(r,r,pi/2);
    locus2(2*r,r*sqrt(2),theta);
    P.xy = box(2,theta-pi/4);
);
if(pi<theta & theta<=3*pi/2,
    locus1(r,r,pi/2);
    locus2(2*r,r*sqrt(2),pi);
    locus3(3*r,r,theta);
    P.xy = box(3,pi-theta);
);

「ベタ」のプログラム,という意味は,このあと整理すれば全体を短くすることができる,という意味だ。よく見るとちょっとおかしなところもあり,それも修正する。

続いて,1辺の長さが同じ正三角形上を転がすものも作った。軌跡はやはり円の一部なので,plot()関数で描ける。一度要領がわかってしまえば少し変えるだけでできた。