@@ -104,17 +104,29 @@ pbio_geometry_side_t pbio_geometry_side_from_vector(pbio_geometry_xyz_t *vector)
104104 return axis | (negative << 2 );
105105}
106106
107+ /**
108+ * Gets the norm of a vector.
109+ *
110+ * @param [in] input The vector.
111+ * @return The norm of the vector.
112+ */
113+ float pbio_geometry_vector_norm (pbio_geometry_xyz_t * input ) {
114+ return sqrtf (input -> x * input -> x + input -> y * input -> y + input -> z * input -> z );
115+ }
116+
107117/**
108118 * Normalizes a vector so it has unit length.
109119 *
120+ * Output is allowed to be same as input, in which case input is normalized.
121+ *
110122 * @param [in] input The vector to normalize.
111123 * @param [out] output The normalized vector.
112124 * @return ::PBIO_ERROR_INVALID_ARG if the input has zero length, otherwise ::PBIO_SUCCESS.
113125 */
114126pbio_error_t pbio_geometry_vector_normalize (pbio_geometry_xyz_t * input , pbio_geometry_xyz_t * output ) {
115127
116128 // Compute the norm.
117- float norm = sqrtf (input -> x * input -> x + input -> y * input -> y + input -> z * input -> z );
129+ float norm = pbio_geometry_vector_norm (input );
118130
119131 // If the vector norm is zero, do nothing.
120132 if (norm == 0.0f ) {
@@ -176,6 +188,25 @@ void pbio_geometry_vector_map(pbio_geometry_matrix_3x3_t *map, pbio_geometry_xyz
176188 output -> z = input -> x * map -> m31 + input -> y * map -> m32 + input -> z * map -> m33 ;
177189}
178190
191+ /**
192+ * Multiplies two 3x3 matrices.
193+ *
194+ * @param [in] a The first 3x3 matrix.
195+ * @param [in] b The second 3x3 matrix.
196+ * @param [out] output The resulting 3x3 matrix after multiplication.
197+ */
198+ void pbio_geometry_matrix_multiply (pbio_geometry_matrix_3x3_t * a , pbio_geometry_matrix_3x3_t * b , pbio_geometry_matrix_3x3_t * output ) {
199+ output -> m11 = a -> m11 * b -> m11 + a -> m12 * b -> m21 + a -> m13 * b -> m31 ;
200+ output -> m12 = a -> m11 * b -> m12 + a -> m12 * b -> m22 + a -> m13 * b -> m32 ;
201+ output -> m13 = a -> m11 * b -> m13 + a -> m12 * b -> m23 + a -> m13 * b -> m33 ;
202+ output -> m21 = a -> m21 * b -> m11 + a -> m22 * b -> m21 + a -> m23 * b -> m31 ;
203+ output -> m22 = a -> m21 * b -> m12 + a -> m22 * b -> m22 + a -> m23 * b -> m32 ;
204+ output -> m23 = a -> m21 * b -> m13 + a -> m22 * b -> m23 + a -> m23 * b -> m33 ;
205+ output -> m31 = a -> m31 * b -> m11 + a -> m32 * b -> m21 + a -> m33 * b -> m31 ;
206+ output -> m32 = a -> m31 * b -> m12 + a -> m32 * b -> m22 + a -> m33 * b -> m32 ;
207+ output -> m33 = a -> m31 * b -> m13 + a -> m32 * b -> m23 + a -> m33 * b -> m33 ;
208+ }
209+
179210/**
180211 * Gets a mapping (a rotation matrix) from two orthogonal base axes.
181212 *
@@ -216,3 +247,101 @@ pbio_error_t pbio_geometry_map_from_base_axes(pbio_geometry_xyz_t *x_axis, pbio_
216247
217248 return PBIO_SUCCESS ;
218249}
250+
251+ /**
252+ * Computes a rotation matrix for a quaternion.
253+ *
254+ * @param [in] q The quaternion.
255+ * @param [out] R The rotation matrix.
256+ */
257+ void pbio_geometry_quaternion_to_rotation_matrix (pbio_geometry_quaternion_t * q , pbio_geometry_matrix_3x3_t * R ) {
258+ R -> m11 = 1 - 2 * (q -> q2 * q -> q2 + q -> q3 * q -> q3 );
259+ R -> m21 = 2 * (q -> q1 * q -> q2 + q -> q3 * q -> q4 );
260+ R -> m31 = 2 * (q -> q1 * q -> q3 - q -> q2 * q -> q4 );
261+ R -> m12 = 2 * (q -> q1 * q -> q2 - q -> q3 * q -> q4 );
262+ R -> m22 = 1 - 2 * (q -> q1 * q -> q1 + q -> q3 * q -> q3 );
263+ R -> m32 = 2 * (q -> q2 * q -> q3 + q -> q1 * q -> q4 );
264+ R -> m13 = 2 * (q -> q1 * q -> q3 + q -> q2 * q -> q4 );
265+ R -> m23 = 2 * (q -> q2 * q -> q3 - q -> q1 * q -> q4 );
266+ R -> m33 = 1 - 2 * (q -> q1 * q -> q1 + q -> q2 * q -> q2 );
267+ }
268+
269+ /**
270+ * Computes a quaternion from a gravity unit vector.
271+ *
272+ * @param [in] g The gravity unit vector.
273+ * @param [out] q The resulting quaternion.
274+ */
275+ void pbio_geometry_quaternion_from_gravity_unit_vector (pbio_geometry_xyz_t * g , pbio_geometry_quaternion_t * q ) {
276+ if (g -> z >= 0 ) {
277+ q -> q4 = sqrtf ((g -> z + 1 ) / 2 );
278+ q -> q1 = g -> y / sqrtf (2 * (g -> z + 1 ));
279+ q -> q2 = - g -> x / sqrtf (2 * (g -> z + 1 ));
280+ q -> q3 = 0 ;
281+ } else {
282+ q -> q4 = - g -> y / sqrtf (2 * (1 - g -> z ));
283+ q -> q1 = - sqrtf ((1 - g -> z ) / 2 );
284+ q -> q2 = 0 ;
285+ q -> q3 = - g -> x / sqrtf (2 * (1 - g -> z ));
286+ }
287+ }
288+
289+ /**
290+ * Computes the rate of change of a quaternion given the angular velocity vector.
291+ *
292+ * @param [in] q Quaternion of the current orientation.
293+ * @param [in] angular_velocity The angular velocity vector in the body frame.
294+ * @param [out] dq The rate of change of the quaternion.
295+ */
296+ void pbio_geometry_quaternion_get_rate_of_change (pbio_geometry_quaternion_t * q , pbio_geometry_xyz_t * angular_velocity , pbio_geometry_quaternion_t * dq ) {
297+
298+ pbio_geometry_xyz_t w = {
299+ .x = pbio_geometry_degrees_to_radians (angular_velocity -> x ),
300+ .y = pbio_geometry_degrees_to_radians (angular_velocity -> y ),
301+ .z = pbio_geometry_degrees_to_radians (angular_velocity -> z ),
302+ };
303+
304+ dq -> q1 = 0.5f * (w .z * q -> q2 - w .y * q -> q3 + w .x * q -> q4 );
305+ dq -> q2 = 0.5f * (- w .z * q -> q1 + w .x * q -> q3 + w .y * q -> q4 );
306+ dq -> q3 = 0.5f * (w .y * q -> q1 - w .x * q -> q2 + w .z * q -> q4 );
307+ dq -> q4 = 0.5f * (- w .x * q -> q1 - w .y * q -> q2 - w .z * q -> q3 );
308+ }
309+
310+ /**
311+ * Normalizes a quaternion so it has unit length.
312+ *
313+ * @param [inout] q The quaternion to normalize.
314+ */
315+ void pbio_geometry_quaternion_normalize (pbio_geometry_quaternion_t * q ) {
316+ float norm = sqrtf (q -> q1 * q -> q1 + q -> q2 * q -> q2 + q -> q3 * q -> q3 + q -> q4 * q -> q4 );
317+
318+ if (norm < 0.0001f && norm > -0.0001f ) {
319+ return ;
320+ }
321+
322+ q -> q1 /= norm ;
323+ q -> q2 /= norm ;
324+ q -> q3 /= norm ;
325+ q -> q4 /= norm ;
326+ }
327+
328+ /**
329+ * Returns the maximum of two floating-point numbers.
330+ *
331+ * @param a The first floating-point number.
332+ * @param b The second floating-point number.
333+ * @return The maximum of the two floating-point numbers.
334+ */
335+ float pbio_geometry_maxf (float a , float b ) {
336+ return a > b ? a : b ;
337+ }
338+
339+ /**
340+ * Returns the absolute value of a floating-point number.
341+ *
342+ * @param a The floating-point number.
343+ * @return The absolute value of the floating-point number.
344+ */
345+ float pbio_geometry_absf (float a ) {
346+ return a < 0 ? - a : a ;
347+ }
0 commit comments