(* /!\ Code écrit par Lilian BESSON - LSV & CMLA & ENS de Cachan. Par respect des droits de propriétés intellectuelles, conservez ce bordereau si vous utilisez tout ou une partie de ce fichier. *) (* *) (* Plot : MOcaml *) (* *) (** {7 Plot : code ml pour ocamlc} *) (** *) (** Plot : Projet MOcaml *)(** ENS de Cachan - 2012 L3 Informatique Projet MOcaml v1.0.4 *)(** Besson Lilian. Inspiré de 'meta_plot.c' et 'script_metaplot.sh' écrits par Lilian Besson en Février 2012. (c) Naereen Corp. *) (* * Ce module fait partis du projet MOcaml, et utilise les modules ANSITerminal, et . * Pour plus de détails, voir la documentation du projet MOcaml, en ligne ou dans les README. *) (* ******************************************************************************************************************************************* *) (** Utilise le module ANSITerminal. *) (*#use "topfind";;*) (*#require "ANSITerminal";;*) open Pervasives;; (*#load "ANSITerminal.cma";;*) module Top = ANSITerminal;; let line () = try (-3 + snd (Top.size ())) with _ -> 36 and column () = try (-1 + fst (Top.size ())) with _ -> 135 ;; (** Récupère la taille de la fenètre ANSI. Ne fonctionne pas lors de l'utilisation d'un wrapper comme "ledit" ou "rlwrap". Par défaut, line = 36; column = 135, résolution de mon terminal en plein écran. L'amélioration du module ANSITerminal est en cours pour régler ça. C'est pas facile ! *) let arrayfloat_of_arrayint = Array.map float_of_int;; (** Change un tableau d'entiers en tableau de flottants. *) let bool_of_int i = (i = 1) and int_of_bool = function | true -> 1 | false -> 0;; (** Conversions entiers et booléens. *) let bool_of_float i = (i = 1.0) and float_of_bool = function | true -> 1.0 | false -> 0.0;; (** Conversions entiers et flottants. *) let len = Array.length;; let maxminof_array mon_ordre = function | [||] -> raise Not_found; | y_vect -> let maxy = ref y_vect.(0) in let n = Array.length y_vect in for i = 1 to (n-1) do if (mon_ordre !maxy y_vect.(i)) then maxy := y_vect.(i); done; !maxy;; (** Calcul du max/min d'un tableau quelconque pour un ordre quelconque. *) let maxof_array a = maxminof_array ( < ) a (** Calcul du max. *) and minof_array a = maxminof_array ( > ) a;; (** Calcul du min. *) let ( ^= ) r a = r := !r ^ a;; (** Actualise une référence string. *) open Pervasives;; exception Mauvaise_valeur_gauche;; (** Si le programme cherche à évaluer une valeur trop a gauche (bug). *) exception Mauvaise_valeur_droite;; (** Si le programme cherche à évaluer une valeur trop a droite (bug). *) exception Dessin_impossible;; (** Si les paramètres du tracé font qu'il est impossible a réaliser. Par exemple si [maxx] < [minx] ou [maxy] < [miny]. *) let getchar () = input_char stdin;; (** Comme le getchar du C. *) (** {6 Paramêtres graphiques du tracés.} *) type fleches = Haut | Bas | HautG | BasG | Gauche | Droite | GaucheG | DroiteG | DiagHautDroite | DiagHautGauche | DiagBasDroite | DiagBasGauche | DiagHautDroiteG | DiagHautGaucheG | DiagBasDroiteG | DiagBasGaucheG | AxeHoriz | AxeVerti | Trou | Centre | LegX;; (** Différentes flèches et élément d'un tracé. *) let fleche = function | true -> ( function | Haut -> "↑" | Bas -> "↓" | HautG -> "⇑" | BasG -> "⇓" | Gauche -> "←" | Droite -> "→" | GaucheG -> "⇐" | DroiteG -> "⇒" | DiagHautDroite -> "↗" | DiagHautGauche -> "↖" | DiagBasDroite -> "↘" | DiagBasGauche -> "↙" | DiagHautDroiteG -> "⇗" | DiagHautGaucheG -> "⇖" | DiagBasDroiteG -> "⇘" | DiagBasGaucheG -> "⇙" | AxeHoriz -> "−" | AxeVerti -> "|" | Trou -> " " | Centre -> "+" | LegX -> "X" ) | false -> ( function | Haut -> "h" | Bas -> "b" | HautG -> "^" | BasG -> "B" | Gauche -> "g" | Droite -> "=" | GaucheG -> "<" | DroiteG -> ">" | DiagHautDroite -> "/" | DiagHautGauche -> "j" | DiagBasDroite -> "\\" | DiagBasGauche -> "l" | DiagHautDroiteG -> "I" | DiagHautGaucheG -> "J" | DiagBasDroiteG -> "K" | DiagBasGaucheG -> "L" | AxeHoriz -> "-" | AxeVerti -> "|" | Trou -> " " | Centre -> "+" | LegX -> "x" ) ;; (** Méthode pour afficher les flèches et les différents éléments d'un tracés. Si vous voulez customisé l'affichage, il suffit de le faire par là. Pas besoin de rentrer dans le code. *) (* ******************************************************************************************************************************************* *) (** {6 Afficher un tableau de flottants.} *) let plot_array ~vect:y_vect ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(full_ascii = true) () = if (minx >= maxx) then raise Dessin_impossible; if (miny >= maxy) then raise Dessin_impossible; if (0 = (Array.length y_vect)) then raise Dessin_impossible; let taille_X = column () and taille_Y = line () in (** Récupère la taille de l'écran. *) let mon_ecran = Array.create_matrix (1+taille_X) (1+taille_Y) " " in (** Matrice des caractères de l'écran. Convention : ne mettre que des chaines de longueur ANSI = 1 (longueur ASCII != longueur ANSI !!). *) let taille_Y_vect = Array.length y_vect in let min_Y = minof_array y_vect and max_Y = maxof_array y_vect in let f_loc x = if (x < 0.) then raise Mauvaise_valeur_gauche; if (x > float_of_int(taille_Y_vect)) then raise Mauvaise_valeur_droite; y_vect.(int_of_float x); in let fm_X = 0. and fM_X = float_of_int(taille_Y_vect - 1) and fm_Y = (1.0 -. (float_of_bool(min_Y > 0.))*.0.04 +. (float_of_bool(min_Y < 0.))*.0.04 ) *. min_Y and fM_Y = (1.0 +. (float_of_bool(max_Y > 0.))*.0.04 -. (float_of_bool(max_Y < 0.))*.0.04 ) *. max_Y in let a_X = ( ((float_of_int taille_X) -. 1.)/.(fM_X -. fm_X) ) and b_X = 1. -. (float_of_int(taille_X - 1)/.(fM_X -. fm_X)) *. fm_X and a_Y = ( ((float_of_int taille_Y) -. 1.)/.(fM_Y -. fm_Y) ) and b_Y = 1. -. (float_of_int(taille_Y - 1)/.(fM_Y -. fm_Y)) *. fm_Y in let theta_x_inv indice = ((1. /. a_X) *. float_of_int(indice) -. (b_X /. a_X)) in let theta_y_ceil y = int_of_float (a_Y *. y +. b_Y) in let u_vect = Array.create (taille_X + 2) 0 in for i = 1 to taille_X do u_vect.(i) <- theta_y_ceil (f_loc (theta_x_inv i)) done; u_vect.(0) <- u_vect.(1); u_vect.(taille_X + 1) <- u_vect.(taille_X); Printf.fprintf mon_out "\ny=f(x)\tD_plot = [%f; %f] × [%f; %f]\t\ttitre = [%s]" minx maxx min_Y max_Y title; flush_all (); for i = taille_Y downto 0 do for j = 0 to taille_X do mon_ecran.(j).(i) <- (fleche full_ascii Trou); if ((i = taille_Y) && (j = 0)) then mon_ecran.(j).(i) <- (fleche full_ascii HautG); if ((i <> taille_Y) && (j = 0)) then mon_ecran.(j).(i) <- (fleche full_ascii AxeVerti); if ((i = 0) && (j <> 0) && (j <> taille_X)) then mon_ecran.(j).(i) <- (fleche full_ascii AxeHoriz); if ((i = 0) && (j = taille_X)) then mon_ecran.(j).(i) <- (fleche full_ascii GaucheG); if ((i = 1) && (j = taille_X)) then mon_ecran.(j).(i) <- (fleche full_ascii Centre); if ((i = 0) && (j = 0)) then mon_ecran.(j).(i) <- (fleche full_ascii LegX); if ((j > 0) && (u_vect.(j) <> 0)) then begin if (u_vect.(j) = i) then mon_ecran.(j).(i) <- (fleche full_ascii Gauche); if (float_of_int(u_vect.(j - 1)) < ((1. -. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then mon_ecran.(j).(i) <- (fleche full_ascii Haut); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then mon_ecran.(j).(i) <- (fleche full_ascii Haut); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then mon_ecran.(j).(i) <- (fleche full_ascii DiagBasDroite); if (float_of_int(u_vect.(j - 1)) < ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then mon_ecran.(j).(i) <- (fleche full_ascii DiagHautDroite); end; done; done; for i = taille_Y downto 0 do Printf.fprintf mon_out "\n"; for j = 0 to taille_X do Printf.fprintf mon_out "%s" mon_ecran.(j).(i); done; done; Printf.fprintf mon_out "\nTitre = [%s]\tprojet MOcaml © 2012 Naereen Corp." title ; Printf.fprintf mon_out " (appuyez sur Enter)"; flush_all (); if param then (ignore (getchar())); ();; (** Affiche les valeurs d'un tableau. @param vect Le tableau a afficher, @param title Le titre du graphique produit, @param param Paramêtre de contrôle, @param mon_out Out_channel ou écrire le graphique, valant par défaut le channel de sortie [stdout], @param minx A faire, @param maxx A faire, @param miny A faire, @param maxy A faire. @param full_ascii Renseigne si tout les caractères baroques peuvent être affichés. Dans certain terminaux, non. Si vous voyez qu'un dessin ne se fait pas avec les flèches normales, continuez avec ~full_ascii:false. *) let plot_list ~liste:y_vect ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(full_ascii = true) () = plot_array ~vect:(Array.of_list y_vect) ~title:title ~param:param ~mon_out:mon_out ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Idem, mais avec une liste. *) let plot_array_int ~vect:y_vect ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(full_ascii = true) () = plot_array ~vect:(Array.map float_of_int y_vect) ~title:title ~param:param ~mon_out:mon_out ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Idem, mais avec un tableau d'entiers. *) let plot_list_int ~liste:y_vect ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(full_ascii = true) () = plot_array_int ~vect:(Array.of_list y_vect) ~title:title ~param:param ~mon_out:mon_out ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Idem, mais avec une liste d'entiers. *) (* ******************************************************************************************************************************************* *) (** {6 Avec support de la couleur du module ANSITerminal.} *) let plotC_array ~vect:y_vect ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(full_ascii = true) () = if (minx >= maxx) then raise Dessin_impossible; if (miny >= maxy) then raise Dessin_impossible; if (0 = (Array.length y_vect)) then raise Dessin_impossible; let taille_X = column () and taille_Y = line () in (** Récupère la taille de l'écran. *) let mon_ecran = Array.create_matrix (1+taille_X) (1+taille_Y) " " in (** Matrice des caractères de l'écran. Convention : ne mettre que des chaines de longueur ANSI = 1 (longueur ASCII != longueur ANSI !!). *) let taille_Y_vect = Array.length y_vect in let min_Y = minof_array y_vect and max_Y = maxof_array y_vect in let f_loc x = if (x < 0.) then raise Mauvaise_valeur_gauche; if (x > float_of_int(taille_Y_vect)) then raise Mauvaise_valeur_droite; y_vect.(int_of_float x); in let fm_X = 0. and fM_X = float_of_int(taille_Y_vect - 1) and fm_Y = (1.0 -. (float_of_bool(min_Y > 0.))*.0.04 +. (float_of_bool(min_Y < 0.))*.0.04 ) *. min_Y and fM_Y = (1.0 +. (float_of_bool(max_Y > 0.))*.0.04 -. (float_of_bool(max_Y < 0.))*.0.04 ) *. max_Y in let a_X = ( ((float_of_int taille_X) -. 1.)/.(fM_X -. fm_X) ) and b_X = 1. -. (float_of_int(taille_X - 1)/.(fM_X -. fm_X)) *. fm_X and a_Y = ( ((float_of_int taille_Y) -. 1.)/.(fM_Y -. fm_Y) ) and b_Y = 1. -. (float_of_int(taille_Y - 1)/.(fM_Y -. fm_Y)) *. fm_Y in let theta_x_inv indice = ((1. /. a_X) *. float_of_int(indice) -. (b_X /. a_X)) in let theta_y_ceil y = int_of_float (a_Y *. y +. b_Y) in let u_vect = Array.create (taille_X + 2) 0 in for i = 1 to taille_X do u_vect.(i) <- theta_y_ceil (f_loc (theta_x_inv i)) done; u_vect.(0) <- u_vect.(1); u_vect.(taille_X + 1) <- u_vect.(taille_X); ANSITerminal.printf [ANSITerminal.Bold; ANSITerminal.Underlined] "\ny=f(x)\tD_plot = [%f; %f] × [%f; %f]\t\ttitre = [%s]" minx maxx min_Y max_Y title; flush_all (); let aff_axe = ANSITerminal.print_string [ANSITerminal.Bold; ANSITerminal.yellow] and aff_tro = ANSITerminal.print_string [] and aff_fle = ANSITerminal.print_string [ANSITerminal.Bold; ANSITerminal.green] in let quoi = ref 0 in let aff q = match !q with |0 -> aff_tro |1 -> aff_axe |_ -> aff_fle in for i = taille_Y downto 0 do Printf.printf "\n"; for j = 0 to taille_X do mon_ecran.(j).(i) <- (fleche full_ascii Trou); quoi := 0; if ((i = taille_Y) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii HautG);); if ((i <> taille_Y) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii AxeVerti);); if ((i = 0) && (j <> 0) && (j <> taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii AxeHoriz);); if ((i = 0) && (j = taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii DroiteG);); if ((i = 1) && (j = taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii LegX);); if ((i = 0) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii Centre);); if ((j > 0) && (u_vect.(j) <> 0)) then begin if (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Droite);); if (float_of_int(u_vect.(j - 1)) < ((1. -. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Haut);); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Bas);); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii DiagBasDroite);); if (float_of_int(u_vect.(j - 1)) < ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii DiagHautDroite);); end; aff quoi (mon_ecran.(j).(i)); done; done; (* for i = taille_Y downto 0 do*) (* for j = 0 to taille_X do*) (* Printf.printf "%s" mon_ecran.(j).(i);*) (* done;*) (* done;*) ANSITerminal.printf [ANSITerminal.Bold; ANSITerminal.Underlined] "\nTitre = [%s]\tprojet MOcaml © 2012 Naereen Corp." title ; ANSITerminal.printf [ANSITerminal.blue] " (appuyez sur Enter)"; flush_all (); if param then (ignore (getchar())); ();; (** Affiche les valeurs d'un tableau. @param vect Le tableau a afficher, @param title Le titre du graphique produit, @param param Paramêtre de contrôle, @param mon_out Out_channel ou écrire le graphique, valant par défaut le channel de sortie [stdout], @param minx A faire, @param maxx A faire, @param miny A faire, @param maxy A faire. Supporte les couleurs ANSI pour faire un graphe plus joli. *) (** {6 Pour afficher des fonctions.} *) let array_of_fun ?(minx = -10.0) ?(maxx = 10.0) ?(nb = 135) ~f:ma_fonction = if (minx >= maxx) then raise Dessin_impossible; if (0 >= nb) then raise Dessin_impossible; let result = Array.create nb (ma_fonction minx) in let pas = (maxx -. minx) /. (float_of_int (nb - 1)) in for i = 0 to (nb - 1) do result.(i) <- ma_fonction (minx +. (float_of_int i) *. pas); done; result;; (** Donne un tableau de valeurs pour une fonction float -> float. *) let array_int_of_fun ?(minx = -10.0) ?(maxx = 10.0) ?(nb = 135) ~f:ma_fonction = let ma_fonction2 x = (ma_fonction (int_of_float x)) in (array_of_fun ~f:ma_fonction2 ~minx:minx ~maxx:maxx ~nb:nb);; (** Donne un tableau de valeurs pour une fonction int -> int. *) let plot_fun ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) ?(full_ascii = true) ~f:ma_fonction () = plot_array ~vect:(array_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~title:title ~param:param ~mon_out:mon_out ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float. *) let plotC_fun ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) ?(full_ascii = true) ~f:ma_fonction () = plotC_array ~vect:(array_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~title:title ~param:param ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float, avec couleurs ANSI. *) let plot_fun_int ?(title = "MOcaml Plot") ?(param = true) ?(mon_out = Pervasives.stdout) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) ?(full_ascii = true) ~f:ma_fonction () = plot_array ~vect:(array_int_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~title:title ~param:param ~mon_out:mon_out ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float. *) let plotC_fun_int ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) ?(full_ascii = true) ~f:ma_fonction () = plotC_array ~vect:(array_int_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~title:title ~param:param ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float, avec couleurs ANSI. *) (* ******************************************************************************************************************************************* *) (** {6 Avec un support de la couleur customisable.} *) let plotCc_array ~vect:y_vect ?(style_fond = []) ?(style_axe = [ANSITerminal.Bold; ANSITerminal.yellow]) ?(style_pt = [ANSITerminal.Bold; ANSITerminal.green]) ?(full_ascii = true) ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) () = if (minx >= maxx) then raise Dessin_impossible; if (miny >= maxy) then raise Dessin_impossible; if (0 = (Array.length y_vect)) then raise Dessin_impossible; let taille_X = column () and taille_Y = line () in (** Récupère la taille de l'écran. *) let mon_ecran = Array.create_matrix (1+taille_X) (1+taille_Y) " " in (** Matrice des caractères de l'écran. Convention : ne mettre que des chaines de longueur ANSI = 1 (longueur ASCII != longueur ANSI !!). *) let taille_Y_vect = Array.length y_vect in let min_Y = minof_array y_vect and max_Y = maxof_array y_vect in let f_loc x = if (x < 0.) then raise Mauvaise_valeur_gauche; if (x > float_of_int(taille_Y_vect)) then raise Mauvaise_valeur_droite; y_vect.(int_of_float x); in let fm_X = 0. and fM_X = float_of_int(taille_Y_vect - 1) and fm_Y = (1.0 -. (float_of_bool(min_Y > 0.))*.0.04 +. (float_of_bool(min_Y < 0.))*.0.04 ) *. min_Y and fM_Y = (1.0 +. (float_of_bool(max_Y > 0.))*.0.04 -. (float_of_bool(max_Y < 0.))*.0.04 ) *. max_Y in let a_X = ( ((float_of_int taille_X) -. 1.)/.(fM_X -. fm_X) ) and b_X = 1. -. (float_of_int(taille_X - 1)/.(fM_X -. fm_X)) *. fm_X and a_Y = ( ((float_of_int taille_Y) -. 1.)/.(fM_Y -. fm_Y) ) and b_Y = 1. -. (float_of_int(taille_Y - 1)/.(fM_Y -. fm_Y)) *. fm_Y in let theta_x_inv indice = ((1. /. a_X) *. float_of_int(indice) -. (b_X /. a_X)) in let theta_y_ceil y = int_of_float (a_Y *. y +. b_Y) in let u_vect = Array.create (taille_X + 2) 0 in for i = 1 to taille_X do u_vect.(i) <- theta_y_ceil (f_loc (theta_x_inv i)) done; u_vect.(0) <- u_vect.(1); u_vect.(taille_X + 1) <- u_vect.(taille_X); ANSITerminal.printf [ANSITerminal.Bold; ANSITerminal.Underlined] "\ny=f(x)\tD_plot = [%f; %f] × [%f; %f]\t\ttitre = [%s]" minx maxx min_Y max_Y title; flush_all (); let aff_axe = ANSITerminal.print_string (style_fond @ style_axe) and aff_tro = ANSITerminal.print_string style_fond and aff_fle = ANSITerminal.print_string (style_fond @ style_pt) in let quoi = ref 0 in let aff q = match !q with |0 -> aff_tro |1 -> aff_axe |_ -> aff_fle in for i = taille_Y downto 0 do Printf.printf "\n"; for j = 0 to taille_X do mon_ecran.(j).(i) <- (fleche full_ascii Trou); quoi := 0; if ((i = taille_Y) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii HautG);); if ((i <> taille_Y) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii AxeVerti);); if ((i = 0) && (j <> 0) && (j <> taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii AxeHoriz);); if ((i = 0) && (j = taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii DroiteG);); if ((i = 1) && (j = taille_X)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii LegX);); if ((i = 0) && (j = 0)) then (quoi := 1; mon_ecran.(j).(i) <- (fleche full_ascii Centre);); if ((j > 0) && (u_vect.(j) <> 0)) then begin if (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Droite);); if (float_of_int(u_vect.(j - 1)) < ((1. -. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Haut);); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.09) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii Bas);); if (float_of_int(u_vect.(j - 1)) > ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii DiagBasDroite);); if (float_of_int(u_vect.(j - 1)) < ((1. +. 0.00) *. float_of_int(u_vect.(j)))) && (u_vect.(j) = i) then (quoi := 2; mon_ecran.(j).(i) <- (fleche full_ascii DiagHautDroite);); end; aff quoi (mon_ecran.(j).(i)); done; done; (* for i = taille_Y downto 0 do*) (* for j = 0 to taille_X do*) (* Printf.printf "%s" mon_ecran.(j).(i);*) (* done;*) (* done;*) ANSITerminal.printf [ANSITerminal.Bold; ANSITerminal.Underlined] "\nTitre = [%s]\tprojet MOcaml © 2012 Naereen Corp." title ; ANSITerminal.printf [ANSITerminal.blue] " (appuyez sur Enter)"; flush_all (); if param then (ignore (getchar())); ();; (** Affiche les valeurs d'un tableau. @param vect Le tableau a afficher, @param title Le titre du graphique produit, @param param Paramêtre de contrôle, @param mon_out Out_channel ou écrire le graphique, valant par défaut le channel de sortie [stdout], @param minx A faire, @param maxx A faire, @param miny A faire, @param maxy A faire. Supporte les couleurs ANSI pour faire un graphe plus joli, et ces paramètres de mises en formes ANSI sont customisables : @param style_axe Définit le style des axes, @param style_fond Définit le style du fond, @param style_pt Définit le style des points. Pour plus de détails sur le type ANSITerminal.style, voir la documentation incluse dans le Readme. *) (** {6 Styles ANSI} *) (** Voici un rappel des styles disponibles dans le module ANSITerminal : type color = ANSITerminal.color = Black | Red | Green | Yellow | Blue | Magenta | Cyan | White | Default type style = ANSITerminal.style = Reset | Bold | Underlined | Blink | Inverse | Hidden | Foreground of color | Background of color *) let plotCc_fun ~f:ma_fonction ?(style_fond = []) ?(style_axe = [ANSITerminal.Bold; ANSITerminal.yellow]) ?(style_pt = [ANSITerminal.Bold; ANSITerminal.green]) ?(full_ascii = true) ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) () = plotCc_array ~vect:(array_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~style_fond:style_fond ~style_axe:style_axe ~style_pt:style_pt ~title:title ~param:param ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float, avec couleurs ANSI customisables. *) let plotCc_fun_int ~f:ma_fonction ?(style_fond = []) ?(style_axe = [ANSITerminal.Bold; ANSITerminal.yellow]) ?(style_pt = [ANSITerminal.Bold; ANSITerminal.green]) ?(full_ascii = true) ?(title = "MOcaml Plot") ?(param = true) ?(minx = -10.0) ?(maxx = 10.0) ?(miny = -10.0) ?(maxy = 10.0) ?(nb = 135) () = plotCc_array ~vect:(array_int_of_fun ~nb:nb ~minx:minx ~maxx:maxx ~f:ma_fonction) ~style_fond:style_fond ~style_axe:style_axe ~style_pt:style_pt ~title:title ~param:param ~minx:minx ~maxx:maxx ~miny:miny ~maxy:maxy ~full_ascii:full_ascii ();; (** Dessine le graphique d'une fonction float -> float, avec couleurs ANSI customisables. *) (* ******************************************************************************************************************************************* *) (** {6 Un essai d'extension de syntaxe} *) (** Afin de se rapprocher de la syntaxe de plot en Maple par exemple. *) let x = ref 0.0 ;; (** A voir. *) (* TODO : check *) let init () = x := 0.0; ANSITerminal.print_string [ANSITerminal.Bold] "\nMOcaml Plot : bien initialisé.\n";; (** Initialise MOcaml Plot. A compléter au besoin. *) (** Fonction de typage *) let typage x = let tag_x = Obj.tag (Obj.repr x) in if tag_x = Obj.int_tag then "int" else if tag_x = Obj.string_tag then "string" else if tag_x = Obj.double_tag then "float" (*/!\*) else if tag_x = Obj.tag (Obj.repr [||]) then "array" else "unknown";; let to_float x = let x_untyped = Obj.magic x and type_x = typage x in match type_x with | "int" -> float_of_int (Obj.magic (x_untyped)) | "float" -> 1.0 *. (Obj.magic (x_untyped)) | _ -> 0.0;; (** Transforme "n'importe quoi" en flottants. *) let ( -- ) a b = (a,b);; (** Pour créer un interval. *) let plot ?(full_ascii = true) (f,(a,b)) = plotC_fun ~f:f ~minx:(to_float a) ~maxx:(to_float b) ~full_ascii:full_ascii ();; (** Syntaxe améliorée. *) (* On peut faire un essai : plot(cos,-2--3);; *) (** {6 Encore plus d'extensions : vers de la surcharge ?} *) let __nom_temporaire__ = "/tmp/TEMP__MOcamlPlot__TEMP.ml";; let __nom_temporaire2__ = "/tmp/TEMP2__MOcamlPlot__TEMP2.ml";; (** Fichiers temporaires utilisés pour la suite. *) (** Renvoie le contenu de la première ligne d'un fichier texte. L'argument peut être aussi bien l'adresse relative qu'absolue. *) let __parse_fichier file = (* fichiers a une seule lignes *) input_line (open_in file);; let res () = float_of_string(__parse_fichier __nom_temporaire2__);; (** On va écrire un programme qui écrira le résultat de son calcul dans le second fichier temporaire. Cette fonction en récupère la valeur. *) let execcaml s () = match Sys.command ("ocaml -init \"\" "^s) with |0 -> () |_ -> failwith "[MOcaml Plot] Erreur dans l'évaluation de l'argument.";; (** On interprétera le fichier TEMP avec cette fonction. *) (** {5 Un eval style Maple : très très salement codé en ocaml...} *) let evals ?(p = 53) ?(nomv = "x") ?(x = (Obj.magic 0.)) chaine_f = let outout = open_out __nom_temporaire__ in Printf.fprintf outout "#use \"/home/lilian/.mocaml/MOcamlPlot/MOcamlPlotSurcharge.ml\";;\n"; Printf.fprintf outout "let %s = %.53f;;\n" nomv (to_float x); Printf.fprintf outout "let outout = open_out \"%s\";;\n" __nom_temporaire2__; (* Printf.fprintf outout "Printf.fprintf outout \"%%.53f\" (to_float(%s));;\n" chaine_f;*) Printf.fprintf outout "Printf.fprintf outout \"%%.%df\" (to_float(%s));;\n" p chaine_f; Printf.fprintf outout "close_out outout ;;"; flush_all (); close_out outout; execcaml __nom_temporaire__ (); res ();; (** Permet d'évaluer le contenu d'une string ocaml. @param p Renseigne sur la précision maximum du calcul effectuée. En béta. @param nomv Chaine de caractère renseignant sur le nom de la variable libre de l'expression calculée. Par défaut = "x". @param x Valeur de la variable libre. Ces trois paramètres sont optionnels, et par défaut x = 0.0. @param chaine_f Chaine qu'on cherche à évaluer. *) (* #use "/home/lilian/.mocaml/MOcamlPlot/MOcamlPlotSurcharge.ml";; *) (*#load "surcharge.cma";;*) (** On utilise le petit module surcharge fait pour le projet. *) let eval ?(nomv = "x") ?(x = (Obj.magic 0.)) xpoly = let type_x = Surcharge.typage xpoly in let x_untyped = Obj.magic xpoly in match type_x with | "int" -> to_float xpoly; | "float" -> to_float xpoly; | "string" -> (evals ~x:x ~nomv:nomv (Surcharge.to_string x_untyped)); | "array" -> 0.0; | _ -> 0.0;; (** Et cette fonction permet d'évaluer un élément ocaml. Si le type de l'élément n'est pas simple, 0.0 est renvoyé. @param nomv Nom de l'éventuelle variable libre de l'expression. @param x Valeur de cette variable libre. @param xpoly Elément a évaluer. Fonctionne si est un entier, un flottant, un booléen, ou une chaine. Les résultats pour les autres types sont aléatoires. *) let pplot ?(nomv = "x") ?(full_ascii = true) xpoly (a,b) = plot( (fun xxx -> (eval ~nomv:nomv ~x:xxx xpoly) ), (a,b)) ~full_ascii:full_ascii;; (** On utilise donc tout ca pour proposer une méthode de dessin de graphe, fortement polymorphique, mais très très salement codée (Si vous pensez que j'exagère ou si vous pensez le contraire, jetez un oeil attentif a ce qui est fait dans ce programme et dans le module Surcharge : c'est sale !) @param xpoly Peut être une constante, entière ou flottante, ou une chaine. Ce second cas n'a d'intéret que si la chaine dépend d'une variable libre, @param nomv Et ce second paramètre est justement le nom de cette variable libre. Par défaut, "x". *) (** Pour le moment, sans vraiment de raison, c'est très lent. En béta ! *) let polyPlot ?(nomv = "x") ?(range = Obj.magic(-10.,10.)) ?(full_ascii = true) xpoly = match Surcharge.typage xpoly with | "array" -> plotC_array ~vect:(Surcharge.to_array xpoly) ~full_ascii:full_ascii ~minx:(to_float(fst(range))) ~maxx:(to_float(snd(range))) (); | "arrayf" -> plotC_array ~vect:(Surcharge.to_array xpoly) ~full_ascii:full_ascii ~minx:(to_float(fst(range))) ~maxx:(to_float(snd(range))) (); | _ -> (pplot ~nomv:nomv ~full_ascii:full_ascii xpoly range);; (** Le mieux que j'ai pu faire. On a ici une fonction qui peut afficher : des constantes entières ou flottantes, des tableaux ou des listes d'entiers ou de flottants, et des chaines de caractères représentant des expressions ayant une variable libre. Ca marche très bien ! Mais qu'est-ce que c'est sale... *) (*if not(!(Sys.interactive)) then ANSITerminal.print_string [ANSITerminal.Bold] "[MOcaml Plot] : initialisé !\n";;*) (* Un exemple pour conclure *) (*polyPlot "sin(x)" ~range:(-3--9);;*) (* Merci a Romain Vernoux pour l'idée sur la surcharge. *) (* /!\ Code écrit par Lilian BESSON - LSV & CMLA & ENS de Cachan. Par respect des droits de propriétés intellectuelles, conservez ce bordereau si vous utilisez tout ou une partie de ce fichier. *)