17 "title" :
"3D Transform",
18 "description" :
"A 3D transformation (scale, rotation, translation).",
39 matrix[ 0] = value.
rotation[0] * value.scale.x;
40 matrix[ 1] = value.
rotation[1] * value.scale.x;
41 matrix[ 2] = value.
rotation[2] * value.scale.x;
44 matrix[ 4] = value.
rotation[3] * value.scale.y;
45 matrix[ 5] = value.
rotation[4] * value.scale.y;
46 matrix[ 6] = value.
rotation[5] * value.scale.y;
49 matrix[ 8] = value.
rotation[6] * value.scale.z;
50 matrix[ 9] = value.
rotation[7] * value.scale.z;
51 matrix[10] = value.
rotation[8] * value.scale.z;
54 matrix[12] = value.translation.x;
55 matrix[13] = value.translation.y;
56 matrix[14] = value.translation.z;
68 float inverseTranslation[16];
76 float inverseRotation[16] = {
99 VuoPoint3d inverseScale = (VuoPoint3d){
104 if (isnan(inverseScale.x) || isinf(inverseScale.x))
106 if (isnan(inverseScale.y) || isinf(inverseScale.y))
108 if (isnan(inverseScale.z) || isinf(inverseScale.z))
111 float inverseScaleMatrix[16];
132 if (transform.type == VuoTransformTypeEuler)
133 return transform.rotationSource.euler;
143 if (transform.type == VuoTransformTypeQuaternion)
144 return transform.rotationSource.quaternion;
159 if (transform.type == VuoTransformTypeEuler)
177 t.type = VuoTransformTypeEuler;
179 t.translation = (VuoPoint3d){0,0,0};
181 t.rotationSource.euler = (VuoPoint3d){0,0,0};
192 t.scale = (VuoPoint3d){1,1,1};
204 t.type = VuoTransformTypeEuler;
205 t.translation = translation;
206 t.rotationSource.euler = rotation;
218 matrix[0] = 1. - 2. * (quaternion.y * quaternion.y + quaternion.z * quaternion.z);
219 matrix[1] = 2. * (quaternion.x * quaternion.y + quaternion.w * quaternion.z);
220 matrix[2] = 2. * (quaternion.x * quaternion.z - quaternion.w * quaternion.y);
221 matrix[3] = 2. * (quaternion.x * quaternion.y - quaternion.w * quaternion.z);
222 matrix[4] = 1. - 2. * (quaternion.x * quaternion.x + quaternion.z * quaternion.z);
223 matrix[5] = 2. * (quaternion.y * quaternion.z + quaternion.w * quaternion.x);
224 matrix[6] = 2. * (quaternion.x * quaternion.z + quaternion.w * quaternion.y);
225 matrix[7] = 2. * (quaternion.y * quaternion.z - quaternion.w * quaternion.x);
226 matrix[8] = 1. - 2. * (quaternion.x * quaternion.x + quaternion.y * quaternion.y);
234 matrix[0] = cos(euler.y)*cos(euler.z);
235 matrix[1] = cos(euler.y)*sin(euler.z);
236 matrix[2] = -sin(euler.y);
237 matrix[3] = cos(euler.z)*sin(euler.x)*sin(euler.y) - cos(euler.x)*sin(euler.z);
238 matrix[4] = cos(euler.x)*cos(euler.z) + sin(euler.x)*sin(euler.y)*sin(euler.z);
239 matrix[5] = cos(euler.y)*sin(euler.x);
240 matrix[6] = cos(euler.x)*cos(euler.z)*sin(euler.y) + sin(euler.x)*sin(euler.z);
241 matrix[7] = -cos(euler.z)*sin(euler.x) + cos(euler.x)*sin(euler.y)*sin(euler.z);
242 matrix[8] = cos(euler.x)*cos(euler.y);
255 t.type = VuoTransformTypeQuaternion;
257 t.translation = translation;
261 t.rotationSource.quaternion = q;
275 VuoPoint3d center3d =
VuoPoint3d_make(transform2d.translation.x, transform2d.translation.y, 0);
277 VuoPoint3d scale3d =
VuoPoint3d_make(transform2d.scale.x, transform2d.scale.y, 1);
287 t.translation = (VuoPoint2d){transform.translation.x, transform.translation.y};
289 t.scale = (VuoPoint2d){transform.scale.x, transform.scale.y};
306 t.type = VuoTransformTypeTargeted;
308 t.translation = position;
310 t.rotationSource.target = target;
311 t.rotationSource.upDirection = upDirection;
336 t.
rotation[0] = matrix[ 0] / t.scale.x;
337 t.
rotation[1] = matrix[ 1] / t.scale.x;
338 t.
rotation[2] = matrix[ 2] / t.scale.x;
340 t.
rotation[3] = matrix[ 4] / t.scale.y;
341 t.
rotation[4] = matrix[ 5] / t.scale.y;
342 t.
rotation[5] = matrix[ 6] / t.scale.y;
344 t.
rotation[6] = matrix[ 8] / t.scale.z;
345 t.
rotation[7] = matrix[ 9] / t.scale.z;
346 t.
rotation[8] = matrix[10] / t.scale.z;
348 t.type = VuoTransformTypeQuaternion;
366 VuoReal left = rectangle.center.x - rectangle.size.x/2.;
367 VuoReal right = rectangle.center.x + rectangle.size.x/2.;
368 VuoReal bottom = rectangle.center.y - rectangle.size.y/2.;
369 VuoReal top = rectangle.center.y + rectangle.size.y/2.;
376 VuoReal transformedLeft =
MIN(
MIN(
MIN(topLeft.x, topRight.x), bottomLeft.x), bottomRight.x);
377 VuoReal transformedRight =
MAX(
MAX(
MAX(topLeft.x, topRight.x), bottomLeft.x), bottomRight.x);
378 VuoReal transformedBottom =
MIN(
MIN(
MIN(topLeft.y, topRight.y), bottomLeft.y), bottomRight.y);
379 VuoReal transformedTop =
MAX(
MAX(
MAX(topLeft.y, topRight.y), bottomLeft.y), bottomRight.y);
382 (transformedLeft + transformedRight)/2.,
383 (transformedBottom + transformedTop)/2.,
384 transformedRight - transformedLeft,
385 transformedTop - transformedBottom);
387 return transformedRectangle;
395 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)
397 VuoReal combinedScaleFactor = 1;
398 if (preservePhysicalSize)
399 combinedScaleFactor = backingScaleFactor / imageScaleFactor;
403 imageWidth *= combinedScaleFactor;
404 imageHeight *= combinedScaleFactor;
410 if (viewportWidth <= 0)
412 billboardMatrix[0] = 0;
413 billboardMatrix[5] = 0;
414 billboardMatrix[12] = translationX;
415 billboardMatrix[13] = translationY;
420 billboardMatrix[0] = 2. * imageWidth/viewportWidth;
421 billboardMatrix[5] = billboardMatrix[0] * imageHeight/imageWidth;
425 billboardMatrix[12] = floor((translationX+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.;
426 billboardMatrix[13] = floor((translationY+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.;
433 billboardMatrix[12] += (imageWidth % 2 ? (1./viewportWidth) : 0);
436 billboardMatrix[13] -= (imageHeight % 2 ? (1./viewportWidth) : 0);
439 billboardMatrix[13] += (viewportWidth % 2 ? (1./viewportWidth) : 0);
440 billboardMatrix[13] -= (viewportHeight % 2 ? (1./viewportWidth) : 0);
454 float compositeMatrix[16];
467 q.w = sqrt(1 + basis[0].x + basis[1].y + basis[2].z) / 2;
468 q.x = (basis[2].y - basis[1].z) / (4 * q.w);
469 q.y = (basis[0].z - basis[2].x) / (4 * q.w);
470 q.z = (basis[1].x - basis[0].y) / (4 * q.w);
499 if (json_object_object_get_ex(js,
"target", &o))
502 target.x = json_object_get_double(json_object_array_get_idx(o,0));
503 target.y = json_object_get_double(json_object_array_get_idx(o,1));
504 target.z = json_object_get_double(json_object_array_get_idx(o,2));
507 if (json_object_object_get_ex(js,
"translation", &o))
509 position.x = json_object_get_double(json_object_array_get_idx(o,0));
510 position.y = json_object_get_double(json_object_array_get_idx(o,1));
511 position.z = json_object_get_double(json_object_array_get_idx(o,2));
515 if (json_object_object_get_ex(js,
"upDirection", &o))
517 upDirection.x = json_object_get_double(json_object_array_get_idx(o,0));
518 upDirection.y = json_object_get_double(json_object_array_get_idx(o,1));
519 upDirection.z = json_object_get_double(json_object_array_get_idx(o,2));
525 if (json_object_object_get_ex(js,
"quaternionRotation", &o))
527 t.type = VuoTransformTypeQuaternion;
529 q.x = json_object_get_double(json_object_array_get_idx(o,0));
530 q.y = json_object_get_double(json_object_array_get_idx(o,1));
531 q.z = json_object_get_double(json_object_array_get_idx(o,2));
532 q.w = json_object_get_double(json_object_array_get_idx(o,3));
535 else if (json_object_object_get_ex(js,
"eulerRotation", &o))
537 t.type = VuoTransformTypeEuler;
539 e.x = json_object_get_double(json_object_array_get_idx(o,0));
540 e.y = json_object_get_double(json_object_array_get_idx(o,1));
541 e.z = json_object_get_double(json_object_array_get_idx(o,2));
545 if (json_object_object_get_ex(js,
"translation", &o))
547 t.translation.x = json_object_get_double(json_object_array_get_idx(o,0));
548 t.translation.y = json_object_get_double(json_object_array_get_idx(o,1));
549 t.translation.z = json_object_get_double(json_object_array_get_idx(o,2));
552 if (json_object_object_get_ex(js,
"scale", &o))
554 t.scale.x = json_object_get_double(json_object_array_get_idx(o,0));
555 t.scale.y = json_object_get_double(json_object_array_get_idx(o,1));
556 t.scale.z = json_object_get_double(json_object_array_get_idx(o,2));
565 static inline float cook(
float f)
567 if (fabs(f) < FLT_EPSILON)
580 return json_object_new_string(
"identity");
586 json_object_array_add(o,json_object_new_double(
cook(value.translation.x)));
587 json_object_array_add(o,json_object_new_double(
cook(value.translation.y)));
588 json_object_array_add(o,json_object_new_double(
cook(value.translation.z)));
589 json_object_object_add(js,
"translation", o);
594 if (value.type == VuoTransformTypeQuaternion)
597 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.x)));
598 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.y)));
599 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.z)));
600 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.w)));
601 json_object_object_add(js,
"quaternionRotation", o);
603 else if (value.type == VuoTransformTypeEuler)
606 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.x)));
607 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.y)));
608 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.z)));
609 json_object_object_add(js,
"eulerRotation", o);
614 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.x)));
615 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.y)));
616 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.z)));
617 json_object_object_add(js,
"target", o);
619 o = json_object_new_array();
620 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.x)));
621 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.y)));
622 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.z)));
623 json_object_object_add(js,
"upDirection", o);
626 if (value.type != VuoTransformTypeTargeted)
629 json_object_array_add(o,json_object_new_double(
cook(value.scale.x)));
630 json_object_array_add(o,json_object_new_double(
cook(value.scale.y)));
631 json_object_array_add(o,json_object_new_double(
cook(value.scale.z)));
632 json_object_object_add(js,
"scale", o);
646 return strdup(
"identity transform (no change)");
648 if (value.type == VuoTransformTypeTargeted)
649 return VuoText_format(
"<div>position (%g, %g, %g)</div><div>target (%g, %g, %g)</div><div>up (%g, %g, %g)</div>",
650 value.translation.x, value.translation.y, value.translation.z, value.rotationSource.target.x, value.rotationSource.target.y, value.rotationSource.target.z, value.rotationSource.upDirection.x, value.rotationSource.upDirection.y, value.rotationSource.upDirection.z);
653 if (value.type == VuoTransformTypeQuaternion)
655 value.rotationSource.quaternion.x, value.rotationSource.quaternion.y, value.rotationSource.quaternion.z, value.rotationSource.quaternion.w);
663 char *valueAsString =
VuoText_format(
"<div>translation (%g, %g, %g)</div><div>rotation %s</div><div>scale (%g, %g, %g)</div>",
664 value.translation.x, value.translation.y, value.translation.z, rotation, value.scale.x, value.scale.y, value.scale.z);
666 return valueAsString;