///////////////////////////////////////////////////////////// // Ecrit par Lilian BESSON - ENS de Cachan & Naereen Corp. // LSV & CMLA. (c) 2012 ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // // Meta plot... // ... un essai satisfaisant ///////////////////////////////////////////////////////////// // Chargement des librairies externes : #include #include #include //Pour copier et obtenir la longueur des chaines de caractères. #include //Pour les fonctions gérant le temps (pour afficher la date et heure de création dans les fichiers externes créés) //////////////////////////////////////////////////////////////// // Fonction wait(milliseconds) // permet d'attendre, le temps demandé void wait ( int miliseconds ) { clock_t endwait; //On définit un élément du type 'clock_t' : ce type est définit par la librairie endwait = clock () + (0.001 * miliseconds) * CLOCKS_PER_SEC ; //CLOCKS_PER_SEC : macro pour donné le nombre de tics du processeur, lorsqu'il run du code C compilé, par seconde. L'instruction clock() : fait un tour d'horloge, sans rien faire d'autre while (clock() < endwait) {} } char* temps_courant (){ time_t rawtime; struct tm * timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); asctime (timeinfo); } // En fait, cette fonction ne fait pas un chronomètre très précis : on ne compte pas le temps que met le while(..) a se faire (temps forcément non nul) //////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Fonction principale //////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) //Attend deux arguments . { char* chaine_fonction_a_tracer; char* nom_fichier_arrivee; char* arg1; char* arg2; if (argc != 3){fprintf(stderr, "USAGE : ./meta_plot \n\tva ecrire un code C appelé .c, qui une fois compilé permettra le tracé EN CONSOLE du graphe de la fonction rentrée en premier argument.\nPar Lilian BESSON - © 2012 - ENS de Cachan & LSV & CMLA\n"); fflush(stderr); exit(10);} nom_fichier_arrivee = malloc(sizeof(char) * 4 * (strlen(argv[2]))); chaine_fonction_a_tracer = malloc(sizeof(char) * 4 * (strlen(argv[1]))); //Signature perso printf("\t\t-----------------------------------------------------------------------------------------------------------\n"); printf("\t\t| Ecrit par Lilian BESSON - ENS de Cachan & LSV & CMLA - Jan Fev 2012 |\n"); printf("\t\t| METAplot... un essai satisfaisant |\n"); printf("\t\t-----------------------------------------------------------------------------------------------------------\n"); //Initialisation des variables : arg1 = argv[1]; arg2 = argv[2]; FILE* fichier_ecriture_C = NULL; FILE* fichier_ecriture_makefile = NULL; //Affiche du blabla pour faire plus sérieux ;) printf("\nInitialisation des variables en cours...\n"); printf("Longueur premier argument = %d\nLongueur second argument = %d\n", (strlen(argv[1])), (strlen(argv[2]))); wait(2); printf("\nInitialisation des variables terminée\n"); //Ecrire un Makefile printf("Ecriture du Makefile en cours...\n"); fichier_ecriture_makefile = fopen("Makefile", "w"); fprintf(fichier_ecriture_makefile, "#Ecriture initialisee\n"); fprintf(fichier_ecriture_makefile, "#Fichier Makefile généré le : %s", temps_courant()); fprintf(fichier_ecriture_makefile, "#\n#Makefile généré automatiquement par le programme ./meta_plot\n#Permet de compiler le programme <%s>\n#\tqui sert a tracer EN CONSOLE le graphe de :\n#f(x) := %s\n#Sur une fenêtre quelconque que l'utilisateur rentre en utilisant l'exécutable produit.\n\n#On utilise le compilateur GCC\nCC = gcc\nCFLAGS = -Wall -O3\n#On précise qu'on peut avoir besoin de la librairie \nLDFLAGS = -lm\n\n#Ce qu'on veut faire\n%s : %s.o\n\t$(CC) $^ -o $@ $(LDFLAGS)\n\n%s.o : %s.c\n\t$(CC) %s.c -c $(CFLAGS)\n#\n#Fin Makefile\n#Généré automatiquement par un programme écrit par Lilian BESSON 2012 © ENS de Cachan & LSV & CMLA - Naereen Corp.\n#", arg2, arg1, arg2, arg2, arg2, arg2, arg2); wait(2); printf("Ecriture du Makefile terminée\n"); //Ecrire le programme C //Du blabla, et ouvre le fichier. nom_fichier_arrivee = strcpy(nom_fichier_arrivee, arg2); strcat(arg2, ".c"); printf("Génération du code C permettant d'afficher en Console le graphique de f(x) := \"%s\" en cours...\n", arg1); wait(2); printf("\nGénération du code C terminée.\n"); printf("\nEcriture dans %s.c en cours...\n", nom_fichier_arrivee); wait(2); printf("\nEcriture dans %s.c terminée.\n", nom_fichier_arrivee); fichier_ecriture_C = fopen(arg2, "w"); //Ecrit dans le fichier une grosse chaine, correspondant en gros au programme contenu dans , que j'ai réalisé. //La seule modification est qu'ici sont remplacés toutes les occurences à la définition arithmétique de la fonction a tracer f, par la chaine de caractères que l'utilisateur a rentrée (). fprintf(fichier_ecriture_C, "//\n//Fichier programme C généré le : %s//\n", temps_courant()); fprintf(fichier_ecriture_C, "//Généré automatiquement par un programme écrit par Lilian BESSON 2012 © ENS de Cachan & LSV & CMLA - Naereen Corp.\n#include \n#include \n#include \n#include \n\nvoid wait ( int miliseconds )\n{\n\tclock_t endwait;\n\tendwait = clock () + (0.001 * miliseconds) * CLOCKS_PER_SEC ;\n\twhile (clock() < endwait) {}\n}\n\nvoid my_plot(float* Y_vect, int taille_Y_vect, char* my_title, int mon_param, float m_X0, float M_X0, float m_Y0, float M_Y0);\nfloat ma_fonction_f (float x);\n\nfloat ma_fonction_f (float x){ return %s; }\n\nint main(int argc, char **argv) //\n{\n\n\tint controle_y_n;\n\tint i,j,k;\n\n\tfloat xx;\n\n\tfloat m_X, m_Y, M_X, M_Y;\n\tfloat a_X, a_Y, b_X, b_Y;\n\n\tint taille_X, taille_Y;\n\tfloat* u_vect;\n\nif ((argc < 5)||(argc > 6))\n\t{\n\tfprintf (stderr, \"\\nUsage: ./%s \\n\\tTrace un graphe en console de f(x) = %s \\n\\tSur le domaine D = Dx × Dy = [m_X; M_X] × [m_Y; M_Y]\\n\\tLe parametre est une option : si il est present et non nul, alors le systeme attend l'aval de l'utilisateur, sinon le dessin arrive directement.\\npar Lilian BESSON «Graphique en Console» © 2012\\n\");\n\tfflush (stderr);\n\texit (10);\n\t}\n\n\tif (argc == 6) {controle_y_n = atoi(argv[5]);}\n\tif (argc != 6) {controle_y_n = 0;}\n\n\tif (controle_y_n) {\n\t\tprintf(\"Essai de transformation de segments.\\n\\tContinuer ? (Ctrl + C pour non, enter pour oui)\\n\");\n\t\tgetchar();\n\t}\n\n\tm_X = strtod (argv[1], NULL); M_X = strtod (argv[2], NULL);\n\tm_Y = strtod (argv[3], NULL); M_Y = strtod (argv[4], NULL);\n\n\ttaille_Y = 37;\n\ttaille_X = 135;\n\n\tif (controle_y_n) {\n\t\tprintf(\"Parametres du dessin :\\n\");\n\t\tprintf(\"\\tSur le domaine D_X = [%%f, %%f]\\n\\t et le domaine D_Y = [%%f, %%f]\\n\", m_X, M_X, m_Y, M_Y);\n\t\tif (controle_y_n) {printf (\"Le programme attendra les confirmations successives de l'utilisateur.\\n\");}\n\tif (!controle_y_n) {printf (\"La programme n'attendra aucune confirmation successive de l'utilisateur.\\n\");}\n\t}\n\n\ta_X = ( (taille_X - 1)/(M_X - m_X) );\n\tb_X = 1 - ((taille_X - 1)/(M_X - m_X)) * m_X;\n\n\ta_Y = ( (taille_Y - 1)/(M_Y - m_Y) );\n\tb_Y = 1 - ((taille_Y - 1)/(M_Y - m_Y)) * m_Y;\n\n\tif (controle_y_n) {\n\t\tprintf(\"Données indicatives sur les fonctions de transformations des segments :\\n\\tContinuer ? (Ctrl + C pour non, enter pour oui)\");\n\t\tgetchar();\n\t}\n\n\tfloat theta_x_inv(int indice){return ((1. / a_X) * indice - (b_X / a_X)); }\n\n\tif (controle_y_n) {\n\t\tprintf(\"\\nPour l'affichage : x(.) <- theta_x_inv(.)\\n\");\n\t\tfor (i=1; i<= taille_X; i++){\n\t\t\tprintf(\"x(%%d)=%%f\\t\", i, theta_x_inv(i));\n\t\t\tif ((i % 8) == 7){printf(\"\\n\");}\n\t\t}\n\t}\n\n\tint theta_y_ceil(float y){return ( (a_Y * y + b_Y)); }\n\n\tif (controle_y_n) {\n\t\ti = 0;\n\t\tprintf(\"\\nPour l'affichage : y(.) <- theta_y_ceil(.)\\n\");\n\t\tfor (xx=m_Y; xx<= M_Y; xx += (0.05)*(M_Y - m_Y)){\n\t\t\ti++;\n\t\t\tprintf(\"y(%%f)=%%d\\t\", xx, theta_y_ceil(xx));\n\t\t\tif ((i % 8) == 7){printf(\"\\n\");}\n\t\t}\n\t\tif ((i % 8) != 7){printf(\"\\n\");}\n\t}\n\n\tif (controle_y_n) {\n\t\tprintf(\"Fin de l'essai de transformation de segments.\\n\\tContinuer ? (Ctrl + C pour non, enter pour oui)\\n\");\n\t\tgetchar();\n\t}\n\n\tu_vect = malloc(sizeof(int) * (taille_X + 2));\n\n\tfor (j=1; j<= taille_X; j++){\n\t\tu_vect[j] = theta_y_ceil (ma_fonction_f (theta_x_inv (j)));\n\t}\n\tu_vect[0] = u_vect[1];\n\tu_vect[taille_X + 1] = u_vect[taille_X];\n\n\tmy_plot(u_vect, taille_X, \"Tracé de f(x)=%s\", controle_y_n, m_X, M_X, m_Y, M_Y);\n\n\treturn 0;\n}\n\nvoid my_plot(float* Y_vect, int taille_Y_vect, char* my_title, int mon_param, float m_X0, float M_X0, float m_Y0, float M_Y0){\n\n\tint i,j,k;\n\n\tfloat xx;\n\n\tfloat m_X, m_Y, M_X, M_Y;\n\tfloat a_X, a_Y, b_X, b_Y;\n\tfloat min_Y, max_Y;\n\n\tint taille_X, taille_Y;\n\n\tchar** mon_ecran;\n\n\tint* u_vect;\n\n\tif (taille_Y_vect <= 0) {\n\t\tfprintf(stderr, \"ERROR - my_plot : le vecteur d'entrée doit avoir une taille non nulle et positive.\");\tfflush(stderr);\texit(10);\n\t}\n\n\tmin_Y = Y_vect[0];\n\tmax_Y = Y_vect[0];\n\n\tfor (i=1; i < taille_Y_vect; i++){\n\t\tif (Y_vect[i] < min_Y) { min_Y = Y_vect[i];}\n\t\tif (Y_vect[i] > max_Y) { max_Y = Y_vect[i];}\n\t}\n\n\tm_X = 0;\t\tM_X = (taille_Y_vect - 1);\n\tm_Y = (1.0 - (min_Y > 0)*0.04 + (min_Y < 0)*0.04 ) * min_Y;\tM_Y = (1.0 + (max_Y > 0)*0.04 - (max_Y < 0)*0.04 ) * max_Y;\n\n\tfloat ma_fonction_f_locale (float x){\n\t\tint i;\n\t\tif (x < m_X){fprintf(stderr, \"ERROR - my_plot : la fonction ne doit pas etre appelée la ou elle n'est pas définie : x < m_X.\"); fflush(stderr); exit(10);}\n\t\tif (x > M_X){fprintf(stderr, \"ERROR - my_plot : la fonction ne doit pas etre appelée la ou elle n'est pas définie : x > M_X.\"); fflush(stderr); exit(10);}\n\t\ti = x;\n\t\treturn(Y_vect[i]);\n\t}\n\n\ttaille_Y = 37;\ttaille_X = 135;\n\n\ta_X = ( (taille_X - 1)/(M_X - m_X) );\n\tb_X = 1 - ((taille_X - 1)/(M_X - m_X)) * m_X;\n\n\ta_Y = ( (taille_Y - 1)/(M_Y - m_Y) );\n\tb_Y = 1 - ((taille_Y - 1)/(M_Y - m_Y)) * m_Y;\n\n\tfloat theta_x_inv(int indice){return ((1. / a_X) * indice - (b_X / a_X)); }\n\n\tint theta_y_ceil(float y){return ( (a_Y * y + b_Y)); }\n\n\tmon_ecran\t= malloc(16*sizeof(char*) * (taille_X + 1) * (taille_Y + 1) * (taille_X) * (taille_Y));\n\tu_vect\t= malloc(16*sizeof(int) * (taille_X + 2));\n\n\tfor (j=1; j<= taille_X; j++){\n\t\tu_vect[j] = theta_y_ceil (ma_fonction_f_locale (theta_x_inv (j)));\n\t}\n\tu_vect[0] = u_vect[1];\n\tu_vect[taille_X + 1] = u_vect[taille_X];\n\n\tprintf(\"\\ny=f(x)\\tD_plot = [%%f; %%f] × [%%f; %%f]\\t\\ttitre = [%%s]\", m_X0, M_X0, m_Y0, M_Y0, my_title);\n\n\tfor (i = taille_Y ; i>=0; i--){\n\t\tfor (j=0; j <= taille_X; j++){\n\t\t\tmon_ecran[i + (taille_X + 1)*j] = \" \";\n\t\t\t\tif ((i == taille_Y) && (j == 0)) {mon_ecran[i + (taille_X + 1)*j] = \"⇑\";}\n\t\t\t\tif ((i != taille_Y) && (j == 0)) {mon_ecran[i + (taille_X + 1)*j] = \"|\";}\n\n\t\t\t\tif ((i == 0) && (j != 0) && (j != taille_X)) {mon_ecran[i + (taille_X + 1)*j] = \"−\";}\n\t\t\t\tif ((i == 0) && (j == taille_X)) {mon_ecran[i + (taille_X + 1)*j] = \"⇒\";}\n\t\t\t\tif ((i == 1) && (j == taille_X)) {mon_ecran[i + (taille_X + 1)*j] = \"x\";}\n\n\t\t\t\tif ((i == 0) && (j == 0)) {mon_ecran[i + (taille_X + 1)*j] = \"+\";}\n\n\t\t\tif ((j > 0) && (u_vect[j] != 0)){\n\t\t\tif (u_vect[j] == i) {mon_ecran[i + (taille_X + 1)*j] = \"→\";}\n\n\t\t\t\tif (u_vect[j - 1] > ((1 + 0.00) * u_vect[j])){if (u_vect[j] == i) {mon_ecran[i + (taille_X + 1)*j] = \"↘\";}}\n\t\t\t\tif (u_vect[j - 1] < ((1 + 0.00) * u_vect[j])){if (u_vect[j] == i) {mon_ecran[i + (taille_X + 1)*j] = \"↗\";}}\n\t\t\t\tif (u_vect[j - 1] < ((1 - 0.09) * u_vect[j])){if (u_vect[j] == i) {mon_ecran[i + (taille_X + 1)*j] = \"↑\";}}\n\t\t\t\tif (u_vect[j - 1] > ((1 + 0.09) * u_vect[j])){if (u_vect[j] == i) {mon_ecran[i + (taille_X + 1)*j] = \"↓\";}}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (i = taille_Y; i >= 0; i--){\n\t\tprintf(\"\\n\");\n\t\tfor (j = 0; j <= taille_X; j++){\n\t\t\tprintf(\"%%s\", mon_ecran[i + (taille_X + 1)*j]);\n\t\t}\n\t}\n\t\n\tprintf(\"\\n«Graphique en Console» © 2012\ttitre = [%%s]\\tpar Lilian BESSON\", my_title);\n\tprintf(\" (appuyez sur Enter)\");\n\n\t\n\tgetchar();\n\n\tif (!mon_param){wait(115);}\n\n\tfree(u_vect); free(mon_ecran);\n}\n\n//Généré automatiquement par un programme écrit par Lilian BESSON 2012 © ENS de Cachan & LSV & CMLA - Naereen Corp.\n", arg1, nom_fichier_arrivee, arg1, arg1); //Je sais, c'est ILLISIBLE : mais c'est un peu le but en fait. Pour plus de détail, allez voir le contenu du programme . //Conclure : printf("\nLa génération automatique du code s'est bien passée.\n\tVous pouvez compiler et observer le résultat avec :\n$ gcc -o %s %s.c -lm && ./%s\n\tPuis en appelant :\n$ ./%s minX, MaxX, minY, MaxY, [controle]\n\n\t\tMerci d'avoir choisi «MetaPlot».\tPar Lilian BESSON 2012\n", nom_fichier_arrivee, nom_fichier_arrivee, nom_fichier_arrivee , nom_fichier_arrivee); return 0; //Sort simplement du programme, tout s'est bien passe } /////////////////////////////////////////////////////////////////////////////// // FIN Fonction principale //////////////////////////////////////////////////////////////////////////////// /*/////////////////////////////////////////////////////////////// Mode d'emplois rapide : Ce programme permet de tracer directement dans le terminal un graphique donnant l'allure d'une fonction, sur une fenêtre particulière. Le point 'particulier' c'est que cette fonction et cette fenêtre sont... donnés en arguments ! Imaginiez que vous vouliez voir l'allure qu'a la fonction suivante : f(x) := 1+3*x-7*x*x+0.1*x*x*x, pour x=-10..10 et y=-10..10; mais sans sortir votre TI89, ni Maple, ni GNUplot, ni Octave ni... tout outil un peu évolué ! (En fait, que vous vouliez travailler avec un outil préhistorique) Et bien il vous suffit de taper la ligne de commande suivante (dans la console) : $ gcc -o meta_plot meta_plot.c && ./meta_plot "1 + 3*x - 7*x*x + 0.1*x*x*x" monexp && gcc -o monexp monexp.c -lm && ./monexp -10 10 -10 10 Soit dans un cas plus général : $ gcc -o meta_plot meta_plot.c && ./meta_plot && gcc -o ARG2 ARG2.c -lm && ./ARG2 (A faire dans un répertoire qui contient meta_plot.c (et rien d'autre n'est nécessaire). Le "-lm" est NECESSAIRE par contre) : -------- Le premier argument correspond à l'expression mathématique de notre fonction. Il est plus commode de le rentrer entre double quote (" .. "), afin d'autoriser les espaces. Seules les fonctions de la librairie math.h sont supportées, ainsi que les expressions arithmétiques de bases +,-,*,/,%. Mais en fait, de la façon dont le programme est codé (ie : sans trop de précautions), cette string peut contenir le corps de n'importe quelle fonction satisfaisant le prototype : 'float (float x)', et ne dépendant pas de variables globales. Tout de suite, si on sais rentrer plusieurs lignes de codes dans la string, ca autorise a faire plus (et a faire planter le programme). Enfin, tout ca pour préciser que je ne vérifie PAS DU TOUT la forme qu'a ce premier argument. : -------- Le second argument sera le nom qu'aura notre exécutable permettrant de tracer la fonction. En particulier, si vous avez besoin plusieurs fois de suite de tracer des graphes différents mais avec la même fonction, vous pouvez le faire sans recompiler (d'autant qu'il y a deux compilations) : $ ./ARG2 . Il est conseillé de ne pas utiliser de symboles autres que : les minuscules(a-z), les majuscules(A-Z), les chiffres (0-9), et le tiret '-'. En particulier, l'underscore est déconseillé, et les slash ou antislash sont fortement déconseillé (l'un ou l'autre va faire crasher le programme, selon que vous travailliez sur un système Unix ou Windows). : ----------------------------- Taille de la fenètre que vous souhaitez tracer : ARG3 = valeur minimum que prend l'abscisse x, ARG4 = valeur maximum que prend l'abscisse x, ARG5 = valeur minimum que prend l'ordonnée y, ARG6 = valeur maximum que prend l'ordonnée y, ///////////////////////////////////////////////////////////////*/ ///////////////////////////////////////////////////////////// // Ecrit par Lilian BESSON - ENS de Cachan & Naereen Corp. // LSV & CMLA. (c) 2012 /////////////////////////////////////////////////////////////