Files
comp3958/tinker/cube.ml
T

230 lines
4.7 KiB
OCaml

open Graphics;;
let window_w = 800.;;
let window_h = 800.;;
let screen_space (x, y) =
(
int_of_float ((x +. 1.) /. 2. *. window_w),
int_of_float ((1. -. (y +. 1.) /. 2.) *. window_h)
);;
let project (x, y, z) =
(x /. z, y /. z);;
let rotate_y (x, y, z) angle =
let ox = x in
let oz = z in
(
ox *. cos(angle) -. oz *. sin(angle),
y,
ox *. sin(angle) +. oz *. cos(angle)
);;
let rotate_x (x, y, z) angle =
let oy = y in
let oz = z in
(
x,
oy *. cos(angle) -. oz *. sin(angle),
oy *. sin(angle) +. oz *. cos(angle)
);;
let translate_z (x, y, z) dz =
(x, y +. 0.175, z +. dz);;
(* CUBE *)
let vertecies = [
(0.3, 0.3, 0.3);
(-0.3, 0.3, 0.3);
(-0.3, -0.3, 0.3);
( 0.3, -0.3, 0.3);
(0.3, 0.3, -0.3);
(-0.3, 0.3, -0.3);
(-0.3, -0.3, -0.3);
(0.3, -0.3, -0.3)
];;
let faces = [
(0, 1, 2, 3); (* front *)
(4, 5, 6, 7); (* back *)
(0, 1, 5, 4); (* top *)
(2, 3, 7, 6) (* bottom *)
];;
let draw_line va vb =
let va = project va in
let vb = project vb in
let (x1, y1) = screen_space va in
let (x2, y2) = screen_space vb in
moveto x1 y1;
lineto x2 y2;
();;
let rec get_vertex v i =
match v with
| [] -> (0., 0., 0.)
| x :: xs ->
if i = 0 then x
else get_vertex xs (i - 1);;
let draw_face (a, b, c, d) angle =
let va = (get_vertex vertecies a) in
let vb = (get_vertex vertecies b) in
let vc = (get_vertex vertecies c) in
let vd = (get_vertex vertecies d) in
let va = rotate_y va angle in
let vb = rotate_y vb angle in
let vc = rotate_y vc angle in
let vd = rotate_y vd angle in
let va = rotate_x va angle in
let vb = rotate_x vb angle in
let vc = rotate_x vc angle in
let vd = rotate_x vd angle in
let va = translate_z va 1.25 in
let vb = translate_z vb 1.25 in
let vc = translate_z vc 1.25 in
let vd = translate_z vd 1.25 in
draw_line va vb;
draw_line vb vc;
draw_line vc vd;
draw_line vd va;;
let rec draw_cube faces angle =
match faces with
| [] -> ()
| (a, b, c, d) :: fs ->
draw_face (a, b, c, d) angle;
draw_cube fs angle;;
(* END CUBE *)
(* SPHERE *)
let stacks = 10;;
let slices = 12;;
let radius = 0.175;;
let gen_sphere_vertecies st sl r =
let rec gen_slice j sp cp sv =
if j = -1 then sv
else
let theta = 2. *. 3.1415926 *. float_of_int j /. float_of_int (sl) in
let sinTheta = sin theta in
let cosTheta = cos theta in
gen_slice (j - 1) sp cp ((r *. cosTheta *. sp, r *. cp, r *. sinTheta *. sp) :: sv)
in
let rec gen_stack i sv =
if i = -1 then sv
else
let phi = 3.1415926 *. float_of_int i /. float_of_int (st - 1) in
let sinPhi = sin phi in
let cosPhi = cos phi in
gen_stack (i - 1) (gen_slice (sl - 1) sinPhi cosPhi sv)
in
gen_stack (st - 1) [];;
let s_vertecies = gen_sphere_vertecies stacks slices radius;;
let draw_ellipse ev o =
let f = match ev with
| [] -> (0., 0., 0.)
| a :: _ -> a in
let rec iter_vertex l v =
match v with
| [] -> l
| [a] -> draw_line a l; a
| [a; b] -> draw_line a b; b
| a :: b :: vs ->
draw_line a b;
iter_vertex b (b :: vs)
in
let l = iter_vertex (0., 0., 0.) ev in
if o then draw_line f l;;
let rec get_nth_vert e n =
match e with
| [] -> failwith "cannot find nth vertex"
| x :: xs ->
if n = 0 then x
else get_nth_vert xs (n - 1);;
let draw_sphere v st sl =
let rec render_slices i =
let rec iter_slices j e =
if j = (sl - 1) then e
else
iter_slices (j + 1) (get_nth_vert v (i * sl + j) :: e)
in
let e = iter_slices 0 [] in
draw_ellipse e true;
if i = st - 1 then ()
else render_slices (i + 1)
in
let rec render_stacks j =
let rec iter_stacks i e =
if i = (st - 1) then e
else iter_stacks (i + 1) (get_nth_vert v (i * sl + j) :: e)
in
let e = iter_stacks 0 [] in
draw_ellipse e false;
if j = sl - 1 then ()
else render_stacks (j + 1)
in
render_slices 0;
render_stacks 0;;
let list_translate_z l =
let rec translate r n =
match r with
| [] -> n
| x :: xs -> translate (xs) (translate_z x 1. :: n)
in
translate l [];;
let list_rotate_y l angle =
let rec translate r n =
match r with
| [] -> n
| x :: xs -> translate (xs) (rotate_y x angle :: n)
in
translate l [];;
(* END SPHERE *)
let rec animate angle sv =
clear_graph ();
set_color (rgb 0 0 0);
fill_rect 0 0 800 800;
set_color cyan;
(* draw_cube faces angle; *)
draw_sphere sv stacks slices;
Graphics.synchronize ();
animate (angle +. 0.0005) (list_translate_z (list_rotate_y (gen_sphere_vertecies 10 12 0.175) angle));;
let () =
open_graph " 800x800+560+140";
auto_synchronize false;
animate 0. s_vertecies;
close_graph ()