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;;