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;
384 VuoReal left = rectangle.center.x - rectangle.size.x/2.;
385 VuoReal right = rectangle.center.x + rectangle.size.x/2.;
386 VuoReal bottom = rectangle.center.y - rectangle.size.y/2.;
387 VuoReal top = rectangle.center.y + rectangle.size.y/2.;
394 VuoReal transformedLeft =
MIN(
MIN(
MIN(topLeft.x, topRight.x), bottomLeft.x), bottomRight.x);
395 VuoReal transformedRight =
MAX(
MAX(
MAX(topLeft.x, topRight.x), bottomLeft.x), bottomRight.x);
396 VuoReal transformedBottom =
MIN(
MIN(
MIN(topLeft.y, topRight.y), bottomLeft.y), bottomRight.y);
397 VuoReal transformedTop =
MAX(
MAX(
MAX(topLeft.y, topRight.y), bottomLeft.y), bottomRight.y);
400 (transformedLeft + transformedRight)/2.,
401 (transformedBottom + transformedTop)/2.,
402 transformedRight - transformedLeft,
403 transformedTop - transformedBottom);
405 return transformedRectangle;
413 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)
415 VuoReal combinedScaleFactor = 1;
416 if (preservePhysicalSize)
417 combinedScaleFactor = backingScaleFactor / imageScaleFactor;
421 imageWidth *= combinedScaleFactor;
422 imageHeight *= combinedScaleFactor;
428 if (viewportWidth <= 0)
430 billboardMatrix[0] = 0;
431 billboardMatrix[5] = 0;
432 billboardMatrix[12] = translationX;
433 billboardMatrix[13] = translationY;
438 billboardMatrix[0] = 2. * imageWidth/viewportWidth;
439 billboardMatrix[5] = billboardMatrix[0] * imageHeight/imageWidth;
443 billboardMatrix[12] = floor((translationX+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.;
444 billboardMatrix[13] = floor((translationY+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.;
451 billboardMatrix[12] += (imageWidth % 2 ? (1./viewportWidth) : 0);
454 billboardMatrix[13] -= (imageHeight % 2 ? (1./viewportWidth) : 0);
457 billboardMatrix[13] += (viewportWidth % 2 ? (1./viewportWidth) : 0);
458 billboardMatrix[13] -= (viewportHeight % 2 ? (1./viewportWidth) : 0);
472 float compositeMatrix[16];
485 q.w = sqrt(1 + basis[0].x + basis[1].y + basis[2].z) / 2;
486 q.x = (basis[2].y - basis[1].z) / (4 * q.w);
487 q.y = (basis[0].z - basis[2].x) / (4 * q.w);
488 q.z = (basis[1].x - basis[0].y) / (4 * q.w);
517 if (json_object_object_get_ex(js,
"target", &o))
520 target.x = json_object_get_double(json_object_array_get_idx(o,0));
521 target.y = json_object_get_double(json_object_array_get_idx(o,1));
522 target.z = json_object_get_double(json_object_array_get_idx(o,2));
525 if (json_object_object_get_ex(js,
"translation", &o))
527 position.x = json_object_get_double(json_object_array_get_idx(o,0));
528 position.y = json_object_get_double(json_object_array_get_idx(o,1));
529 position.z = json_object_get_double(json_object_array_get_idx(o,2));
533 if (json_object_object_get_ex(js,
"upDirection", &o))
535 upDirection.x = json_object_get_double(json_object_array_get_idx(o,0));
536 upDirection.y = json_object_get_double(json_object_array_get_idx(o,1));
537 upDirection.z = json_object_get_double(json_object_array_get_idx(o,2));
543 if (json_object_object_get_ex(js,
"quaternionRotation", &o))
545 t.type = VuoTransformTypeQuaternion;
547 q.x = json_object_get_double(json_object_array_get_idx(o,0));
548 q.y = json_object_get_double(json_object_array_get_idx(o,1));
549 q.z = json_object_get_double(json_object_array_get_idx(o,2));
550 q.w = json_object_get_double(json_object_array_get_idx(o,3));
553 else if (json_object_object_get_ex(js,
"eulerRotation", &o))
555 t.type = VuoTransformTypeEuler;
557 e.x = json_object_get_double(json_object_array_get_idx(o,0));
558 e.y = json_object_get_double(json_object_array_get_idx(o,1));
559 e.z = json_object_get_double(json_object_array_get_idx(o,2));
563 if (json_object_object_get_ex(js,
"translation", &o))
565 t.translation.x = json_object_get_double(json_object_array_get_idx(o,0));
566 t.translation.y = json_object_get_double(json_object_array_get_idx(o,1));
567 t.translation.z = json_object_get_double(json_object_array_get_idx(o,2));
570 if (json_object_object_get_ex(js,
"scale", &o))
572 t.scale.x = json_object_get_double(json_object_array_get_idx(o,0));
573 t.scale.y = json_object_get_double(json_object_array_get_idx(o,1));
574 t.scale.z = json_object_get_double(json_object_array_get_idx(o,2));
583 static inline float cook(
float f)
585 if (fabs(f) < FLT_EPSILON)
598 return json_object_new_string(
"identity");
604 json_object_array_add(o,json_object_new_double(
cook(value.translation.x)));
605 json_object_array_add(o,json_object_new_double(
cook(value.translation.y)));
606 json_object_array_add(o,json_object_new_double(
cook(value.translation.z)));
607 json_object_object_add(js,
"translation", o);
612 if (value.type == VuoTransformTypeQuaternion)
615 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.x)));
616 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.y)));
617 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.z)));
618 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.quaternion.w)));
619 json_object_object_add(js,
"quaternionRotation", o);
621 else if (value.type == VuoTransformTypeEuler)
624 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.x)));
625 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.y)));
626 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.euler.z)));
627 json_object_object_add(js,
"eulerRotation", o);
632 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.x)));
633 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.y)));
634 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.target.z)));
635 json_object_object_add(js,
"target", o);
637 o = json_object_new_array();
638 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.x)));
639 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.y)));
640 json_object_array_add(o,json_object_new_double(
cook(value.rotationSource.upDirection.z)));
641 json_object_object_add(js,
"upDirection", o);
644 if (value.type != VuoTransformTypeTargeted)
647 json_object_array_add(o,json_object_new_double(
cook(value.scale.x)));
648 json_object_array_add(o,json_object_new_double(
cook(value.scale.y)));
649 json_object_array_add(o,json_object_new_double(
cook(value.scale.z)));
650 json_object_object_add(js,
"scale", o);
664 return strdup(
"identity transform (no change)");
666 if (value.type == VuoTransformTypeTargeted)
667 return VuoText_format(
"<div>position (%g, %g, %g)</div><div>target (%g, %g, %g)</div><div>up (%g, %g, %g)</div>",
668 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);
671 if (value.type == VuoTransformTypeQuaternion)
673 value.rotationSource.quaternion.x, value.rotationSource.quaternion.y, value.rotationSource.quaternion.z, value.rotationSource.quaternion.w);
681 char *valueAsString =
VuoText_format(
"<div>translation (%g, %g, %g)</div><div>rotation %s</div><div>scale (%g, %g, %g)</div>",
682 value.translation.x, value.translation.y, value.translation.z, rotation, value.scale.x, value.scale.y, value.scale.z);
684 return valueAsString;