#include #include #include #include #include void afficher(void); int initWindow(int, char**, void(*)(void)); void destroyWindow(int); long getFileSize(FILE*); void parseFile(char*, long); bool charger(char*); void printCourbeTerminal(void); void ligne(int, float, float, float, float); float map(float, float, float, float, float); void reshapeCallback(int, int); void axes(float, float, float, float); void histo(int, float, float, float, float); // Variables donneés #define MAXC 20 #define MAXV 100 float courbe[MAXC][MAXV]; float valmin[MAXC]; float valmax[MAXC]; int nc = 0; // # Defines // Utilisés pour `mode_affichage` #define HORIZONTAL 0 #define VERTICAL 1 #define SUPERPOSER 2 // Utilisés pour `type_dessin` #define LIGNE 0 #define LIGNE_AXES 1 #define HISTOGRAMME 2 // pas un vrai histogramme // Variables globales int vx1 = 0, vx2 = 400, vy1 = 0, vy2 = 400; int mode_affichage = HORIZONTAL; int type_dessin = LIGNE; /* Transforme une valeur `val` présente entre `smin` et `smax` et la retourne présente entre `omin` et `omax` */ float map(float smin, float smax, float val, float omin, float omax) { float percent = (val - smin) / (smax - smin); //printf("v%f, p%f, min%f, max%f\n", val, percent, omin, omax); return (omax-omin) * percent + omin; } /* Affiche deux axes allant de : `x1`,`y2` vers `x2`,`y2` et `x2`,`y2` vers `x2`,`y1` */ void axes(float x1, float x2, float y1, float y2) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); glColor3f(1.0,0.5,0.5); glBegin(GL_LINE_STRIP); glVertex2f(x1, y2); glVertex2f(x2, y2); glVertex2f(x2, y1); glEnd(); } /* Trace la courbe à l'index `index` dans le rectangle défini par un point en haut à gauche `hgx` & `hgy` et un point en bas à droite `bdx` & `bdy` Fonction soumise au variables globales `type_dessin`, `mode_affichage`, `courbe`, `valmin` et `valmax` */ void ligne(int index, float hgx, float hgy, float bdx, float bdy) { if(index >= nc) { printf("Courbe non-existante."); return; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); float color = 1.0; if(mode_affichage == SUPERPOSER) color = map(0, nc, index, 0.5, 1.0); glColor3f(color, color, color); glBegin(GL_LINE_STRIP); unsigned int size = (unsigned int)courbe[index][0]; for(unsigned int i = 1; i < size+1; i++) { float pos_x = map(0, size-1, i-1, hgx, bdx); float pos_y = map(valmin[index], valmax[index], courbe[index][i], bdy, hgy); //printf("%d : {%f, %f}\n", i, pos_x, pos_y); if(mode_affichage == VERTICAL) { // On inverse les deux lors d'un affichage vertical float temp = pos_x; pos_x = pos_y; pos_y = temp; } glVertex2f(pos_x, pos_y); } fflush(stdout); glEnd(); if(type_dessin == LIGNE_AXES) { for(unsigned int i = 1; i < size+1; i++) { float pos_x = map(0, size-1, i-1, hgx, bdx); float pos_y = map(valmin[index], valmax[index], courbe[index][i], bdy, hgy); if(mode_affichage == VERTICAL) { axes(bdy, pos_y, hgx, pos_x); }else{ axes(hgx, pos_x, bdy, pos_y); } } } } /* Trace l'histogramme de la courbe à l'index `index` dans le rectangle défini par un point en haut à gauche `hgx` & `hgy` et un point en bas à droite `bdx` & `bdy` Fonction soumise aux variables globales `mode_affichage`, `courbe`, `valmin` et `valmax` */ void histo(int index, float hgx, float hgy, float bdx, float bdy) { if(index >= nc) { printf("Courbe non-existante."); return; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); float color = 1.0; if(mode_affichage == SUPERPOSER) color = map(0, nc, index, 0.5, 1.0); glColor3f(color, color, color); //glBegin(GL_POLYGON); unsigned int size = (unsigned int)courbe[index][0]; for(unsigned int i = 1; i < size+1; i++) { float gauche = map(0, size, i-1, hgx, bdx); float droite = map(0, size, i, hgx, bdx); float haut = map(valmin[index], valmax[index], courbe[index][i], bdy, hgy); float bas = bdy; if(mode_affichage == VERTICAL) { /* Si vertical, on change les variable pour faire "tourner" le rectangle */ float temp = bas; bas = gauche; gauche = haut; haut = droite; droite = temp; } glRectf(gauche, haut, droite, bas); //printf("%d : {g%f, h%f, b%f, d%f}\n", i, gauche, haut, droite, bas); } fflush(stdout); //glEnd(); } /* Fonction d'affichage appelée par glut Fonction soumise au variables globales `type_dessin`, `mode_affichage`, `courbe`, `valmin` et `valmax` */ void afficher(void) { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); if(mode_affichage == HORIZONTAL) { for(unsigned int i = 1; i < nc+1; i++) { float haut = map(0, nc, i-1, 1.0, -1.0); float bas = map(0, nc, i, 1.0, -1.0); if(type_dessin == LIGNE || type_dessin == LIGNE_AXES) { ligne(i-1, -1.0, haut, 1.0, bas); }else{ // type_dessin == HISTO histo(i-1, -1.0, haut, 1.0, bas); } } } if(mode_affichage == VERTICAL) { for(unsigned int i = 1; i < nc+1; i++) { float gauche = map(0, nc, i-1, -1.0, 1.0); float droite = map(0, nc, i, -1.0, 1.0); if(type_dessin == LIGNE || type_dessin == LIGNE_AXES) { ligne(i-1, -1.0, gauche, 1.0, droite); }else{ // type_dessin == HISTO histo(i-1, -1.0, gauche, 1.0, droite); } } } if(mode_affichage == SUPERPOSER) { for(unsigned int i = 1; i < nc+1; i++) { if(type_dessin == LIGNE || type_dessin == LIGNE_AXES) { ligne(i-1, -1.0, 1.0, 1.0, -1.0); }else{ // type_dessin == HISTO histo(i-1, -1.0, 1.0, 1.0, -1.0); } } } glFlush(); } /* Callback lorsque la fenetre est redimensionnée. Actualise les variables globales `vx2` et `vy2` */ void reshapeCallback(int largeur, int hauteur) { vx2 = largeur; vy2 = hauteur; glViewport(0, 0, largeur, hauteur); //glutPostRedisplay(); //printf("Reshape : [%d, %d]\n", vx2, vy2); } /* Initialise la fenètre GLUT, retourne son handle. Attend les valeurs `argc` et `argv` de main ainsi qu'un fonction d'affichage `display` */ int initWindow(int argc, char* argv[], void(*display)(void)) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA); // Une seule fenètre, RGB glutInitWindowPosition(vx1, vy1); // Position glutInitWindowSize(vx2, vy2); // Taille int window = glutCreateWindow("TP1"); glutDisplayFunc(display); // Fonction d'affichage glutReshapeFunc(reshapeCallback); // Redimensionnement return window; } /* Détruit la fenètre passé en paramètre via son handle dans `window` */ void destroyWindow(int window) { glutDestroyWindow(window); } /* Retourne la taille d'un fichier `file` Le fichier doit être correctement ouvert. */ long getFileSize(FILE* file) { // On va à la fin du fichier et on note notre position dans celui-ci fseek(file, 0, SEEK_END); long fileSize = ftell(file); rewind(file); return fileSize; } /* Lis le fichier `file` avec une taille `size` et analyse celui-ci pour saisir son contenu dans les variables globales `courbe`, `valmin` et `valmax` */ void parseFile(char* file, long size) { nc = atoi(file); //printf("nc=%d\n", nc); //printf("====\n%s\n====\n", file); // Pointeur mobile dans le fichier char* pointeur = file; unsigned int line = 0; while(line < nc) { /* Cherche le premier \n à partir du pointeur * /!\ on suppose un fichier encodé en UNIX (LF) /!\ */ pointeur = strchr(pointeur, '\n') + 1; //printf(" ->\"%c\"", *pointeur); int taille_tableau = atoi(pointeur); courbe[line][0] = taille_tableau; //printf(" ->\"%d\" \n", taille_tableau); for(unsigned int i = 1; i < taille_tableau+1; i++) { // On suppose que les nombres sont séparés par un espace pointeur = strchr(pointeur, ' ') + 1; float num = strtof(pointeur, 0); courbe[line][i] = num; if(i == 1) { // Première ligne, on alimente directement valmin et valmax valmin[line] = num; valmax[line] = num; }else{ // Sinon comparaison if(num < valmin[line]) valmin[line] = num; if(num > valmax[line]) valmax[line] = num; } } line++; } } /* Charge un fichier au path `nom` et analyse son contenu. Le contenu sera présent dans les variables globales `courbe`, `valmin` et `valmax` */ bool charger(char* nom) { FILE* file = fopen(nom, "r"); if(file == NULL) { printf("Erreur ouverture fichier.\n"); return false; } long fileSize = getFileSize(file); // Allouer un tableau dans la mémoire de la tailel du tableau + 1(NULL) char* buffer = (char*)malloc(sizeof(char) * fileSize + 1); if(buffer == NULL) { printf("Erreur allocation mémoire.\n"); return false; } buffer[fileSize] = 0; // NULL à la fin du fichier // Lis le fichier dans notre buffer int res = fread(buffer, sizeof(char), fileSize, file); if(res == 0) { printf("Erreur lecture fichier.\n"); return false; } // On libère le fichier fclose(file); // On analyse le contenu parseFile(buffer, fileSize); // On libère la mémoire, le contenu est stocké dans les variables globales free(buffer); return true; } /* Affiche le contenu de la variable globale `courbe` */ void printCourbeTerminal(void) { for(unsigned int i = 0; i < nc; i++) { for(unsigned int j = 0; j < courbe[i][0]+1; j++) { printf("%f", courbe[i][j]); if(j < courbe[i][0]) printf(", "); } printf("\n"); } } int main(int argc, char* argv[]) { if(!charger("valeurs.txt")) return EXIT_FAILURE; printCourbeTerminal(); type_dessin = HISTOGRAMME; mode_affichage = HORIZONTAL; int window = initWindow(argc, argv, afficher); glutMainLoop(); destroyWindow(window); return EXIT_SUCCESS; }