libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo is the group of objects and functions that executes the basic operations of Moldeo 1.0 Platform.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
moMathVector3.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 
3  moMathVector3.cpp
4 
5  ****************************************************************************
6  * *
7  * This source is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This code is distributed in the hope that it will be useful, but *
13  * WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15  * General Public License for more details. *
16  * *
17  * A copy of the GNU General Public License is available on the World *
18  * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
19  * obtain it by writing to the Free Software Foundation, *
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  * *
22  ****************************************************************************
23 
24  Copyright(C) 2006 Fabricio Costa
25 
26  Authors:
27  Fabricio Costa
28  Andrés Colubri
29 
30  Portions taken from
31  Wild Magic Source Code
32  David Eberly
33  http://www.geometrictools.com
34  Copyright (c) 1998-2007
35 
36 *******************************************************************************/
37 
38 #include "moMathVector3.h"
39 
40 #include "moArray.h"
41 moDefineDynamicArray(moVector3iArray)
42 moDefineDynamicArray(moVector3fArray)
43 moDefineDynamicArray(moVector3dArray)
44 
45 // moVector3 class ------------------------------------------------------------
46 /*
47 template <class Real>
48 moVector3<Real>::moVector3 ()
49 {
50  // uninitialized for performance in array construction
51 }
52 
53 template <class Real>
54 moVector3<Real>::moVector3 (Real fX, Real fY, Real fZ)
55 {
56  m_afTuple[0] = fX;
57  m_afTuple[1] = fY;
58  m_afTuple[2] = fZ;
59 }
60 
61 template <class Real>
62 moVector3<Real>::moVector3 (const Real* afTuple)
63 {
64  m_afTuple[0] = afTuple[0];
65  m_afTuple[1] = afTuple[1];
66  m_afTuple[2] = afTuple[2];
67 }
68 */
69 /*
70 template <class Real>
71 moVector3<Real>::moVector3 (const moVector3& rkV) : moAbstract(rkV)
72 {
73  m_afTuple[0] = rkV.m_afTuple[0];
74  m_afTuple[1] = rkV.m_afTuple[1];
75  m_afTuple[2] = rkV.m_afTuple[2];
76 }
77 
78 template <class Real>
79 int moVector3<Real>::CompareArrays (const moVector3& rkV) const
80 {
81  return memcmp(m_afTuple,rkV.m_afTuple,3*sizeof(Real));
82 }
83 
84 template <class Real>
85 bool moVector3<Real>::operator== (const moVector3& rkV) const
86 {
87  return CompareArrays(rkV) == 0;
88 }
89 
90 template <class Real>
91 bool moVector3<Real>::operator!= (const moVector3& rkV) const
92 {
93  return CompareArrays(rkV) != 0;
94 }
95 
96 template <class Real>
97 bool moVector3<Real>::operator< (const moVector3& rkV) const
98 {
99  return CompareArrays(rkV) < 0;
100 }
101 
102 template <class Real>
103 bool moVector3<Real>::operator<= (const moVector3& rkV) const
104 {
105  return CompareArrays(rkV) <= 0;
106 }
107 
108 template <class Real>
109 bool moVector3<Real>::operator> (const moVector3& rkV) const
110 {
111  return CompareArrays(rkV) > 0;
112 }
113 
114 template <class Real>
115 bool moVector3<Real>::operator>= (const moVector3& rkV) const
116 {
117  return CompareArrays(rkV) >= 0;
118 }
119 
120 template <class Real>
121 void moVector3<Real>::GetBarycentrics (const moVector3<Real>& rkV0,
122  const moVector3<Real>& rkV1, const moVector3<Real>& rkV2,
123  const moVector3<Real>& rkV3, Real afBary[4]) const
124 {
125  // compute the vectors relative to V3 of the tetrahedron
126  moVector3<Real> akDiff[4] =
127  {
128  rkV0 - rkV3,
129  rkV1 - rkV3,
130  rkV2 - rkV3,
131  *this - rkV3
132  };
133 
134  // If the vertices have large magnitude, the linear system of
135  // equations for computing barycentric coordinates can be
136  // ill-conditioned. To avoid this, uniformly scale the tetrahedron
137  // edges to be of order 1. The scaling of all differences does not
138  // change the barycentric coordinates.
139  Real fMax = (Real)0.0;
140  int i;
141  for (i = 0; i < 3; i++)
142  {
143  for (int j = 0; j < 3; j++)
144  {
145  Real fValue = moMath<Real>::FAbs(akDiff[i][j]);
146  if (fValue > fMax)
147  {
148  fMax = fValue;
149  }
150  }
151  }
152 
153  // scale down only large data
154  if (fMax > (Real)1.0)
155  {
156  Real fInvMax = ((Real)1.0)/fMax;
157  for (i = 0; i < 4; i++)
158  {
159  akDiff[i] *= fInvMax;
160  }
161  }
162 
163  Real fDet = akDiff[0].Dot(akDiff[1].Cross(akDiff[2]));
164  moVector3<Real> kE1cE2 = akDiff[1].Cross(akDiff[2]);
165  moVector3<Real> kE2cE0 = akDiff[2].Cross(akDiff[0]);
166  moVector3<Real> kE0cE1 = akDiff[0].Cross(akDiff[1]);
167  if (moMath<Real>::FAbs(fDet) > moMath<Real>::ZERO_TOLERANCE)
168  {
169  Real fInvDet = ((Real)1.0)/fDet;
170  afBary[0] = akDiff[3].Dot(kE1cE2)*fInvDet;
171  afBary[1] = akDiff[3].Dot(kE2cE0)*fInvDet;
172  afBary[2] = akDiff[3].Dot(kE0cE1)*fInvDet;
173  afBary[3] = (Real)1.0 - afBary[0] - afBary[1] - afBary[2];
174  }
175  else
176  {
177  // The tetrahedron is potentially flat. Determine the face of
178  // maximum area and compute barycentric coordinates with respect
179  // to that face.
180  moVector3<Real> kE02 = rkV0 - rkV2;
181  moVector3<Real> kE12 = rkV1 - rkV2;
182  moVector3<Real> kE02cE12 = kE02.Cross(kE12);
183  Real fMaxSqrArea = kE02cE12.SquaredLength();
184  int iMaxIndex = 3;
185  Real fSqrArea = kE0cE1.SquaredLength();
186  if (fSqrArea > fMaxSqrArea)
187  {
188  iMaxIndex = 0;
189  fMaxSqrArea = fSqrArea;
190  }
191  fSqrArea = kE1cE2.SquaredLength();
192  if (fSqrArea > fMaxSqrArea)
193  {
194  iMaxIndex = 1;
195  fMaxSqrArea = fSqrArea;
196  }
197  fSqrArea = kE2cE0.SquaredLength();
198  if (fSqrArea > fMaxSqrArea)
199  {
200  iMaxIndex = 2;
201  fMaxSqrArea = fSqrArea;
202  }
203 
204  if (fMaxSqrArea > moMath<Real>::ZERO_TOLERANCE)
205  {
206  Real fInvSqrArea = ((Real)1.0)/fMaxSqrArea;
207  moVector3<Real> kTmp;
208  if (iMaxIndex == 0)
209  {
210  kTmp = akDiff[3].Cross(akDiff[1]);
211  afBary[0] = kE0cE1.Dot(kTmp)*fInvSqrArea;
212  kTmp = akDiff[0].Cross(akDiff[3]);
213  afBary[1] = kE0cE1.Dot(kTmp)*fInvSqrArea;
214  afBary[2] = (Real)0.0;
215  afBary[3] = (Real)1.0 - afBary[0] - afBary[1];
216  }
217  else if (iMaxIndex == 1)
218  {
219  afBary[0] = (Real)0.0;
220  kTmp = akDiff[3].Cross(akDiff[2]);
221  afBary[1] = kE1cE2.Dot(kTmp)*fInvSqrArea;
222  kTmp = akDiff[1].Cross(akDiff[3]);
223  afBary[2] = kE1cE2.Dot(kTmp)*fInvSqrArea;
224  afBary[3] = (Real)1.0 - afBary[1] - afBary[2];
225  }
226  else if (iMaxIndex == 2)
227  {
228  kTmp = akDiff[2].Cross(akDiff[3]);
229  afBary[0] = kE2cE0.Dot(kTmp)*fInvSqrArea;
230  afBary[1] = (Real)0.0;
231  kTmp = akDiff[3].Cross(akDiff[0]);
232  afBary[2] = kE2cE0.Dot(kTmp)*fInvSqrArea;
233  afBary[3] = (Real)1.0 - afBary[0] - afBary[2];
234  }
235  else
236  {
237  akDiff[3] = *this - rkV2;
238  kTmp = akDiff[3].Cross(kE12);
239  afBary[0] = kE02cE12.Dot(kTmp)*fInvSqrArea;
240  kTmp = kE02.Cross(akDiff[3]);
241  afBary[1] = kE02cE12.Dot(kTmp)*fInvSqrArea;
242  afBary[2] = (Real)1.0 - afBary[0] - afBary[1];
243  afBary[3] = (Real)0.0;
244  }
245  }
246  else
247  {
248  // The tetrahedron is potentially a sliver. Determine the edge of
249  // maximum length and compute barycentric coordinates with respect
250  // to that edge.
251  Real fMaxSqrLength = akDiff[0].SquaredLength();
252  iMaxIndex = 0; // <V0,V3>
253  Real fSqrLength = akDiff[1].SquaredLength();
254  if (fSqrLength > fMaxSqrLength)
255  {
256  iMaxIndex = 1; // <V1,V3>
257  fMaxSqrLength = fSqrLength;
258  }
259  fSqrLength = akDiff[2].SquaredLength();
260  if (fSqrLength > fMaxSqrLength)
261  {
262  iMaxIndex = 2; // <V2,V3>
263  fMaxSqrLength = fSqrLength;
264  }
265  fSqrLength = kE02.SquaredLength();
266  if (fSqrLength > fMaxSqrLength)
267  {
268  iMaxIndex = 3; // <V0,V2>
269  fMaxSqrLength = fSqrLength;
270  }
271  fSqrLength = kE12.SquaredLength();
272  if (fSqrLength > fMaxSqrLength)
273  {
274  iMaxIndex = 4; // <V1,V2>
275  fMaxSqrLength = fSqrLength;
276  }
277  moVector3<Real> kE01 = rkV0 - rkV1;
278  fSqrLength = kE01.SquaredLength();
279  if (fSqrLength > fMaxSqrLength)
280  {
281  iMaxIndex = 5; // <V0,V1>
282  fMaxSqrLength = fSqrLength;
283  }
284 
285  if (fMaxSqrLength > moMath<Real>::ZERO_TOLERANCE)
286  {
287  Real fInvSqrLength = ((Real)1.0)/fMaxSqrLength;
288  if (iMaxIndex == 0)
289  {
290  // P-V3 = t*(V0-V3)
291  afBary[0] = akDiff[3].Dot(akDiff[0])*fInvSqrLength;
292  afBary[1] = (Real)0.0;
293  afBary[2] = (Real)0.0;
294  afBary[3] = (Real)1.0 - afBary[0];
295  }
296  else if (iMaxIndex == 1)
297  {
298  // P-V3 = t*(V1-V3)
299  afBary[0] = (Real)0.0;
300  afBary[1] = akDiff[3].Dot(akDiff[1])*fInvSqrLength;
301  afBary[2] = (Real)0.0;
302  afBary[3] = (Real)1.0 - afBary[1];
303  }
304  else if (iMaxIndex == 2)
305  {
306  // P-V3 = t*(V2-V3)
307  afBary[0] = (Real)0.0;
308  afBary[1] = (Real)0.0;
309  afBary[2] = akDiff[3].Dot(akDiff[2])*fInvSqrLength;
310  afBary[3] = (Real)1.0 - afBary[2];
311  }
312  else if (iMaxIndex == 3)
313  {
314  // P-V2 = t*(V0-V2)
315  akDiff[3] = *this - rkV2;
316  afBary[0] = akDiff[3].Dot(kE02)*fInvSqrLength;
317  afBary[1] = (Real)0.0;
318  afBary[2] = (Real)1.0 - afBary[0];
319  afBary[3] = (Real)0.0;
320  }
321  else if (iMaxIndex == 4)
322  {
323  // P-V2 = t*(V1-V2)
324  akDiff[3] = *this - rkV2;
325  afBary[0] = (Real)0.0;
326  afBary[1] = akDiff[3].Dot(kE12)*fInvSqrLength;
327  afBary[2] = (Real)1.0 - afBary[1];
328  afBary[3] = (Real)0.0;
329  }
330  else
331  {
332  // P-V1 = t*(V0-V1)
333  akDiff[3] = *this - rkV1;
334  afBary[0] = akDiff[3].Dot(kE01)*fInvSqrLength;
335  afBary[1] = (Real)1.0 - afBary[0];
336  afBary[2] = (Real)0.0;
337  afBary[3] = (Real)0.0;
338  }
339  }
340  else
341  {
342  // tetrahedron is a nearly a point, just return equal weights
343  afBary[0] = (Real)0.25;
344  afBary[1] = afBary[0];
345  afBary[2] = afBary[0];
346  afBary[3] = afBary[0];
347  }
348  }
349  }
350 }
351 
352 template <class Real>
353 void moVector3<Real>::Orthonormalize (moVector3& rkU, moVector3& rkV, moVector3& rkW)
354 {
355  // If the input vectors are v0, v1, and v2, then the Gram-Schmidt
356  // orthonormalization produces vectors u0, u1, and u2 as follows,
357  //
358  // u0 = v0/|v0|
359  // u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
360  // u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1|
361  //
362  // where |A| indicates length of vector A and A*B indicates dot
363  // product of vectors A and B.
364 
365  // compute u0
366  rkU.Normalize();
367 
368  // compute u1
369  Real fDot0 = rkU.Dot(rkV);
370  rkV -= fDot0*rkU;
371  rkV.Normalize();
372 
373  // compute u2
374  Real fDot1 = rkV.Dot(rkW);
375  fDot0 = rkU.Dot(rkW);
376  rkW -= fDot0*rkU + fDot1*rkV;
377  rkW.Normalize();
378 }
379 
380 template <class Real>
381 void moVector3<Real>::Orthonormalize (moVector3* akV)
382 {
383  Orthonormalize(akV[0],akV[1],akV[2]);
384 }
385 
386 template <class Real>
387 void moVector3<Real>::GenerateOrthonormalBasis (moVector3& rkU, moVector3& rkV,
388  moVector3& rkW)
389 {
390  rkW.Normalize();
391  GenerateComplementBasis(rkU,rkV,rkW);
392 }
393 
394 template <class Real>
395 void moVector3<Real>::GenerateComplementBasis (moVector3& rkU, moVector3& rkV,
396  const moVector3& rkW)
397 {
398  Real fInvLength;
399 
400  if (moMath<Real>::FAbs(rkW.m_afTuple[0]) >=
401  moMath<Real>::FAbs(rkW.m_afTuple[1]) )
402  {
403  // W.x or W.z is the largest magnitude component, swap them
404  fInvLength = moMath<Real>::InvSqrt(rkW.m_afTuple[0]*rkW.m_afTuple[0] +
405  rkW.m_afTuple[2]*rkW.m_afTuple[2]);
406  rkU.m_afTuple[0] = -rkW.m_afTuple[2]*fInvLength;
407  rkU.m_afTuple[1] = (Real)0.0;
408  rkU.m_afTuple[2] = +rkW.m_afTuple[0]*fInvLength;
409  rkV.m_afTuple[0] = rkW.m_afTuple[1]*rkU.m_afTuple[2];
410  rkV.m_afTuple[1] = rkW.m_afTuple[2]*rkU.m_afTuple[0] -
411  rkW.m_afTuple[0]*rkU.m_afTuple[2];
412  rkV.m_afTuple[2] = -rkW.m_afTuple[1]*rkU.m_afTuple[0];
413  }
414  else
415  {
416  // W.y or W.z is the largest magnitude component, swap them
417  fInvLength = moMath<Real>::InvSqrt(rkW.m_afTuple[1]*rkW.m_afTuple[1] +
418  rkW.m_afTuple[2]*rkW.m_afTuple[2]);
419  rkU.m_afTuple[0] = (Real)0.0;
420  rkU.m_afTuple[1] = +rkW.m_afTuple[2]*fInvLength;
421  rkU.m_afTuple[2] = -rkW.m_afTuple[1]*fInvLength;
422  rkV.m_afTuple[0] = rkW.m_afTuple[1]*rkU.m_afTuple[2] -
423  rkW.m_afTuple[2]*rkU.m_afTuple[1];
424  rkV.m_afTuple[1] = -rkW.m_afTuple[0]*rkU.m_afTuple[2];
425  rkV.m_afTuple[2] = rkW.m_afTuple[0]*rkU.m_afTuple[1];
426  }
427 }
428 
429 template <class Real>
430 void moVector3<Real>::ComputeExtremes (int iVQuantity, const moVector3* akPoint,
431  moVector3& rkMin, moVector3& rkMax)
432 {
433  if (!(iVQuantity > 0 && akPoint)) return;
434 
435  rkMin = akPoint[0];
436  rkMax = rkMin;
437  for (int i = 1; i < iVQuantity; i++)
438  {
439  const moVector3<Real>& rkPoint = akPoint[i];
440  for (int j = 0; j < 3; j++)
441  {
442  if (rkPoint[j] < rkMin[j])
443  {
444  rkMin[j] = rkPoint[j];
445  }
446  else if (rkPoint[j] > rkMax[j])
447  {
448  rkMax[j] = rkPoint[j];
449  }
450  }
451  }
452 }
453 
454 
455 // arithmetic operations
456 template <class Real>
457 moVector3<Real> moVector3<Real>::operator+ (const moVector3& rkV) const
458 {
459  moVector3<Real> ret(m_afTuple[0]+rkV.m_afTuple[0], m_afTuple[1]+rkV.m_afTuple[1], m_afTuple[2]+rkV.m_afTuple[2]);
460  return ret;
461 }
462 
463 
464 template <class Real>
465 moVector3<Real> moVector3<Real>::operator- (const moVector3& rkV) const
466 {
467  return moVector3<Real>(m_afTuple[0]-rkV.m_afTuple[0],m_afTuple[1]-rkV.m_afTuple[1],m_afTuple[2]-rkV.m_afTuple[2]);
468 }
469 
470 
471 template <class Real>
472 moVector3<Real> moVector3<Real>::operator* (Real fScalar) const
473 {
474  return moVector3<Real>(
475  fScalar*m_afTuple[0],
476  fScalar*m_afTuple[1],
477  fScalar*m_afTuple[2]);
478 }
479 
480 
481 template <class Real>
482 moVector3<Real> moVector3<Real>::operator/ (Real fScalar) const
483 {
484  moVector3<Real> kQuot;
485 
486  if (fScalar != (Real)0.0)
487  {
488  Real fInvScalar = ((Real)1.0)/fScalar;
489  kQuot.m_afTuple[0] = fInvScalar*m_afTuple[0];
490  kQuot.m_afTuple[1] = fInvScalar*m_afTuple[1];
491  kQuot.m_afTuple[2] = fInvScalar*m_afTuple[2];
492  }
493  else
494  {
495  kQuot.m_afTuple[0] = moMath<Real>::MAX_REAL;
496  kQuot.m_afTuple[1] = moMath<Real>::MAX_REAL;
497  kQuot.m_afTuple[2] = moMath<Real>::MAX_REAL;
498  }
499 
500  return kQuot;
501 }
502 template <class Real>
503 moVector3<Real> moVector3<Real>::operator- () const
504 {
505  return moVector3<Real>(-m_afTuple[0], -m_afTuple[1], -m_afTuple[2]);
506 }
507 
508 // arithmetic updates
509 template <class Real>
510 moVector3<Real>& moVector3<Real>::operator+= (const moVector3& rkV)
511 {
512  m_afTuple[0] += rkV.m_afTuple[0];
513  m_afTuple[1] += rkV.m_afTuple[1];
514  m_afTuple[2] += rkV.m_afTuple[2];
515  return *this;
516 }
517 template <class Real>
518 moVector3<Real>& moVector3<Real>::operator-= (const moVector3& rkV)
519 {
520  m_afTuple[0] -= rkV.m_afTuple[0];
521  m_afTuple[1] -= rkV.m_afTuple[1];
522  m_afTuple[2] -= rkV.m_afTuple[2];
523  return *this;
524 }
525 template <class Real>
526 moVector3<Real>& moVector3<Real>::operator*= (const Real fScalar)
527 {
528  m_afTuple[0] *= fScalar;
529  m_afTuple[1] *= fScalar;
530  m_afTuple[2] *= fScalar;
531  return *this;
532 }
533 template <class Real>
534 moVector3<Real>& moVector3<Real>::operator/= (const Real fScalar)
535 {
536  if (fScalar != (Real)0.0)
537  {
538  Real fInvScalar = ((Real)1.0)/fScalar;
539  m_afTuple[0] *= fInvScalar;
540  m_afTuple[1] *= fInvScalar;
541  m_afTuple[2] *= fInvScalar;
542  }
543  else
544  {
545  m_afTuple[0] = moMath<Real>::MAX_REAL;
546  m_afTuple[1] = moMath<Real>::MAX_REAL;
547  m_afTuple[2] = moMath<Real>::MAX_REAL;
548  }
549 
550  return *this;
551 }
552 */
553 /*
554 // vector operations
555 template <class Real>
556 Real moVector3<Real>::Length () const
557 {
558  return moMath<Real>::Sqrt(
559  m_afTuple[0]*m_afTuple[0] +
560  m_afTuple[1]*m_afTuple[1] +
561  m_afTuple[2]*m_afTuple[2]);
562 }
563 
564 
565 template <class Real>
566 Real moVector3<Real>::SquaredLength () const
567 {
568  return
569  m_afTuple[0]*m_afTuple[0] +
570  m_afTuple[1]*m_afTuple[1] +
571  m_afTuple[2]*m_afTuple[2];
572 }
573 template <class Real>
574 Real moVector3<Real>::Dot (const moVector3& rkV) const
575 {
576  return
577  m_afTuple[0]*rkV.m_afTuple[0] +
578  m_afTuple[1]*rkV.m_afTuple[1] +
579  m_afTuple[2]*rkV.m_afTuple[2];
580 }
581 
582 
583 template <class Real>
584 Real moVector3<Real>::Normalize ()
585 {
586  Real fLength = Length();
587 
588  if (fLength > moMath<Real>::ZERO_TOLERANCE)
589  {
590  Real fInvLength = ((Real)1.0)/fLength;
591  m_afTuple[0] *= fInvLength;
592  m_afTuple[1] *= fInvLength;
593  m_afTuple[2] *= fInvLength;
594  }
595  else
596  {
597  fLength = (Real)0.0;
598  m_afTuple[0] = (Real)0.0;
599  m_afTuple[1] = (Real)0.0;
600  m_afTuple[2] = (Real)0.0;
601  }
602 
603  return fLength;
604 }
605 
606 // The cross products are computed using the right-handed rule. Be aware
607 // that some graphics APIs use a left-handed rule. If you have to compute
608 // a cross product with these functions and send the result to the API
609 // that expects left-handed, you will need to change sign on the vector
610 // (replace each component value c by -c).
611 
612 template <class Real>
613 moVector3<Real> moVector3<Real>::Cross (const moVector3& rkV) const
614 {
615  moVector3<Real> kCross(
616  m_afTuple[1]*rkV.m_afTuple[2] - m_afTuple[2]*rkV.m_afTuple[1],
617  m_afTuple[2]*rkV.m_afTuple[0] - m_afTuple[0]*rkV.m_afTuple[2],
618  m_afTuple[0]*rkV.m_afTuple[1] - m_afTuple[1]*rkV.m_afTuple[0]);
619  return kCross;
620 }
621 
622 template <class Real>
623 moVector3<Real> moVector3<Real>::UnitCross (const moVector3& rkV) const
624 {
625  moVector3<Real> kCross(
626  m_afTuple[1]*rkV.m_afTuple[2] - m_afTuple[2]*rkV.m_afTuple[1],
627  m_afTuple[2]*rkV.m_afTuple[0] - m_afTuple[0]*rkV.m_afTuple[2],
628  m_afTuple[0]*rkV.m_afTuple[1] - m_afTuple[1]*rkV.m_afTuple[0]);
629  kCross.Normalize();
630  return kCross;
631 }
632 
633 
634 // Cosine between 'this' vector and rkV.
635 template <class Real>
636 Real moVector3<Real>::Cosine (const moVector3<Real>& rkV)
637 {
638  Real l = Length();
639  Real lv = rkV.Length();
640  if ((0 < l) && (0 < lv)) return Dot(rkV) / (l * lv);
641  else return 0;
642 }
643 // Angle between 'this' vector and rkV.
644 template <class Real>
645 Real moVector3<Real>::Angle (const moVector3<Real>& rkV) {
646  return moMath<Real>::ACos(Cosine(rkV));
647 }
648 */
649 template<> const moVector3<MOlong> moVector3<MOlong>::ZERO(0,0,0);
650 template<> const moVector3<MOlong> moVector3<MOlong>::UNIT_X(1,0,0);
651 template<> const moVector3<MOlong> moVector3<MOlong>::UNIT_Y(0,1,0);
652 template<> const moVector3<MOlong> moVector3<MOlong>::UNIT_Z(0,0,1);
653 template<> const moVector3<MOlong> moVector3<MOlong>::ONE(1,1,1);
654 
655 template<> const moVector3<MOfloat> moVector3<MOfloat>::ZERO(0.0f,0.0f,0.0f);
656 template<> const moVector3<MOfloat> moVector3<MOfloat>::UNIT_X(1.0f,0.0f,0.0f);
657 template<> const moVector3<MOfloat> moVector3<MOfloat>::UNIT_Y(0.0f,1.0f,0.0f);
658 template<> const moVector3<MOfloat> moVector3<MOfloat>::UNIT_Z(0.0f,0.0f,1.0f);
659 template<> const moVector3<MOfloat> moVector3<MOfloat>::ONE(1.0f,1.0f,1.0f);
660 
661 template<> const moVector3<MOdouble> moVector3<MOdouble>::ZERO(0.0,0.0,0.0);
662 template<> const moVector3<MOdouble> moVector3<MOdouble>::UNIT_X(1.0,0.0,0.0);
663 template<> const moVector3<MOdouble> moVector3<MOdouble>::UNIT_Y(0.0,1.0,0.0);
664 template<> const moVector3<MOdouble> moVector3<MOdouble>::UNIT_Z(0.0,0.0,1.0);
665 template<> const moVector3<MOdouble> moVector3<MOdouble>::ONE(1.0,1.0,1.0);
666 
667 
#define MOfloat
Definition: moTypes.h:403
#define MOlong
Definition: moTypes.h:391
#define moDefineDynamicArray(name)
Definition: moArray.cpp:222
#define MOdouble
Definition: moTypes.h:404