solstice-anim

Geometry animation library of the solstice app
git clone git://git.meso-star.com/solstice-anim.git
Log | Files | Refs | README | LICENSE

commit 3a6af45ede4a8048a565463423357acacbd5642a
parent 41207c9e88332cf99dbeb5d5d8b4b87207351f42
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 24 Oct 2016 18:28:45 +0200

Add 2 axis pivots ans some more tests (both 1 and 2 axis)

Not ready to use anyway, as convergence needs to be improved

Diffstat:
Msrc/sanim_node.c | 434+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/test_sanim_node_pivot.c | 398++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/test_sanim_node_transform.c | 1+
3 files changed, 637 insertions(+), 196 deletions(-)

diff --git a/src/sanim_node.c b/src/sanim_node.c @@ -20,6 +20,7 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/double33.h> +#include <rsys/double2.h> #include <math.h> @@ -64,20 +65,32 @@ d34_set_identity(double dst[12]) { } static double* -set_Xpivot_transform +get_Xpivot_transform (const double angle, const double spacing, double transform[12]) { - double offset[3]; ASSERT(transform); d33_rotation_pitch(transform, angle); - d3_set(transform + 9, d3(offset, 0, spacing, 0)); + d3(transform + 9, 0, spacing, 0); return transform; } static double* -set_Zpivot_transform(const double angle, double transform[12]) { +compose_Xpivot_transform + (const double angle, + const double spacing, + double accum[12]) +{ + double pivot[12]; + ASSERT(accum); + get_Xpivot_transform(angle, spacing, pivot); + d34_muld34(accum, pivot, accum); + return accum; +} + +static double* +get_Zpivot_transform(const double angle, double transform[12]) { ASSERT(transform); d33_rotation_roll(transform, angle); d3_splat(transform + 9, 0); @@ -85,20 +98,71 @@ set_Zpivot_transform(const double angle, double transform[12]) { } static double* -set_pivot_transform(const struct pivot_data* pivot, double transform[12]) { - double tmp[12]; +compose_Zpivot_transform(const double angle, double accum[12]) { + double pivot[12]; + ASSERT(accum); + get_Zpivot_transform(angle, pivot); + d34_muld34(accum, pivot, accum); + return accum; +} + +static double* +get_ZXpivot_transform + (const double angleZ, + const double angleX, + const double spacing, + double transform[12]) +{ + ASSERT(transform); + get_Xpivot_transform(angleX, spacing, transform); + compose_Zpivot_transform(angleZ, transform); + return transform; +} + +static double* +compose_ZXpivot_transform + (const double angleZ, + const double angleX, + const double spacing, + double accum[12]) +{ + ASSERT(accum); + compose_Xpivot_transform(angleX, spacing, accum); + compose_Zpivot_transform(angleZ, accum); + return accum; +} + +static double* +compose_pivot_transform(const struct pivot_data* pivot, double accum[12]) { + ASSERT(pivot && accum); + switch (pivot->pivot.type) { + case PIVOT_SINGLE_AXIS: { + ASSERT(pivot->angleZ == 0); + compose_Xpivot_transform(pivot->angleX, 0, accum); + break; + } + case PIVOT_TWO_AXIS: { + compose_ZXpivot_transform( + pivot->angleZ, pivot->angleX, pivot->pivot.data.pivot2.spacing, accum); + break; + } + default: FATAL("Unreachable code.\n"); break; + } + return accum; +} + +static double* +get_pivot_transform(const struct pivot_data* pivot, double transform[12]) { ASSERT(pivot && transform); switch (pivot->pivot.type) { case PIVOT_SINGLE_AXIS: { ASSERT(pivot->angleZ == 0); - set_Xpivot_transform(pivot->angleX, 0, transform); + get_Xpivot_transform(pivot->angleX, 0, transform); break; } case PIVOT_TWO_AXIS: { - set_Xpivot_transform( - pivot->angleX, pivot->pivot.data.pivot2.spacing, transform); - set_Zpivot_transform(pivot->angleZ, tmp); - d34_muld34(transform, tmp, transform); + get_ZXpivot_transform( + pivot->angleZ, pivot->angleX, pivot->pivot.data.pivot2.spacing, transform); break; } default: FATAL("Unreachable code.\n"); break; @@ -107,18 +171,18 @@ set_pivot_transform(const struct pivot_data* pivot, double transform[12]) { } static double* -set_node_transform +node_get_own_transform (struct sanim_node* node, - const char include_pivot, + const int include_pivot, double transform[12]) { - double tmp[12]; ASSERT(node && node->data && transform); if (include_pivot && node->data->pivot_data) { - set_pivot_transform(node->data->pivot_data, transform); - d33_rotation(tmp, SPLIT3(node->data->rotations)); - d3_set(tmp + 9, node->data->translation); - d34_muld34(transform, tmp, transform); + double local[12]; + get_pivot_transform(node->data->pivot_data, transform); + d33_rotation(local, SPLIT3(node->data->rotations)); + d3_set(local + 9, node->data->translation); + d34_muld34(transform, local, transform); } else { d33_rotation(transform, SPLIT3(node->data->rotations)); @@ -128,50 +192,48 @@ set_node_transform } static double* -compose_node_transform(struct sanim_node* node, double transform[12]) { - double tmp[12]; - ASSERT(node && node->data && transform); +compose_node_transform(struct sanim_node* node, double accum[12]) { + double local[12]; + ASSERT(node && node->data && accum); if (node->data->pivot_data) { - set_pivot_transform(node->data->pivot_data, tmp); - d34_muld34(transform, tmp, transform); + compose_pivot_transform(node->data->pivot_data, accum); } - d33_rotation(tmp, SPLIT3(node->data->rotations)); - d3_set(tmp + 9, node->data->translation); - d34_muld34(transform, tmp, transform); - return transform; + d33_rotation(local, SPLIT3(node->data->rotations)); + d3_set(local + 9, node->data->translation); + d34_muld34(accum, local, accum); + return accum; } static void node_get_transform (struct sanim_node* node, - const char include_own_pivot, + const int include_own_pivot, double transform[12]) { - struct sanim_node* ptr; + struct sanim_node* father; ASSERT(node && node->data && transform); - set_node_transform(node, include_own_pivot, transform); - ptr = node->data->father; - while (ptr) { - compose_node_transform(ptr, transform); - ptr = ptr->data->father; + father = node->data->father; + node_get_own_transform(node, include_own_pivot, transform); + while (father) { + compose_node_transform(father, transform); + father = father->data->father; } } static void compute_single_axis_angle - (const double ref_normal[3], - const double rotated_n[3], + (const double ref_2D[2], + const double rotated_2D[2], double* angle ) { - ASSERT(ref_normal && rotated_n && angle); - ASSERT(d3_is_normalized(rotated_n)); - ASSERT(d3_is_normalized(ref_normal)); - /* normals should be in the YZ plane */ - ASSERT(ref_normal[0] == 0); - ASSERT(rotated_n[0] == 0); - *angle = - atan2(-(ref_normal[2] * rotated_n[1] - ref_normal[1] * rotated_n[2]), - ref_normal[1] * rotated_n[1] + ref_normal[2] * rotated_n[2]); + double x, y; + ASSERT(ref_2D && rotated_2D && angle); + ASSERT(d2_is_normalized(rotated_2D)); + ASSERT(d2_is_normalized(ref_2D)); + /* in the YZ plane */ + y = d2_cross(ref_2D, rotated_2D); + x = d2_dot(ref_2D, rotated_2D); + *angle = atan2(y, x); } static res_T @@ -180,16 +242,19 @@ pivot_solve_single_axis_sun const double in_dir[3]) { double mat[12], inv[12]; - double local_in[3], rotated_n[3]; - const double* ref_normal; - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_SINGLE_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_SUN); + double local_in[3]; + double local_in_2D[2], rotated_n_2D[2]; + const double* ref_normal_2D; + struct pivot_data* pivot_data; + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_SINGLE_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_SUN); ASSERT(d3_is_normalized(in_dir)); - ref_normal = node->data->pivot_data->pivot.data.pivot1.ref_normal; - ASSERT(d3_is_normalized(ref_normal)); + ref_normal_2D = pivot_data->pivot.data.pivot1.ref_normal + 1; + ASSERT(d2_is_normalized(ref_normal_2D)); /* get in_dir in local space */ node_get_transform(node, 0, mat); @@ -197,17 +262,15 @@ pivot_solve_single_axis_sun d33_muld3(local_in, inv, in_dir); /* solve in the YZ plane */ - local_in[0] = 0; - if (d3_normalize(local_in, local_in) < 0.25) { + if (d2_normalize(local_in_2D, local_in + 1) < 0.25) { /* not really in the YZ-plane */ return RES_BAD_ARG; } /* rotated_n = -local_in */ - d3_muld(rotated_n, local_in, -1); + d2_muld(rotated_n_2D, local_in_2D, -1); - compute_single_axis_angle( - ref_normal, rotated_n, &node->data->pivot_data->angleX); + compute_single_axis_angle(ref_normal_2D, rotated_n_2D, &pivot_data->angleX); return RES_OK; } @@ -217,90 +280,83 @@ pivot_solve_single_axis_line const double in_dir[3]) { double mat[12], inv[9]; - double local_in[3], rotated_n[3], local_out[3], local_target[3], ref_point[3]; - const double* ref_normal; + double local_in[3], local_target[3], ref_point[3]; + double rotated_n_2D[2], local_out_2D[2], local_in_2D[2]; + const double* ref_normal_2D; + struct pivot_data* pivot_data; double angle, previous_angle, delta; - double c1, c2; + double d1, d2; int cpt = 0; - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_SINGLE_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_POINT); + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_SINGLE_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_POINT); ASSERT(d3_is_normalized(in_dir)); - ref_normal = node->data->pivot_data->pivot.data.pivot1.ref_normal; - ASSERT(d3_is_normalized(ref_normal)); - d3_set(ref_point, node->data->pivot_data->pivot.data.pivot1.ref_point); + ref_normal_2D = pivot_data->pivot.data.pivot1.ref_normal + 1; + ASSERT(pivot_data->pivot.data.pivot1.ref_normal[0] == 0); /* solve in YZ plane */ + ASSERT(d2_is_normalized(ref_normal_2D)); + d3_set(ref_point, pivot_data->pivot.data.pivot1.ref_point); /* get in_dir in local space */ node_get_transform(node, 0, mat); d33_transpose(inv, mat); /* no scale factors: inverse is transpose */ d33_muld3(local_in, inv, in_dir); + /* solve in the YZ plane */ + if (d2_normalize(local_in_2D, local_in + 1) < 0.25) { + /* not really in the YZ-plane */ + return RES_BAD_ARG; + } /* get target point in local space */ - if (node->data->pivot_data->tracking.data.point.target_is_local) { - d3_set(local_target, node->data->pivot_data->tracking.data.point.target); + if (pivot_data->tracking.data.point.target_is_local) { + d3_set(local_target, pivot_data->tracking.data.point.target); } else { - d3_sub(local_target, node->data->pivot_data->tracking.data.point.target, mat + 9); + d3_sub(local_target, pivot_data->tracking.data.point.target, mat + 9); d33_muld3(local_target, inv, local_target); } /* check if in, target_point and ref_point are compatible */ - c1 = local_target[1] * local_target[1] + local_target[2] * local_target[2]; - c2 = ref_point[1] * ref_point[1] + ref_point[2] * ref_point[2]; - if (c1 <= c2) { - /* target in the pivot*/ + d1 = d2_dot(local_target + 1, local_target + 1); /* in the YZ plane */ + d2 = d2_dot(ref_point + 1, ref_point + 1); + if (d1 <= d2) { + /* target in the pivot */ return RES_BAD_ARG; } - else { - double a, b, c; - a = local_in[1] * local_in[1] + local_in[2] * local_in[2]; - b = -2 * (local_in[1] * local_target[1] + local_in[2] * local_target[2]); - c = c1 - c2; - if (b * b - 4 * a * c >= 0) { - /* no possible reflexion to the target */ - return RES_BAD_ARG; - } - } angle = 0; do { double pivot[12]; - /* compute rotated_n */ - d3_sub(local_out, local_target, ref_point); - - /* solve in the YZ plane */ - local_in[0] = 0; - if (d3_normalize(local_in, local_in) < 0.25) { - /* not really in the YZ-plane */ - return RES_BAD_ARG; - } - local_out[0] = 0; - if (d3_normalize(local_out, local_out) < 0.25) { + /* compute 2D normal after rotation */ + d2_sub(local_out_2D, local_target + 1, ref_point + 1); + if (d2_normalize(local_out_2D, local_out_2D) < 0.25) { /* not really in the YZ-plane */ return RES_BAD_ARG; } /* rotated_n = bisectrix of local_in and out_dir */ - d3_sub(rotated_n, local_out, local_in); - if (d3_normalize(rotated_n, rotated_n) < 1e-4) { + d2_sub(rotated_n_2D, local_out_2D, local_in_2D); + if (d2_normalize(rotated_n_2D, rotated_n_2D) < 1e-4) { /* tangent rays */ return RES_BAD_ARG; } - ASSERT(rotated_n[0] == 0); previous_angle = angle; - compute_single_axis_angle(ref_normal, rotated_n, &angle); - delta = fabs(previous_angle - angle); - if (delta < 1e-10 || ++cpt == 25) break; - set_Xpivot_transform(angle, 0, pivot); + compute_single_axis_angle(ref_normal_2D, rotated_n_2D, &angle); + + delta = previous_angle - angle; + if (fabs(delta) < 1e-10 || ++cpt == 100) + break; + + get_Xpivot_transform(angle, 0, pivot); /* update ref_point */ - d33_muld3(ref_point, pivot, node->data->pivot_data->pivot.data.pivot1.ref_point); + d33_muld3(ref_point, pivot, pivot_data->pivot.data.pivot1.ref_point); /* no d3_add(ref_point, ref_point, pivot + 9) as pivot has no offset to add */ } while (1); - - node->data->pivot_data->angleX = angle; + + pivot_data->angleX = angle; return RES_OK; } @@ -310,53 +366,46 @@ pivot_solve_single_axis_dir const double in_dir[3]) { double mat[12], inv[12]; - double local_in[3], rotated_n[3], local_out[3]; - const double* ref_normal; - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_SINGLE_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_OUT_DIR); + double local_in[3], local_out[3]; + double local_in_2D[2], rotated_n_2D[2], local_out_2D[2]; + const double* ref_normal_2D; + struct pivot_data* pivot_data; + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_SINGLE_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_OUT_DIR); ASSERT(d3_is_normalized(in_dir)); - ASSERT(d3_is_normalized(node->data->pivot_data->tracking.data.out_dir.u)); - - - ref_normal = node->data->pivot_data->pivot.data.pivot1.ref_normal; - ASSERT(d3_is_normalized(ref_normal)); - - /* check if in and out directions are compatible */ - if (d3_dot(in_dir, ref_normal) >= 0) { - /* no possible reflexion to the target */ - return RES_BAD_ARG; - } + ASSERT(d3_is_normalized(pivot_data->tracking.data.out_dir.u)); + ref_normal_2D = pivot_data->pivot.data.pivot1.ref_normal + 1; + ASSERT(pivot_data->pivot.data.pivot1.ref_normal[0] == 0); /* solve in YZ plane */ + ASSERT(d2_is_normalized(ref_normal_2D)); + /* get in_dir and out_dir in local space */ node_get_transform(node, 0, mat); d33_transpose(inv, mat); /* no scale factors: inverse is transpose */ d33_muld3(local_in, inv, in_dir); - d33_muld3(local_out, inv, node->data->pivot_data->tracking.data.out_dir.u); + d33_muld3(local_out, inv, pivot_data->tracking.data.out_dir.u); /* solve in the YZ plane */ - local_in[0] = 0; - if (d3_normalize(local_in, local_in) < 0.25) { + if (d2_normalize(local_in_2D, local_in + 1) < 0.25) { /* not really in the YZ-plane */ return RES_BAD_ARG; } - local_out[0] = 0; - if (d3_normalize(local_out, local_out) < 0.25) { + if (d2_normalize(local_out_2D, local_out + 1) < 0.25) { /* not really in the YZ-plane */ return RES_BAD_ARG; } /* rotated_n = bisectrix of local_in and out_dir */ - d3_sub(rotated_n, local_out, local_in); - if (d3_normalize(rotated_n, rotated_n) < 1e-4) { + d2_sub(rotated_n_2D, local_out_2D, local_in_2D); + if (d2_normalize(rotated_n_2D, rotated_n_2D) < 1e-4) { /* tangent rays */ return RES_BAD_ARG; } - ASSERT(rotated_n[0] == 0); - compute_single_axis_angle( - ref_normal, rotated_n, &node->data->pivot_data->angleX); + compute_single_axis_angle(ref_normal_2D, rotated_n_2D, &pivot_data->angleX); return RES_OK; } @@ -393,24 +442,16 @@ compute_two_axis_angles double* angleX, double* angleZ) { - double _cosX, sinZ, cosZ; /* ref normal is <0,1,0> */ ASSERT(rotated_n && angleX && angleZ); ASSERT(d3_is_normalized(rotated_n)); - if (fabs(rotated_n[2]) >= 0.9999) { + if (fabs(rotated_n[2]) >= 1) { *angleX = 0.5 * sign(rotated_n[2]) * PI; *angleZ = 0; return; } - *angleX = -asin(rotated_n[2]); - _cosX = 1 / cos(*angleX); - sinZ = rotated_n[0] * _cosX; - cosZ = rotated_n[1] * _cosX; - if (fabs(cosZ) >= 0.9999) { - *angleZ = cosZ > 0 ? 0 : PI; - return; - } - *angleZ = sinZ > 0 ? acos(cosZ) : 2 * PI - acos(cosZ); + *angleX = asin(rotated_n[2]); + *angleZ = atan2(-rotated_n[0], rotated_n[1]); } FINLINE res_T @@ -420,10 +461,12 @@ pivot_solve_two_axis_sun { double mat[12], inv[12]; double local_in[3], rotated_n[3]; - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_TWO_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_SUN); + struct pivot_data* pivot_data; + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_TWO_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_SUN); ASSERT(d3_is_normalized(in_dir)); /* get in_dir in local space */ @@ -435,8 +478,7 @@ pivot_solve_two_axis_sun /* rotated_n = -local_in */ d3_muld(rotated_n, local_in, -1); - compute_two_axis_angles( - rotated_n, &node->data->pivot_data->angleX, &node->data->pivot_data->angleZ); + compute_two_axis_angles(rotated_n, &pivot_data->angleX, &pivot_data->angleZ); return RES_OK; } @@ -445,11 +487,73 @@ pivot_solve_two_axis_point (struct sanim_node* node, const double in_dir[3]) { - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_TWO_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_POINT); + double mat[12], inv[9]; + double local_in[3], rotated_n[3], local_out[3], local_target[3], ref_point[3]; + double angleX, angleZ, previous_angleX, previous_angleZ, delta; + struct pivot_data* pivot_data; + int cpt = 0; + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_TWO_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_POINT); + ASSERT(d3_is_normalized(in_dir)); + + d3_set(ref_point, pivot_data->pivot.data.pivot2.ref_point); + ref_point[1] += pivot_data->pivot.data.pivot2.spacing; + + /* get in_dir in local space */ + node_get_transform(node, 0, mat); + d33_transpose(inv, mat); /* no scale factors: inverse is transpose */ + d33_muld3(local_in, inv, in_dir); + ASSERT(d3_is_normalized(local_in)); + /* get target point in local space */ + if (pivot_data->tracking.data.point.target_is_local) { + d3_set(local_target, pivot_data->tracking.data.point.target); + } + else { + d3_sub(local_target, pivot_data->tracking.data.point.target, mat + 9); + d33_muld3(local_target, inv, local_target); + } + + /* check if in, target_point and ref_point are compatible */ + if (d3_dot(local_target, local_target) <= d3_dot(ref_point, ref_point)) { + /* target in the pivot */ + return RES_BAD_ARG; + } + + angleX = angleZ = 0; + do { + double pivot[12]; + /* compute rotated_n */ + d3_sub(local_out, local_target, ref_point); + d3_normalize(local_out, local_out); + + /* rotated_n = bisectrix of local_in and out_dir */ + d3_sub(rotated_n, local_out, local_in); + if (d3_normalize(rotated_n, rotated_n) < 1e-4) { + /* tangent rays */ + return RES_BAD_ARG; + } + + previous_angleX = angleX; + previous_angleZ = angleZ; + compute_two_axis_angles(rotated_n, &angleX, &angleZ); + + delta = MMAX(fabs(previous_angleX - angleX), fabs(previous_angleZ - angleZ)); + if (delta < 1e-10 || ++cpt == 100) + break; + + get_ZXpivot_transform( + angleZ, angleX, pivot_data->pivot.data.pivot2.spacing, pivot); + /* update ref_point */ + d33_muld3(ref_point, pivot, pivot_data->pivot.data.pivot2.ref_point); + d3_add(ref_point, ref_point, pivot + 9); + } while (1); + + pivot_data->angleX = angleX; + pivot_data->angleZ = angleZ; return RES_OK; } @@ -460,18 +564,20 @@ pivot_solve_two_axis_dir { double mat[12], inv[12]; double local_in[3], rotated_n[3], local_out[3]; - ASSERT(node && in_dir); - ASSERT(node->data->pivot_data); - ASSERT(node->data->pivot_data->pivot.type == PIVOT_TWO_AXIS); - ASSERT(node->data->pivot_data->tracking.policy == TRACKING_OUT_DIR); + struct pivot_data* pivot_data; + ASSERT(node && node->data && in_dir); + pivot_data = node->data->pivot_data; + ASSERT(pivot_data); + ASSERT(pivot_data->pivot.type == PIVOT_TWO_AXIS); + ASSERT(pivot_data->tracking.policy == TRACKING_OUT_DIR); ASSERT(d3_is_normalized(in_dir)); - ASSERT(d3_is_normalized(node->data->pivot_data->tracking.data.out_dir.u)); + ASSERT(d3_is_normalized(pivot_data->tracking.data.out_dir.u)); /* get in_dir and out_dir in local space */ node_get_transform(node, 0, mat); d33_transpose(inv, mat); /* no scale factors: inverse is transpose */ d33_muld3(local_in, inv, in_dir); - d33_muld3(local_out, inv, node->data->pivot_data->tracking.data.out_dir.u); + d33_muld3(local_out, inv, pivot_data->tracking.data.out_dir.u); /* rotated_n = bisectrix of local_in and out_dir */ d3_sub(rotated_n, local_out, local_in); @@ -480,8 +586,7 @@ pivot_solve_two_axis_dir return RES_BAD_ARG; } - compute_two_axis_angles( - rotated_n, &node->data->pivot_data->angleX, &node->data->pivot_data->angleZ); + compute_two_axis_angles(rotated_n, &pivot_data->angleX, &pivot_data->angleZ); return RES_OK; } @@ -527,6 +632,8 @@ copy_and_normalise_pivot_data d3_set(dest->pivot.data.pivot1.ref_point, pivot->data.pivot1.ref_point); break; case PIVOT_TWO_AXIS: + if (pivot->data.pivot2.spacing < 0) + return RES_BAD_ARG; d3_set(dest->pivot.data.pivot2.ref_point, pivot->data.pivot2.ref_point); dest->pivot.data.pivot2.spacing = pivot->data.pivot2.spacing; break; @@ -656,11 +763,10 @@ sanim_node_solve_pivot return pivot_solve_single_axis(node, dir); break; case PIVOT_TWO_AXIS: - pivot_solve_two_axis(node, dir); + return pivot_solve_two_axis(node, dir); break; default: FATAL("Unreachable code.\n"); break; } - return RES_OK; } res_T diff --git a/src/test_sanim_node_pivot.c b/src/test_sanim_node_pivot.c @@ -23,35 +23,41 @@ main(int argc, char** argv) { struct mem_allocator allocator; struct my_type t1, t2, t3; - struct sanim_pivot pivot1; + struct sanim_pivot pivot; struct sanim_tracking tracking; double transform[12]; double transl[3], rot[3], in_dir[3], n[3], tmp[3]; + const double y_ref_normal[3] = { 0, 1, 0 }; (void) argc, (void) argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(my_type_init_pivot(&allocator, NULL, &tracking, &t1), RES_BAD_ARG); - CHECK(my_type_init_pivot(&allocator, &pivot1, NULL, &t1), RES_BAD_ARG); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, NULL), RES_BAD_ARG); + CHECK(my_type_init_pivot(&allocator, &pivot, NULL, &t1), RES_BAD_ARG); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, NULL), RES_BAD_ARG); + + /* + * 1 axis pivots + * (in/out dirs can be off the YZ plane) + */ /* 1 axis tracking sun */ tracking.policy = TRACKING_SUN; - pivot1.type = PIVOT_SINGLE_AXIS; - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); /* ref_normal not in the YZ plane */ - d3(pivot1.data.pivot1.ref_normal, 1, 0, 1); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t1), RES_BAD_ARG); - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t1), RES_OK); + d3(pivot.data.pivot1.ref_normal, 1, 0, 1); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t1), RES_BAD_ARG); + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t1), RES_OK); CHECK(my_type_release(&t1), RES_OK); - CHECK(my_type_init_pivot(NULL, &pivot1, &tracking, &t1), RES_OK); + CHECK(my_type_init_pivot(NULL, &pivot, &tracking, &t1), RES_OK); CHECK(my_type_release(&t1), RES_OK); CHECK(my_type_init(&allocator, &t1), RES_OK); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t2), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); CHECK(my_type_init(&allocator, &t3), RES_OK); CHECK(my_type_add_child(&t1, &t2), RES_OK); @@ -71,7 +77,7 @@ main(int argc, char** argv) d3(in_dir, 1, 0.2, -1); CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); CHECK(my_type_get_transform(&t3, transform), RES_OK); - d33_muld3(n, transform, pivot1.data.pivot1.ref_normal); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); CHECK(d3_eq_eps(transform + 9, d3(tmp, -sqrt(2), 3, 2), 1e-10), 1); @@ -82,12 +88,12 @@ main(int argc, char** argv) /* 1 axis tracking with a fixed output dir */ tracking.policy = TRACKING_OUT_DIR; - pivot1.type = PIVOT_SINGLE_AXIS; - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); d3(tracking.data.out_dir.u, 0, 1, 0); CHECK(my_type_init(&allocator, &t1), RES_OK); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t2), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); CHECK(my_type_init(&allocator, &t3), RES_OK); CHECK(my_type_add_child(&t1, &t2), RES_OK); @@ -107,12 +113,12 @@ main(int argc, char** argv) CHECK(my_type_release(&t3), RES_OK); tracking.policy = TRACKING_OUT_DIR; - pivot1.type = PIVOT_SINGLE_AXIS; - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); d3(tracking.data.out_dir.u, 1, 0, 1); CHECK(my_type_init(&allocator, &t1), RES_OK); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t2), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); CHECK(my_type_init(&allocator, &t3), RES_OK); CHECK(my_type_add_child(&t1, &t2), RES_OK); @@ -126,8 +132,8 @@ main(int argc, char** argv) d3(in_dir, 1, -0.3, -1); CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); CHECK(my_type_get_transform(&t3, transform), RES_OK); - d33_muld3(n, transform, pivot1.data.pivot1.ref_normal); - CHECK(d3_eq_eps(pivot1.data.pivot1.ref_normal, n, 1e-10), 1); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); + CHECK(d3_eq_eps(pivot.data.pivot1.ref_normal, n, 1e-10), 1); CHECK(d3_eq_eps(transform + 9, d3(n, -1, 3, 3), 1e-10), 1); CHECK(my_type_release(&t1), RES_OK); @@ -137,14 +143,43 @@ main(int argc, char** argv) /* 1 axis tracking a target point */ tracking.policy = TRACKING_POINT; - pivot1.type = PIVOT_SINGLE_AXIS; - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); - d3(pivot1.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + d3(pivot.data.pivot1.ref_point, 0, 0, 0); + d3(tracking.data.point.target, 0, 0, 30); + tracking.data.point.target_is_local = 1; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 1, 0.1, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + d3(pivot.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); d3(tracking.data.point.target, 0, 10, 30); tracking.data.point.target_is_local = 1; CHECK(my_type_init(&allocator, &t1), RES_OK); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t2), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); CHECK(my_type_init(&allocator, &t3), RES_OK); CHECK(my_type_add_child(&t1, &t2), RES_OK); @@ -158,8 +193,7 @@ main(int argc, char** argv) d3(in_dir, 1, 0.1, 0); CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); CHECK(my_type_get_transform(&t3, transform), RES_OK); - d3(n, 0, 0, 1); - d33_muld3(n, transform, n); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); CHECK(my_type_release(&t1), RES_OK); @@ -169,14 +203,14 @@ main(int argc, char** argv) /* same 1 axis tracking with a non-local target point */ tracking.policy = TRACKING_POINT; - pivot1.type = PIVOT_SINGLE_AXIS; - d3(pivot1.data.pivot1.ref_normal, 0, 0, 1); - d3(pivot1.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + d3(pivot.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); d3(tracking.data.point.target, -10, 2, 32); tracking.data.point.target_is_local = 0; CHECK(my_type_init(&allocator, &t1), RES_OK); - CHECK(my_type_init_pivot(&allocator, &pivot1, &tracking, &t2), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); CHECK(my_type_init(&allocator, &t3), RES_OK); CHECK(my_type_add_child(&t1, &t2), RES_OK); @@ -190,14 +224,314 @@ main(int argc, char** argv) d3(in_dir, 1, -0.5, 0); CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); CHECK(my_type_get_transform(&t3, transform), RES_OK); - d3(n, 0, 0, 1); - d33_muld3(n, transform, n); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); CHECK(my_type_release(&t1), RES_OK); CHECK(my_type_release(&t2), RES_OK); CHECK(my_type_release(&t3), RES_OK); + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + d3(pivot.data.pivot1.ref_point, 0, 5, 5); + d3(tracking.data.point.target, -12, 2, -10); + tracking.data.point.target_is_local = 0; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 1, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, pivot.data.pivot1.ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, -1, 0, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 3, 1), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + /* + * 2 axis pivots + * (using only one axis at a time) + */ + + /* 2 axis tracking sun */ + + tracking.policy = TRACKING_SUN; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + d3(pivot.data.pivot2.ref_point, 0, 0, 1); + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + d3_splat(transl, +1); + d3(rot, 0, 0, PI / 2); + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 1, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 3, 2 + sqrt(2)), 1e-10), 1); + + d3(in_dir, 0, 1, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, 0, -1, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 0, 3), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + /* 2 axis tracking sun */ + + tracking.policy = TRACKING_SUN; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + d3_splat(transl, +1); + d3(rot, 0, 0, PI / 2); + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 1, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 3, 2 + sqrt(2)), 1e-10), 1); + + d3(in_dir, 0, 1, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, 0, -1, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 0, 3), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + /* 2 axis tracking with a fixed output dir */ + + tracking.policy = TRACKING_OUT_DIR; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + d3(tracking.data.out_dir.u, 0, 1, 0); + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 0, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, 0, sqrt(2) / 2, sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, 1, 3, 2 + sqrt(2)), 1e-10), 1); + + d3(in_dir, -1, 0, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, sqrt(2) / 2, sqrt(2) / 2, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, 3 * sqrt(2) / 2, 2 + sqrt(2) / 2, 3), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + /* 2 axis tracking a target point */ + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 0; + d3(pivot.data.pivot2.ref_point, 0, 0, 0); + d3(tracking.data.point.target, 30, 0, 0); + tracking.data.point.target_is_local = 1; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, -1, 0, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, sqrt(2) / 2, sqrt(2) / 2, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, sqrt(2), 2, 3), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = sqrt(2); + d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); + d3(tracking.data.point.target, 30, -11, 0); + tracking.data.point.target_is_local = 1; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, -1, 0, 0); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, sqrt(2) / 2, sqrt(2) / 2, 0), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, 1 + sqrt(2), 3, 3), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); + d3(tracking.data.point.target, 0, 30, 10); + tracking.data.point.target_is_local = 1; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 0, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, -sqrt(2) / 2, 0, +sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, -1, 3, 2 + sqrt(2)), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); + d3(tracking.data.point.target, 0, 30, 12); + tracking.data.point.target_is_local = 0; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 0, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, 0, sqrt(2) / 2, sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, 1, 3, 2 + sqrt(2)), 1e-10), 1); + + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); + + tracking.policy = TRACKING_POINT; + pivot.type = PIVOT_TWO_AXIS; + pivot.data.pivot2.spacing = 1; + d3(pivot.data.pivot2.ref_point, 10, 8 * sqrt(2), 5 * sqrt(2)); + d3(tracking.data.point.target, 10, 12, 15); + tracking.data.point.target_is_local = 0; + + CHECK(my_type_init(&allocator, &t1), RES_OK); + CHECK(my_type_init_pivot(&allocator, &pivot, &tracking, &t2), RES_OK); + CHECK(my_type_init(&allocator, &t3), RES_OK); + + CHECK(my_type_add_child(&t1, &t2), RES_OK); + CHECK(my_type_add_child(&t2, &t3), RES_OK); + + CHECK(my_type_set_translation(&t1, transl), RES_OK); + CHECK(my_type_set_rotations(&t1, rot), RES_OK); + CHECK(my_type_set_translation(&t2, transl), RES_OK); + CHECK(my_type_set_translation(&t3, transl), RES_OK); + + d3(in_dir, 0, 0, -1); + CHECK(sanim_node_solve_pivot(&t2.node, in_dir), RES_OK); + CHECK(my_type_get_transform(&t3, transform), RES_OK); + d33_muld3(n, transform, y_ref_normal); + CHECK(d3_eq_eps(n, d3(tmp, 0, sqrt(2) / 2, sqrt(2) / 2), 1e-10), 1); + CHECK(d3_eq_eps(transform + 9, d3(tmp, 1, 3, 2 + sqrt(2)), 1e-10), 1); + + /* release memory */ + CHECK(my_type_release(&t1), RES_OK); + CHECK(my_type_release(&t2), RES_OK); + CHECK(my_type_release(&t3), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHECK(mem_allocated_size(), 0); diff --git a/src/test_sanim_node_transform.c b/src/test_sanim_node_transform.c @@ -131,6 +131,7 @@ main(int argc, char** argv) CHECK(d33_eq_eps(transform, transform_, 1e-10), 1); CHECK(d3_eq_eps(transform + 9, transform_ + 9, 1e-10), 1); + /* release memory */ CHECK(my_type_release(&t1), RES_OK); CHECK(my_type_release(&t2), RES_OK); CHECK(my_type_release(&t3), RES_OK);