Mokkosuで内トロコイド


「(本名)くん、Mokkosu  を書こうよ」
というわけで Mokkosu 内トロコイドを書くことになった。
#1 作ってみた
![trochoid.jpg](https://qiita-image-store.s3.amazonaws.com/0/72592/613d50ef-5f85-1c01-4b7a-ca2ec64bf6bc.jpeg)


実装したのは以下の機能
・ 内側、外側、描画点のサイズの変更
・ 各サイズのリセット
・ カラフルな線

#2 ソースコード
```Mokkosu:trochoid.mok

# ここにコードを入力して、上の緑色の三角を押すと実行できます。
include "Graphics.mok";
include "List.mok";
include "Print.mok";

let map_tup3 f (x,y,z) = (f x, f y, f z);
let rc = ref 100;
let rm = ref 50;
let rd = ref 10;

let cwheel i =
    {
    _ ? i < 30 -> call Color::get_Red();
    _ ? i < 60 -> call Color::get_OrangeRed();
    _ ? i < 90 -> call Color::get_Orange();
    _ ? i < 120 -> call Color::get_Gold();
    _ ? i < 159 -> call Color::get_Yellow();
    _ ? i < 180 -> call Color::get_GreenYellow();
    _ ? i < 210 -> call Color::get_Green();
    _ ? i < 240 -> call Color::get_DarkBlue();
    _ ? i < 270 -> call Color::get_Blue();
    _ ? i < 300 -> call Color::get_BlueViolet();
    _ ? i < 330 -> call Color::get_Violet();
    _ ? i < 360 -> call Color::get_Magenta();
    _ -> error "alien."
    }
    ();
let get_pen n =
    let color =
        cwheel n
    in
    new Pen(color,3);

let get_pos rc rm rd =
    let dr = rc -. rm in
    for theta <- 0 .. 360;
    in
    let dth = int_to_double theta /. pi2 in
    let x = dr *. cos dth +. rd *. cos (dr /. rm *. dth) +. 150.0 in
    let y = dr *. sin dth -. rd *. sin (dr /. rm *. dth) +. 150.0 in
    (double_to_int x, double_to_int y);
    

do set_size 600 300;


## Create Labels
let inner_circle_label = new Label ();
let outer_circle_label = new Label ();
let draw_circle_label = new Label ();
let inner_circle_label_dis = new Label ();
let outer_circle_label_dis = new Label ();
let draw_circle_label_dis = new Label ();

do inner_circle_label.set_Location(new Point(300,100));
do inner_circle_label.set_Text("Inner circle");
do outer_circle_label.set_Location(new Point(400,100));
do outer_circle_label.set_Text("Outer circle");
do draw_circle_label.set_Location(new Point(500,100));
do draw_circle_label.set_Text("Drawing point");

do inner_circle_label_dis.set_Location(
    new Point(inner_circle_label.get_Left(),
    inner_circle_label.get_Height() + inner_circle_label.get_Top() + 10)
    );
do inner_circle_label_dis.set_Text(!rm |> to_string);
do outer_circle_label_dis.set_Location(
    new Point(outer_circle_label.get_Left(),
    outer_circle_label.get_Height() + outer_circle_label.get_Top() + 10)
    );
do outer_circle_label_dis.set_Text(!rc |> to_string);
do draw_circle_label_dis.set_Location(
    new Point(draw_circle_label.get_Left(),
    draw_circle_label.get_Height() + draw_circle_label.get_Top() + 10)
    );
do draw_circle_label_dis.set_Text(!rd |> to_string);

## Create buttons
let up_inner_circle = new Button ();
let down_inner_circle =  new Button ();
let up_draw_point = new Button ();
let down_draw_point = new Button ();
let up_outer_circle = new Button ();
let down_outer_circle =  new Button ();
let reset_button = new Button ();

do up_inner_circle.set_Text("Up");
do up_inner_circle.set_Location(
    new Point(inner_circle_label_dis.get_Left(), 
    inner_circle_label_dis.get_Height() + inner_circle_label_dis.get_Top() + 10)
    );
do down_inner_circle.set_Text("Down");
do down_inner_circle.set_Location(
    new Point(up_inner_circle.get_Left(),
              up_inner_circle.get_Height() + up_inner_circle.get_Top() + 10)
    );
do up_outer_circle.set_Text("Up");
do up_outer_circle.set_Location(
    new Point(outer_circle_label_dis.get_Left(), 
    outer_circle_label_dis.get_Height() + outer_circle_label_dis.get_Top() + 10)
    );
do down_outer_circle.set_Text("Down");
do down_outer_circle.set_Location(
    new Point(up_outer_circle.get_Left(),
              up_outer_circle.get_Height() + up_outer_circle.get_Top() + 10)
    );
do up_draw_point.set_Text("Up");
do up_draw_point.set_Location(
    new Point(draw_circle_label_dis.get_Left(), 
    draw_circle_label_dis.get_Height() + draw_circle_label_dis.get_Top() + 10)
    );
do down_draw_point.set_Text("Down");
do down_draw_point.set_Location(
    new Point(up_draw_point.get_Left(),
              up_draw_point.get_Height() + up_draw_point.get_Top() + 10)
    );
do reset_button.set_Text("Reset");
do reset_button.set_Location(
    new Point(up_inner_circle.get_Left(),
              down_inner_circle.get_Height () + down_inner_circle.get_Top() + 10
             ));

# EventHandlers
let err () =
    "Outer circle must be greater than or equal to Inner circle. Please change other parameters."
    |> msgbox;
let up_inner_circle_event ((sender : {Object}), (e : {EventArgs})) =
    do
    if !rm + 10 >= !rc ->
        do 
        rm := !rc;
        err ();
        end
    else rm :=  !rm + 10;
    inner_circle_label_dis.set_Text(!rm |> to_string);
    redraw ();
    end;
let down_inner_circle_event ((sender : {Object}), (e : {EventArgs})) =
    do 
    if !rm > 10 -> rm := !rm - 10
    else rm := 0;
    inner_circle_label_dis.set_Text(!rm |> to_string);
    redraw ();
    end;
let up_outer_circle_event ((sender : {Object}), (e : {EventArgs})) =
    do  
    rc :=  !rc + 10;
    outer_circle_label_dis.set_Text(!rc |> to_string);
    redraw ();
    end;
let down_outer_circle_event ((sender : {Object}), (e : {EventArgs})) =
    do 
    if !rc <= 10 -> rc := 10
    else if !rm >= !rc - 10 ->
        do
        rc := !rm; 
        err ();
        end
    else rc := !rc - 10;
    outer_circle_label_dis.set_Text(!rc |> to_string);
    redraw ();
    end;
let up_draw_point_event ((sender : {Object}), (e : {EventArgs})) =
    do
    rd :=  !rd + 10;
    draw_circle_label_dis.set_Text(!rd |> to_string);
    redraw();
    end;
let down_draw_point_event ((sender : {Object}), (e : {EventArgs})) =
    do 
    rd := !rd - 10;
    draw_circle_label_dis.set_Text(!rd |> to_string);
    redraw ();
    end;
let reset_ev ((sender : {Object}), (e : {EventArgs})) =
    do
    rc := 100;
    rm := 100;
    rd := 100;
    inner_circle_label_dis.set_Text(!rm |> to_string);
    outer_circle_label_dis.set_Text(!rc |> to_string);
    draw_circle_label_dis.set_Text(!rd |> to_string);
    redraw ();
    end;

## Set EventHandler
do up_inner_circle.add_Click (delegate EventHandler up_inner_circle_event);
do down_inner_circle.add_Click (delegate EventHandler down_inner_circle_event);
do up_outer_circle.add_Click (delegate EventHandler up_outer_circle_event);
do down_outer_circle.add_Click (delegate EventHandler down_outer_circle_event);
do up_draw_point.add_Click (delegate EventHandler up_draw_point_event);
do down_draw_point.add_Click (delegate EventHandler down_draw_point_event);
do reset_button.add_Click (delegate EventHandler reset_ev);

## Add labels and buttons to Form
do _form.get_Controls().Add(inner_circle_label);
do _form.get_Controls().Add(outer_circle_label);
do _form.get_Controls().Add(draw_circle_label);
do _form.get_Controls().Add(inner_circle_label_dis);
do _form.get_Controls().Add(outer_circle_label_dis);
do _form.get_Controls().Add(draw_circle_label_dis);
do _form.get_Controls().Add(up_inner_circle);
do _form.get_Controls().Add(down_inner_circle);
do _form.get_Controls().Add(up_outer_circle);
do _form.get_Controls().Add(down_outer_circle);
do _form.get_Controls().Add(up_draw_point);
do _form.get_Controls().Add(down_draw_point);
do _form.get_Controls().Add(reset_button);


do scene "main" {
    ~Draw(gr) -> 
        let pos = get_pos (int_to_double !rc) (int_to_double !rm) (int_to_double !rd) in
        iteri (\n (x,y) -> 
                if n <> 360 -> 
                  (uncurry (draw_line gr (get_pen n) x y))
                    (nth pos (n+1))) pos;    _ -> ();
};



do show_window "main" |> ignore;

```

#3 おわりに
100行くらいで書けるかなと思っていたがそう甘くはなかった。
あと .NET で少し躓いたがある程度慣れたかなと。