From 6a36edf9a01a795b7d11a48e9c23f27aa719db88 Mon Sep 17 00:00:00 2001 From: pavl-g Date: Sun, 4 Jan 2026 14:20:23 +0200 Subject: [PATCH 1/8] arithmos: created a gimbal-system library and matrix rotation --- .../arithmos/vectorspaces/gimbal_system.h | 35 ++++ .../arithmos/vectorspaces/matrix/matrix3.h | 31 +++ .../src/include/electronetsoft/util/types.h | 2 + .../arithmos/gimbal/init_rotator_gimbal.c | 72 +++++++ .../arithmos/gimbal/preprocess_orientator.c | 35 ++++ .../arithmos/gimbal/rotate_gimbal.c | 80 ++++++++ .../arithmos/vector3d/vec3d_rotate.c | 191 +----------------- 7 files changed, 256 insertions(+), 190 deletions(-) create mode 100644 sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h create mode 100644 sdk/core/src/include/electronetsoft/arithmos/vectorspaces/matrix/matrix3.h create mode 100644 sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c create mode 100644 sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_orientator.c create mode 100644 sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/rotate_gimbal.c diff --git a/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h new file mode 100644 index 0000000..3f2f272 --- /dev/null +++ b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h @@ -0,0 +1,35 @@ +#ifndef _GIMBAL_SYS_H_ +#define _GIMBAL_SYS_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rotation_metadata { + matrix *in_orientation; + matrix *out_orientation; +}; + +void preprocess_orientator(vector3d *v, vector3d *axis); + +status_code init_rotator_gimbal(vector3d axis, matrix *__rotator, + vec_component angle, + vec_component *angle1, + vec3d_gimbal *gimbal); + +status_code rotate_gimbal(vector3d axis, vec_component angle1, + matrix *__rotator, + vec3d_gimbal *in_gimbal, + vec3d_gimbal *out_gimbal, + vec3d_processors *procs); + +#ifdef __cplusplus +}; +#endif + +#endif \ No newline at end of file diff --git a/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/matrix/matrix3.h b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/matrix/matrix3.h new file mode 100644 index 0000000..65b4989 --- /dev/null +++ b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/matrix/matrix3.h @@ -0,0 +1,31 @@ +#ifndef _MAT_3D_H_ +#define _MAT_3D_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct mat3_gimbal { + matrix mat3d; + vec3d_gimbal gimbal3d; +}; + +struct mat3_processors { + mat_processors processors; + void (*on_gimbal_lock_trap)(mat3_gimbal rotated, + vector_gimbal gimbal, + vec_component angle); +}; + +status_code mat3_translate(matrix, matrix, matrix *, mat_processors); +status_code mat3_rotate(mat3_gimbal m, vector3d axis, + mat3_gimbal *out, vec_component angle, + mat3_processors proc); +#ifdef __cplusplus +}; +#endif + +#endif \ No newline at end of file diff --git a/sdk/core/src/include/electronetsoft/util/types.h b/sdk/core/src/include/electronetsoft/util/types.h index dd700ca..65d77f3 100644 --- a/sdk/core/src/include/electronetsoft/util/types.h +++ b/sdk/core/src/include/electronetsoft/util/types.h @@ -114,6 +114,8 @@ typedef enum mat_iterator { ROW_CONVENTION_ITERATOR = ((INT32_MAX >> 16) ^ INT32_MAX), COLUMN_CONVENTION_ITERATOR = ROW_CONVENTION_ITERATOR - 1, } mat_iterator; +typedef struct mat3_gimbal (mat3_gimbal); +typedef struct mat3_processors (mat3_processors); typedef struct caller_graph (caller_graph); diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c new file mode 100644 index 0000000..f7982bb --- /dev/null +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c @@ -0,0 +1,72 @@ +#include + +status_code init_rotator_gimbal(vector3d axis, matrix *__rotator, + vec_component angle, + vec_component *angle1, + vec3d_gimbal *gimbal) { + + if (NULL == __rotator || NULL == __rotator->element) { + return EUNDEFINEDBUFFER; + } + + if (get_vec_gimbal(axis) == GIMBAL_Z) { + // rotate around z-axis + // pre-processing automata + // Let the X-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. + + // work in XY plane + __rotator->element[0][0] = vector2d_cos(angle); + __rotator->element[0][1] = -vector2d_sin(angle); + __rotator->element[1][0] = vector2d_sin(angle); + __rotator->element[1][1] = vector2d_cos(angle); + __rotator->element[2][2] = 1; + + if (NULL != gimbal && NULL != angle1) { + gimbal->z_gimbal += angle; + *angle1 = gimbal->z_gimbal; + } + + } else if (get_vec_gimbal(axis) == GIMBAL_Y) { + // rotate around y-axis + // pre-processing automata + // Let the X-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Z-axis in the R(3) space be the Y-axis in the 2D projection. + + // work in XZ plane + __rotator->element[0][0] = vector2d_cos(angle); + __rotator->element[0][2] = -vector2d_sin(angle); + __rotator->element[2][0] = vector2d_sin(angle); + __rotator->element[2][2] = vector2d_cos(angle); + __rotator->element[1][1] = 1; + + if (NULL != gimbal && NULL != angle1) { + gimbal->y_gimbal += angle; + *angle1 = gimbal->y_gimbal; + } + + } else if (get_vec_gimbal(axis) == GIMBAL_X) { + + // rotate around x-axis + // pre-processing automata + // Let the Z-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. + + // work in ZY plane + __rotator->element[2][2] = vector2d_cos(angle); + __rotator->element[2][1] = -vector2d_sin(angle); + __rotator->element[1][2] = vector2d_sin(angle); + __rotator->element[1][1] = vector2d_cos(angle); + __rotator->element[0][0] = 1; + + if (NULL != gimbal && NULL != angle1) { + gimbal->x_gimbal += angle; + *angle1 = gimbal->x_gimbal; + } + + } else { + return EINCOMPATTYPE; + } + + return PASS; +} diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_orientator.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_orientator.c new file mode 100644 index 0000000..952950c --- /dev/null +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_orientator.c @@ -0,0 +1,35 @@ +#include + +void preprocess_orientator(vector3d *v, vector3d *axis) { + + // create a column vector matrix + vec_component axis_x[1] = {axis->x,}; + vec_component axis_y[1] = {axis->y,}; + vec_component axis_z[1] = {axis->z,}; + vec_component *axis_comps[3] = {axis_x, axis_y, axis_z}; + matrix __axis = { + .element = axis_comps, + .m = 3, + .n = 1 + }; + + // find the position of the orientation vectors + vec_component _axis_x[1] = {0,}; + vec_component _axis_y[1] = {0,}; + vec_component _axis_z[1] = {0,}; + vec_component *_axis_comps[3] = {_axis_x, _axis_y, _axis_z}; + matrix ___axis = { + .element = _axis_comps, + .m = 3, + .n = 1 + }; + + mat_processors proc = { + }; + + mat_product(*(v->gimbal.orientation), __axis, &___axis, proc); + + axis->x = *(___axis.element[0]); + axis->y = *(___axis.element[1]); + axis->z = *(___axis.element[2]); +} diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/rotate_gimbal.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/rotate_gimbal.c new file mode 100644 index 0000000..4c0644a --- /dev/null +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/rotate_gimbal.c @@ -0,0 +1,80 @@ +#include + +static inline status_code __on_entry_iterated(mat_proc_sig proc_sig) { + struct rotation_metadata *metadata = proc_sig.metadata; + matrix *in_orientation = metadata->in_orientation; + matrix *out_orientation = metadata->out_orientation; + uint64_t row_index = proc_sig.row_index; + uint64_t col_index = proc_sig.col_index; + + out_orientation->element[row_index][col_index] = + in_orientation->element[row_index][col_index]; + + return PASS; +} + +status_code rotate_gimbal(vector3d axis, vec_component angle1, + matrix *__rotator, + vec3d_gimbal *in_gimbal, + vec3d_gimbal *out_gimbal, + vec3d_processors *procs) { + + status_code __code = init_rotator_gimbal(axis, __rotator, angle1, + NULL, NULL); + if (PASS != __code) { + if (NULL != procs && NULL != procs->on_op_failed) { + procs->on_op_failed(&vec3d_rotate, __code); + } + return __code; + } + + // init the output orientation matrix + vec_component _orient_x[3] = {0, 0, 0,}; + vec_component _orient_y[3] = {0, 0, 0,}; + vec_component _orient_z[3] = {0, 0, 0,}; + vec_component *_orient_comps[3] = {_orient_x, _orient_y, _orient_z}; + matrix __orient = { + .element = _orient_comps, + .m = 3, + .n = 3 + }; + + mat_processors mat_procs = { + }; + + __code = mat_product(*__rotator, + *(in_gimbal->orientation), + &__orient, mat_procs); + if (PASS != __code) { + if (NULL != procs && NULL != procs->on_op_failed) { + procs->on_op_failed(&vec3d_rotate, __code); + } + return __code; + } + + struct rotation_metadata metadata = { + .in_orientation = &__orient, + .out_orientation = out_gimbal->orientation + }; + + mat_procs.on_entry_iterated = &__on_entry_iterated; + mat_procs.metadata = &metadata; + + __code = mat_iterate_elements(__orient, ROW_CONVENTION_ITERATOR, mat_procs); + if (PASS != __code) { + if (NULL != procs && NULL != procs->on_op_failed) { + procs->on_op_failed(&vec3d_rotate, __code); + } + return __code; + } + + if (get_vec_gimbal(axis) == GIMBAL_Z) { + out_gimbal->z_gimbal = 0; + } else if (get_vec_gimbal(axis) == GIMBAL_Y) { + out_gimbal->y_gimbal = 0; + } else { + out_gimbal->x_gimbal = 0; + } + + return PASS; +} \ No newline at end of file diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/vector3d/vec3d_rotate.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/vector3d/vec3d_rotate.c index bf68fbc..90c9fd4 100644 --- a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/vector3d/vec3d_rotate.c +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/vector3d/vec3d_rotate.c @@ -1,131 +1,8 @@ #include #include +#include #include -struct rotation_metadata { - matrix *in_orientation; - matrix *out_orientation; -}; - -static inline void preprocess_orientator(vector3d *v, vector3d *axis) { - - // create a column vector matrix - vec_component axis_x[1] = {0,}; - vec_component axis_y[1] = {0,}; - vec_component axis_z[1] = {0,}; - vec_component *axis_comps[3] = {axis_x, axis_y, axis_z}; - matrix __axis = { - .element = axis_comps, - .m = 3, - .n = 1 - }; - - mat_processors procs = { - }; - mat_create_from_vector3d(*axis, &__axis, procs); - - // find the position of the orientation vectors - vec_component _axis_x[1] = {0,}; - vec_component _axis_y[1] = {0,}; - vec_component _axis_z[1] = {0,}; - vec_component *_axis_comps[3] = {_axis_x, _axis_y, _axis_z}; - matrix ___axis = { - .element = _axis_comps, - .m = 3, - .n = 1 - }; - mat_product(*(v->gimbal.orientation), __axis, &___axis, procs); - - axis->x = *(___axis.element[0]); - axis->y = *(___axis.element[1]); - axis->z = *(___axis.element[2]); -} - -static inline status_code __on_entry_iterated(mat_proc_sig proc_sig) { - struct rotation_metadata *metadata = proc_sig.metadata; - matrix *in_orientation = metadata->in_orientation; - matrix *out_orientation = metadata->out_orientation; - uint64_t row_index = proc_sig.row_index; - uint64_t col_index = proc_sig.col_index; - - out_orientation->element[row_index][col_index] = - in_orientation->element[row_index][col_index]; - - return PASS; -} - -static inline status_code init_rotator_gimbal(vector3d axis, - matrix *__rotator, - vec_component angle, - vec_component *angle1, - vec3d_gimbal *gimbal) { - - if (NULL == __rotator || NULL == __rotator->element) { - return EUNDEFINEDBUFFER; - } - - if (get_vec_gimbal(axis) == GIMBAL_Z) { - // rotate around z-axis - // pre-processing automata - // Let the X-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. - - // work in XY plane - __rotator->element[0][0] = vector2d_cos(angle); - __rotator->element[0][1] = -vector2d_sin(angle); - __rotator->element[1][0] = vector2d_sin(angle); - __rotator->element[1][1] = vector2d_cos(angle); - __rotator->element[2][2] = 1; - - if (NULL != gimbal && NULL != angle1) { - gimbal->z_gimbal += angle; - *angle1 = gimbal->z_gimbal; - } - - } else if (get_vec_gimbal(axis) == GIMBAL_Y) { - // rotate around y-axis - // pre-processing automata - // Let the X-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Z-axis in the R(3) space be the Y-axis in the 2D projection. - - // work in XZ plane - __rotator->element[0][0] = vector2d_cos(angle); - __rotator->element[0][2] = -vector2d_sin(angle); - __rotator->element[2][0] = vector2d_sin(angle); - __rotator->element[2][2] = vector2d_cos(angle); - __rotator->element[1][1] = 1; - - if (NULL != gimbal && NULL != angle1) { - gimbal->y_gimbal += angle; - *angle1 = gimbal->y_gimbal; - } - - } else if (get_vec_gimbal(axis) == GIMBAL_X) { - - // rotate around x-axis - // pre-processing automata - // Let the Z-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. - - // work in ZY plane - __rotator->element[2][2] = vector2d_cos(angle); - __rotator->element[2][1] = -vector2d_sin(angle); - __rotator->element[1][2] = vector2d_sin(angle); - __rotator->element[1][1] = vector2d_cos(angle); - __rotator->element[0][0] = 1; - - if (NULL != gimbal && NULL != angle1) { - gimbal->x_gimbal += angle; - *angle1 = gimbal->x_gimbal; - } - - } else { - return EINCOMPATTYPE; - } - - return PASS; -} - static inline status_code rotate_about_gimbal(matrix *__rotator, matrix *__col_vec, matrix *_col_vec, @@ -151,72 +28,6 @@ static inline status_code rotate_about_gimbal(matrix *__rotator, return PASS; } -static inline status_code rotate_gimbal(vector3d axis, vec_component angle1, - matrix *__rotator, - vec3d_gimbal *in_gimbal, - vec3d_gimbal *out_gimbal, - vec3d_processors *procs) { - - status_code __code = init_rotator_gimbal(axis, __rotator, angle1, - NULL, NULL); - if (PASS != __code) { - if (NULL != procs && NULL != procs->on_op_failed) { - procs->on_op_failed(&vec3d_rotate, __code); - } - return __code; - } - - // init the output orientation matrix - vec_component _orient_x[3] = {0, 0, 0,}; - vec_component _orient_y[3] = {0, 0, 0,}; - vec_component _orient_z[3] = {0, 0, 0,}; - vec_component *_orient_comps[3] = {_orient_x, _orient_y, _orient_z}; - matrix __orient = { - .element = _orient_comps, - .m = 3, - .n = 3 - }; - - mat_processors mat_procs = { - }; - - __code = mat_product(*__rotator, - *(in_gimbal->orientation), - &__orient, mat_procs); - if (PASS != __code) { - if (NULL != procs && NULL != procs->on_op_failed) { - procs->on_op_failed(&vec3d_rotate, __code); - } - return __code; - } - - struct rotation_metadata metadata = { - .in_orientation = &__orient, - .out_orientation = out_gimbal->orientation - }; - - mat_procs.on_entry_iterated = &__on_entry_iterated; - mat_procs.metadata = &metadata; - - __code = mat_iterate_elements(__orient, ROW_CONVENTION_ITERATOR, mat_procs); - if (PASS != __code) { - if (NULL != procs && NULL != procs->on_op_failed) { - procs->on_op_failed(&vec3d_rotate, __code); - } - return __code; - } - - if (get_vec_gimbal(axis) == GIMBAL_Z) { - out_gimbal->z_gimbal = 0; - } else if (get_vec_gimbal(axis) == GIMBAL_Y) { - out_gimbal->y_gimbal = 0; - } else { - out_gimbal->x_gimbal = 0; - } - - return PASS; -} - status_code vec3d_rotate(vector3d v, vector3d axis, vec_component angle, vector3d *out, vec3d_processors *procs) { From 9a028a7deea190589ed06e4073e8da35a864f507 Mon Sep 17 00:00:00 2001 From: pavl-g Date: Sun, 4 Jan 2026 14:21:03 +0200 Subject: [PATCH 2/8] arithmos/matrix3: added matrix3d rotator library --- .../arithmos/matrix3/mat3_rotate.c | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c new file mode 100644 index 0000000..e3db492 --- /dev/null +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c @@ -0,0 +1,93 @@ +#include +#include + +status_code mat3_rotate(mat3_gimbal in, vector3d axis, + mat3_gimbal *out, vec_component angle, + mat3_processors proc) { + + // preprocessing automata -- input validation phases + if (NULL == in.mat3d.element || + NULL == out || + NULL == out->mat3d.element || + NULL == out->gimbal3d.orientation->element) { + return EUNDEFINEDBUFFER; + } + + // test in.mat3d against in.gimbal3d + if (in.mat3d.m != in.gimbal3d.orientation->m || + in.mat3d.n != in.gimbal3d.orientation->n || + in.mat3d.m != in.mat3d.n || + in.mat3d.m != 3) { + return EBUFFERTURNCATION; + } + + // test in.gimbal3d against out.gimbal3d + if (in.gimbal3d.orientation->m != out->gimbal3d.orientation->m || + in.gimbal3d.orientation->n != out->gimbal3d.orientation->n || + out->gimbal3d.orientation->m != out->gimbal3d.orientation->n || + out->gimbal3d.orientation->m != 3) { + return EBUFFERTURNCATION; + } + + // test in.mat3d against out->mat3d + if (in.mat3d.m != out->mat3d.m || + in.mat3d.n != out->mat3d.n) { + return EBUFFERTURNCATION; + } + + status_code __code; + vec_component angle1 = 0; + + // preprocessing automata -- initialize the input column vector + preprocess_orientator(&axis, &axis); + vec3d_abs(axis, &axis, NULL); + + // preprocessing automata -- allocate rotator matrix for the angular motion + vec_component __rotate_x[3] = {0, 0, 0,}; + vec_component __rotate_y[3] = {0, 0, 0,}; + vec_component __rotate_z[3] = {0, 0, 0,}; + vec_component *__rotate_comps[3] = {__rotate_x, __rotate_y, __rotate_z}; + matrix __rotator = { + .element = __rotate_comps, + .m = 3, + .n = 3, + }; + + // preprocessing automata -- init rotator matrix for the angular motion with an angular + // rotator vector matrix + __code = init_rotator_gimbal(axis, &__rotator, angle, + &angle1, &out->gimbal3d); + if (PASS != __code) { + return __code; + } + + // processing automata -- rotate the matrix + __code = mat_product(in.mat3d, __rotator, &(out->mat3d), proc.processors); + if (PASS != __code) { + return __code; + } + + // post-processing automata -- handle gimbals and gimbal rotation + if (vector2d_abs(vector2d_cos(angle1)) <= ___ROTATION_MIN_THRESHOLD + && vector2d_abs(vector2d_sin(angle1)) == 1) { + if (NULL != proc.on_gimbal_lock_trap) { + proc.on_gimbal_lock_trap(*out, get_vec_gimbal(axis), angle); + } + // rotate the gimbals axes (the orientation) + __code = rotate_gimbal(axis, angle1, &__rotator, + &(in.gimbal3d), + &out->gimbal3d, + NULL); + if (PASS != __code) { + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure((mat_proc_sig) { + + }, __code); + } + return __code; + } + } + + return PASS; +} + From 6fd539d0ed0a970796d9613761b668254ee40cdb Mon Sep 17 00:00:00 2001 From: pavl-g Date: Tue, 6 Jan 2026 11:10:36 +0200 Subject: [PATCH 3/8] arithmos: introduced a preprocessor for mat3d --- .../arithmos/vectorspaces/gimbal_system.h | 2 ++ .../electronetsoft/arithmos_calculus.h | 1 + .../gimbal/preprocess_mat3_orientator.c | 20 +++++++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_mat3_orientator.c diff --git a/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h index 3f2f272..1990146 100644 --- a/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h +++ b/sdk/core/src/include/electronetsoft/arithmos/vectorspaces/gimbal_system.h @@ -17,6 +17,8 @@ struct rotation_metadata { void preprocess_orientator(vector3d *v, vector3d *axis); +status_code preprocess_mat3_orientator(vec3d_gimbal, vector3d *); + status_code init_rotator_gimbal(vector3d axis, matrix *__rotator, vec_component angle, vec_component *angle1, diff --git a/sdk/core/src/include/electronetsoft/arithmos_calculus.h b/sdk/core/src/include/electronetsoft/arithmos_calculus.h index 98394ab..a58fe36 100644 --- a/sdk/core/src/include/electronetsoft/arithmos_calculus.h +++ b/sdk/core/src/include/electronetsoft/arithmos_calculus.h @@ -1,3 +1,4 @@ #include +#include #include #include \ No newline at end of file diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_mat3_orientator.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_mat3_orientator.c new file mode 100644 index 0000000..a1f3120 --- /dev/null +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/preprocess_mat3_orientator.c @@ -0,0 +1,20 @@ +#include +#include + +status_code preprocess_mat3_orientator(vec3d_gimbal gimbal, vector3d *axis) { + if (NULL == axis || + NULL == gimbal.orientation || + NULL == gimbal.orientation->element) { + return EUNDEFINEDBUFFER; + } + + vector3d v3 = { + .gimbal = (vec3d_gimbal) { + .orientation = gimbal.orientation + } + }; + + preprocess_orientator(&v3, axis); + + return PASS; +} \ No newline at end of file From f0916fd7601b62ecb20a231bf6f004e33ff9741c Mon Sep 17 00:00:00 2001 From: pavl-g Date: Tue, 6 Jan 2026 11:11:33 +0200 Subject: [PATCH 4/8] arithmos/gimbal: indentations for init_rotator_gimbal --- .../arithmos/gimbal/init_rotator_gimbal.c | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c index f7982bb..d2d75c9 100644 --- a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/gimbal/init_rotator_gimbal.c @@ -10,59 +10,59 @@ status_code init_rotator_gimbal(vector3d axis, matrix *__rotator, } if (get_vec_gimbal(axis) == GIMBAL_Z) { - // rotate around z-axis - // pre-processing automata - // Let the X-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. + // rotate around z-axis + // pre-processing automata + // Let the X-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. - // work in XY plane - __rotator->element[0][0] = vector2d_cos(angle); - __rotator->element[0][1] = -vector2d_sin(angle); - __rotator->element[1][0] = vector2d_sin(angle); - __rotator->element[1][1] = vector2d_cos(angle); - __rotator->element[2][2] = 1; + // work in XY plane + __rotator->element[0][0] = vector2d_cos(angle); + __rotator->element[0][1] = -vector2d_sin(angle); + __rotator->element[1][0] = vector2d_sin(angle); + __rotator->element[1][1] = vector2d_cos(angle); + __rotator->element[2][2] = 1; - if (NULL != gimbal && NULL != angle1) { - gimbal->z_gimbal += angle; - *angle1 = gimbal->z_gimbal; - } + if (NULL != gimbal && NULL != angle1) { + gimbal->z_gimbal += angle; + *angle1 = gimbal->z_gimbal; + } } else if (get_vec_gimbal(axis) == GIMBAL_Y) { - // rotate around y-axis - // pre-processing automata - // Let the X-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Z-axis in the R(3) space be the Y-axis in the 2D projection. + // rotate around y-axis + // pre-processing automata + // Let the X-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Z-axis in the R(3) space be the Y-axis in the 2D projection. - // work in XZ plane - __rotator->element[0][0] = vector2d_cos(angle); - __rotator->element[0][2] = -vector2d_sin(angle); - __rotator->element[2][0] = vector2d_sin(angle); - __rotator->element[2][2] = vector2d_cos(angle); - __rotator->element[1][1] = 1; + // work in XZ plane + __rotator->element[0][0] = vector2d_cos(angle); + __rotator->element[0][2] = -vector2d_sin(angle); + __rotator->element[2][0] = vector2d_sin(angle); + __rotator->element[2][2] = vector2d_cos(angle); + __rotator->element[1][1] = 1; - if (NULL != gimbal && NULL != angle1) { - gimbal->y_gimbal += angle; - *angle1 = gimbal->y_gimbal; - } + if (NULL != gimbal && NULL != angle1) { + gimbal->y_gimbal += angle; + *angle1 = gimbal->y_gimbal; + } } else if (get_vec_gimbal(axis) == GIMBAL_X) { - // rotate around x-axis - // pre-processing automata - // Let the Z-axis in the R(3) space be the X-axis in the 2D projection. - // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. + // rotate around x-axis + // pre-processing automata + // Let the Z-axis in the R(3) space be the X-axis in the 2D projection. + // Let the Y-axis in the R(3) space be the Y-axis in the 2D projection. - // work in ZY plane - __rotator->element[2][2] = vector2d_cos(angle); - __rotator->element[2][1] = -vector2d_sin(angle); - __rotator->element[1][2] = vector2d_sin(angle); - __rotator->element[1][1] = vector2d_cos(angle); - __rotator->element[0][0] = 1; + // work in ZY plane + __rotator->element[2][2] = vector2d_cos(angle); + __rotator->element[2][1] = -vector2d_sin(angle); + __rotator->element[1][2] = vector2d_sin(angle); + __rotator->element[1][1] = vector2d_cos(angle); + __rotator->element[0][0] = 1; - if (NULL != gimbal && NULL != angle1) { - gimbal->x_gimbal += angle; - *angle1 = gimbal->x_gimbal; - } + if (NULL != gimbal && NULL != angle1) { + gimbal->x_gimbal += angle; + *angle1 = gimbal->x_gimbal; + } } else { return EINCOMPATTYPE; From 4b68d8435d455a8ae51b962ae9d31805f81d5861 Mon Sep 17 00:00:00 2001 From: pavl-g Date: Tue, 6 Jan 2026 11:12:09 +0200 Subject: [PATCH 5/8] arithmos/matrix3: applied API changes --- .../arithmos/matrix3/mat3_rotate.c | 70 +++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c index e3db492..5d07015 100644 --- a/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c +++ b/sdk/core/src/libs/electrostatic-primer/electronetsoft/arithmos/matrix3/mat3_rotate.c @@ -5,11 +5,32 @@ status_code mat3_rotate(mat3_gimbal in, vector3d axis, mat3_gimbal *out, vec_component angle, mat3_processors proc) { + caller_graph caller = { + .api = "arithmos:matrix3#mat3_rotate", + .func = &mat3_rotate, + .params = NULL, + .root = proc.processors.root, + }; + + mat_proc_sig proc_sig = { + .proc = proc.processors, + .caller = caller, + .metadata = proc.processors.metadata, + }; + // preprocessing automata -- input validation phases if (NULL == in.mat3d.element || + NULL == in.gimbal3d.orientation || + NULL == in.gimbal3d.orientation->element || NULL == out || NULL == out->mat3d.element || + NULL == out->gimbal3d.orientation || NULL == out->gimbal3d.orientation->element) { + + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, EUNDEFINEDBUFFER); + } + return EUNDEFINEDBUFFER; } @@ -18,6 +39,11 @@ status_code mat3_rotate(mat3_gimbal in, vector3d axis, in.mat3d.n != in.gimbal3d.orientation->n || in.mat3d.m != in.mat3d.n || in.mat3d.m != 3) { + + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, EBUFFERTURNCATION); + } + return EBUFFERTURNCATION; } @@ -26,21 +52,46 @@ status_code mat3_rotate(mat3_gimbal in, vector3d axis, in.gimbal3d.orientation->n != out->gimbal3d.orientation->n || out->gimbal3d.orientation->m != out->gimbal3d.orientation->n || out->gimbal3d.orientation->m != 3) { + + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, EBUFFERTURNCATION); + } + return EBUFFERTURNCATION; } // test in.mat3d against out->mat3d if (in.mat3d.m != out->mat3d.m || in.mat3d.n != out->mat3d.n) { + + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, EBUFFERTURNCATION); + } + return EBUFFERTURNCATION; } + proc_sig.mat = out->mat3d; + status_code __code; vec_component angle1 = 0; // preprocessing automata -- initialize the input column vector - preprocess_orientator(&axis, &axis); - vec3d_abs(axis, &axis, NULL); + __code = preprocess_mat3_orientator(in.gimbal3d, &axis); + if (PASS != __code) { + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, __code); + } + return __code; + } + + __code = vec3d_abs(axis, &axis, NULL); + if (PASS != __code) { + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, __code); + } + return __code; + } // preprocessing automata -- allocate rotator matrix for the angular motion vec_component __rotate_x[3] = {0, 0, 0,}; @@ -58,12 +109,18 @@ status_code mat3_rotate(mat3_gimbal in, vector3d axis, __code = init_rotator_gimbal(axis, &__rotator, angle, &angle1, &out->gimbal3d); if (PASS != __code) { + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, __code); + } return __code; } // processing automata -- rotate the matrix __code = mat_product(in.mat3d, __rotator, &(out->mat3d), proc.processors); if (PASS != __code) { + if (NULL != proc.processors.on_op_failure) { + proc.processors.on_op_failure(proc_sig, __code); + } return __code; } @@ -78,16 +135,19 @@ status_code mat3_rotate(mat3_gimbal in, vector3d axis, &(in.gimbal3d), &out->gimbal3d, NULL); + if (PASS != __code) { if (NULL != proc.processors.on_op_failure) { - proc.processors.on_op_failure((mat_proc_sig) { - - }, __code); + proc.processors.on_op_failure(proc_sig, __code); } return __code; } } + if (NULL != proc.processors.on_op_success) { + proc.processors.on_op_success(proc_sig); + } + return PASS; } From e12eeeaf4f12990d3b4c7acb36585988b24e61af Mon Sep 17 00:00:00 2001 From: pavl-g Date: Wed, 3 Jun 2026 02:53:58 +0300 Subject: [PATCH 6/8] examples: added unit test for the matrix rotation api --- .../calculus/test_3d_mat_gimbal_rotation.c | 464 ++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 sdk/examples/src/calculus/test_3d_mat_gimbal_rotation.c diff --git a/sdk/examples/src/calculus/test_3d_mat_gimbal_rotation.c b/sdk/examples/src/calculus/test_3d_mat_gimbal_rotation.c new file mode 100644 index 0000000..1a8be82 --- /dev/null +++ b/sdk/examples/src/calculus/test_3d_mat_gimbal_rotation.c @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include + +// Helper function to print gimbal state +static void print_gimbal_state(const char *label, mat3_gimbal gimbal) { + fprintf(stdout, CYAN "%s\n" RESET, label); + fprintf(stdout, CYAN " X-Gimbal angle: %f\n" RESET, gimbal.gimbal3d.x_gimbal); + fprintf(stdout, CYAN " Y-Gimbal angle: %f\n" RESET, gimbal.gimbal3d.y_gimbal); + fprintf(stdout, CYAN " Z-Gimbal angle: %f\n" RESET, gimbal.gimbal3d.z_gimbal); +} + +// Helper function to print gimbal orientation matrix +static void print_gimbal_orientation(const char *label, mat3_gimbal gimbal) { + fprintf(stdout, CYAN "%s\n" RESET, label); + fprintf(stdout, CYAN " X-Gimbal orientation: [%f, %f, %f]\n" RESET, + gimbal.gimbal3d.orientation->element[0][0], + gimbal.gimbal3d.orientation->element[1][0], + gimbal.gimbal3d.orientation->element[2][0]); + fprintf(stdout, CYAN " Y-Gimbal orientation: [%f, %f, %f]\n" RESET, + gimbal.gimbal3d.orientation->element[0][1], + gimbal.gimbal3d.orientation->element[1][1], + gimbal.gimbal3d.orientation->element[2][1]); + fprintf(stdout, CYAN " Z-Gimbal orientation: [%f, %f, %f]\n" RESET, + gimbal.gimbal3d.orientation->element[0][2], + gimbal.gimbal3d.orientation->element[1][2], + gimbal.gimbal3d.orientation->element[2][2]); +} + +// Test 1: Rotate around X-axis by 90 degrees +static status_code assert_x_rotation_90(mat3_gimbal r0, mat3_gimbal r, + vec_component angle) { + if (r.gimbal3d.x_gimbal != angle) { + fprintf(stdout, RED "(1) Failed to assert the X-Gimbal Angle Rotated Orthogonally!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(1) Asserted X-Gimbal Angle Rotated Orthogonally!\n" RESET); + + if (r.gimbal3d.y_gimbal != 0) { + fprintf(stdout, RED "(2) Failed to assert the Y-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(2) Asserted the Y-Gimbal angle unchanged!\n" RESET); + + if (r.gimbal3d.z_gimbal != 0) { + fprintf(stdout, RED "(3) Failed to assert the Z-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(3) Asserted the Z-Gimbal angle unchanged!\n" RESET); + + // assert the position of the X Gimbal (Which should never change!) + if ((r.gimbal3d.orientation->element[0][0] != 1) || + (r.gimbal3d.orientation->element[1][0] != 0) || + (r.gimbal3d.orientation->element[2][0] != 0)) { + fprintf(stdout, RED "(4) Failed to assert the X-Gimbal orientation unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(4) Asserted the X-Gimbal orientation unchanged!\n" RESET); + + // assert the new position of the Y Gimbal (After performing a Pi/2 X-gimbal rotation) + if (!(vector2d_abs(r.gimbal3d.orientation->element[1][1]) <= + ___ROTATION_MIN_THRESHOLD) || + (r.gimbal3d.orientation->element[0][1] != 0) || + (r.gimbal3d.orientation->element[2][1] != -1)) { + fprintf(stdout, RED "(5) Failed to assert the new Y-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(5) Asserted the new Y-Gimbal orientation!\n" RESET); + + // assert the new position of the Z Gimbal (After performing a Pi/2 X-gimbal rotation). + if ((vector2d_abs(r.gimbal3d.orientation->element[0][2]) != 0) || + (vector2d_abs(r.gimbal3d.orientation->element[1][2]) != 1) || + !(vector2d_abs(r.gimbal3d.orientation->element[2][2]) <= ___ROTATION_MIN_THRESHOLD)){ + fprintf(stdout, RED "(6) Failed to assert the new Z-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(6) Asserted the new Z-Gimbal orientation!\n" RESET); + + return ASSERTION_SUCCESS; +} + +// Test 2: Rotate around Y-axis by 90 degrees +static status_code assert_y_rotation_90(mat3_gimbal r0, mat3_gimbal r, + vec_component angle) { + if (r.gimbal3d.y_gimbal != angle) { + fprintf(stdout, RED "(1) Failed to assert the Y-Gimbal Angle Rotated Orthogonally!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(1) Asserted Y-Gimbal Angle Rotated Orthogonally!\n" RESET); + + if (r.gimbal3d.x_gimbal != 0) { + fprintf(stdout, RED "(2) Failed to assert the X-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(2) Asserted the X-Gimbal angle unchanged!\n" RESET); + + if (r.gimbal3d.z_gimbal != 0) { + fprintf(stdout, RED "(3) Failed to assert the Z-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(3) Asserted the Z-Gimbal angle unchanged!\n" RESET); + + // assert the position of the Y Gimbal (Which should never change!) + if ((r.gimbal3d.orientation->element[0][1] != 0) || + (r.gimbal3d.orientation->element[1][1] != 1) || + (r.gimbal3d.orientation->element[2][1] != 0)) { + fprintf(stdout, RED "(4) Failed to assert the Y-Gimbal orientation unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(4) Asserted the Y-Gimbal orientation unchanged!\n" RESET); + + // assert the new position of the X Gimbal (After performing a Pi/2 Y-gimbal rotation) + if (!(vector2d_abs(r.gimbal3d.orientation->element[0][0]) <= + ___ROTATION_MIN_THRESHOLD) || + (r.gimbal3d.orientation->element[0][1] != 0) || + (r.gimbal3d.orientation->element[2][0] != 1)) { + fprintf(stdout, RED "(5) Failed to assert the new X-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(5) Asserted the new X-Gimbal orientation!\n" RESET); + + // assert the new position of the Z Gimbal (After performing a Pi/2 Y-gimbal rotation). + if ((vector2d_abs(r.gimbal3d.orientation->element[0][2]) != 1) || + !(r.gimbal3d.orientation->element[1][2] <= ___ROTATION_MIN_THRESHOLD) || + !(vector2d_abs(r.gimbal3d.orientation->element[2][2]) <= ___ROTATION_MIN_THRESHOLD)){ + fprintf(stdout, RED "(6) Failed to assert the new Z-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(6) Asserted the new Z-Gimbal orientation!\n" RESET); + + return ASSERTION_SUCCESS; +} + +// Test 3: Rotate around Z-axis by 90 degrees +static status_code assert_z_rotation_90(mat3_gimbal r0, mat3_gimbal r, + vec_component angle) { + if (r.gimbal3d.z_gimbal != angle) { + fprintf(stdout, RED "(1) Failed to assert the Z-Gimbal Angle Rotated Orthogonally!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(1) Asserted Z-Gimbal Angle Rotated Orthogonally!\n" RESET); + + if (r.gimbal3d.x_gimbal != 0) { + fprintf(stdout, RED "(2) Failed to assert the X-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(2) Asserted the X-Gimbal angle unchanged!\n" RESET); + + if (r.gimbal3d.y_gimbal != 0) { + fprintf(stdout, RED "(3) Failed to assert the Y-Gimbal angle unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(3) Asserted the Y-Gimbal angle unchanged!\n" RESET); + + // assert the position of the Z Gimbal (Which should never change!) + if ((r.gimbal3d.orientation->element[0][2] != 0) || + (r.gimbal3d.orientation->element[1][2] != 0) || + (r.gimbal3d.orientation->element[2][2] != 1)) { + fprintf(stdout, RED "(4) Failed to assert the Z-Gimbal orientation unchanged!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(4) Asserted the Z-Gimbal orientation unchanged!\n" RESET); + + // assert the new position of the X Gimbal (After performing a Pi/2 Z-gimbal rotation) + if (!(vector2d_abs(r.gimbal3d.orientation->element[0][0]) <= + ___ROTATION_MIN_THRESHOLD) || + (r.gimbal3d.orientation->element[1][0] != 1) || + !(vector2d_abs(r.gimbal3d.orientation->element[2][0]) <= ___ROTATION_MIN_THRESHOLD)) { + fprintf(stdout, RED "(5) Failed to assert the new X-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(5) Asserted the new X-Gimbal orientation!\n" RESET); + + // assert the new position of the Y Gimbal (After performing a Pi/2 Z-gimbal rotation). + if ((vector2d_abs(r.gimbal3d.orientation->element[0][1]) != 1) || + !(r.gimbal3d.orientation->element[1][1] <= ___ROTATION_MIN_THRESHOLD) || + (r.gimbal3d.orientation->element[2][1] != 0)){ + fprintf(stdout, RED "(6) Failed to assert the new Y-Gimbal orientation!\n" RESET); + return ASSERTION_FAILURE; + } + + fprintf(stdout, GREEN "(6) Asserted the new Y-Gimbal orientation!\n" RESET); + + return ASSERTION_SUCCESS; +} + +// Execute test 1: Rotation around X-axis +static inline int64_t execute_x_rotation(void **inputs) { + // 1) Create an identity matrix for the initial position + vec_component __rotate_x[3] = {1, 0, 0,}; + vec_component __rotate_y[3] = {0, 1, 0,}; + vec_component __rotate_z[3] = {0, 0, 1,}; + vec_component *__rotate_comps[3] = {__rotate_x, + __rotate_y, + __rotate_z}; + + // 2) Create an identity matrix for the orientator matrix + vec_component __gimbal_x[3] = {1, 0, 0,}; + vec_component __gimbal_y[3] = {0, 1, 0,}; + vec_component __gimbal_z[3] = {0, 0, 1,}; + vec_component *__gimbal_comps[3] = {__gimbal_x, + __gimbal_y, + __gimbal_z}; + + matrix __gimbal = { + .element = __gimbal_comps, + .m = 3, + .n = 3, + }; + + mat3_gimbal mat_gimbal = { + .mat3d = (matrix) { + .element = __rotate_comps, + .m = 3, + .n = 3, + }, + .gimbal3d = (vec3d_gimbal) { + .orientation = &__gimbal, + .x_gimbal = 0, + .y_gimbal = 0, + .z_gimbal = 0 + } + }; + + mat3_gimbal initial_state = mat_gimbal; + + mat3_processors processors = { + }; + + fprintf(stdout, "\n=== Test 1: Rotate identity matrix around X-axis by 90 degrees ===\n"); + + print_gimbal_state(YELLOW "Initial Gimbal Angles:" RESET, initial_state); + print_gimbal_orientation(YELLOW "Initial Gimbal Orientations:" RESET, initial_state); + + status_code __code = mat3_rotate(mat_gimbal, VEC3_X_COMPONENT, &mat_gimbal, M_PI/2, processors); + + if (PASS != __code) { + fprintf(stderr, RED "Error: %d\n" RESET, __code); + return __code; + } + + print_gimbal_state(YELLOW "Rotated Gimbal Angles:" RESET, mat_gimbal); + print_gimbal_orientation(YELLOW "Rotated Gimbal Orientations:" RESET, mat_gimbal); + fprintf(stdout, YELLOW "Expected X-Gimbal Angle: %f (radians = π/2)\n" RESET, M_PI/2); + + fprintf(stdout, "\n" YELLOW "Performing assertions...\n" RESET); + status_code assertion_result = assert_x_rotation_90(initial_state, mat_gimbal, 0); + return assertion_result; +} + +// Execute test 2: Rotation around Y-axis +static inline int64_t execute_y_rotation(void **inputs) { + // 1) Create an identity matrix for the initial position + vec_component __rotate_x[3] = {1, 0, 0,}; + vec_component __rotate_y[3] = {0, 1, 0,}; + vec_component __rotate_z[3] = {0, 0, 1,}; + vec_component *__rotate_comps[3] = {__rotate_x, + __rotate_y, + __rotate_z}; + + // 2) Create an identity matrix for the orientator matrix + vec_component __gimbal_x[3] = {1, 0, 0,}; + vec_component __gimbal_y[3] = {0, 1, 0,}; + vec_component __gimbal_z[3] = {0, 0, 1,}; + vec_component *__gimbal_comps[3] = {__gimbal_x, + __gimbal_y, + __gimbal_z}; + + matrix __gimbal = { + .element = __gimbal_comps, + .m = 3, + .n = 3, + }; + + mat3_gimbal mat_gimbal = { + .mat3d = (matrix) { + .element = __rotate_comps, + .m = 3, + .n = 3, + }, + .gimbal3d = (vec3d_gimbal) { + .orientation = &__gimbal, + .x_gimbal = 0, + .y_gimbal = 0, + .z_gimbal = 0 + } + }; + + mat3_gimbal initial_state = mat_gimbal; + + mat3_processors processors = { + }; + + fprintf(stdout, "\n=== Test 2: Rotate identity matrix around Y-axis by 90 degrees ===\n"); + + print_gimbal_state(YELLOW "Initial Gimbal Angles:" RESET, initial_state); + print_gimbal_orientation(YELLOW "Initial Gimbal Orientations:" RESET, initial_state); + + status_code __code = mat3_rotate(mat_gimbal, VEC3_Y_COMPONENT, &mat_gimbal, M_PI/2, processors); + + if (PASS != __code) { + fprintf(stderr, RED "Error: %d\n" RESET, __code); + return __code; + } + + print_gimbal_state(YELLOW "Rotated Gimbal Angles:" RESET, mat_gimbal); + print_gimbal_orientation(YELLOW "Rotated Gimbal Orientations:" RESET, mat_gimbal); + fprintf(stdout, YELLOW "Expected Y-Gimbal Angle: %f (radians = π/2)\n" RESET, M_PI/2); + + fprintf(stdout, "\n" YELLOW "Performing assertions...\n" RESET); + status_code assertion_result = assert_y_rotation_90(initial_state, mat_gimbal, 0); + return assertion_result; +} + +// Execute test 3: Rotation around Z-axis +static inline int64_t execute_z_rotation(void **inputs) { + // 1) Create an identity matrix for the initial position + vec_component __rotate_x[3] = {1, 0, 0,}; + vec_component __rotate_y[3] = {0, 1, 0,}; + vec_component __rotate_z[3] = {0, 0, 1,}; + vec_component *__rotate_comps[3] = {__rotate_x, + __rotate_y, + __rotate_z}; + + // 2) Create an identity matrix for the orientator matrix + vec_component __gimbal_x[3] = {1, 0, 0,}; + vec_component __gimbal_y[3] = {0, 1, 0,}; + vec_component __gimbal_z[3] = {0, 0, 1,}; + vec_component *__gimbal_comps[3] = {__gimbal_x, + __gimbal_y, + __gimbal_z}; + + matrix __gimbal = { + .element = __gimbal_comps, + .m = 3, + .n = 3, + }; + + mat3_gimbal mat_gimbal = { + .mat3d = (matrix) { + .element = __rotate_comps, + .m = 3, + .n = 3, + }, + .gimbal3d = (vec3d_gimbal) { + .orientation = &__gimbal, + .x_gimbal = 0, + .y_gimbal = 0, + .z_gimbal = 0 + } + }; + + mat3_gimbal initial_state = mat_gimbal; + + mat3_processors processors = { + }; + + fprintf(stdout, "\n=== Test 3: Rotate identity matrix around Z-axis by 90 degrees ===\n"); + + print_gimbal_state(YELLOW "Initial Gimbal Angles:" RESET, initial_state); + print_gimbal_orientation(YELLOW "Initial Gimbal Orientations:" RESET, initial_state); + + status_code __code = mat3_rotate(mat_gimbal, VEC3_Z_COMPONENT, &mat_gimbal, M_PI/2, processors); + + if (PASS != __code) { + fprintf(stderr, RED "Error: %d\n" RESET, __code); + return __code; + } + + print_gimbal_state(YELLOW "Rotated Gimbal Angles:" RESET, mat_gimbal); + print_gimbal_orientation(YELLOW "Rotated Gimbal Orientations:" RESET, mat_gimbal); + fprintf(stdout, YELLOW "Expected Z-Gimbal Angle: %f (radians = π/2)\n" RESET, M_PI/2); + + fprintf(stdout, "\n" YELLOW "Performing assertions...\n" RESET); + status_code assertion_result = assert_z_rotation_90(initial_state, mat_gimbal, 0); + return assertion_result; +} + +static inline status_code assert(int64_t prop0, int64_t prop1) { +return ((status_code) (prop0 == prop1) && ASSERTION_SUCCESS); +} + +static inline void on_assertion_success(unit_test *test) { + fprintf(stdout, GREEN "✓ Test passed!\n" RESET); +} + +static inline void on_assertion_failure(unit_test *test) { + fprintf(stderr, RED "✗ Test failed!\n" RESET); +} + +int main() { + fprintf(stdout, "\n========================================\n"); + fprintf(stdout, "Matrix3 Rotation API Unit Tests\n"); + fprintf(stdout, "========================================\n"); + + // Test 1: Rotation around X-axis + unit_test test_x = { + .on_assertion_success = &on_assertion_success, + .on_assertion_failure = &on_assertion_failure, + .assert = &assert, + .execute = &execute_x_rotation, + .proposition = ASSERTION_SUCCESS, + }; + + // Test 2: Rotation around Y-axis + unit_test test_y = { + .on_assertion_success = &on_assertion_success, + .on_assertion_failure = &on_assertion_failure, + .assert = &assert, + .execute = &execute_y_rotation, + .proposition = ASSERTION_SUCCESS, + }; + + // Test 3: Rotation around Z-axis + unit_test test_z = { + .on_assertion_success = &on_assertion_success, + .on_assertion_failure = &on_assertion_failure, + .assert = &assert, + .execute = &execute_z_rotation, + .proposition = ASSERTION_SUCCESS, + }; + + fprintf(stdout, "\nRunning tests...\n"); + + status_code __code_x = assert_test(&test_x); + if (ASSERTION_SUCCESS != __code_x) { + fprintf(stderr, RED "Error in Test 1: %d\n" RESET, __code_x); + } + + status_code __code_y = assert_test(&test_y); + if (ASSERTION_SUCCESS != __code_y) { + fprintf(stderr, RED "Error in Test 2: %d\n" RESET, __code_y); + } + + status_code __code_z = assert_test(&test_z); + if (ASSERTION_SUCCESS != __code_z) { + fprintf(stderr, RED "Error in Test 3: %d\n" RESET, __code_z); + } + + fprintf(stdout, "\n========================================\n"); + fprintf(stdout, "Tests completed!\n"); + fprintf(stdout, "========================================\n"); + + return 0; +} From f729493cef37007ee1fa725e4f4637ecc1cb9982 Mon Sep 17 00:00:00 2001 From: pavl-g Date: Wed, 3 Jun 2026 02:55:26 +0300 Subject: [PATCH 7/8] examples: updated other unit tests --- sdk/examples/src/calculus/test_3d_z_gimbal_rotation.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/examples/src/calculus/test_3d_z_gimbal_rotation.c b/sdk/examples/src/calculus/test_3d_z_gimbal_rotation.c index bb4ebab..0686739 100644 --- a/sdk/examples/src/calculus/test_3d_z_gimbal_rotation.c +++ b/sdk/examples/src/calculus/test_3d_z_gimbal_rotation.c @@ -131,6 +131,7 @@ static inline int64_t execute(void **inputs) { status_code __code = vec3d_rotate(v, VEC3_Z_COMPONENT, M_PI/2, &v, &processors); if (__code != PASS) { fprintf(stderr, "Error: %d\n", __code); + return __code; } fprintf(stdout, "Vx Orientation = (%f, %f, %f)\n", v.gimbal.orientation->element[0][0], v.gimbal.orientation->element[1][0], v.gimbal.orientation->element[2][0]); From bfd4232757b76cb1c485c95a77ed535e16337085 Mon Sep 17 00:00:00 2001 From: pavl-g Date: Wed, 3 Jun 2026 03:02:52 +0300 Subject: [PATCH 8/8] workflows/build-test: added a job step for test_3d_mat_gimbal_rotation --- .github/workflows/build-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 8956c82..c80d832 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -100,6 +100,9 @@ jobs: - name: Testing Arithmos Calculus (3D Gimbal Rotation around Z-axis) run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_3d_z_gimbal_rotation.c" "test_3d_z_gimbal_rotation" + - name: Testing Arithmos Matrix Rotation API + run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_3d_mat_gimbal_rotation.c" "test_3d_mat_gimbal_rotation" + - name: Testing Arithmos Calculus (Matrix Algebra Operations -- mat_product) run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_mat_product.c" "test_mat_product"