/* proj3d-cor.c - Edouard Thiel - 02/06/2001 Compilation : cc proj3d-cor.c -o proj3d-cor `~/helium/helium-cfg --cflags --libs` -lm Exécution : proj3d-cor But du TP : - Programmer des transformations géométriques 3D en coordonnées homogènes : les rotations sur les 3 axes, et la projection conique sur un plan (c-à-d la projection perspective). - L'interface du programme est entièrement fournie. - Les fonctions à compléter sont toutes dans la partie "Algorithmes". */ #include #include He_node *princ, *canvas, *panel1, *panel2, *mess1, *fen1, *panel3, *text_aX, *text_aY, *text_aZ, *text_dD; int c_gris, c_rouge, c_vert, c_bleu, c_jaune, c_cyan, c_magenta; double angleP = 5, distP = 1.02; #define ZEDIM 4 typedef double Matr[ZEDIM][ZEDIM]; /* [ligne][colonne] */ typedef double Vec[ZEDIM]; /*--------------------------- A F F I C H A G E ------------------------------*/ void init_couleurs () { c_gris = HeAllocRgb (150, 150, 150, he_white); c_rouge = HeAllocRgb (255, 0, 0, he_black); c_vert = HeAllocRgb (0, 255, 0, he_black); c_bleu = HeAllocRgb (0, 0, 255, he_black); c_jaune = HeAllocRgb (255, 255, 0, he_black); c_cyan = HeAllocRgb (0, 255, 255, he_black); c_magenta = HeAllocRgb (255, 0, 255, he_black); } /* * Dessins de base */ void couleur (int coul) { XSetForeground (he_display, he_gc, coul); } void dessin_ligne (Window win, int x1, int y1, int x2, int y2) { XDrawLine (he_display, win, he_gc, x1, y1, x2, y2); } /*-------------------------- A L G O R I T H M E S ---------------------------*/ /* * Affiche la matrice pour la mise au point du programme */ void affi_matr (Matr m) { int i, j; for (i = 0; i < ZEDIM; i++) { for (j = 0; j < ZEDIM; j++) printf ("%2.3f ", m[i][j]); printf ("\n"); } } /* * Initialise la matrice m à la matrice unité */ void matr_unite (Matr m) { int i, j; for (i = 0; i < ZEDIM; i++) for (j = 0; j < ZEDIM; j++) m[i][j] = 0; for (i = 0; i < ZEDIM; i++) m[i][i] = 1; } /* * Recopie la matrice m dans la matrice res */ void copie_matr (Matr m, Matr res) { int i, j; for (i = 0; i < ZEDIM; i++) for (j = 0; j < ZEDIM; j++) res[i][j] = m[i][j]; } /* * Multiplie la matrice m1 par la matrice m2 et place le résultat dans res */ void mult_matr_matr (Matr m1, Matr m2, Matr res) { int i, j, k; double d; for (i = 0; i < ZEDIM; i++) for (j = 0; j < ZEDIM; j++) { d = 0; for (k = 0; k < ZEDIM; k++) d += m1[i][k] * m2[k][j]; res[i][j] = d; } } /* * Multiplie la matrice m1 par le vecteur v2 et place le résultat dans res */ void mult_matr_vec (Matr m1, Vec v2, Vec res) { int i, k; double d; for (i = 0; i < ZEDIM; i++) { d = 0; for (k = 0; k < ZEDIM; k++) d += m1[i][k] * v2[k]; res[i] = d; } } /* * Fait l'operation : m = T*m * où T est la matrice de la projection conique sur le plan XY * et de centre (0,0,-D) */ void mult_projection (Matr m, double d) { Matr res, tmp = { { d, 0, 0, 0 }, { 0, d, 0, 0 }, { 0, 0, d, 0 }, { 0, 0, 1, d } }; mult_matr_matr (tmp, m, res); copie_matr (res, m); } /* * Fait l'operation : m = T*m * où T est la matrice de rotation sur l'axe des X et d'angle r (en degrés) */ void mult_rot_X (Matr m, double r) { double a = r * M_PI / 180, c = cos(a), s = sin(a); Matr res, tmp = { { 1, 0, 0, 0 }, { 0, c, s, 0 }, { 0,-s, c, 0 }, { 0, 0, 0, 1 } }; mult_matr_matr (tmp, m, res); copie_matr (res, m); } /* * Fait l'operation : m = T*m * où T est la matrice de rotation sur l'axe des Y et d'angle r (en degrés) */ void mult_rot_Y (Matr m, double r) { double a = r * M_PI / 180, c = cos(a), s = sin(a); Matr res, tmp = { { c, 0, s, 0 }, { 0, 1, 0, 0 }, {-s, 0, c, 0 }, { 0, 0, 0, 1 } }; mult_matr_matr (tmp, m, res); copie_matr (res, m); } /* * Fait l'operation : m = T*m * où T est la matrice de rotation sur l'axe des Z et d'angle r (en degrés) */ void mult_rot_Z (Matr m, double r) { double a = r * M_PI / 180, c = cos(a), s = sin(a); Matr res, tmp = { { c, s, 0, 0 }, {-s, c, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; mult_matr_matr (tmp, m, res); copie_matr (res, m); } /* * Calcule la matrice m du produit des transformations simples. */ void calcul_transfo3D (Matr m, double angleX, double angleY, double angleZ, double distD) { /* Remarque : dans cet ordre, la rotation en Z est indépendante des 2 autres, qui elles ne sont pas indépendantes ! */ matr_unite (m); mult_rot_X (m, angleX); mult_rot_Y (m, angleY); mult_rot_Z (m, angleZ); mult_projection (m, distD); } /* * Transformation géométrique d'un sommet en coordonnées homogènes : * - on applique la matrice de transformation m au vecteur (x1, y1, z1, 1). * - on obtient un vecteur (x', y', z', t'). * - si t' != 0, le résultat est *x2=x'/t', *y2=y'/t', *z2 = z'/t'. */ void appli_transfo3D (Matr m, double x1, double y1, double z1, double *x2, double *y2, double *z2) { Vec v1, v2; v1[0] = x1; v1[1] = y1; v1[2] = z1; v1[3] = 1; mult_matr_vec (m, v1, v2); if (v2[3] == 0) { *x2 = *y2 = *z2 = 0; return; } *x2 = v2[0]/v2[3]; *y2 = v2[1]/v2[3]; *z2 = v2[2]/v2[3]; } /* * Dessin du cube en projection perspective : * - calcule la matrice m du produit des transformations simples * - applique m aux sommets 3D du cube --> sommets 2D * - adapte les coordonnées des sommets 2D à la taille du canvas * - dessine le cube avec les arêtes Ox en rouge, Oy en vert, oZ en bleu */ void dessin_projection_cube (Window win, int larg, int haut, double angleX, double angleY, double angleZ, double distD) { double cx[8] = {-1, 1,-1, 1,-1, 1,-1, 1 }, cy[8] = {-1,-1, 1, 1,-1,-1, 1, 1 }, cz[8] = {-1,-1,-1,-1, 1, 1, 1, 1 }, ecr_mul; int ex[8], ey[8], i; Matr m; /* Calcule la matrice m du produit des transformations simples */ calcul_transfo3D (m, angleX, angleY, angleZ, distD); /* Applique m aux sommets du cube */ for (i = 0; i < 8; i++) appli_transfo3D (m, cx[i], cy[i], cz[i], &cx[i], &cy[i], &cz[i]); /* Adapte les coordonnées à la taille du canvas */ ecr_mul = (haut < larg) ? haut : larg; ecr_mul *= 0.25; for (i = 0; i < 8; i++) { ex[i] = cx[i] * ecr_mul + larg/2; ey[i] = cy[i] * ecr_mul + haut/2; } /* Dessine le cube avec les arêtes Ox en rouge, Oy en vert, oZ en bleu */ couleur (c_rouge); dessin_ligne (win, ex[0], ey[0], ex[1], ey[1]); dessin_ligne (win, ex[2], ey[2], ex[3], ey[3]); dessin_ligne (win, ex[4], ey[4], ex[5], ey[5]); dessin_ligne (win, ex[6], ey[6], ex[7], ey[7]); couleur (c_vert); dessin_ligne (win, ex[0], ey[0], ex[2], ey[2]); dessin_ligne (win, ex[1], ey[1], ex[3], ey[3]); dessin_ligne (win, ex[4], ey[4], ex[6], ey[6]); dessin_ligne (win, ex[5], ey[5], ex[7], ey[7]); couleur (c_bleu); dessin_ligne (win, ex[0], ey[0], ex[4], ey[4]); dessin_ligne (win, ex[1], ey[1], ex[5], ey[5]); dessin_ligne (win, ex[2], ey[2], ex[6], ey[6]); dessin_ligne (win, ex[3], ey[3], ex[7], ey[7]); } /*-------------------------------- U T I L E --------------------------------*/ He_node *create_textP (He_node *panel, char *nom, He_notify_proc proc, char *val) { He_node *tmp; HeCreateMessageP (panel, nom, TRUE); tmp = HeCreateText (panel); HeSetTextVisibleLen (tmp, 8); HeSetTextValue (tmp, val); HeSetTextNotifyProc (tmp, proc); HeSetPanelLayout (panel, HE_LINE_FEED); return tmp; } void set_text_double (He_node *hn, double d) { char bla[100]; sprintf (bla, "%.2f", d); HeSetTextValue (hn, bla); } /*--------------------------- C A L L B A C K S ------------------------------*/ void princ_resize (He_node *hn, int width, int height) { HeSetWidth (panel1, width); HeSetWidth (panel2, width); HeJustify (panel2, NULL, HE_BOTTOM); HeExpand (canvas, panel2, HE_BOTTOM); HeExpand (canvas, NULL, HE_RIGHT); HeJustify (fen1, princ, HE_LEFT); } void princ_replace_proc (He_node *hn, int xb, int yb) { HeJustify (fen1, princ, HE_LEFT); HeSetY (fen1, HeGetY(princ)); } void raz_proc (He_node *hn) { HeSetTextValue (text_aX, "0"); HeSetTextValue (text_aY, "0"); HeSetTextValue (text_aZ, "0"); HeSetTextValue (text_dD, "5"); HePostRepaint (canvas); } void canvas_repaint (He_node *hn, Window win) { int larg = HeGetWidth (canvas), haut = HeGetHeight (canvas); double angleX = atof(HeGetTextValue (text_aX)), angleY = atof(HeGetTextValue (text_aY)), angleZ = atof(HeGetTextValue (text_aZ)), distD = atof(HeGetTextValue (text_dD)); HeDrawBg (canvas, he_white); dessin_projection_cube (win, larg, haut, angleX, angleY, angleZ, distD); } void canvas_event (He_node *hn, He_event *hev) { double v; int re = FALSE; switch (hev->type) { case KeyPress : { switch (hev->str[0]) { case 'X' : v = atof(HeGetTextValue(text_aX)) - angleP; if (v < 0) v += 360; set_text_double(text_aX, v); re = TRUE; break; case 'x' : v = atof(HeGetTextValue(text_aX)) + angleP; if (v >= 360) v -= 360; set_text_double(text_aX, v); re = TRUE; break; case 'Y' : v = atof(HeGetTextValue(text_aY)) - angleP; if (v < 0) v += 360; set_text_double(text_aY, v); re = TRUE; break; case 'y' : v = atof(HeGetTextValue(text_aY)) + angleP; if (v >= 360) v -= 360; set_text_double(text_aY, v); re = TRUE; break; case 'Z' : v = atof(HeGetTextValue(text_aZ)) - angleP; if (v < 0) v += 360; set_text_double(text_aZ, v); re = TRUE; break; case 'z' : v = atof(HeGetTextValue(text_aZ)) + angleP; if (v >= 360) v -= 360; set_text_double(text_aZ, v); re = TRUE; break; case 'D' : v = atof(HeGetTextValue(text_dD)) / distP; set_text_double(text_dD, v); re = TRUE; break; case 'd' : v = atof(HeGetTextValue(text_dD)) * distP; set_text_double(text_dD, v); re = TRUE; break; case 'i' : raz_proc (NULL); break; } } break; } if (re) HePostRepaint (canvas); } void appli_proc (He_node *hn) { HePostRepaint (canvas); } void fen1_proc (He_node *hn) { HeSetShow (fen1, HeGetToggleValue(hn)); } void quit_proc (He_node *hn) { HeQuit(0); } /*--------------------------------- M A I N ----------------------------------*/ int main (int argc, char **argv) { int ygap; HeInit (&argc, &argv); init_couleurs (); princ = HeCreateFrame (); HeSetFrameLabel (princ, "Projection 3D (cor)"); HeSetFrameResizeProc (princ, princ_resize); HeSetFrameReplaceProc (princ, princ_replace_proc); panel1 = HeCreatePanel (princ); HeCreateToggleLedP (panel1, "Paramètres", fen1_proc, FALSE); HeCreateButtonP (panel1, "Quit", quit_proc, NULL); HeFit (panel1); canvas = HeCreateCanvas (princ); HeSetCanvasRepaintProc (canvas, canvas_repaint); HeSetCanvasEventProc (canvas, canvas_event); HeSetWidth (canvas, 400); HeSetHeight (canvas, 400); panel2 = HeCreatePanel (princ); mess1 = HeCreateMessageP (panel2, "Touches : x, X, y, Y, z, Z, d, D, i", FALSE); HeFit (panel2); HeJustify (canvas, panel1, HE_TOP); HeJustify (panel2, canvas, HE_TOP); HeFit (princ); fen1 = HeCreateFrame (); HeSetFrameLabel (fen1, "Paramètres"); panel3 = HeCreatePanel (fen1); ygap = HeGetPanelYGap (panel3); HeSetPanelYGap (panel3, 2); text_aX = create_textP (panel3, "angle X", appli_proc, "0"); text_aY = create_textP (panel3, "angle Y", appli_proc, "0"); text_aZ = create_textP (panel3, "angle Z", appli_proc, "0"); text_dD = create_textP (panel3, " dist D", appli_proc, "5.0"); HeSetPanelYGap (panel3, ygap+5); HeCreateButtonP (panel3, "Init", raz_proc, NULL); HeFit (panel3); HeFit (fen1); return HeMainLoop (princ); }