Skip to content

Commit ac6a653

Browse files
authored
Merge pull request #90 from Electrostat-Lab/unit-testing
arithmos/vector3d: added Vector3d Calculus Unit tests and library optimizations
2 parents d1fdb3e + 398e031 commit ac6a653

File tree

16 files changed

+611
-58
lines changed

16 files changed

+611
-58
lines changed

.github/workflows/build-test.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,30 @@ jobs:
8585
- name: Testing "hello_switching_mux.c"
8686
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "hello_switching_mux.c" "hello-switching-mux"
8787

88+
- name: Testing Arithmos Calculus (2D Vector Rotation)
89+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_vec2d_rotation.c" "test_2d_rotation"
90+
91+
- name: Testing Arithmos Calculus (3D Gimbal Rotation Sequence)
92+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_vec3d_rotation.c" "test_3d_rotation"
93+
94+
- name: Testing Arithmos Calculus (3D Gimbal Rotation around X-axis)
95+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_3d_x_gimbal_rotation.c" "test_3d_x_gimbal_rotation"
96+
97+
- name: Testing Arithmos Calculus (3D Gimbal Rotation around Y-axis)
98+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_3d_y_gimbal_rotation.c" "test_3d_y_gimbal_rotation"
99+
100+
- name: Testing Arithmos Calculus (3D Gimbal Rotation around Z-axis)
101+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_3d_z_gimbal_rotation.c" "test_3d_z_gimbal_rotation"
102+
103+
- name: Testing Arithmos Calculus (Matrix Algebra Operations -- mat_product)
104+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_mat_product.c" "test_mat_product"
105+
106+
- name: Testing Arithmos Calculus (Matrix Algebra Operations -- mat_add)
107+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_matrix_addition.c" "test_mat_addition"
108+
109+
- name: Testing Arithmos Calculus (Matrix Algebra Operations -- mat_iterate_elements)
110+
run: sudo ./helper-scripts/ci-cd/test-electrostatic.sh "calculus/test_matrix_iteration.c" "test_mat_traversal"
111+
88112
- name: Compiling electrostatic4j Java Binding API
89113
run: sudo ./helper-scripts/ci-cd/compile-e4j.sh
90114

electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/vectorspaces/vector3d/vector3d.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,28 @@ struct vec3d_polar {
5858
vec_component theta; // angle with +ve direction of xy plane
5959
};
6060

61+
/**
62+
* @brief Defines the encodings for a set of three gimbal axes.
63+
* @note Those encodings are constant numbers; the don't swap orientation
64+
* with one another.
65+
*/
66+
typedef enum {
67+
GIMBAL_X = (INT16_MAX >> 8) ^ INT16_MAX,
68+
GIMBAL_Y = GIMBAL_X - 1,
69+
GIMBAL_Z = GIMBAL_Y - 1
70+
} vector_gimbal;
71+
6172
struct vec3d_processors {
73+
/**
74+
* @brief A function pointer to be called on a gimbal lock trap. A gimbal trap is a
75+
* software trap that is executed when a potential angle that could produce gimbal
76+
* lock is being floating-point approached or reached.
77+
* @param rotated the rotated vector in the R(3) vectorspace.
78+
* @param gimbal the gimbal around which the rotational motion is being executed.
79+
* @param angle the last angle that triggered this gimbal trap
80+
* (it shouldn't have to be PI/2 or -PI/2).
81+
*/
82+
void (*on_gimbal_lock_trap)(vector3d rotated, vector_gimbal gimbal, vec_component angle);
6283
/**
6384
* @brief A function pointer to be called on a successful operation.
6485
* @param caller A void pointer to the original calling context or object.
@@ -79,6 +100,26 @@ extern vector3d VEC3_Y_COMPONENT;
79100

80101
extern vector3d VEC3_Z_COMPONENT;
81102

103+
static inline vector_gimbal get_vec_gimbal(vector3d axis) {
104+
if ((axis.x > ___ROTATION_MIN_THRESHOLD) &&
105+
((axis.y >= 0) && (axis.y < 1)) &&
106+
((axis.z >= 0) && (axis.z < 1))) {
107+
108+
return GIMBAL_X;
109+
} else if ((axis.y > ___ROTATION_MIN_THRESHOLD) &&
110+
((axis.x >= 0) && (axis.x < 1)) &&
111+
((axis.z >= 0) && (axis.z < 1))) {
112+
113+
return GIMBAL_Y;
114+
} else if ((axis.z > ___ROTATION_MIN_THRESHOLD) &&
115+
((axis.y >= 0) && (axis.y < 1)) &&
116+
((axis.x >= 0) && (axis.x < 1))) {
117+
118+
return GIMBAL_Z;
119+
}
120+
return -1;
121+
}
122+
82123
/**
83124
* @brief Adds a scalar value to the vector components and returns a new vector.
84125
*

electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/algorithm/arithmos/vector3d/vec3d_rotate.c

Lines changed: 36 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ struct rotation_metadata {
77
matrix *out_orientation;
88
};
99

10-
typedef enum {
11-
GIMBAL_X = (INT16_MAX >> 8) ^ INT16_MAX,
12-
GIMBAL_Y = GIMBAL_X - 1,
13-
GIMBAL_Z = GIMBAL_Y - 1
14-
} vector_gimbal;
15-
1610
static inline void preprocess_orientator(vector3d *v, vector3d *axis) {
1711

1812
// create a column vector matrix
@@ -60,30 +54,16 @@ static inline status_code __on_entry_iterated(mat_proc_sig proc_sig) {
6054
return PASS;
6155
}
6256

63-
static inline vector_gimbal get_vec_gimbal(vector3d *axis) {
64-
if ((axis->x > ___ROTATION_MIN_THRESHOLD) &&
65-
((axis->y >= 0) && (axis->y < 1)) &&
66-
((axis->z >= 0) && (axis->z < 1))) {
67-
68-
return GIMBAL_X;
69-
} else if ((axis->y > ___ROTATION_MIN_THRESHOLD) &&
70-
((axis->x >= 0) && (axis->x < 1)) &&
71-
((axis->z >= 0) && (axis->z < 1))) {
72-
73-
return GIMBAL_Y;
74-
} else if ((axis->z > ___ROTATION_MIN_THRESHOLD) &&
75-
((axis->y >= 0) && (axis->y < 1)) &&
76-
((axis->x >= 0) && (axis->x < 1))) {
77-
78-
return GIMBAL_Z;
79-
}
80-
return -1;
81-
}
82-
83-
static inline status_code init_rotator_gimbal(vector3d *axis, matrix *__rotator,
57+
static inline status_code init_rotator_gimbal(vector3d axis,
58+
matrix *__rotator,
8459
vec_component angle,
8560
vec_component *angle1,
8661
vec3d_gimbal *gimbal) {
62+
63+
if (NULL == __rotator || NULL == __rotator->element) {
64+
return EUNDEFINEDBUFFER;
65+
}
66+
8767
if (get_vec_gimbal(axis) == GIMBAL_Z) {
8868
// rotate around z-axis
8969
// pre-processing automata
@@ -97,8 +77,10 @@ static inline status_code init_rotator_gimbal(vector3d *axis, matrix *__rotator,
9777
__rotator->element[1][1] = vector2d_cos(angle);
9878
__rotator->element[2][2] = 1;
9979

100-
gimbal->z_gimbal += angle;
101-
*angle1 = gimbal->z_gimbal;
80+
if (NULL != gimbal && NULL != angle1) {
81+
gimbal->z_gimbal += angle;
82+
*angle1 = gimbal->z_gimbal;
83+
}
10284

10385
} else if (get_vec_gimbal(axis) == GIMBAL_Y) {
10486
// rotate around y-axis
@@ -113,8 +95,11 @@ static inline status_code init_rotator_gimbal(vector3d *axis, matrix *__rotator,
11395
__rotator->element[2][2] = vector2d_cos(angle);
11496
__rotator->element[1][1] = 1;
11597

116-
gimbal->y_gimbal += angle;
117-
*angle1 = gimbal->y_gimbal;
98+
if (NULL != gimbal && NULL != angle1) {
99+
gimbal->y_gimbal += angle;
100+
*angle1 = gimbal->y_gimbal;
101+
}
102+
118103
} else if (get_vec_gimbal(axis) == GIMBAL_X) {
119104

120105
// rotate around x-axis
@@ -129,8 +114,11 @@ static inline status_code init_rotator_gimbal(vector3d *axis, matrix *__rotator,
129114
__rotator->element[1][1] = vector2d_cos(angle);
130115
__rotator->element[0][0] = 1;
131116

132-
gimbal->x_gimbal += angle;
133-
*angle1 = gimbal->x_gimbal;
117+
if (NULL != gimbal && NULL != angle1) {
118+
gimbal->x_gimbal += angle;
119+
*angle1 = gimbal->x_gimbal;
120+
}
121+
134122
} else {
135123
return EINCOMPATTYPE;
136124
}
@@ -163,31 +151,19 @@ static inline status_code rotate_about_gimbal(matrix *__rotator,
163151
return PASS;
164152
}
165153

166-
static inline status_code rotate_gimbal(vector3d *axis, vec_component angle1,
154+
static inline status_code rotate_gimbal(vector3d axis, vec_component angle1,
167155
matrix *__rotator,
168156
vec3d_gimbal *in_gimbal,
169157
vec3d_gimbal *out_gimbal,
170158
vec3d_processors *procs) {
171-
if (get_vec_gimbal(axis) == GIMBAL_Z) {
172-
__rotator->element[0][0] = vector2d_cos(angle1);
173-
__rotator->element[0][1] = -vector2d_sin(angle1);
174-
__rotator->element[1][0] = vector2d_sin(angle1);
175-
__rotator->element[1][1] = vector2d_cos(angle1);
176-
__rotator->element[2][2] = 1;
177-
} else if (get_vec_gimbal(axis) == GIMBAL_Y) {
178-
__rotator->element[0][0] = vector2d_cos(angle1);
179-
__rotator->element[0][2] = -vector2d_sin(angle1);
180-
__rotator->element[2][0] = vector2d_sin(angle1);
181-
__rotator->element[2][2] = vector2d_cos(angle1);
182-
__rotator->element[1][1] = 1;
183-
} else if (get_vec_gimbal(axis) == GIMBAL_X) {
184-
__rotator->element[2][2] = vector2d_cos(angle1);
185-
__rotator->element[2][1] = -vector2d_sin(angle1);
186-
__rotator->element[1][2] = vector2d_sin(angle1);
187-
__rotator->element[1][1] = vector2d_cos(angle1);
188-
__rotator->element[0][0] = 1;
189-
} else {
190-
return EINCOMPATTYPE;
159+
160+
status_code __code = init_rotator_gimbal(axis, __rotator, angle1,
161+
NULL, NULL);
162+
if (PASS != __code) {
163+
if (NULL != procs && NULL != procs->on_op_failed) {
164+
procs->on_op_failed(&vec3d_rotate, __code);
165+
}
166+
return __code;
191167
}
192168

193169
// init the output orientation matrix
@@ -204,8 +180,7 @@ static inline status_code rotate_gimbal(vector3d *axis, vec_component angle1,
204180
mat_processors mat_procs = {
205181
};
206182

207-
status_code __code =
208-
mat_product(*__rotator,
183+
__code = mat_product(*__rotator,
209184
*(in_gimbal->orientation),
210185
&__orient, mat_procs);
211186
if (PASS != __code) {
@@ -301,7 +276,7 @@ status_code vec3d_rotate(vector3d v, vector3d axis, vec_component angle,
301276
preprocess_orientator(&v, &axis);
302277
vec3d_abs(axis, &axis, NULL);
303278

304-
__code = init_rotator_gimbal(&axis, &__rotator, angle,
279+
__code = init_rotator_gimbal(axis, &__rotator, angle,
305280
&angle1, &out->gimbal);
306281

307282
if (PASS != __code) {
@@ -323,8 +298,11 @@ status_code vec3d_rotate(vector3d v, vector3d axis, vec_component angle,
323298

324299
if (vector2d_abs(vector2d_cos(angle1)) <= ___ROTATION_MIN_THRESHOLD
325300
&& vector2d_abs(vector2d_sin(angle1)) == 1) {
301+
if (NULL != procs && NULL != procs->on_gimbal_lock_trap) {
302+
procs->on_gimbal_lock_trap(*out, get_vec_gimbal(axis), angle);
303+
}
326304
// rotate the gimbals axes (the orientation)
327-
__code = rotate_gimbal(&axis, angle1, &__rotator,
305+
__code = rotate_gimbal(axis, angle1, &__rotator,
328306
&(v.gimbal),
329307
&out->gimbal, procs);
330308
if (PASS != __code) {
275 KB
Loading
325 KB
Loading
282 KB
Loading

electrostatic-sandbox-framework/electrostatic-examples/src/hello_vector2d.c renamed to electrostatic-sandbox-framework/electrostatic-examples/src/calculus/hello_vector2d.c

File renamed without changes.

0 commit comments

Comments
 (0)