455 lines
10 KiB
C
455 lines
10 KiB
C
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <GL/glut.h>
|
|
|
|
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;
|
|
}
|