Vuo  2.0.2
VuoTransform.h
Go to the documentation of this file.
1 
10 #pragma once
11 
12 #include "VuoInteger.h"
13 #include <math.h>
14 #include <float.h>
15 #include "VuoPoint3d.h"
16 #include "VuoPoint4d.h"
17 #include "VuoRectangle.h"
18 #include "VuoTransform2d.h"
19 #include <stdio.h>
20 
33 {
34  VuoTransformTypeEuler,
35  VuoTransformTypeQuaternion,
36  VuoTransformTypeTargeted
37 };
38 
45 typedef struct
46 {
47  VuoPoint3d translation;
48  float rotation[9];
49  VuoPoint3d scale;
50 
51  // The following values are stored so we can display a meaningful summary.
52  enum VuoTransformType type;
53  struct
54  {
55  VuoPoint3d euler;
56  VuoPoint4d quaternion;
57  struct
58  {
59  VuoPoint3d target;
60  VuoPoint3d upDirection;
61  };
62  } rotationSource;
63 } VuoTransform;
64 
65 void VuoTransform_getMatrix(const VuoTransform value, float *matrix) __attribute__((nonnull));
66 void VuoTransform_getBillboardMatrix(VuoInteger imageWidth, VuoInteger imageHeight, VuoReal imageScaleFactor, VuoBoolean preservePhysicalSize, VuoReal translationX, VuoReal translationY, VuoInteger viewportWidth, VuoInteger viewportHeight, VuoReal backingScaleFactor, VuoPoint2d mesh0, float *billboardMatrix) __attribute__((nonnull));
67 VuoPoint3d VuoTransform_getEuler(const VuoTransform transform);
68 VuoPoint4d VuoTransform_getQuaternion(const VuoTransform transform);
69 VuoPoint3d VuoTransform_getDirection(const VuoTransform transform);
71 VuoTransform VuoTransform_makeEuler(VuoPoint3d translation, VuoPoint3d rotation, VuoPoint3d scale);
72 VuoTransform VuoTransform_makeQuaternion(VuoPoint3d translation, VuoPoint4d rotation, VuoPoint3d scale);
73 void VuoTransform_rotationMatrixFromQuaternion(const VuoPoint4d quaternion, float *matrix) __attribute__((nonnull));
74 void VuoTransform_rotationMatrixFromEuler(const VuoPoint3d euler, float *matrix) __attribute__((nonnull));
75 
78 
79 VuoTransform VuoTransform_makeFromTarget(VuoPoint3d position, VuoPoint3d target, VuoPoint3d upDirection);
80 VuoTransform VuoTransform_makeFromMatrix4x4(const float *matrix) __attribute__((nonnull));
82 
86 static inline VuoPoint4d VuoTransform_quaternionComposite(VuoPoint4d a, VuoPoint4d b) __attribute__((const));
87 static inline VuoPoint4d VuoTransform_quaternionComposite(VuoPoint4d a, VuoPoint4d b)
88 {
89  VuoPoint4d q;
90  // Hamilton product (a.w, a.x, a.y, a.z) * (b.w, b.x, b.y, b.z)
91  q.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
92  q.y = a.w*b.y + a.y*b.w + a.z*b.x - a.x*b.z;
93  q.z = a.w*b.z + a.z*b.w + a.x*b.y - a.y*b.x;
94  q.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
95  return VuoPoint4d_normalize(q);
96 }
97 
101 static inline VuoPoint4d VuoTransform_quaternionFromAxisAngle(VuoPoint3d axis, float angle) __attribute__((const));
102 static inline VuoPoint4d VuoTransform_quaternionFromAxisAngle(VuoPoint3d axis, float angle)
103 {
104  VuoPoint4d q;
105  VuoPoint3d axisNormalized = VuoPoint3d_normalize(axis);
106  q.x = axisNormalized.x * sinf(angle/2.f);
107  q.y = axisNormalized.y * sinf(angle/2.f);
108  q.z = axisNormalized.z * sinf(angle/2.f);
109  q.w = cosf(angle/2.f);
110  return VuoPoint4d_normalize(q);
111 }
112 
113 VuoPoint4d VuoTransform_quaternionFromBasis(VuoPoint3d basis[3]);
114 
120 static inline VuoPoint4d VuoTransform_quaternionFromVectors(VuoPoint3d from, VuoPoint3d to) __attribute__((const));
121 static inline VuoPoint4d VuoTransform_quaternionFromVectors(VuoPoint3d from, VuoPoint3d to)
122 {
123  // http://books.google.com/books?id=hiBFUv_FT0wC&pg=PA214&lpg=PA214&dq=Stan+Melax's+article+in+Game+Programming+Gems&source=bl&ots=OCjDPwza1h&sig=6_bDSzTrnI3qCEG9vtVV_mDBgg8&hl=en&sa=X&ei=ffReUsSaBIrMqAGg6YD4Aw&ved=0CCsQ6AEwAA#v=onepage&q=Stan%20Melax's%20article%20in%20Game%20Programming%20Gems&f=false
124  VuoPoint4d q = { 0, 0, 0, 1 };
125 
126  if (VuoPoint3d_magnitude(from) == 0 || VuoPoint3d_magnitude(to) == 0)
127  return q;
128 
129  VuoPoint3d fromNormalized = VuoPoint3d_normalize(from);
130  VuoPoint3d toNormalized = VuoPoint3d_normalize(to);
131 
132  VuoPoint3d c = VuoPoint3d_crossProduct(fromNormalized, toNormalized);
133  float d = VuoPoint3d_dotProduct(fromNormalized, toNormalized);
134  float s = sqrtf( (1+d)*2 );
135 
136  q.x = c.x / s;
137  q.y = c.y / s;
138  q.z = c.z / s;
139  q.w = s / 2.f;
140 
141  return q;
142 }
143 
148 static inline VuoPoint4d VuoTransform_quaternionFromMatrix(const float *rotation) __attribute__((nonnull));
149 static inline VuoPoint4d VuoTransform_quaternionFromMatrix(const float *rotation)
150 {
151  float t;
152  VuoPoint4d q;
153 
154  float m00 = rotation[0],
155  m01 = rotation[1],
156  m02 = rotation[2],
157  m10 = rotation[3],
158  m11 = rotation[4],
159  m12 = rotation[5],
160  m20 = rotation[6],
161  m21 = rotation[7],
162  m22 = rotation[8];
163 
164  if (m22 < 0)
165  {
166  if (m00 > m11)
167  {
168  t = 1 + m00 - m11 - m22;
169  q = VuoPoint4d_make( t, m01+m10, m20+m02, m12-m21 );
170  }
171  else
172  {
173  t = 1 - m00 + m11 - m22;
174  q = VuoPoint4d_make( m01+m10, t, m12+m21, m20-m02 );
175  }
176  }
177  else
178  {
179  if (m00 < -m11)
180  {
181  t = 1 - m00 - m11 + m22;
182  q = VuoPoint4d_make( m20+m02, m12+m21, t, m01-m10 );
183  }
184  else
185  {
186  t = 1 + m00 + m11 + m22;
187  q = VuoPoint4d_make( m12-m21, m20-m02, m01-m10, t );
188  }
189  }
190 
191  return VuoPoint4d_multiply(q, 0.5f / sqrt(t));
192 }
193 
198 static inline VuoPoint4d VuoTransform_quaternionFromEuler(const VuoPoint3d euler) __attribute__((const));
199 static inline VuoPoint4d VuoTransform_quaternionFromEuler(const VuoPoint3d euler)
200 {
201  VuoPoint4d q;
202 
203  double t0 = cos(euler.z * 0.5);
204  double t1 = sin(euler.z * 0.5);
205  double t2 = cos(euler.x * 0.5);
206  double t3 = sin(euler.x * 0.5);
207  double t4 = cos(euler.y * 0.5);
208  double t5 = sin(euler.y * 0.5);
209 
210  q.w = t0 * t2 * t4 + t1 * t3 * t5;
211  q.x = t0 * t3 * t4 - t1 * t2 * t5;
212  q.y = t0 * t2 * t5 + t1 * t3 * t4;
213  q.z = t1 * t2 * t4 - t0 * t3 * t5;
214 
215  return VuoPoint4d_normalize(q);
216 }
217 
222 static inline VuoPoint3d VuoTransform_eulerFromQuaternion(const VuoPoint4d quaternion) __attribute__((const));
223 static inline VuoPoint3d VuoTransform_eulerFromQuaternion(const VuoPoint4d quaternion)
224 {
225  VuoPoint3d ea;
226 
227  double ysqr = quaternion.y * quaternion.y;
228 
229  // roll (x-axis rotation)
230  double t0 = + 2.0 * (quaternion.w * quaternion.x + quaternion.y * quaternion.z);
231  double t1 = + 1.0 - 2.0 * (quaternion.x * quaternion.x + ysqr);
232  ea.x = atan2(t0, t1);
233 
234  // pitch (y-axis rotation)
235  double t2 = +2.0 * (quaternion.w * quaternion.y - quaternion.z * quaternion.x);
236  t2 = t2 > 1.0 ? 1.0 : t2;
237  t2 = t2 < -1.0 ? -1.0 : t2;
238  ea.y = asin(t2);
239 
240  // yaw (z-axis rotation)
241  double t3 = +2.0 * (quaternion.w * quaternion.z + quaternion.x * quaternion.y);
242  double t4 = +1.0 - 2.0 * (ysqr + quaternion.z * quaternion.z);
243  ea.z = atan2(t3, t4);
244 
245  return ea;
246 }
247 
251 static inline VuoPoint3d VuoTransform_eulerFromMatrix(const float *matrix) __attribute__((nonnull));
252 static inline VuoPoint3d VuoTransform_eulerFromMatrix(const float *matrix)
253 {
254  // "Euler Angle Conversion" by Ken Shoemake. Graphics Gems IV, pp. 222–229.
255  VuoPoint3d ea;
256 
257  double cy = sqrt(matrix[0] * matrix[0] + matrix[1] * matrix[1]);
258 
259  if (cy > 16 * FLT_EPSILON)
260  {
261  ea.x = atan2f( matrix[5], matrix[8]);
262  ea.y = atan2f(-matrix[2], cy);
263  ea.z = atan2f( matrix[1], matrix[0]);
264  }
265  else
266  {
267  ea.x = atan2f(-matrix[7], matrix[4]);
268  ea.y = atan2f(-matrix[2], cy);
269  ea.z = 0;
270  }
271 
272  return ea;
273 }
274 
278 static inline VuoPoint3d VuoTransform_rotateVectorWithQuaternion(const VuoPoint3d v, const VuoPoint4d q) __attribute__((const));
279 static inline VuoPoint3d VuoTransform_rotateVectorWithQuaternion(const VuoPoint3d v, const VuoPoint4d q)
280 {
281  // https://math.stackexchange.com/questions/40164/how-do-you-rotate-a-vector-by-a-unit-quaternion/535223
282  VuoPoint4d vQuaternion = (VuoPoint4d){v.x, v.y, v.z, 0};
283  VuoPoint4d qConjugate = (VuoPoint4d){-q.x, -q.y, -q.z, q.w};
284  VuoPoint4d result = VuoTransform_quaternionComposite(VuoTransform_quaternionComposite(q, vQuaternion), qConjugate);
285  return (VuoPoint3d){result.x, result.y, result.z};
286 }
287 
291 static inline bool VuoTransform_isIdentity(const VuoTransform transform)
292 {
293  const float tolerance = 0.00001f;
294  return fabs(transform.translation.x) < tolerance
295  && fabs(transform.translation.y) < tolerance
296  && fabs(transform.translation.z) < tolerance
297  && fabs(transform.scale.x - 1.) < tolerance
298  && fabs(transform.scale.y - 1.) < tolerance
299  && fabs(transform.scale.z - 1.) < tolerance
300  && (
301  (transform.type == VuoTransformTypeEuler
302  && fabs(transform.rotationSource.euler.x) < tolerance
303  && fabs(transform.rotationSource.euler.y) < tolerance
304  && fabs(transform.rotationSource.euler.z) < tolerance
305  )
306  ||
307  (transform.type == VuoTransformTypeQuaternion
308  && fabs(transform.rotationSource.quaternion.x) < tolerance
309  && fabs(transform.rotationSource.quaternion.y) < tolerance
310  && fabs(transform.rotationSource.quaternion.z) < tolerance
311  && (fabs(transform.rotationSource.quaternion.w - 1.) < tolerance || fabs(transform.rotationSource.quaternion.w + 1.) < tolerance)
312  )
313  ||
314  (transform.type == VuoTransformTypeTargeted
315  && fabs(transform.rotationSource.target.x - 1.) < tolerance
316  && fabs(transform.rotationSource.target.y) < tolerance
317  && fabs(transform.rotationSource.target.z) < tolerance
318  )
319  );
320 }
321 
325 static inline void VuoTransform_multiplyMatrices4x4(const float *a, const float *b, float *outputMatrix) __attribute__((nonnull));
326 static inline void VuoTransform_multiplyMatrices4x4(const float *a, const float *b, float *outputMatrix)
327 {
328  outputMatrix[0*4+0] = a[0*4+0] * b[0*4+0] + a[0*4+1] * b[1*4+0] + a[0*4+2] * b[2*4+0] + a[0*4+3] * b[3*4+0];
329  outputMatrix[0*4+1] = a[0*4+0] * b[0*4+1] + a[0*4+1] * b[1*4+1] + a[0*4+2] * b[2*4+1] + a[0*4+3] * b[3*4+1];
330  outputMatrix[0*4+2] = a[0*4+0] * b[0*4+2] + a[0*4+1] * b[1*4+2] + a[0*4+2] * b[2*4+2] + a[0*4+3] * b[3*4+2];
331  outputMatrix[0*4+3] = a[0*4+0] * b[0*4+3] + a[0*4+1] * b[1*4+3] + a[0*4+2] * b[2*4+3] + a[0*4+3] * b[3*4+3];
332  outputMatrix[1*4+0] = a[1*4+0] * b[0*4+0] + a[1*4+1] * b[1*4+0] + a[1*4+2] * b[2*4+0] + a[1*4+3] * b[3*4+0];
333  outputMatrix[1*4+1] = a[1*4+0] * b[0*4+1] + a[1*4+1] * b[1*4+1] + a[1*4+2] * b[2*4+1] + a[1*4+3] * b[3*4+1];
334  outputMatrix[1*4+2] = a[1*4+0] * b[0*4+2] + a[1*4+1] * b[1*4+2] + a[1*4+2] * b[2*4+2] + a[1*4+3] * b[3*4+2];
335  outputMatrix[1*4+3] = a[1*4+0] * b[0*4+3] + a[1*4+1] * b[1*4+3] + a[1*4+2] * b[2*4+3] + a[1*4+3] * b[3*4+3];
336  outputMatrix[2*4+0] = a[2*4+0] * b[0*4+0] + a[2*4+1] * b[1*4+0] + a[2*4+2] * b[2*4+0] + a[2*4+3] * b[3*4+0];
337  outputMatrix[2*4+1] = a[2*4+0] * b[0*4+1] + a[2*4+1] * b[1*4+1] + a[2*4+2] * b[2*4+1] + a[2*4+3] * b[3*4+1];
338  outputMatrix[2*4+2] = a[2*4+0] * b[0*4+2] + a[2*4+1] * b[1*4+2] + a[2*4+2] * b[2*4+2] + a[2*4+3] * b[3*4+2];
339  outputMatrix[2*4+3] = a[2*4+0] * b[0*4+3] + a[2*4+1] * b[1*4+3] + a[2*4+2] * b[2*4+3] + a[2*4+3] * b[3*4+3];
340  outputMatrix[3*4+0] = a[3*4+0] * b[0*4+0] + a[3*4+1] * b[1*4+0] + a[3*4+2] * b[2*4+0] + a[3*4+3] * b[3*4+0];
341  outputMatrix[3*4+1] = a[3*4+0] * b[0*4+1] + a[3*4+1] * b[1*4+1] + a[3*4+2] * b[2*4+1] + a[3*4+3] * b[3*4+1];
342  outputMatrix[3*4+2] = a[3*4+0] * b[0*4+2] + a[3*4+1] * b[1*4+2] + a[3*4+2] * b[2*4+2] + a[3*4+3] * b[3*4+2];
343  outputMatrix[3*4+3] = a[3*4+0] * b[0*4+3] + a[3*4+1] * b[1*4+3] + a[3*4+2] * b[2*4+3] + a[3*4+3] * b[3*4+3];
344 }
345 
349 static inline void VuoTransform_copyMatrix4x4(const float *sourceMatrix, float *destMatrix) __attribute__((nonnull));
350 static inline void VuoTransform_copyMatrix4x4(const float *sourceMatrix, float *destMatrix)
351 {
352  for (int i=0; i<16; ++i)
353  destMatrix[i] = sourceMatrix[i];
354 }
355 
360 static inline VuoPoint3d VuoTransform_getMatrix4x4Translation(const float *matrix) __attribute__((nonnull));
361 static inline VuoPoint3d VuoTransform_getMatrix4x4Translation(const float *matrix)
362 {
363  return (VuoPoint3d){matrix[12], matrix[13], matrix[14]};
364 }
365 
370 static inline VuoPoint3d VuoTransform_getMatrix4x4Scale(const float *matrix) __attribute__((nonnull));
371 static inline VuoPoint3d VuoTransform_getMatrix4x4Scale(const float *matrix)
372 {
373  return (VuoPoint3d){
374  VuoPoint3d_magnitude((VuoPoint3d){matrix[0], matrix[1], matrix[ 2]}),
375  VuoPoint3d_magnitude((VuoPoint3d){matrix[4], matrix[5], matrix[ 6]}),
376  VuoPoint3d_magnitude((VuoPoint3d){matrix[8], matrix[9], matrix[10]})
377  };
378 }
379 
383 static inline void VuoTransform_printMatrix4x4(const float *matrix) __attribute__((nonnull));
384 static inline void VuoTransform_printMatrix4x4(const float *matrix)
385 {
386  for (int i=0; i<4; ++i)
387  fprintf(stderr, "[ %11.6f %11.6f %11.6f %11.6f ]\n",matrix[i+0*4],matrix[i+1*4],matrix[i+2*4],matrix[i+3*4]);
388 }
389 
390 void VuoTransform_invertMatrix4x4(const float *matrix, float *outputInvertedMatrix) __attribute__((nonnull));
391 
398 static inline VuoPoint3d VuoTransform_transformPoint(const float *matrix, VuoPoint3d point) __attribute__((nonnull));
399 static inline VuoPoint3d VuoTransform_transformPoint(const float *matrix, VuoPoint3d point)
400 {
401  return (VuoPoint3d){
402  point.x * matrix[0] + point.y * matrix[4] + point.z * matrix[ 8] + matrix[12],
403  point.x * matrix[1] + point.y * matrix[5] + point.z * matrix[ 9] + matrix[13],
404  point.x * matrix[2] + point.y * matrix[6] + point.z * matrix[10] + matrix[14]
405  };
406 }
407 
408 VuoPoint2d VuoTransform_transform_VuoPoint2d(VuoTransform transform, VuoPoint2d point);
409 VuoPoint3d VuoTransform_transform_VuoPoint3d(VuoTransform transform, VuoPoint3d point);
410 
419 static inline VuoPoint3d VuoTransform_transformVector(const float *matrix, VuoPoint3d point) __attribute__((nonnull));
420 static inline VuoPoint3d VuoTransform_transformVector(const float *matrix, VuoPoint3d point)
421 {
422  return (VuoPoint3d){
423  point.x * matrix[0] + point.y * matrix[4] + point.z * matrix[ 8],
424  point.x * matrix[1] + point.y * matrix[5] + point.z * matrix[ 9],
425  point.x * matrix[2] + point.y * matrix[6] + point.z * matrix[10]
426  };
427 }
428 
429 
430 VuoRectangle VuoTransform_transformRectangle(const float *matrix, VuoRectangle rectangle) __attribute__((nonnull));
431 
433 struct json_object * VuoTransform_getJson(const VuoTransform value);
434 char * VuoTransform_getSummary(const VuoTransform value);
435 
437 
441 char * VuoTransform_getString(const VuoTransform value);
445