例 - Cinderella Documentation
Description: The user's guide to the Interactive Geometry Software Cinderella

コンテンツにスキップ

# 例

## 小さなプログラム例

この節では、CindyScript を使った小さなプログラムの例をあげます。それぞれの例は、CindyScript でいろいろなものの取り扱いかたを示します。

### 重心

３つの点の重心 D を設定します。状況により色が変わるようにします。この例では、点Dのx座標の正負により色が変わります。

    //in draw
    D.xy=(A+B+C)/3;
    D.color=if(D.x>0,
       (1,1,0),
       (0,0,1)
    )

// in draw　とあるのは、Drawスロットに書く、という意味です。

このコードは順番に実行されます。点Dの位置を計算して `D.xy` に代入することでDの位置が決まります。点Dの色はＤの位置によって if 文で設定されます。

### 選択と集積

x軸の上下で点を分類してネットワーク状に線で結びます。適当に点をいくつかとっておいて次のスクリプトをdrawスロットに書いて実行します。

    //in draw
    pts=allpoints();
    above=select(pts,p,p.y>0);
    below=pts--above;
    segs=pairs(above);
    drawall(segs,color->(0.6,0,0));
    segs=pairs(below);
    drawall(segs,color->(0,0.6,0))

x軸より上の点を`select` 演算子により選びだします。それを全体から引くとx軸より下の点が得られます。 `pairs`演算子で点を２つずつ結びます。

### 凸型外殻の描画

すべての点を内部に含む凸型の外殻を描きます。数の不安定性に対処する`~>`演算子の働きを見てください。

    //in draw
    pts=allpoints();
    leftof(A,B):=select(pts,p,area(A,B,p)~>0);
    rightof(A,B):=select(pts,p,area(A,B,p)~<0);

    isedge(A,B):=(leftof(A,B)==[]%rightof(A,B)==[]);
    segments=pairs(pts);
    hull=select(segments,seg,isedge(seg_1,seg_2));
    drawall(hull);

凸型外殻の計算は非常にうまい幾何学的原則によってなされます。凸型外殻の中にすべての点が入ります。 `leftof` と `rightof` というユーザー定義関数は線分ABのどちら側にあるかで点を分類します。さらにこれを用いて `isedge` を定義し２つの点のペアが凸型外殻の端となるかどうかを調べます。ここで、あいまいな比較 `~<0` の使い方に着目してください。最後に、すべての端の線を描画します。

### アナログ時計

時針、分針、秒針をもったアナログ時計を作ります。まず、原点を始点とする3つの矢線を描いておきます。その終点をB,C,Dとします。それから次のスクリプトを Timer Tick スロットに書いて実行します。

    //in timerstep
    t=time();

    p(x):=(sin(2*pi*x),cos(2*pi*x));
    B.xy=p(t_3/60)*4;
    C.xy=p(t_2/60)*5;
    D.xy=p((t_1*60+t_2)/(12*60))*3.5;

    apply(1..12,i,draw(p(i/12)*5));
    apply(1..60,i,draw(p(i/60)*5,size->1));

    drawtext((3,5),t);

点はスクリプトで描きます。時計盤の円は「円を描く」モードで描いておきます。この時計は、 `time` 関数がコンピュータのシステム時間にアクセスするのを利用しています。ｔがリストであることを利用して秒針は1秒ごとに動くようになっています。

### 最短距離にある点

点Aに最も近い点を緑の円で囲んで示します。

    //in draw
    pts=allpoints();
    s=sort(pts,|#-A|);
    p=s_2;
    draw(p,size->20);

上のコードではA自身が最短になるために、距離で並べ替えた後、2番目に近いものをとっています。もうひとつの方法は、あらかじめ点Aを除外しておくものです。次のコードをご覧ください。

    //in draw
    pts=allpoints()--[A];
    s=sort(pts,|#-A|);
    p=s_1;
    draw(p,size->20);

### 簡単な模様

点を動かして簡単な模様を描きます。線の色は点の色がそのまま使われます。まず、点をいくつかとり、色を変えておきます。（下図では3つ）//in draw 以下のスクリプトを Drawスロットに、// in init 以下を Initializationスロットに書いて実行します。

    //in draw
    forall(pts,p,
       p:"trace"=p:"trace" ++ [p.xy]
    );

    ![](../assets/wiki_up/Ex6.png)

    tr0=[[1,0],[0,1]];
    tr1=[[-1,0],[0,1]];
    tr2=[[-1,0],[0,-1]];
    tr3=[[1,0],[0,-1]];

    trs=[tr0,tr1,tr2,tr3];

    forall(trs,t,
     forall(pts,p,
       connect((p:"trace")*t,color->p.color,size->2);
     );
    );

    //in init
    pts=allpoints();
    forall(pts,p,p:"trace"=[]);

変数 `"trace"` に、自分自身の軌跡がどんどん追加されていくことを見てください。

### 回帰直線

すべての点に対する回帰直線を描きます。最小2乗法により正方形を描いていきます。

    //in draw

    //Least-square line
    pts=allpoints();
    m=apply(pts,(1,#.x));
    y=apply(pts,#.y);
    ma=transpose(m)*m;

    ![](../assets/wiki_up/Ex7.png)
    mb=transpose(m)*y;
    mainv=inverse(ma);
    v=mainv*mb;
    f(x):=v_2*x+v_1;
    plot(f(x));

    //Draw the squares

    sq(x,y1,y2):=(
       d=y2-y1;
       p=((x,y1),(x,y2),(x+d,y2),(x+d,y1),(x,y1));
       drawpoly(p,color->(1,0.5,0.5),alpha->0.4);
       connect(p,color->(.8,0,0));
    );

    forall(pts,sq(#.x,#.y,(f(#.x))));

このコードでは、回帰直線を見つけるために高度な行列計算をしています。

### ひまわり

チュートリアルのひまわりよりちょっといい方法です。

    //in draw
    n=round(100*|B,E|);

    ![](../assets/wiki_up/Ex8.png)
    d=0.01*(|D,F|/|D,C|-.5);
    ang=137.508°+d;
    repeat(n,i,
      w=ang*i;
      r=sqrt(i)*.2;
      p=(sin(w),cos(w))*r;
      draw(p,color->(1,0.8,0));
    );
    drawtext((-5,-6),"n="+n);
    drawtext((0,-6),"w="+180*ang/pi+"?");

このコードは、ヒマワリが成長するときに現れる特定の角度 `ang=137.508deg.`を用いています。

### 関数プロット

関数式を自由に入力してそのグラフを描きます。

    //in draw

    //Parameter sliders
    a=K.x;
    b=L.x;
    c=M.x;
    d=N.x;
    drawtext(K+(0.2,0.2),"a="+a);
    drawtext(L+(0.2,0.2),"b="+b);
    drawtext(M+(0.2,0.2),"c="+c);
    drawtext(N+(0.2,0.2),"d="+d);

    //Parse and plot
    f(x):=parse(Text0.val);
    plot(f(x),color->red(0.6),size->2);

関数式は、シンデレラの文字入力ボタンで "Text0'' のところに書きます。これを直接解釈し、上のスライダできまる係数を使ってグラフを描きます。

### 色をまぜる

3つの点A,B,Cを赤、緑、青の電球としましょう。この３つの色の混ざり具合をシミュレートします。

    //in draw

    colorplot(
     (1-|#,A|/4,
      1-|#,B|/4,
      1-|#,C|/4),
     (-5,-5),(5,5),pxlres->3
    )

このカラーミキサーは実に単純です。 `colorplot` 関数が、平面上の各点における色の混ざり具合を計算します。

##

### ジュリア集合

フラクタルとして有名なジュリア集合です。複素数平面上の点Ｃが表す複素数によって計算されます。

    //in draw

    g(z,c):=z^2+c;

    julia(z):=(
      iter=0;
      while(iter<100 & |z|<2,
        z=g(z,complex(C.xy));
        iter=iter+1;
      );
      1-iter/100;
    );

    colorplot(julia(complex(#))
       ,A,B,startres->16,pxlres->1);

ここでも `colorplot` 関数が大きな役割を果たします。上のコードで定義されている `julia` 関数は、各点の色を反復的に計算します。`startres` と `pxlres` 修飾子を使うことでより細かい図を描くことができます。

### 群れのシミュレーション

魚の群れをシミュレートします。それぞれの魚は隣の魚と同じ方向でしかもその場所に泳ごうとします。すべての魚は点Uによって与えられる障害を避けなければなりません。

    //in draw

    ms=allmasses()--[U];
    lim=0.5;
    apply(ms,m,
      near=select(ms,p,|p-m|<4);
      avg=sum(near,m,m.v)/length(near);
      m.v=m.v+.2*(avg);
      if(|m.v|>lim,m.v=lim*m.v/|m.v|)
      //Draw connections
      apply(near,draw(#,m,color->(0,0,0),alpha->0.2));
    );

ここで、魚と障害物は正電荷を帯びた粒子としてモデル化されます。これにより、魚は互いに押しのけあいます。スクリプトはそれぞれの点の速度を設定します。