DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
utlRotationMatrixFromVectors.h
Go to the documentation of this file.
1 /* from
2  * @article{MollerHughes99,
3  author = "Tomas Moller and John F. Hughes",
4  title = "Efficiently Building a Matrix to Rotate One Vector to Another",
5  journal = "journal of graphics tools",
6  volume = "4",
7  number = "4",
8  pages = "1-4",
9  year = "1999",
10 }
11 http://jgt.akpeters.com/papers/MollerHughes99/code.html
12 */
13 #ifndef __utlRotationMatrixFromVectors_h
14 #define __utlRotationMatrixFromVectors_h
15 
16 
17 #include <cmath>
18 #include "utlCore.h"
19 
20 namespace utl
21 {
22 
35 template <class VectorType, class MatrixType>
36 void
37 RotationMatrixFromUnitNormVectors(const VectorType& from, const VectorType& to, MatrixType& mtx)
38 {
39  const double epsilon = 0.000001;
40 
41  double e, h, f;
42  // MatrixType mtx(3,3);
43 
44  VectorType v(from);
45  v[0] = from[1] * to[2] - from[2] * to[1];
46  v[1] = from[2] * to[0] - from[0] * to[2];
47  v[2] = from[0] * to[1] - from[1] * to[0];
48  // VectorType v = CrossProduct(from, to);
49 
50  e = from[0]*to[0]+from[1]*to[1]+from[2]*to[2];
51  f = (e < 0) ? -e : e;
52  if( f > 1.0 - epsilon ) /* "from" and "to"-vector almost parallel */
53  {
54  VectorType ut(from), vt(from); /* temporary storage vectors */
55  VectorType x(from); /* vector most nearly orthogonal to "from" */
56  double c1, c2, c3; /* coefficients for later use */
57  int i, j;
58 
59  x[0] = (from[0] > 0.0) ? from[0] : -from[0];
60  x[1] = (from[1] > 0.0) ? from[1] : -from[1];
61  x[2] = (from[2] > 0.0) ? from[2] : -from[2];
62 
63  if( x[0] < x[1] )
64  {
65  if( x[0] < x[2] )
66  {
67  x[0] = 1.0; x[1] = x[2] = 0.0;
68  }
69  else
70  {
71  x[2] = 1.0; x[0] = x[1] = 0.0;
72  }
73  }
74  else
75  {
76  if( x[1] < x[2] )
77  {
78  x[1] = 1.0; x[0] = x[2] = 0.0;
79  }
80  else
81  {
82  x[2] = 1.0; x[0] = x[1] = 0.0;
83  }
84  }
85 
86  ut[0] = x[0] - from[0]; ut[1] = x[1] - from[1]; ut[2] = x[2] - from[2];
87  vt[0] = x[0] - to[0]; vt[1] = x[1] - to[1]; vt[2] = x[2] - to[2];
88 
89  c1 = 2.0 / (ut[0]*ut[0]+ut[1]*ut[1]+ut[2]*ut[2]);
90  c2 = 2.0 / (vt[0]*vt[0]+vt[1]*vt[1]+vt[2]*vt[2]);
91  c3 = c1 * c2 * (ut[0]*vt[0]+ut[1]*vt[1]+ut[2]*vt[2]);
92  for( i = 0; i < 3; i++ )
93  {
94  for( j = 0; j < 3; j++ )
95  {
96  mtx(i,j) = -c1 * ut[i] * ut[j] - c2 * vt[i] * vt[j] + c3 * vt[i] * ut[j];
97  }
98  mtx(i,i) += 1.0;
99  }
100 
101  }
102  else /* the most common case, unless "from"="to", or "from"=-"to" */
103  {
104  /* ...otherwise use this hand optimized version (9 mults less) */
105  double hvx, hvz, hvxy, hvxz, hvyz;
106  /* h = (1.0 - e)/DOT(v, v); old code */
107  h = 1.0 / (1.0 + e); /* optimization by Gottfried Chen */
108  hvx = h * v[0];
109  hvz = h * v[2];
110  hvxy = hvx * v[1];
111  hvxz = hvx * v[2];
112  hvyz = hvz * v[1];
113  mtx(0,0) = e + hvx * v[0];
114  mtx(0,1) = hvxy - v[2];
115  mtx(0,2) = hvxz + v[1];
116 
117  mtx(1,0) = hvxy + v[2];
118  mtx(1,1) = e + h * v[1] * v[1];
119  mtx(1,2) = hvyz - v[0];
120 
121  mtx(2,0) = hvxz - v[1];
122  mtx(2,1) = hvyz + v[0];
123  mtx(2,2) = e + hvz * v[2];
124  }
125 }
126 
128 template <class VectorType, class MatrixType>
129 void
130 RotationMatrixFromVectors(const VectorType& from, const VectorType& to, MatrixType& mat)
131 {
132  VectorType from_unit(from);
133  VectorType to_unit(to);
134  double sum_from=0.0, sum_to=0.0;
135  for ( int i = 0; i < 3; i += 1 )
136  {
137  sum_from += from_unit[i]*from_unit[i];
138  sum_to += to_unit[i]*to_unit[i];
139  }
140  utlException(std::abs(sum_from)<1e-20 || std::abs(sum_to)<1e-20, "the vector has unit norm");
141  double norm_from = std::sqrt(sum_from);
142  double norm_to = std::sqrt(sum_to);
143 
144  for ( int i = 0; i < 3; i += 1 )
145  {
146  from_unit[i] /= norm_from;
147  to_unit[i] /= norm_to;
148  }
149  RotationMatrixFromUnitNormVectors<VectorType, MatrixType>(from_unit,to_unit, mat);
150  double factor = norm_to/norm_from;
151  for ( int i = 0; i < 3; ++i )
152  for ( int j = 0; j < 3; ++j )
153  mat(i,j) *= factor;
154 }
155 
156 // /*
157 // * A function for creating a rotation matrix that rotates a vector called
158 // * "from" into another vector called "to".
159 // * Input : from[3], to[3] which both must be *normalized* non-zero vectors
160 // * Output: mtx[3][3] -- a 3x3 matrix in colum-major form
161 // * Authors: Tomas Moller, John Hughes
162 // * "Efficiently Building a Matrix to Rotate One Vector to Another"
163 // * Journal of Graphics Tools, 4(4):1-4, 1999
164 // */
165 // void fromToRotation(double from[3], double to[3], double mtx[3][3]) {
166 // double v[3];
167 // double e, h, f;
168 
169 // CROSS(v, from, to);
170 // e = DOT(from, to);
171 // f = (e < 0)? -e:e;
172 // if (f > 1.0 - epsilon) /* "from" and "to"-vector almost parallel */
173 // {
174 // double u[3], v[3]; /* temporary storage vectors */
175 // double x[3]; /* vector most nearly orthogonal to "from" */
176 // double c1, c2, c3; /* coefficients for later use */
177 // int i, j;
178 
179 // x[0] = (from[0] > 0.0)? from[0] : -from[0];
180 // x[1] = (from[1] > 0.0)? from[1] : -from[1];
181 // x[2] = (from[2] > 0.0)? from[2] : -from[2];
182 
183 // if (x[0] < x[1])
184 // {
185 // if (x[0] < x[2])
186 // {
187 // x[0] = 1.0; x[1] = x[2] = 0.0;
188 // }
189 // else
190 // {
191 // x[2] = 1.0; x[0] = x[1] = 0.0;
192 // }
193 // }
194 // else
195 // {
196 // if (x[1] < x[2])
197 // {
198 // x[1] = 1.0; x[0] = x[2] = 0.0;
199 // }
200 // else
201 // {
202 // x[2] = 1.0; x[0] = x[1] = 0.0;
203 // }
204 // }
205 
206 // u[0] = x[0] - from[0]; u[1] = x[1] - from[1]; u[2] = x[2] - from[2];
207 // v[0] = x[0] - to[0]; v[1] = x[1] - to[1]; v[2] = x[2] - to[2];
208 
209 // c1 = 2.0 / DOT(u, u);
210 // c2 = 2.0 / DOT(v, v);
211 // c3 = c1 * c2 * DOT(u, v);
212 
213 // for (i = 0; i < 3; i++) {
214 // for (j = 0; j < 3; j++) {
215 // mtx[i][j] = - c1 * u[i] * u[j]
216 // - c2 * v[i] * v[j]
217 // + c3 * v[i] * u[j];
218 // }
219 // mtx[i][i] += 1.0;
220 // }
221 // }
222 // else /* the most common case, unless "from"="to", or "from"=-"to" */
223 // {
224 // #if 0
225 // /* unoptimized version - a good compiler will optimize this. */
226 // /* h = (1.0 - e)/DOT(v, v); old code */
227 // h = 1.0/(1.0 + e); /* optimization by Gottfried Chen */
228 // mtx[0][0] = e + h * v[0] * v[0];
229 // mtx[0][1] = h * v[0] * v[1] - v[2];
230 // mtx[0][2] = h * v[0] * v[2] + v[1];
231 
232 // mtx[1][0] = h * v[0] * v[1] + v[2];
233 // mtx[1][1] = e + h * v[1] * v[1];
234 // mtx[1][2] = h * v[1] * v[2] - v[0];
235 
236 // mtx[2][0] = h * v[0] * v[2] - v[1];
237 // mtx[2][1] = h * v[1] * v[2] + v[0];
238 // mtx[2][2] = e + h * v[2] * v[2];
239 // #else
240 // /* ...otherwise use this hand optimized version (9 mults less) */
241 // double hvx, hvz, hvxy, hvxz, hvyz;
242 // /* h = (1.0 - e)/DOT(v, v); old code */
243 // h = 1.0/(1.0 + e); /* optimization by Gottfried Chen */
244 // hvx = h * v[0];
245 // hvz = h * v[2];
246 // hvxy = hvx * v[1];
247 // hvxz = hvx * v[2];
248 // hvyz = hvz * v[1];
249 // mtx[0][0] = e + hvx * v[0];
250 // mtx[0][1] = hvxy - v[2];
251 // mtx[0][2] = hvxz + v[1];
252 
253 // mtx[1][0] = hvxy + v[2];
254 // mtx[1][1] = e + h * v[1] * v[1];
255 // mtx[1][2] = hvyz - v[0];
256 
257 // mtx[2][0] = hvxz - v[1];
258 // mtx[2][1] = hvyz + v[0];
259 // mtx[2][2] = e + hvz * v[2];
260 // #endif
261 // }
262 // }
263 
266 }
267 
268 
269 #endif
void RotationMatrixFromVectors(const VectorType &from, const VectorType &to, MatrixType &mat)
#define utlException(cond, expout)
Definition: utlCoreMacro.h:548
T abs(const T x)
template version of the fabs function
Definition: utl.h:90
void RotationMatrixFromUnitNormVectors(const VectorType &from, const VectorType &to, MatrixType &mtx)