/* trans2d-tp.c - Edouard Thiel - 02/06/2001 Compilation : cc trans2d-tp.c -o trans2d-tp `~/helium/helium-cfg --cflags --libs` -lm Exécution : trans2d-tp But du TP : - Programmer des transformations géométriques 2D en coordonnées homogènes ; d'abord des transformations simples, puis des transformations composées (multiplication de matrices 3x3). - 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, *bnouv, *tog1, *fen1, *tog2, *panel2, *text_angle, *text_rapport, *text_x, *text_y, *panel3, *mess1; int c_gris, c_rouge, c_vert, c_bleu, c_jaune, c_cyan, c_magenta; enum { TRANS_TRANSLATION, TRANS_ROTATION, TRANS_SYM_POINT, TRANS_SYM_DROITE, TRANS_HOMOTHETIE, TRANS_AFFINITE_ORTHO }; int etat_trans = TRANS_TRANSLATION, etat_dessin = TRUE; char *legende1 = "Faites un dessin à la souris", *legende2 = "Bouton 1 : x,y bouton 2 : angle bouton 3 : rapport"; #define SMAX 1000 int Sx[SMAX], Sy[SMAX], Sn = 0; #define ZEDIM 3 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_point (Window win, int x, int y) { XDrawPoint (he_display, win, he_gc, x, y); } void dessin_ligne (Window win, int x1, int y1, int x2, int y2) { XDrawLine (he_display, win, he_gc, x1, y1, x2, y2); } void dessin_fleche (Window win, int x1, int y1, int x2, int y2) { int dx = x1-x2, dy=y1-y2, x, y; double l, a, e = 25*M_PI/180, d = 10; if (dx == 0 && dy == 0) return; l = sqrt(dx*dx+dy*dy); a = acos(dx/l); if (dy < 0) a = -a; dessin_ligne (win, x1, y1, x2, y2); x = x2+d*cos(a+e)+0.5; y = y2+d*sin(a+e)+0.5; dessin_ligne (win, x, y, x2, y2); x = x2+d*cos(a-e)+0.5; y = y2+d*sin(a-e)+0.5; dessin_ligne (win, x, y, x2, y2); } void dessin_tic (Window win, int x1, int y1, int x2, int y2) { int dx = x1-x2, dy=y1-y2, x, y; double l, d = 6; if (dx == 0 && dy == 0) return; l = sqrt(dx*dx+dy*dy); dessin_ligne (win, x1, y1, x2, y2); x = -dy*d/l+0.5; y = dx*d/l+0.5; dessin_ligne (win, x2-x, y2-y, x2+x, y2+y); } void dessin_cercle (Window win, int x, int y, int r) { XDrawArc (he_display, win, he_gc, x-r, y-r, 2*r, 2*r, 0, 360*64); } void dessin_croix (Window win, int x, int y) { int d = 5; dessin_ligne (win, x, y-d, x, y+d); dessin_ligne (win, x+d, y, x-d, y); } void dessin_rond (Window win, int x, int y) { int d = 3; dessin_cercle (win, x, y, d); } /* * Dessin d'un segment (Sx[i-1],Sy[i-1]), (Sx[i],Sy[i]) */ void dessin_segment (Window win, int i) { if (i == 0) dessin_point (win, Sx[0], Sy[0]); else dessin_ligne (win, Sx[i-1], Sy[i-1], Sx[i], Sy[i]); } /* * Schématise la transformation */ void dessin_schema (Window win, int larg, int haut, double angle, double rapport, double parx, double pary) { switch (etat_trans) { case TRANS_TRANSLATION : { couleur (c_bleu); dessin_rond (win, larg/2, haut/2); dessin_fleche (win, larg/2, haut/2, larg/2+parx, haut/2+pary); } break; case TRANS_ROTATION : { double a = angle*M_PI/180, d = larg/8; couleur (c_bleu); dessin_rond (win, parx, pary); dessin_fleche (win, parx, pary, parx+d, pary); dessin_fleche (win, parx, pary, parx+cos(a)*d, pary+sin(a)*d); } break; case TRANS_SYM_POINT : { couleur (c_bleu); dessin_croix (win, parx, pary); } break; case TRANS_SYM_DROITE : { double a = angle*M_PI/180, d = 1000, x = cos(a)*d, y = sin(a)*d; couleur (c_bleu); dessin_rond (win, parx, pary); dessin_ligne (win, parx-x, pary-y, parx+x, pary+y); } break; case TRANS_HOMOTHETIE : { double d = larg/8; couleur (c_bleu); dessin_rond (win, parx, pary); dessin_tic (win, parx, pary, parx+d, pary); dessin_tic (win, parx, pary, parx+d*rapport, pary); } break; case TRANS_AFFINITE_ORTHO : { double a = angle*M_PI/180, d = 1000, x = cos(a)*d, y = sin(a)*d; couleur (c_bleu); dessin_rond (win, parx, pary); dessin_ligne (win, parx-x, pary-y, parx+x, pary+y); d = larg/8; x = cos(a)*d, y = sin(a)*d; dessin_tic (win, parx, pary, parx-y, pary+x); dessin_tic (win, parx, pary, parx-y*rapport, pary+x*rapport); } break; } } /*-------------------------- 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) { /* A COMPLETER */ } /* * Recopie la matrice m dans la matrice res */ void copie_matr (Matr m, Matr res) { /* A COMPLETER */ } /* * 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) { /* A COMPLETER */ } /* * 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) { /* A COMPLETER */ } /* * Fait l'operation : m = T*m * où T est la matrice de la translation (dx,dy) */ void mult_translation (Matr m, double dx, double dy) { /* A COMPLETER */ } /* * Fait l'operation : m = T*m * où T est la matrice de la rotation d'angle deg et de centre 0 */ void mult_rotation (Matr m, double deg) { /* A COMPLETER */ } /* * Fait l'operation : m = T*m * où T est la matrice de l'homothetie de rapport r et de centre 0 */ void mult_homothetie (Matr m, double r) { /* A COMPLETER */ } /* * Fait l'operation : m = T*m * où T est la matrice de l'affinité orthogonale à Ox de rapport r */ void mult_affinite_ortho_Ox (Matr m, double r) { /* A COMPLETER */ } /* * Calcule la matrice m du produit des transformations simples. */ void calcul_transfo2D (Matr m, double angle, double rapport, double parx, double pary) { matr_unite (m); switch (etat_trans) { case TRANS_TRANSLATION : { mult_translation (m, parx, pary); } break; case TRANS_ROTATION : { mult_translation (m, -parx, -pary); mult_rotation (m, angle); mult_translation (m, parx, pary); } break; case TRANS_SYM_POINT : { /* A COMPLETER */ } break; case TRANS_SYM_DROITE : { /* A COMPLETER */ } break; case TRANS_HOMOTHETIE : { /* A COMPLETER */ } break; case TRANS_AFFINITE_ORTHO : { /* A COMPLETER */ } break; } } /* * Transformation géométrique d'un sommet en coordonnées homogènes : * - on applique la matrice de transformation m au vecteur (x1, y1, 1). * - on obtient un vecteur (x', y', t'). * - si t' est différent de 0, le résultat est *x2=x'/t', *y2=y'/t'. */ void appli_transfo2D (Matr m, int x1, int y1, int *x2, int *y2) { /* A COMPLETER */ /* n'importe quoi juste pour avoir qq chose */ *x2 = x1 + 10; *y2 = y1 + 20; } /*--------------------------- 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 canvas_repaint (He_node *hn, Window win) { int i, x1, y1, x2, y2, larg = HeGetWidth (canvas), haut = HeGetHeight (canvas); double angle = atof (HeGetTextValue(text_angle)), rapport = atof (HeGetTextValue(text_rapport)), parx = atof (HeGetTextValue(text_x)), pary = atof (HeGetTextValue(text_y)); Matr m; HeDrawBg (canvas, he_white); if (HeGetToggleValue(tog1)) dessin_schema (win, larg, haut, angle, rapport, parx, pary); couleur (c_gris); for (i = 0; i < Sn; i++) dessin_segment (win, i); if (Sn == 0 || etat_dessin || !HeGetToggleValue(tog1)) return; couleur (c_rouge); calcul_transfo2D (m, angle, rapport, parx, pary); appli_transfo2D (m, Sx[0], Sy[0], &x1, &y1); for (i = 1; i < Sn; i++) { x2 = x1; y2 = y1; appli_transfo2D (m, Sx[i], Sy[i], &x1, &y1); dessin_ligne (win, x1, y1, x2, y2); } } void canvas_event (He_node *hn, He_event *hev) { switch (hev->type) { case ButtonPress : case MotionNotify : if (hev->sb == 0) break; if (etat_dessin) { if (Sn < SMAX) { couleur (he_black); Sx[Sn] = hev->sx; Sy[Sn] = hev->sy; dessin_segment (hev->win, Sn++); } } else { switch (hev->sb) { case 1 : { /* Coordonnées x,y */ char bla[80]; int x = hev->sx, y = hev->sy; if (etat_trans == TRANS_TRANSLATION) { x -= HeGetWidth(canvas)/2; y -= HeGetHeight(canvas)/2; } sprintf(bla, "%d", x); HeSetTextValue(text_x, bla); sprintf(bla, "%d", y); HeSetTextValue(text_y, bla); HePostRepaint (canvas); } break; case 2 : { /* Angle */ static int old_x, old_y; char bla[80]; int angle; if (!HeGetActive(text_angle)) break; if (hev->type == MotionNotify) { angle = (atoi(HeGetTextValue(text_angle)) + hev->sx - old_x + hev->sy - old_y ) % 360; if (angle < 0) angle = 360 - angle; sprintf(bla, "%d", angle); HeSetTextValue(text_angle, bla); HePostRepaint (canvas); } old_x = hev->sx; old_y = hev->sy; } break; case 3 : { /* Rapport */ static int old_x, old_y; char bla[80]; double rapport; if (!HeGetActive(text_rapport)) break; if (hev->type == MotionNotify) { rapport = (atof(HeGetTextValue(text_rapport)) + (hev->sx - old_x + hev->sy - old_y)/50. ); if (rapport < -4) rapport = -4; if (rapport > 4) rapport = 4; sprintf(bla, "%.2f", rapport); HeSetTextValue(text_rapport, bla); HePostRepaint (canvas); } old_x = hev->sx; old_y = hev->sy; } break; } } break; case ButtonRelease : if (etat_dessin) { HeSetActive (bnouv, TRUE); etat_dessin = FALSE; HeSetMessageLabel (mess1, legende2); HePostRepaint (canvas); } break; } } void grise_params (int g_angle, int g_rapport) { HeSetActive (text_angle, g_angle); HeSetActive (HeGetClientData(text_angle), g_angle); HeSetActive (text_rapport, g_rapport); HeSetActive (HeGetClientData(text_rapport), g_rapport); } void tog1_proc (He_node *hn) { HeSetShow (fen1, HeGetToggleValue(tog1)); HePostRepaint (canvas); } void tog2_proc (He_node *hn) { char *nom = HeGetToggleLabel (hn); if (HeGetToggleValue (hn) == FALSE) return; if (strcmp (nom, "Translation") == 0) { etat_trans = TRANS_TRANSLATION; grise_params (FALSE,FALSE); } else if (strcmp (nom, "Rotation") == 0) { etat_trans = TRANS_ROTATION; grise_params (TRUE,FALSE); } else if (strcmp (nom, "Symétrie point") == 0) { etat_trans = TRANS_SYM_POINT; grise_params (FALSE,FALSE); } else if (strcmp (nom, "Symétrie droite") == 0) { etat_trans = TRANS_SYM_DROITE; grise_params (TRUE,FALSE); } else if (strcmp (nom, "Homothétie") == 0) { etat_trans = TRANS_HOMOTHETIE; grise_params (FALSE,TRUE); } else if (strcmp (nom, "Affinité ortho") == 0) { etat_trans = TRANS_AFFINITE_ORTHO; grise_params (TRUE,TRUE); } HePostRepaint (canvas); } void appli_proc (He_node *hn) { HePostRepaint (canvas); } void vide_proc (He_node *hn) { Sn = 0; etat_dessin = TRUE; HeSetActive (bnouv, FALSE); HeSetMessageLabel (mess1, legende1); HePostRepaint (canvas); } void quit_proc (He_node *hn) { HeQuit(0); } /*-------------------------------- U T I L E --------------------------------*/ He_node *create_textP (He_node *panel, char *nom, He_notify_proc proc, char *val) { He_node *tmp1, *tmp2; tmp1 = HeCreateMessageP (panel, nom, TRUE); tmp2 = HeCreateText (panel); HeSetTextVisibleLen (tmp2, 8); HeSetTextValue (tmp2, val); HeSetTextNotifyProc (tmp2, proc); HeSetPanelLayout (panel, HE_LINE_FEED); HeSetClientData (tmp2, tmp1); return tmp2; } /*--------------------------------- M A I N ----------------------------------*/ int main (int argc, char **argv) { He_node *tmp1; int ygap; HeInit (&argc, &argv); init_couleurs (); princ = HeCreateFrame (); HeSetFrameLabel (princ, "Transformations 2D"); HeSetFrameResizeProc (princ, princ_resize); HeSetFrameReplaceProc (princ, princ_replace_proc); panel1 = HeCreatePanel (princ); bnouv = HeCreateButtonP (panel1, "Nouveau dessin", vide_proc, NULL); HeSetActive (bnouv, FALSE); tog1 = HeCreateToggle (panel1, HE_LED); HeSetToggleLabel (tog1, "Transformations"); HeSetToggleNotifyProc (tog1, tog1_proc); HeCreateButtonP (panel1, "Quit", quit_proc, NULL); HeFit (panel1); canvas = HeCreateCanvas (princ); HeSetCanvasRepaintProc (canvas, canvas_repaint); HeSetCanvasEventProc (canvas, canvas_event); HeSetWidth (canvas, 500); HeSetHeight (canvas, 500); panel2 = HeCreatePanel (princ); mess1 = HeCreateMessageP (panel2, legende1, FALSE); HeFit(panel2); HeJustify (canvas, panel1, HE_TOP); HeJustify (panel2, canvas, HE_TOP); HeFit (princ); fen1 = HeCreateFrame (); HeSetFrameLabel (fen1, "Transformations"); panel3 = HeCreatePanel (fen1); HeSetPanelLayout (panel3, HE_VERTICAL); ygap = HeGetPanelYGap (panel3); HeSetPanelYGap (panel3, 2); tog2 = HeCreateToggleRadioP (panel3, "Translation", tog2_proc, NULL); HeCreateToggleRadioP (panel3, "Rotation", tog2_proc, tog2); HeCreateToggleRadioP (panel3, "Symétrie point", tog2_proc, tog2); HeCreateToggleRadioP (panel3, "Symétrie droite", tog2_proc, tog2); HeCreateToggleRadioP (panel3, "Homothétie", tog2_proc, tog2); HeCreateToggleRadioP (panel3, "Affinité ortho", tog2_proc, tog2); HeSetPanelLayout (panel3, HE_LINE_FEED); HeSetPanelYGap (panel3, ygap); text_x = create_textP (panel3, " x", appli_proc, "50"); HeSetPanelYGap (panel3, 2); text_y = create_textP (panel3, " y", appli_proc, "20"); text_angle = create_textP (panel3, " Angle", appli_proc, "45.0"); text_rapport = create_textP (panel3, "Rapport", appli_proc, "-0.5"); grise_params (FALSE,FALSE); HeSetPanelYGap (panel3, ygap+5); tmp1 = HeCreateButtonP (panel3, "Appliquer", appli_proc, NULL); HeFit (panel3); HeSetWidth (tmp1, HeGetWidth(panel3)-2*HeGetPanelXAlign(panel3)); HeFit (fen1); return HeMainLoop (princ); }