/* Courbe B-Spline non rationnelle uniforme */ /* */ /* Auteur: Nicolas JANEY */ /* nicolas.janey@univ-fcomte.fr */ /* Mars 2019 */ #include #include #include #include #include #include #include "Pos3D.h" /* Variables et constantes globales */ static const float blanc[] = { 1.0F,1.0F,1.0F,1.0F }; static const float gris[] = { 0.7F,0.7F,0.7F,1.0F }; static float rx = 0.0F; static float ry = 0.0F; static float rz = 0.0F; static int nb = 100; static int nP = 0; static int aff = 0; static float tCouleur[7][3] = { { 1.0F,1.0F,1.0F }, { 1.0F,0.0F,1.0F }, { 0.0F,1.0F,1.0F }, { 1.0F,1.0F,0.0F }, { 1.0F,0.0F,0.0F }, { 0.0F,1.0F,0.0F }, { 0.0F,0.0F,1.0F } }; static int taille = 4; static int nbPoints = 10; static Pos3D *tPos[] = { new Pos3D(-6.0,-4.0, 1.0), new Pos3D(-4.5, 3.0, 2.0), new Pos3D( 2.0, 2.0, 3.0), new Pos3D( 5.5,-3.0, 1.0), new Pos3D( 4.5,-2.0,-3.0), new Pos3D( 4.0, 4.0,-4.0), new Pos3D( 0.0, 5.0,-2.0), new Pos3D( 2.0,-2.0,-1.0), new Pos3D(-1.0,-5.0,-2.0), new Pos3D(-3.5,-4.0, 0.0) }; static double NRUBS[4][4] = { { -1.0/6.0, 3.0/6.0, -3.0/6.0, 1.0/6.0 }, { 3.0/6.0, -6.0/6.0, 3.0/6.0, 0.0 }, { -3.0/6.0, 0.0, 3.0/6.0, 0.0 }, { 1.0/6.0, 4.0/6.0, 1.0/6.0, 0.0 } }; static double CATMULL_ROM[4][4] = { { -1.0/2.0, 3.0/2.0, -3.0/2.0, 1.0/2.0 }, { 2.0/2.0, -5.0/2.0, 4.0/2.0, -1.0/2.0 }, { -1.0/2.0, 0.0, 1.0/2.0, 0.0 }, { 0.0, 2.0/2.0, 0.0, 0.0 } }; static void vertex(Pos3D *p,int couleur,double taille) { glPushMatrix(); glColor3f(tCouleur[couleur%7][0],tCouleur[couleur%7][1],tCouleur[couleur%7][2]); glTranslated(p->x,p->y,p->z); glutSolidSphere(taille,36,18); glPopMatrix(); } /////////////////////////////////////////////////// /* Calcul la position d'un point sur une courbe */ /* B-Spline controlee par quatre sommets */ /* g : le tableau des 4 sommets de controle */ /* t : la valeur de calcul du point */ /* t a prendre dans l'intervalle [0.0,1.0] */ /* mb : la matrice de base */ /* p : le point resultat */ static void determinationPositionSurBSpline(Pos3D **g,double t,double mb[4][4],Pos3D *p) { double vt[4] = { t*t*t,t*t,t,1.0 }; double vtmb[4] = { 0.0,0.0,0.0,0.0 }; for ( int j = 0 ; j < 4 ; j++ ) { for ( int k = 0 ; k < 4 ; k++ ) vtmb[j] += vt[k] * mb[k][j] ; } p->x = p->y = p->z = 0.0; for ( int j = 0 ; j < 4 ; j++ ) { p->x += vtmb[j] * g[j]->x ; p->y += vtmb[j] * g[j]->y ; p->z += vtmb[j] * g[j]->z ; } } /* Calcul les points definissant une courbe */ /* B-Spline par morceaux definie par un ensemble */ /* de sommets de controle */ /* tPos : le tableau des sommets de controle */ /* n : le nombre de sommets de contrôle */ /* mb : la matrice de base */ /* nb : le nombre de points a calculer */ /* tRes : le tableau de points resultat */ static void calculBSpline(Pos3D **tPos,int n,double mb[4][4],int nb,Pos3D **tRes) { for ( int i = 0 ; i < nb ; i++ ) { double pos = i/(nb-1.0)*(n-3); int nb =(int) pos; if ( nb == n-3 ) nb = n-4; double t = pos-nb; determinationPositionSurBSpline(&tPos[nb],t,mb,tRes[i]); } } /////////////////////////////////////////////////// static void determinationPositionSurBSpline(Pos3D **tPos,int n,double pos,double mb[4][4],Pos3D *p) { int nb =(int) pos; if ( nb == n-3 ) nb = n-4; double t = pos-nb; determinationPositionSurBSpline(&tPos[nb],t,mb,p); } static Pos3D **allocationPos3D(int n) { Pos3D **tP =(Pos3D **) calloc(n,sizeof(Pos3D *)); for ( int i = 0 ; i < n ; i++ ) tP[i] = new Pos3D(); return tP; } static void desallocationPos3D(Pos3D **tP,int n) { for ( int i = 0 ; i < n ; i++ ) delete(tP[i]); free(tP); } static void modelisationBSpline(Pos3D **tPos,int n,int nb,double mb[4][4]) { Pos3D **tP = allocationPos3D(nb); calculBSpline(tPos,n,mb,nb,tP); for ( int i = 0 ; i < nb ; i++ ) { double pos = i/(nb-1.0)*(n-3); vertex(tP[i],( pos < n-3 ) ? (int) pos : n-4,0.05); } desallocationPos3D(tP,nb); } static Pos3D **creationTableauPremiereEtDernierePositionsDupliquees(Pos3D **tPos,int n,int nb) { Pos3D **tP = allocationPos3D(n+2*nb); int p = 0; for ( int i = 0 ; i < nb ; i++,p++) { tP[p]->x = tPos[0]->x; tP[p]->y = tPos[0]->y; tP[p]->z = tPos[0]->z; } for ( int i = 0 ; i < n ; i++,p++) { tP[p]->x = tPos[i]->x; tP[p]->y = tPos[i]->y; tP[p]->z = tPos[i]->z; } for ( int i = 0 ; i < nb ; i++,p++) { tP[p]->x = tPos[n-1]->x; tP[p]->y = tPos[n-1]->y; tP[p]->z = tPos[n-1]->z; } return tP; } /* Fonction executee lors de l'appui */ /* d'une touche de curseur ou d'une touche */ /* page up ou page down */ static void special(int key,int x,int y) { switch (key) { case GLUT_KEY_UP : rx++; glutPostRedisplay(); break; case GLUT_KEY_DOWN : rx--; glutPostRedisplay(); break; case GLUT_KEY_LEFT : ry++; glutPostRedisplay(); break; case GLUT_KEY_RIGHT : ry--; glutPostRedisplay(); break; case GLUT_KEY_PAGE_UP : switch (glutGetModifiers()) { case GLUT_ACTIVE_ALT : nb++; glutPostRedisplay(); break; case GLUT_ACTIVE_CTRL : nP++; if ( nP == nb ) nP = nb-1; glutPostRedisplay(); break; default : rz++; glutPostRedisplay(); } break; case GLUT_KEY_PAGE_DOWN : switch (glutGetModifiers()) { case GLUT_ACTIVE_ALT : nb--; if ( nb == 1 ) nb = 2; if ( nP == nb ) nP = nb-1; glutPostRedisplay(); break; case GLUT_ACTIVE_CTRL : nP--; if ( nP < 0 ) nP = 0; glutPostRedisplay(); break; default : rz--; glutPostRedisplay(); } break; } } /* Fonction d'initialisation des parametres */ /* OpenGL ne changeant pas au cours de la vie */ /* du programme */ static void init(void) { glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); } /* Scene dessinee */ static void dessinerOpenGL(Pos3D **tP,int n) { glBegin(GL_LINE_STRIP); for ( int i = 0 ; i < n ; i++ ) { glVertex3d(tP[i]->x,tP[i]->y,tP[i]->z); } glEnd(); } static void scene(void) { switch (aff) { case 0 : glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); break; case 1 : { glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); int nbSplines = taille-3; double pos =(double) nP/(nb-1)*nbSplines; Pos3D p; determinationPositionSurBSpline(tPos,taille,pos,NRUBS,&p); vertex(&p,0,0.2); } break; case 2 : { glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); modelisationBSpline(tPos,taille,nb,NRUBS); } break; case 3 : { glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); Pos3D **ntPos = creationTableauPremiereEtDernierePositionsDupliquees(tPos,taille,2); modelisationBSpline(ntPos,taille+4,nb,NRUBS); desallocationPos3D(ntPos,taille+4); } break; case 4 : { glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); modelisationBSpline(tPos,taille,nb,CATMULL_ROM); } break; case 5 : { glColor3f(0.75F,0.75F,0.75F); dessinerOpenGL(tPos,taille); Pos3D **ntPos = creationTableauPremiereEtDernierePositionsDupliquees(tPos,taille,1); modelisationBSpline(ntPos,taille+2,nb,CATMULL_ROM); desallocationPos3D(ntPos,taille+2); } break; } } /* Fonction executee lors d'un rafraichissement */ /* de la fenetre de dessin */ static void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(rx,1.0F,0.0F,0.0F); glRotatef(ry,0.0F,1.0F,0.0F); glRotatef(rz,0.0F,0.0F,1.0F); scene(); glPopMatrix(); glFlush(); glutSwapBuffers(); int error = glGetError(); if ( error != GL_NO_ERROR ) printf("Erreur OpenGL: %d\n",error); } /* Fonction executee lors d'un changement */ /* de la taille de la fenetre OpenGL */ /* -> Ajustement de la camera de visualisation */ static void reshape(int tx,int ty) { glViewport(0,0,tx,ty); glMatrixMode(GL_PROJECTION); glLoadIdentity(); double ratio =(double) tx/ty; if ( ratio >= 1.0 ) glOrtho(-6.0*ratio,6.0*ratio,-6.0,6.0,-10.0,10.0); else glOrtho(-6.0,6.0,-6.0/ratio,6.0/ratio,-10.0,10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* Fonction executee lors de la frappe */ /* d'une touche du clavier */ static void keyboard(unsigned char key,int x,int y) { switch (key) { case 0x0D : taille = ( taille == 10 ) ? 4 : 10; glutPostRedisplay(); break; case 0x20 : aff = (aff+1)%6; glutPostRedisplay(); break; case 0x1B : exit(0); break; } } static void clean(void) { for ( int i = 0 ; i < nbPoints ; i++ ) { delete(tPos[i]); } } /* Fonction principale */ int main(int argc,char **argv) { atexit(clean); glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE); glutInitWindowSize(450,300); glutInitWindowPosition(50,50); glutCreateWindow("Une courbe B-Spline"); init(); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutDisplayFunc(display); glutMainLoop(); return(0); }