Computer tools >
Caml
Caml
Summary
3D_UI.ml
#open"graphics";;
clear_graph();;
(* 3D User Interface: use 2 4 6 8 arrows to rotate the cube given as an example *)
open_graph "1000x750+400+20";;
type vecteur == float * float * float ;;
type pt == float * float * float ;;
type pt_2D == int * int ;;
type pt_2D_float == float * float ;;
type vecteur_2D == float * float ;;
type angle == float ;;
type base == pt * vecteur * vecteur * vecteur ;;
type face == pt vect ;;
type polyèdre == face vect ;;
type parallélépipède == pt * vecteur * vecteur * vecteur ;;
type cube == pt * vecteur * vecteur * float ;;
type cylindre == pt * vecteur * float * float ;;
type sphère == pt * float * int ;;
type Forme = Poly of polyèdre | Para of parallélépipède | C of cube | Cyl of cylindre | S of sphère;;
type Objet = V of vecteur | P of pt | B of base | F of face | Poly of polyèdre | Para of parallélépipède | C of cube | Cyl of cylindre | S of sphère;;
type Objet_coloré == Objet * color;;
let Pi = 3.1415926;; (* Données *)
let xpf = 600.;; (* Coord. du pt de fuite *)
let ypf = 500.;;
let ((xo, yo, zo) as origine) = (ref 200.,ref (-.200.),ref (-.100.));;
let ((xa, ya, za) as origine_axes) = (ref 0.,ref 0.,ref 0.);;
let de = 2000.;; (* Distance à l'écran *)
let nb_pts_basique = 50;;
let plot_pt_de_fuite r = fill_circle (int_of_float xpf) (int_of_float ypf) r;;
plot_pt_de_fuite 2;;
let proj x z = let d = (de+.z) in if d <> 0. then de*.x/.d else failwith "Division par zéro dans proj";; (* Projections sur l'écran *)
let projx x z = let d = (de+. !zo+.z) in if d <> 0. then int_of_float (xpf +. de*.(!xo+.x)/.d) else failwith "Division par zéro dans projx";;
let projy y z = let d = (de+. !zo+.z) in if d <> 0. then int_of_float (ypf +. de*.(!yo+.y)/.d) else failwith "Division par zéro dans projy";;
let proj2 ((x,y,z):pt) = let d = (de+. !zo+.z) in if d <> 0. then ((int_of_float(xpf +. de*.(!xo+. x)/.d), int_of_float (ypf +. de*.(!yo+.y)/.d)):pt_2D) else failwith "Division par zéro dans proj2";;
let proj_float ((x,y,z):pt) = let d = (de+. !zo+.z) in if d <> 0. then ((xpf +. de*.(!xo+.x)/.d, ypf +. de*.(!yo+.y)/.d):pt_2D_float) else failwith "Division par zéro dans proj2";;
let plot_3D ((x,y,z):pt) = plot (projx x z) (projy y z);;
let moveto_3D ((x,y,z):pt) = moveto (projx x z) (projy y z);;
let lineto_3D ((x,y,z):pt) = lineto (projx x z) (projy y z);;
let ((_,e1,e2,e3):base) = ((!xo,!yo,!zo), (100.,0.,0.),(0.,100.,0.),(0.,0.,100.));;
let Segment ((x,y,z):pt) ((x',y',z'):pt) = moveto_3D (x,y,z); lineto_3D (x',y',z');;
let Vecteur ((x0,y0,z0):pt) ((u,v,w):vecteur) = (* Vecteur *)
let (x,y,z) = (x0+.u,y0+.v,z0+.w ) in
let n = sqrt(v*.v+.w*.w) in
moveto_3D (x0,y0,z0); lineto_3D (x,y,z);
if n <> 0. then(
lineto_3D (x-.u/.10.+.n/.20., y-.v/.10.-.u*.v/.n/.20., z-.w/.10.-.u*.w/.n/.20.);
moveto_3D (x-.u/.10.-.n/.20., y-.v/.10.+.u*.v/.n/.20., z-.w/.10.+.u*.w/.n/.20.); lineto_3D (x,y,z)
) else(
lineto_3D (x-.u/.10.+.n/.20., y-.u/.20., z);
moveto_3D (x-.u/.10.-.n/.20., y+.u/.20., z); lineto_3D (x,y,z)
);;
let draw_poly tab couleur = (* Faces *)
set_color couleur;
let v = vect_length tab in
let rec draw_poly_depuis = function
0 -> moveto (fst (tab.(0))) (snd (tab.(0))); draw_poly_depuis 1
|n when n = v -> let (x,y) = tab.(0) in lineto x y
|n -> let (x,y) = tab.(n) in lineto x y ; draw_poly_depuis (n+1)
in draw_poly_depuis 0;;
let draw_poly_3D couleur tab =
set_color couleur;
let v = vect_length tab in
let rec draw_poly_3D_depuis = function
0 -> moveto_3D (tab.(0)); draw_poly_3D_depuis 1
|n when n = v -> lineto_3D (tab.(0))
|n -> lineto_3D tab.(n); draw_poly_3D_depuis (n+1)
in draw_poly_3D_depuis 0;;
let Face couleur couleur_bord (tab: face) =
set_color couleur;
fill_poly (map_vect (proj2) tab);
draw_poly_3D couleur_bord tab;;
let prod_vect ((u1,v1,w1):vecteur) ((u2,v2,w2):vecteur) = (* Fonctions vectorielles élémentaires *)
((v1*.w2 -. w1*.v2 , w1*.u2 -. u1*.w2 , u1*.v2 -. v1*.u2):vecteur);;
let prod_scal ((u1,v1,w1):vecteur) ((u2,v2,w2):vecteur) =
u1*.u2 +. v1*.v2 +. w1*.w2;;
let norme ((u,v,w):vecteur) = sqrt(u*.u +. v*.v +. w*.w);;
let norme2 ((u,v,w):vecteur) = u*.u +. v*.v +. w*.w;;
let norme_2D (u,v) = sqrt(u*.u +. v*.v);;
let norme2_2D ((u,v):vecteur_2D) = u*.u +. v*.v;;
let prod_ext lambda ((u,v,w):vecteur) =
((lambda*.u,lambda*.v,lambda*.w):vecteur);;
let prod_ext_2D lambda ((u,v):vecteur_2D) =
((lambda*.u,lambda*.v):vecteur_2D);;
let somme_vect ((a,b,c):vecteur) ((a',b',c'):vecteur) = ((a+.a',b+.b',c+.c'):vecteur);;
let diff_vect ((a,b,c):vecteur) ((a',b',c'):vecteur) = ((a-.a',b-.b',c-.c'):vecteur);;
let somme_vect_2D ((a,b):vecteur_2D) ((a',b'):vecteur_2D) = ((a+.a',b+.b'):vecteur_2D);;
let diff_vect_2D ((a,b):vecteur_2D) ((a',b'):vecteur_2D) = ((a-.a',b-.b'):vecteur_2D);;
let Base ((x0,y0,z0):pt) ((u1,v1,w1):vecteur) ((u2,v2,w2):vecteur) ((u3,v3,w3):vecteur) =
Vecteur (x0,y0,z0) (u1,v1,w1); Vecteur (x0,y0,z0) (u2,v2,w2); Vecteur (x0,y0,z0) (u3,v3,w3);;
let Axes ((x0,y0,z0):pt) ((u1,v1,w1):vecteur) ((u2,v2,w2):vecteur) ((u3,v3,w3):vecteur) =
Segment (x0,y0,z0) (somme_vect (x0,y0,z0) (prod_ext 3. (u1,v1,w1))); Segment (x0,y0,z0) (somme_vect (x0,y0,z0) (prod_ext 3. (u2,v2,w2))); Segment (x0,y0,z0) (somme_vect (x0,y0,z0) (prod_ext 10. (u3,v3,w3)));;
let Ellipse ((xc,yc,zc):pt) a b (phi:angle) nb_pts (couleur:color) (couleur_bord:color) =
let a' = proj a zc in
let face_2D = make_vect nb_pts (0,0) in
for i = 0 to nb_pts-1 do
let theta = float_of_int i *. 2. *.Pi /. (float_of_int nb_pts) in
let x' = a *. (cos theta) in
let y' = b *. (sin theta) in
let k = de/.(de+. !zo+.zc) in
let c = cos phi in
let s = sin phi in
face_2D.(i) <- ((int_of_float (xpf +. (!xo +. xc +. x' *. c -. y' *. s)*.k)), (int_of_float (ypf +. (!yo +. yc +. y' *. c +. x' *. s)*.k)));
done;
set_color couleur;
fill_poly face_2D;
draw_poly face_2D couleur_bord;;
let Sphère ((xc,yc,zc):pt) r nb_pts (couleur:color) (couleur_bord) = (* Sphère *)
let xc' = !xo+.xc in
let yc' = !yo+.yc in
let n2 = norme2_2D (xc',yc') in
let n = sqrt n2 in
let r2 = r*.r in
let d = de+. !zo+.zc in
let d2 = d*.d in
let lambda1 = (n*.d +. r*.sqrt(n2 +. d2 -. r2)) /. (n2 -. r2) in
let lambda2 = (n*.d -. r*.sqrt(n2 +. d2 -. r2)) /. (n2 -. r2) in
let x1 = (n +. lambda1 *. d) /. (lambda1*.lambda1 +. 1.) in
let x2 = (n +. lambda2 *. d) /. (lambda2*.lambda2 +. 1.) in
let z1' = lambda1 *. x1 in
let z2' = lambda2 *. x2 in
let xe1 = proj x1 (z1'-.de) in
let xe2 = proj x2 (z2'-.de) in
let xec = (xe1 +. xe2)/.2. in
let a = (xe1 -. xe2)/.2. in
let b = de*.r/.(sqrt(d2-.r2)) in
let psi = if n+.xc' <> 0. then 2.*.atan (yc'/.(n+.xc')) else Pi in
let x = xec*.(cos psi) in
let y = xec*.(sin psi) in
Ellipse (x-. !xo,y-. !yo,-. !zo) a b psi nb_pts (couleur:color) (couleur_bord:color);;
let Animation_sphère ((x0,y0,z0):pt) r nb_pts (v0:vecteur) ((gx,gy,gz):vecteur) tps (couleur:color) =
let rec anim_restante (x,y,z) (vx,vy,vz) = function
(_,0) -> ()
|((((xp,yp,zp),rp,nb_ptsp):sphère),tps') -> fill_circle (projx x z) (projy y z) 10; Sphère (x,y,z) r nb_pts couleur black;Sphère (x+.vx,y+.vy,z+.vz) r nb_pts couleur black; Sphère (x+.2.*.vx+.gx,y+.2.*.vy+.gy,z+.2.*.vz+.gz) r nb_pts couleur black; anim_restante (x+.vx,y+.vy,z+.vz) (vx+.gx,vy+.gy,vz+.gz) (((x,y,z), r, nb_pts), (tps'-1))
in
anim_restante (x0,y0,z0) v0 (((10.,10.,10.),1.,3),tps);;
Animation_sphère ((-.200.), (-.10.), 0.) 50. 20 (1.,1.,-.3.) (0.,-.0.01,0.) 20 red;;
let plot_3D_cartésiennes ((x,y,z):pt) couleur = set_color (127+127*256+127*256*256);
moveto_3D (x, !ya, !za); lineto_3D (x, !ya, z);
moveto_3D (!xa, !ya, z); lineto_3D (x, !ya, z); lineto_3D (x, y, z);
set_color couleur; Sphère (x,y,z) 3. 100 couleur black;;
let Cercle ((x,y,z) as O:pt) (v:vecteur) r nb_pts (couleur:color) (couleur_bord:color) =
let v' = (prod_vect O v) in
let v'r = prod_ext (r /. (norme v')) v' in
let v'' = (prod_vect v v'r) in
let v''r = prod_ext (r /. (norme v'')) v'' in
let face = make_vect nb_pts (0.,0.,0.) in
for i = 0 to nb_pts-1 do
let theta = float_of_int i *. 2. *.Pi /. (float_of_int nb_pts) in
let c = cos theta in
let s = sin theta in
face.(i) <- somme_vect O (somme_vect (prod_ext c v'r) (prod_ext s v''r))
done;
Face couleur couleur_bord face;;
let Cylindre ((x0,y0,z0) as O:pt) (v:vecteur) r h nb_pts (couleur:color) (couleur_bord:color) = (* Cylindre *)
let vh = prod_ext (h/.(norme v)) v in
let (x,y,z) = somme_vect (x0,y0,z0) vh in
Cercle (x0,y0,z0) v r nb_pts couleur couleur_bord;
Cercle (x,y,z) v r nb_pts couleur couleur_bord;
let O'' = prod_vect (somme_vect O (0.,0.,de)) v in
let O''r = prod_ext (r /. (norme O'')) O'' in
let O' = prod_ext (1./. (norme2 v)) (prod_vect O'' v) in
let O'r = prod_ext (r /. (norme O')) O' in
let c = (sqrt (norme2 O' -. r*.r))/.(norme O') in
let s = r/.(norme O') in
let face = make_vect 4 (0.,0.,0.) in
face.(0) <- somme_vect O (somme_vect (prod_ext s O'r) (prod_ext c O''r));
face.(1) <- somme_vect O (somme_vect (prod_ext s O'r) (prod_ext (-.c) O''r) );
face.(2) <- somme_vect O (somme_vect (somme_vect (prod_ext s O'r) (prod_ext (-.c) O''r)) vh) ;
face.(3) <- somme_vect O (somme_vect (somme_vect (prod_ext s O'r) (prod_ext c O''r)) vh );
Face couleur couleur face;
set_color couleur_bord;
moveto_3D (somme_vect O (somme_vect (prod_ext s O'r) (prod_ext c O''r)));
lineto_3D (somme_vect O (somme_vect (somme_vect (prod_ext s O'r) (prod_ext c O''r)) vh ));
moveto_3D (somme_vect O (somme_vect (prod_ext s O'r) (prod_ext (-.c) O''r) ));
lineto_3D (somme_vect O (somme_vect (somme_vect (prod_ext s O'r) (prod_ext (-.c) O''r)) vh) );
if prod_scal (somme_vect O (0.,0.,de)) v >= 0. then
Cercle (x0,y0,z0) v r nb_pts couleur couleur_bord;
if prod_scal (somme_vect(somme_vect O (0.,0.,de)) vh) v <= 0. then
Cercle (x,y,z) v r nb_pts couleur couleur_bord;;
let centre (f:face) = (* Parallélépipède... *)
let n = vect_length f in
let n' = float_of_int n in
let rec somme_tab = function
0 -> f.(0)
|i -> somme_vect (somme_tab (i-1)) (f.(i))
in
prod_ext (1./.n') (somme_tab (n-1));;
let Parallélépipède ((x000,y000,z000):pt) ((u1,v1,w1) as v:vecteur) ((u2,v2,w2) as v':vecteur) ((u3,v3,w3) as v'':vecteur) (couleur:color) (couleur_bord:color) =
let x100 = x000+.u1 in let y100 = y000+.v1 in let z100 = z000+.w1 in
let x010 = x000+.u2 in let y010 = y000+.v2 in let z010 = z000+.w2 in
let x001 = x000+.u3 in let y001 = y000+.v3 in let z001 = z000+.w3 in
let x111 = x000+.u1+.u2+.u3 in let y111 = y000+.v1+.v2+.v3 in let z111 = z000+.w1+.w2+.w3 in
let x011 = x111-.u1 in let y011 = y111-.v1 in let z011 = z111-.w1 in
let x101 = x111-.u2 in let y101 = y111-.v2 in let z101 = z111-.w2 in
let x110 = x111-.u3 in let y110 = y111-.v3 in let z110 = z111-.w3 in
let f1 = [|(x000,y000,z000);(x100,y100,z100);(x110,y110,z110);(x010,y010,z010)|] in
let f2 = [|(x001,y001,z001);(x101,y101,z101);(x111,y111,z111);(x011,y011,z011)|] in
let f3 = [|(x000,y000,z000);(x100,y100,z100);(x101,y101,z101);(x001,y001,z001)|] in
let f4 = [|(x010,y010,z010);(x110,y110,z110);(x111,y111,z111);(x011,y011,z011)|] in
let f5 = [|(x000,y000,z000);(x001,y001,z001);(x011,y011,z011);(x010,y010,z010)|] in
let f6 = [|(x100,y100,z100);(x101,y101,z101);(x111,y111,z111);(x110,y110,z110)|] in
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f1)) v'') >= 0. then Face blue couleur_bord f1;
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f2)) v'') <= 0. then Face cyan couleur_bord f2;
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f3)) v') >= 0. then Face red couleur_bord f3;
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f4)) v') <= 0. then Face green couleur_bord f4;
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f5)) v) >= 0. then Face black couleur_bord f5;
if (prod_scal (somme_vect (!xo, !yo, !zo +. de) (centre f6)) v) <= 0. then Face magenta couleur_bord f6;;
let Parallélépipède_rectangle ((x0,y0,z0):pt) ((u1,v1,w1):vecteur) ((u2,v2,w2):vecteur) z (couleur:color) =
let v' = (prod_vect (u1,v1,w1) (u2,v2,w2)) in
let v'' = (prod_ext (z/.(norme v')) v') in
Parallélépipède (x0,y0,z0) (u1,v1,w1) (u2,v2,w2) v'' couleur black;;
let Cube ((x0,y0,z0) as O:pt) ((u1,v1,w1 as v):vecteur) ((u2,v2,w2 as v'):vecteur) a (couleur:color) couleur_bord =
let e = prod_ext (a/.(norme v)) v in
let v'' = prod_vect e v' in
let e'' = prod_ext (a/.(norme v'')) v'' in
let e' = prod_ext (1./.a) (prod_vect e'' e) in
Parallélépipède O e e' e'' couleur couleur_bord;;
let Dessine objet couleur couleur_bord = (* Dessine *)
set_color couleur; match objet with
V (v:vecteur) -> Vecteur (!xo,!yo,!zo) v
|P (p:pt) -> plot_3D p
|B (((o:pt),(v:vecteur),(v':vecteur),(v'':vecteur)):base) -> Base o v v' v''
|F (f:face) -> Face couleur couleur_bord f
|Poly (p:polyèdre) -> do_vect (Face couleur couleur_bord) p
|Para ((o,v,v',v''):parallélépipède) -> Parallélépipède o v v' v'' couleur couleur_bord
|C ((o,v,v',a):cube) -> Cube o v v' a couleur couleur_bord
|Cyl (o,v,r,h:cylindre) -> Cylindre o v r h 50 couleur couleur_bord
|S (o,r,nb_pts:sphère) -> Sphère o r 50 couleur couleur_bord;;
let rec Affiche liste_objets_colorés = match liste_objets_colorés with
[]->()
|((objet, couleur):Objet_coloré)::liste_objets_colorés' -> Dessine objet couleur black; Affiche liste_objets_colorés';;
let Sol bordg bordd borde bordp h = moveto_3D (bordg,h,borde); lineto_3D (bordd, h, borde); lineto_3D (bordd, h, bordp); lineto_3D (bordg, h, bordp); lineto_3D (bordg, h, borde);;
let projection ((x,y,z) as OA:pt) ((vx,vy,vz) as v:vecteur) = (* Rotation... *)
(((prod_ext (prod_scal OA v /. (norme2 v)) v)):pt);;
let rotation ((x,y,z) as OA:pt) ((vx,vy,vz) as v:vecteur) (theta:angle) =
let n = norme v in
let p = projection OA v in
let pt' = diff_vect OA p in
((somme_vect (somme_vect p (prod_ext (cos theta) pt')) (prod_ext (sin theta /. n) (prod_vect v pt'))):pt);;
let rotation_cube ((o,v1,v2,a):cube) ((vx,vy,vz) as v:vecteur) (theta:angle) =
((rotation o v theta, rotation v1 v theta, rotation v2 v theta, a):cube);;
let rotation_liste liste_objets_colorés ((vx,vy,vz) as v:vecteur) (theta:angle) = map (fun objet_coloré -> match objet_coloré with C(cube), couleur ->((C(rotation_cube cube v theta), couleur):Objet_coloré)) (liste_objets_colorés:Objet_coloré list);;
clear_graph();;
(*
Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) (-.4.*.Pi/.7.))) red black;;
Dessine (C ((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) red;;
Vecteur (0.,-.220.,0.) (prod_ext 2. e2);;
Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) (Pi/.6.))) red;;
Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) (Pi/.3.))) red;;
Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) Pi)) red;;
Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) (2.*.Pi/.3.))) red;; *)
plot_3D_cartésiennes (100.,100.,500.) black;;
Axes (!xa,!ya,!za) e1 e2 e3;;
for i = 0 to 5 do xo:=-.500.+.200.*. (float_of_int i); yo:=-.300.+.100.*. (float_of_int i); zo:=200.-.100.*. (float_of_int i); Dessine (C (rotation_cube(((200.,-200.,10.),(100.,300.,50.),(50.,100.,0.),100.)) (e2) (2.*.Pi/.3.))) red black; done;;
xo:= 30.;yo:= -.0.;zo:= -.400.;;
Cylindre (-.350.,-.175.,-.475.) (100.,0.,0.) 10. 150. 100 cyan black;;
Cube (-.200.,-.200.,-.500.) (100.,0.,0.) (0.,100.,0.) 50. red black;;
Cylindre (-.175.,-.150.,-.475.) (0.,100.,0.) 15. 50. 100 blue black;;
Cylindre (-.150.,-.175.,-.475.) (100.,0.,0.) 15. 150. 100 blue black;;
let rec Animation liste_objets_colorés theta = function
0->print_string " fin!"
|tps->
let k = read_key() in
clear_graph();
if k=`4` then(
Affiche (rotation_liste liste_objets_colorés (0.,1.,0.) theta);
Animation (rotation_liste liste_objets_colorés (0.,1.,0.) theta) theta (tps-1));
if k=`6` then(
Affiche (rotation_liste liste_objets_colorés (0.,1.,0.) (-.theta));
Animation (rotation_liste liste_objets_colorés (0.,1.,0.) (-.theta)) theta (tps-1));
if k=`8` then(
Affiche (rotation_liste liste_objets_colorés (1.,0.,0.) theta);
Animation (rotation_liste liste_objets_colorés (1.,0.,0.) theta) theta (tps-1));
if k=`2` then(
Affiche (rotation_liste liste_objets_colorés (1.,0.,0.) (-.theta));
Animation (rotation_liste liste_objets_colorés (1.,0.,0.) (-.theta)) theta (tps-1));;
Animation [((C((100.,0.,0.), (0.,100.,0.), (0.,0.,100.), 100.),red):Objet_coloré)] (Pi/.12.) 100;;