Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpArit.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Le module "arit.c" contient les procedures arithmetiques.
33  *
34  * Authors:
35  * Jean-Luc CORRE
36  *
37 *****************************************************************************/
38 
39 #include "vpArit.h"
40 #include "vpMy.h"
41 #include <math.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <visp3/core/vpMath.h>
45 
46 #ifndef DOXYGEN_SHOULD_SKIP_THIS
47 BEGIN_VISP_NAMESPACE
48 /*
49  * La procedure "fprintf_matrix" affiche une matrice sur un fichier.
50  * Entree :
51  * fp Fichier en sortie.
52  * m Matrice a ecrire.
53  */
54 void fprintf_matrix(FILE *fp, Matrix m)
55 {
56  int i;
57 
58  fprintf(fp, "(matrix\n");
59  for (i = 0; i < 4; i++)
60  fprintf(fp, "\t%.4f\t%.4f\t%.4f\t%.4f\n", m[i][0], m[i][1], m[i][2], m[i][3]);
61  fprintf(fp, ")\n");
62 }
63 
64 /*
65  * La procedure "ident_matrix" initialise la matrice par la matrice identite.
66  * Entree :
67  * m Matrice a initialiser.
68  */
69 void ident_matrix(Matrix m)
70 {
71  static Matrix identity = IDENTITY_MATRIX;
72 
73  // bcopy ((char *) identity, (char *) m, sizeof (Matrix));
74  memmove((char *)m, (char *)identity, sizeof(Matrix));
75  /*
76  * Version moins rapide.
77  *
78  * int i, j;
79  *
80  * for (i = 0; i < 4; i++)
81  * for (j = 0; j < 4; j++)
82  * m[i][j] = (i == j) ? 1.0 : 0.0;
83  */
84 }
85 
86 /*
87  * La procedure "premult_matrix" pre multiplie la matrice par la seconde.
88  * Entree :
89  * a Premiere matrice du produit a = b * a.
90  * b Seconde matrice du produit.
91  */
92 void premult_matrix(Matrix a, Matrix b)
93 {
94  Matrix m;
95  int i, j;
96 
97  for (i = 0; i < 4; i++)
98  for (j = 0; j < 4; j++)
99  m[i][j] = b[i][0] * a[0][j] + b[i][1] * a[1][j] + b[i][2] * a[2][j] + b[i][3] * a[3][j];
100  // bcopy ((char *) m, (char *) a, sizeof (Matrix));
101  memmove((char *)a, (char *)m, sizeof(Matrix));
102 }
103 
104 /*
105  * La procedure "premult3_matrix" premultiplie la matrice par une matrice 3x3.
106  * Note : La procedure "premult3_matrix" optimise "premutl_matrix".
107  * Entree :
108  * a Premiere matrice du produit a = b * a.
109  * b Seconde matrice du produit 3x3.
110  */
111 void premult3_matrix(Matrix a, Matrix b)
112 {
113  Matrix m;
114  int i, j;
115 
116  // bcopy ((char *) a, (char *) m, sizeof (Matrix));
117  memmove((char *)m, (char *)a, sizeof(Matrix));
118  for (i = 0; i < 3; i++)
119  for (j = 0; j < 4; j++)
120  a[i][j] = b[i][0] * m[0][j] + b[i][1] * m[1][j] + b[i][2] * m[2][j];
121 }
122 
123 /*
124  * La procedure "prescale_matrix" premultiplie la matrice par l'homothetie.
125  * Entree :
126  * m Matrice a multiplier m = vp * m.
127  * vp Vecteur d'homothetie.
128  */
129 void prescale_matrix(Matrix m, Vector *vp)
130 {
131  int i;
132 
133  for (i = 0; i < 4; i++) {
134  m[0][i] *= vp->x;
135  m[1][i] *= vp->y;
136  m[2][i] *= vp->z;
137  }
138 }
139 
140 /*
141  * La procedure "pretrans_matrix" premultiplie la matrice par la translation.
142  * Entree :
143  * m Matrice a multiplier m = vp * m.
144  * vp Vecteur de translation.
145  */
146 void pretrans_matrix(Matrix m, Vector *vp)
147 {
148  int i;
149 
150  for (i = 0; i < 4; i++)
151  m[3][i] += vp->x * m[0][i] + vp->y * m[1][i] + vp->z * m[2][i];
152 }
153 
154 /*
155  * La procedure "postleft_matrix" postmultiplie la matrice
156  * par une matrice gauche sur un des axes.
157  * Entree :
158  * m Matrice a rendre gauche m = m * left.
159  * axis Axe de la matrice gauche 'x', 'y' ou 'z'.
160  */
161 void postleft_matrix(Matrix m, char axis)
162 {
163 
164  int i;
165 
166  switch (axis) {
167  case 'x':
168  for (i = 0; i < 4; i++)
169  m[i][0] = -m[i][0];
170  break;
171  case 'y':
172  for (i = 0; i < 4; i++)
173  m[i][1] = -m[i][1];
174  break;
175  case 'z':
176  for (i = 0; i < 4; i++)
177  m[i][2] = -m[i][2];
178  break;
179  default: {
180  static char proc_name[] = "postleft_matrix";
181  fprintf(stderr, "%s: axis unknown\n", proc_name);
182  break;
183  }
184  }
185 }
186 
187 /*
188  * La procedure "postmult_matrix" post multiplie la matrice par la seconde.
189  * Entree :
190  * a Premiere matrice du produit a = a * b.
191  * b Seconde matrice du produit.
192  */
193 void postmult_matrix(Matrix a, Matrix b)
194 {
195  Matrix m;
196  int i, j;
197 
198  for (i = 0; i < 4; i++)
199  for (j = 0; j < 4; j++)
200  m[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j] + a[i][3] * b[3][j];
201  // bcopy ((char *) m, (char *) a, sizeof (Matrix));
202  memmove((char *)a, (char *)m, sizeof(Matrix));
203 }
204 
205 /*
206  * La procedure "postmult3_matrix" postmultiplie la matrice par une matrice
207  * 3x3. Note : La procedure "postmult3_matrix" optimise "postmutl_matrix".
208  * Entree :
209  * a Premiere matrice du produit a = a * b.
210  * b Seconde matrice du produit 3x3.
211  */
212 void postmult3_matrix(Matrix a, Matrix b)
213 {
214  Matrix m;
215  int i, j;
216 
217  // bcopy ((char *) a, (char *) m, sizeof (Matrix));
218  memmove((char *)m, (char *)a, sizeof(Matrix));
219  for (i = 0; i < 4; i++)
220  for (j = 0; j < 3; j++)
221  a[i][j] = m[i][0] * b[0][j] + m[i][1] * b[1][j] + m[i][2] * b[2][j];
222 }
223 
224 /*
225  * La procedure "postscale_matrix" post multiplie la matrice par l'homothetie.
226  * Entree :
227  * m Matrice a multiplier m = m * vp.
228  * vp Vecteur d'homothetie.
229  */
230 void postscale_matrix(Matrix m, Vector *vp)
231 {
232  int i;
233 
234  for (i = 0; i < 4; i++) {
235  m[i][0] *= vp->x;
236  m[i][1] *= vp->y;
237  m[i][2] *= vp->z;
238  }
239 }
240 
241 /*
242  * La procedure "posttrans_matrix" post mutiplie la matrice par la
243  * translation. Entree : m Matrice a multiplier m = m * vp. vp
244  * Vecteur de translation.
245  */
246 void posttrans_matrix(Matrix m, Vector *vp)
247 {
248  int i;
249 
250  for (i = 0; i < 4; i++) {
251  m[i][0] += m[i][3] * vp->x;
252  m[i][1] += m[i][3] * vp->y;
253  m[i][2] += m[i][3] * vp->z;
254  }
255 }
256 
257 /*
258  * La procedure "transpose_matrix" transpose la matrice.
259  * Entree :
260  * m Matrice a transposer.
261  */
262 void transpose_matrix(Matrix m)
263 {
264  unsigned int i, j;
265  float t;
266 
267  for (i = 0; i < 4; i++)
268  for (j = 0; j < i; j++)
269  SWAP(m[i][j], m[j][i], t);
270 }
271 
272 /*
273  * La procedure "cosin_to_angle" calcule un angle a partir d'un cosinus
274  * et d'un sinus.
275  * Entree :
276  * ca, sa Cosinus et Sinus de l'angle.
277  * Sortie :
278  * Angle en radians.
279  */
280 float cosin_to_angle(float ca, float sa)
281 {
282  float a; /* angle a calculer */
283 
284  if (FABS(ca) < M_EPSILON) {
285  a = (sa > (float)0.0) ? (float)M_PI_2 : (float)(-M_PI_2);
286  }
287  else {
288  a = (float)atan((double)(sa / ca));
289  if (ca < (float)0.0)
290  a += (sa >(float)0.0) ? (float)M_PI : (float)(-M_PI);
291  }
292  return (a);
293 }
294 
295 /*
296  * La procedure "cosin_to_lut" precalcule les tables des "cosinus" et "sinus".
297  * Les tables possedent "2 ** level" entrees pour M_PI_2 radians.
298  * Entree :
299  * level Niveau de decomposition.
300  * coslut Table pour la fonction "cosinus".
301  * sinlut Table pour la fonction "sinus".
302  */
303 void cosin_to_lut(Index level, float *coslut, float *sinlut)
304 {
305  int i;
306  int i_pi_2 = TWO_POWER(level);
307  int quad; /* quadrant courant */
308  double a; /* angle courant */
309  double step = M_PI_2 / (double)i_pi_2;
310 
311  quad = 0;
312  coslut[quad] = 1.0;
313  sinlut[quad] = 0.0; /* 0 */
314  quad += i_pi_2;
315  coslut[quad] = 0.0;
316  sinlut[quad] = 1.0; /* PI/2 */
317  quad += i_pi_2;
318  coslut[quad] = -1.0;
319  sinlut[quad] = 0.0; /* PI */
320  quad += i_pi_2;
321  coslut[quad] = 0.0;
322  sinlut[quad] = -1.0; /* 3PI/2*/
323 
324  for (i = 1, a = step; i < i_pi_2; i++, a += step) {
325  float ca = (float)cos(a);
326  quad = 0;
327  coslut[quad + i] = ca; /* cos(a) */
328  quad += i_pi_2;
329  sinlut[quad - i] = ca; /* sin(PI/2-a) */
330  sinlut[quad + i] = ca; /* sin(PI/2+a) */
331  quad += i_pi_2;
332  coslut[quad - i] = -ca; /* cos(PI-a) */
333  coslut[quad + i] = -ca; /* cos(PI+a) */
334  quad += i_pi_2;
335  sinlut[quad - i] = -ca; /* sin(3PI/2-a) */
336  sinlut[quad + i] = -ca; /* sin(3PI/2+a) */
337  quad += i_pi_2;
338  coslut[quad - i] = ca; /* cos(2PI-a) */
339  }
340 }
341 
342 /*
343  * La procedure "norm_vector" normalise le vecteur.
344  * Si la norme est nulle la normalization n'est pas effectuee.
345  * Entree :
346  * vp Le vecteur a norme.
347  * Sortie :
348  * La norme du vecteur.
349  */
350 float norm_vector(Vector *vp)
351 {
352  float norm; /* norme du vecteur */
353 
354  if ((norm = (float)sqrt((double)DOT_PRODUCT(*vp, *vp))) > M_EPSILON) {
355  vp->x /= norm;
356  vp->y /= norm;
357  vp->z /= norm;
358  }
359  else {
360  static char proc_name[] = "norm_vector";
361  fprintf(stderr, "%s: nul vector\n", proc_name);
362  }
363  return (norm);
364 }
365 
366 /*
367  * La procedure "plane_norme" calcule le vecteur norme orthogonal au plan
368  * defini par les 3 points.
369  * Entree :
370  * np Le vecteur norme orthogonal au plan.
371  * ap, bp, cp Points formant un repere du plan.
372  */
373 void plane_norme(Vector *np, Point3f *ap, Point3f *bp, Point3f *cp)
374 {
375  Vector u, v;
376 
377  DIF_COORD3(u, *bp, *ap); /* base orthonorme (ap, u, v) */
378  DIF_COORD3(v, *cp, *ap);
379  norm_vector(&u);
380  norm_vector(&v);
381  CROSS_PRODUCT(*np, u, v);
382 }
383 
384 /*
385  * La procedure "point_matrix" deplace un point 3D dans un espace 4D.
386  * Une matrice homogene 4x4 effectue le changement de repere.
387  * Entree :
388  * p4 Point homogene resultat = p3 x m.
389  * p3 Point a deplacer.
390  * m Matrice de changement de repere.
391  */
392 void point_matrix(Point4f *p4, Point3f *p3, Matrix m)
393 {
394  float x = p3->x, y = p3->y, z = p3->z;
395 
396  p4->x = COORD3_COL(x, y, z, m, 0);
397  p4->y = COORD3_COL(x, y, z, m, 1);
398  p4->z = COORD3_COL(x, y, z, m, 2);
399  p4->w = COORD3_COL(x, y, z, m, 3);
400 }
401 
402 /*
403  * La procedure "point_3D_3D" deplace un tableau de points 3D dans un espace
404  * 3D. Une matrice 4x3 effectue le changement de repere. La quatrieme colonne
405  * de la matrice vaut [0, 0, 0, 1] et n'est pas utilisee. Entree : ip
406  * Tableau de points 3D a deplacer. size Taille du tableau
407  * "ip". m Matrice de changement de repere. Entree/Sortie : op
408  * Tableau de points 3D resultat.
409  */
410 void point_3D_3D(Point3f *ip, int size, Matrix m, Point3f *op)
411 {
412  Point3f *pend = ip + size; /* borne de ip */
413 
414  for (; ip < pend; ip++, op++) {
415  float x = ip->x;
416  float y = ip->y;
417  float z = ip->z;
418 
419  op->x = COORD3_COL(x, y, z, m, 0);
420  op->y = COORD3_COL(x, y, z, m, 1);
421  op->z = COORD3_COL(x, y, z, m, 2);
422  }
423 }
424 
425 /*
426  * La procedure "point_3D_4D" deplace un tableau de points 3D dans un espace
427  * 4D. Une matrice homogene 4x4 effectue le changement de repere. Entree : p3
428  * Tableau de points 3D a deplacer. size Taille du tableau
429  * "p3". m Matrice de changement de repere. Entree/Sortie : p4
430  * Tableau de points 4D resultat.
431  */
432 void point_3D_4D(Point3f *p3, int size, Matrix m, Point4f *p4)
433 {
434  Point3f *pend = p3 + size; /* borne de p3 */
435 
436  for (; p3 < pend; p3++, p4++) {
437  float x = p3->x;
438  float y = p3->y;
439  float z = p3->z;
440 
441  p4->x = COORD3_COL(x, y, z, m, 0);
442  p4->y = COORD3_COL(x, y, z, m, 1);
443  p4->z = COORD3_COL(x, y, z, m, 2);
444  p4->w = COORD3_COL(x, y, z, m, 3);
445  }
446 }
447 
448 /*
449  * La procedure "rotate_vector" transforme le vecteur
450  * par la rotation de sens trigonometrique d'angle et d'axe donnes.
451  * Entree :
452  * vp Vecteur a transformer.
453  * a Angle de rotation en degres.
454  * axis Vecteur directeur de l'axe de rotation.
455  */
456 void rotate_vector(Vector *vp, float a, Vector *axis)
457 {
458  Vector n, u, v, cross;
459  float f;
460 
461  a *= (float)M_PI / (float)180.0; /* passage en radians */
462 
463  n = *axis; /* norme le vecteur directeur */
464  norm_vector(&n);
465 
466  /*
467  * Avant rotation, vp vaut :
468  * u + v
469  * Apres rotation, vp vaut :
470  * u + cos(a) * v + sin(a) * (n^vp)
471  * = u + cos(a) * v + sin(a) * (n^v)
472  * avec u = (vp.n) * n, v = vp-u;
473  * ou "u" est la projection de "vp" sur l'axe "axis",
474  * et "v" est la composante de "vp" perpendiculaire a "axis".
475  */
476  f = DOT_PRODUCT(*vp, n);
477  u = n;
478  MUL_COORD3(u, f, f, f); /* (vp.n) * n */
479 
480  DIF_COORD3(v, *vp, u); /* calcule "v" */
481 
482  f = (float)cos((double)a);
483  MUL_COORD3(v, f, f, f); /* v * cos(a) */
484 
485  CROSS_PRODUCT(cross, n, *vp);
486  f = (float)sin((double)a);
487  MUL_COORD3(cross, f, f, f); /* (n^v) * sin(a) */
488 
489  SET_COORD3(*vp, u.x + v.x + cross.x, u.y + v.y + cross.y, u.z + v.z + cross.z);
490 }
491 
492 /*
493  * La procedure "upright_vector" calcule un vecteur perpendiculaire.
494  * Les vecteurs ont un produit scalaire nul.
495  * Entree :
496  * vp Vecteur origine.
497  * Entree/Sortie :
498  * up Vecteur perpendiculaire a vp.
499  */
500 void upright_vector(Vector *vp, Vector *up)
501 {
502  if (FABS(vp->z) > M_EPSILON) { /* x et y sont fixes */
503  up->z = -(vp->x + vp->y) / vp->z;
504  up->x = up->y = 1.0;
505  }
506  else if (FABS(vp->y) > M_EPSILON) { /* x et z sont fixes */
507  up->y = -(vp->x + vp->z) / vp->y;
508  up->x = up->z = 1.0;
509  }
510  else if (FABS(vp->x) > M_EPSILON) { /* y et z sont fixes */
511  up->x = -(vp->y + vp->z) / vp->x;
512  up->y = up->z = 1.0;
513  }
514  else {
515  static char proc_name[] = "upright_vector";
516  up->x = up->y = up->z = 0.0;
517  fprintf(stderr, "%s: nul vector\n", proc_name);
518  return;
519  }
520 }
521 
522 /*
523  * La procedure "Matrix_to_Position" initialise la position par la matrice.
524  * Si M est la matrice, et P la position : M = R.Sid.T, P = (R,Sid,T).
525  * On suppose que la matrice de rotation 3x3 de M est unitaire.
526  * Entree :
527  * m Matrice de rotation et de translation.
528  * pp Position a initialiser.
529  */
530 void Matrix_to_Position(Matrix m, AritPosition *pp)
531 {
532  Matrix_to_Rotate(m, &pp->rotate);
533  SET_COORD3(pp->scale, 1.0, 1.0, 1.0);
534  SET_COORD3(pp->translate, m[3][0], m[3][1], m[3][2]);
535 }
536 
537 /*
538  * La procedure "Matrix_to_Rotate" initialise la rotation par la matrice.
539  * Si M est la matrice, si R est la matrice de rotation :
540  *
541  * | m00 m01 m02 0 |
542  * M = Rx.Ry.Rz = | m10 m11 m12 0 |
543  * | m20 m21 m22 0 |
544  * | 0 0 0 1 |
545  *
546  * et m00 = cy.cz m01 = cy.sz m02 = -sy
547  * m10 = sx.sy.cz-cx.sz m11 = sx.sy.sz+cx.cz m12 = sx.cy
548  * m20 = cx.sy.cz+sx.sz m21 = cx.sy.sz-sx.cz m22 = cx.cy
549  * avec ci = cos Oi et si = sin Oi.
550  *
551  * R = Rx.Ry.Rz
552  * Rx rotation autour de Ox d'angle O1
553  * Ry rotation autour de Oy d'angle O2
554  * Rz rotation autour de Oz d'angle O3
555  *
556  * Singularite : si |ry| == 90 degres alors rz = 0,
557  * soit une rotation d'axe 0z et d'angle "rx + rz".
558  *
559  * Entree :
560  * m Matrice contenant la composition des rotations.
561  * vp Rotations par rapport aux axes d'un repere droit en degres.
562  */
563 void Matrix_to_Rotate(Matrix m, Vector *vp)
564 {
565  float sy = -m[0][2];
566  float cy = (float)sqrt(1.0 - (double)(sy * sy));
567  float cx, sx;
568 
569  if (FABS(cy) > M_EPSILON) {
570  float sz = m[0][1] / cy;
571  float cz = m[0][0] / cy;
572 
573  sx = m[1][2] / cy;
574  cx = m[2][2] / cy;
575 
576  SET_COORD3(*vp, cosin_to_angle(cx, sx), cosin_to_angle(cy, sy), cosin_to_angle(cz, sz));
577  }
578  else { /* RZ = 0 => Ry = +/- 90 degres */
579  sx = m[1][1];
580  cx = -m[2][1];
581 
582  SET_COORD3(*vp, cosin_to_angle(cx, sx), (sy > (float)0.0) ? (float)M_PI_2 : (float)(-M_PI_2), (float)0.0);
583  }
584  vp->x *= (float)180.0 / (float)M_PI; /* passage en degres */
585  vp->y *= (float)180.0 / (float)M_PI;
586  vp->z *= (float)180.0 / (float)M_PI;
587 }
588 
589 /*
590  * La procedure "Position_to_Matrix" initialise la matrice par la position.
591  * Matrice resultat : M = Sx.Sy.Sz.Rx.Ry.Rz.Tx.Ty.Tz
592  * Entree :
593  * pp Position de reference.
594  * m Matrice a initialiser.
595  */
596 void Position_to_Matrix(AritPosition *pp, Matrix m)
597 {
598  Rotate_to_Matrix(&pp->rotate, m); /* rotation */
599  prescale_matrix(m, &pp->scale); /* homothetie */
600  m[3][0] = pp->translate.x; /* translation */
601  m[3][1] = pp->translate.y;
602  m[3][2] = pp->translate.z;
603 }
604 
605 /*
606  * La procedure "Rotate_to_Matrix" initialise la matrice par la rotation.
607  *
608  * | m00 m01 m02 0 |
609  * M = Rx.Ry.Rz = | m10 m11 m12 0 |
610  * | m20 m21 m22 0 |
611  * | 0 0 0 1 |
612  *
613  * Rx rotation autour de Ox d'angle O1
614  * Ry rotation autour de Oy d'angle O2
615  * Rz rotation autour de Oz d'angle O3
616  * et m00 = cy.cz m01 = cy.sz m02 = -sy
617  * m10 = sx.sy.cz-cx.sz m11 = sx.sy.sz+cx.cz m12 = sx.cy
618  * m20 = cx.sy.cz+sx.sz m21 = cx.sy.sz-sx.cz m22 = cx.cy
619  * avec ci = cos Oi et si = sin Oi.
620  *
621  * Entree :
622  * vp Rotations par rapport aux axes d'un repere droit en degres.
623  * m Matrice a initialiser.
624  */
625 void Rotate_to_Matrix(Vector *vp, Matrix m)
626 {
627  float rx = vp->x * (float)M_PI / (float)180.0, /* passage en radians */
628  ry = vp->y * (float)M_PI / (float)180.0, rz = vp->z * (float)M_PI / (float)180.0;
629  float cx = (float)cos((double)rx), sx = (float)sin((double)rx), cy = (float)cos((double)ry),
630  sy = (float)sin((double)ry), cz = (float)cos((double)rz), sz = (float)sin((double)rz);
631 
632  m[0][0] = cy * cz;
633  m[1][0] = (sx * sy * cz) - (cx * sz);
634  m[2][0] = (cx * sy * cz) + (sx * sz);
635 
636  m[0][1] = cy * sz;
637  m[1][1] = (sx * sy * sz) + (cx * cz);
638  m[2][1] = (cx * sy * sz) - (sx * cz);
639 
640  m[0][2] = -sy;
641  m[1][2] = sx * cy;
642  m[2][2] = cx * cy;
643 
644  m[0][3] = m[1][3] = m[2][3] = 0.0;
645  m[3][0] = m[3][1] = m[3][2] = 0.0;
646  m[3][3] = 1.0;
647 }
648 
649 /*
650  * La procedure "Rotaxis_to_Matrix" initialise la matrice par la rotation
651  * d'angle et d'axe donnes.
652  * Si M est la matrice, O l'angle et N le vecteur directeur de l'axe :
653  *
654  * M = cos(O) Id3 + (1 - cosO) Nt N + sinO N~
655  *
656  * | NxNxverO+ cosO NxNyverO+NzsinO NxNzverO-NxsinO 0 |
657  * M = | NxNyverO-NzsinO NyNyverO+ cosO NyNzverO+NxsinO 0 |
658  * | NxNzverO+NysinO NyNzverO-NxsinO NzNzverO+ cosO 0 |
659  * | 0 0 0 1 |
660  *
661  * O angle de rotation.
662  * N Vecteur directeur norme de l'axe de rotation.
663  * Nt Vecteur transpose.
664  * N~ | 0 Nz -Ny|
665  * |-Nz 0 Nx|
666  * | Ny -Nx 0 |
667  * Entree :
668  * a Angle de rotation en degres.
669  * axis Vecteur directeur de l'axe de la rotation.
670  * m Matrice a initialiser.
671  */
672 void Rotaxis_to_Matrix(float a, Vector *axis, Matrix m)
673 {
674  float cosa;
675  float sina;
676  float vera; /* 1 - cosa */
677  Vector n; /* vecteur norme*/
678  Vector conv; /* verO n */
679  Vector tilde; /* sinO n */
680 
681  a *= (float)M_PI / (float)180.0; /* passage en radians */
682 
683  cosa = (float)cos((double)a);
684  sina = (float)sin((double)a);
685  vera = (float)1.0 - cosa;
686 
687  n = *axis; /* norme le vecteur directeur */
688  norm_vector(&n);
689  tilde = conv = n;
690  MUL_COORD3(conv, vera, vera, vera);
691  MUL_COORD3(tilde, sina, sina, sina);
692 
693  m[0][0] = conv.x * n.x + cosa;
694  m[0][1] = conv.x * n.y + tilde.z;
695  m[0][2] = conv.x * n.z - tilde.y;
696 
697  m[1][0] = conv.y * n.x - tilde.z;
698  m[1][1] = conv.y * n.y + cosa;
699  m[1][2] = conv.y * n.z + tilde.x;
700 
701  m[2][0] = conv.z * n.x + tilde.y;
702  m[2][1] = conv.z * n.y - tilde.x;
703  m[2][2] = conv.z * n.z + cosa;
704 
705  m[0][3] = m[2][3] = m[1][3] = 0.0;
706  m[3][0] = m[3][1] = m[3][2] = 0.0;
707  m[3][3] = 1.0;
708 }
709 
710 /*
711  * La procedure "Rotrans_to_Matrix" initialise la matrice par la rotation
712  * et de la translation.
713  * Entree :
714  * rp Vecteur des angles de rotation en degres.
715  * tp Vecteur des coordonnees de translation.
716  * m Matrice a initialiser.
717  */
718 void Rotrans_to_Matrix(Vector *rp, Vector *tp, Matrix m)
719 {
720  Rotate_to_Matrix(rp, m); /* matrice de rotation */
721  m[3][0] = tp->x; /* matrice de translation */
722  m[3][1] = tp->y;
723  m[3][2] = tp->z;
724 }
725 
726 /*
727  * La procedure "Scale_to_Matrix" initialise la matrice par l'homothetie.
728  * Entree :
729  * vp Vecteur des coordonnees d'homothetie.
730  * m Matrice a initialiser.
731  */
732 void Scale_to_Matrix(Vector *vp, Matrix m)
733 {
734  ident_matrix(m);
735  m[0][0] = vp->x;
736  m[1][1] = vp->y;
737  m[2][2] = vp->z;
738 }
739 
740 /*
741  * La procedure "Translate_to_Matrix" initialise la matrice par la
742  * translation. Entree : vp Vecteur des coordonnees de
743  * translation. m Matrice a initialiser.
744  */
745 void Translate_to_Matrix(Vector *vp, Matrix m)
746 {
747  ident_matrix(m);
748  m[3][0] = vp->x;
749  m[3][1] = vp->y;
750  m[3][2] = vp->z;
751 }
752 END_VISP_NAMESPACE
753 #endif