Vuo  2.4.0
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
45typedef 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;
64
65void VuoTransform_getMatrix(const VuoTransform value, float *matrix) __attribute__((nonnull));
66void 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));
67VuoPoint3d VuoTransform_getEuler(const VuoTransform transform);
68VuoPoint4d VuoTransform_getQuaternion(const VuoTransform transform);
69VuoPoint3d VuoTransform_getDirection(const VuoTransform transform);
71VuoTransform VuoTransform_makeEuler(VuoPoint3d translation, VuoPoint3d rotation, VuoPoint3d scale);
72VuoTransform VuoTransform_makeQuaternion(VuoPoint3d translation, VuoPoint4d rotation, VuoPoint3d scale);
73void VuoTransform_rotationMatrixFromQuaternion(const VuoPoint4d quaternion, float *matrix) __attribute__((nonnull));
74void VuoTransform_rotationMatrixFromEuler(const VuoPoint3d euler, float *matrix) __attribute__((nonnull));
75
78
79VuoTransform VuoTransform_makeFromTarget(VuoPoint3d position, VuoPoint3d target, VuoPoint3d upDirection);
80VuoTransform VuoTransform_makeFromMatrix4x4(const float *matrix) __attribute__((nonnull));
82
86static inline VuoPoint4d VuoTransform_quaternionComposite(VuoPoint4d a, VuoPoint4d b) __attribute__((const));
87static 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
101static inline VuoPoint4d VuoTransform_quaternionFromAxisAngle(VuoPoint3d axis, float angle) __attribute__((const));
102static 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
113VuoPoint4d VuoTransform_quaternionFromBasis(VuoPoint3d basis[3]);
114
120static inline VuoPoint4d VuoTransform_quaternionFromVectors(VuoPoint3d from, VuoPoint3d to) __attribute__((const));
121static 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
148static inline VuoPoint4d VuoTransform_quaternionFromMatrix(const float *rotation) __attribute__((nonnull));
149static 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
198static inline VuoPoint4d VuoTransform_quaternionFromEuler(const VuoPoint3d euler) __attribute__((const));
199static 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
222static inline VuoPoint3d VuoTransform_eulerFromQuaternion(const VuoPoint4d quaternion) __attribute__((const));
223static 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
251static inline VuoPoint3d VuoTransform_eulerFromMatrix(const float *matrix) __attribute__((nonnull));
252static 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
278static inline VuoPoint3d VuoTransform_rotateVectorWithQuaternion(const VuoPoint3d v, const VuoPoint4d q) __attribute__((const));
279static 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
291static 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
325static inline void VuoTransform_multiplyMatrices4x4(const float *a, const float *b, float *outputMatrix) __attribute__((nonnull));
326static 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
349static inline void VuoTransform_copyMatrix4x4(const float *sourceMatrix, float *destMatrix) __attribute__((nonnull));
350static 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
360static inline VuoPoint3d VuoTransform_getMatrix4x4Translation(const float *matrix) __attribute__((nonnull));
361static inline VuoPoint3d VuoTransform_getMatrix4x4Translation(const float *matrix)
362{
363 return (VuoPoint3d){matrix[12], matrix[13], matrix[14]};
364}
365
370static inline VuoPoint3d VuoTransform_getMatrix4x4Scale(const float *matrix) __attribute__((nonnull));
371static 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
383static inline void VuoTransform_printMatrix4x4(const float *matrix) __attribute__((nonnull));
384static 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
390void VuoTransform_invertMatrix4x4(const float *matrix, float *outputInvertedMatrix) __attribute__((nonnull));
391
398static inline VuoPoint3d VuoTransform_transformPoint(const float *matrix, VuoPoint3d point) __attribute__((nonnull));
399static 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
408VuoPoint2d VuoTransform_transform_VuoPoint2d(VuoTransform transform, VuoPoint2d point);
409VuoPoint3d VuoTransform_transform_VuoPoint3d(VuoTransform transform, VuoPoint3d point);
410
419static inline VuoPoint3d VuoTransform_transformVector(const float *matrix, VuoPoint3d point) __attribute__((nonnull));
420static 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
430VuoRectangle VuoTransform_transformRectangle(const float *matrix, VuoRectangle rectangle) __attribute__((nonnull));
431
433struct json_object * VuoTransform_getJson(const VuoTransform value);
434char * VuoTransform_getSummary(const VuoTransform value);
435
437
445