From 7b09710392d35fb55b52031d447a542d99fc6b4b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 19 Aug 2014 17:10:03 -0400 Subject: Modularize the libdimension codebase. --- libdimension/dimension/math/aabb.h | 129 +++++++++++++++++++++++ libdimension/dimension/math/matrix.h | 193 +++++++++++++++++++++++++++++++++++ libdimension/dimension/math/ray.h | 83 +++++++++++++++ libdimension/dimension/math/scalar.h | 103 +++++++++++++++++++ libdimension/dimension/math/vector.h | 183 +++++++++++++++++++++++++++++++++ 5 files changed, 691 insertions(+) create mode 100644 libdimension/dimension/math/aabb.h create mode 100644 libdimension/dimension/math/matrix.h create mode 100644 libdimension/dimension/math/ray.h create mode 100644 libdimension/dimension/math/scalar.h create mode 100644 libdimension/dimension/math/vector.h (limited to 'libdimension/dimension/math') diff --git a/libdimension/dimension/math/aabb.h b/libdimension/dimension/math/aabb.h new file mode 100644 index 0000000..14cc575 --- /dev/null +++ b/libdimension/dimension/math/aabb.h @@ -0,0 +1,129 @@ +/************************************************************************* + * Copyright (C) 2009-2014 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Axis-aligned bounding boxes. + */ + +#ifndef DMNSN_MATH_H +#error "Please include instead of this header directly." +#endif + +/** An axis-aligned bounding box. */ +typedef struct dmnsn_aabb { + dmnsn_vector min; /**< The coordinate-wise minimum extent of the box. */ + dmnsn_vector max; /**< The coordinate-wise maximum extent of the box. */ +} dmnsn_aabb; + +/** A standard format string for bounding boxes. */ +#define DMNSN_AABB_FORMAT "(<%g, %g, %g> ==> <%g, %g, %g>)" +/** The appropriate arguements to printf() a bounding box. */ +#define DMNSN_AABB_PRINTF(box) \ + DMNSN_VECTOR_PRINTF((box).min), DMNSN_VECTOR_PRINTF((box).max) + +/** + * Construct a new bounding box. + * @param[in] min The minimal extent of the bounding box. + * @param[in] max The maximal extent of the bounding box. + * @return The new bounding box. + */ +DMNSN_INLINE dmnsn_aabb +dmnsn_new_aabb(dmnsn_vector min, dmnsn_vector max) +{ + dmnsn_aabb box = { min, max }; + return box; +} + +/** Return the bounding box which contains nothing. */ +DMNSN_INLINE dmnsn_aabb +dmnsn_zero_aabb(void) +{ + dmnsn_aabb box = { + { DMNSN_INFINITY, DMNSN_INFINITY, DMNSN_INFINITY }, + { -DMNSN_INFINITY, -DMNSN_INFINITY, -DMNSN_INFINITY } + }; + return box; +} + +/** Return the bounding box which contains everything. */ +DMNSN_INLINE dmnsn_aabb +dmnsn_infinite_aabb(void) +{ + dmnsn_aabb box = { + { -DMNSN_INFINITY, -DMNSN_INFINITY, -DMNSN_INFINITY }, + { DMNSN_INFINITY, DMNSN_INFINITY, DMNSN_INFINITY } + }; + return box; +} + +/** + * Construct a new symmetric bounding box. + * @param[in] r The extent of the bounding box from the origin. + * @return The new bounding box. + */ +DMNSN_INLINE dmnsn_aabb +dmnsn_symmetric_aabb(dmnsn_vector r) +{ + dmnsn_vector minus_r = dmnsn_vector_negate(r); + dmnsn_aabb box = { + dmnsn_vector_min(r, minus_r), + dmnsn_vector_max(r, minus_r) + }; + return box; +} + +/** Return whether \p p is within the axis-aligned bounding box. */ +DMNSN_INLINE bool +dmnsn_aabb_contains(dmnsn_aabb box, dmnsn_vector p) +{ + return (p.x >= box.min.x && p.y >= box.min.y && p.z >= box.min.z) + && (p.x <= box.max.x && p.y <= box.max.y && p.z <= box.max.z); +} + +/** Return whether a bounding box is infinite. */ +DMNSN_INLINE bool +dmnsn_aabb_is_infinite(dmnsn_aabb box) +{ + return box.min.x == -DMNSN_INFINITY; +} + +/** + * Expand a bounding box to contain a point + * @param[in] box The bounding box to expand. + * @param[in] point The point to swallow. + * @return The expanded bounding box. + */ +DMNSN_INLINE dmnsn_aabb +dmnsn_aabb_swallow(dmnsn_aabb box, dmnsn_vector point) +{ + dmnsn_aabb ret = { + dmnsn_vector_min(box.min, point), + dmnsn_vector_max(box.max, point) + }; + return ret; +} + +/** Return whether a bounding box has any NaN components. */ +DMNSN_INLINE bool +dmnsn_aabb_isnan(dmnsn_aabb box) +{ + return dmnsn_vector_isnan(box.min) || dmnsn_vector_isnan(box.max); +} diff --git a/libdimension/dimension/math/matrix.h b/libdimension/dimension/math/matrix.h new file mode 100644 index 0000000..7471bf5 --- /dev/null +++ b/libdimension/dimension/math/matrix.h @@ -0,0 +1,193 @@ +/************************************************************************* + * Copyright (C) 2009-2014 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Affine transformation matrices. + */ + +#ifndef DMNSN_MATH_H +#error "Please include instead of this header directly." +#endif + +/** A 4x4 affine transformation matrix, with implied [0 0 0 1] bottom row. */ +typedef struct dmnsn_matrix { + double n[3][4]; /**< The matrix elements in row-major order. */ +} dmnsn_matrix; + +/** A standard format string for matricies. */ +#define DMNSN_MATRIX_FORMAT \ + "[%g\t%g\t%g\t%g]\n" \ + "[%g\t%g\t%g\t%g]\n" \ + "[%g\t%g\t%g\t%g]\n" \ + "[%g\t%g\t%g\t%g]" +/** The appropriate arguements to printf() a matrix. */ +#define DMNSN_MATRIX_PRINTF(m) \ + (m).n[0][0], (m).n[0][1], (m).n[0][2], (m).n[0][3], \ + (m).n[1][0], (m).n[1][1], (m).n[1][2], (m).n[1][3], \ + (m).n[2][0], (m).n[2][1], (m).n[2][2], (m).n[2][3], \ + 0.0, 0.0, 0.0, 1.0 + +/** Construct a new transformation matrix. */ +DMNSN_INLINE dmnsn_matrix +dmnsn_new_matrix(double a0, double a1, double a2, double a3, + double b0, double b1, double b2, double b3, + double c0, double c1, double c2, double c3) +{ + dmnsn_matrix m = { { { a0, a1, a2, a3 }, + { b0, b1, b2, b3 }, + { c0, c1, c2, c3 } } }; + return m; +} + +/** Construct a new transformation matrix from column vectors. */ +DMNSN_INLINE dmnsn_matrix +dmnsn_new_matrix4(dmnsn_vector a, dmnsn_vector b, dmnsn_vector c, + dmnsn_vector d) +{ + dmnsn_matrix m = { { { a.x, b.x, c.x, d.x }, + { a.y, b.y, c.y, d.y }, + { a.z, b.z, c.z, d.z } } }; + return m; +} + +/** Extract column vectors from a matrix. */ +DMNSN_INLINE dmnsn_vector +dmnsn_matrix_column(dmnsn_matrix M, unsigned int i) +{ + return dmnsn_new_vector(M.n[0][i], M.n[1][i], M.n[2][i]); +} + +/** Return the identity matrix. */ +dmnsn_matrix dmnsn_identity_matrix(void); + +/** + * A scale transformation. + * @param[in] s A vector with components representing the scaling factor in + * each axis. + * @return The transformation matrix. + */ +dmnsn_matrix dmnsn_scale_matrix(dmnsn_vector s); +/** + * A translation. + * @param[in] d The vector to translate by. + * @return The transformation matrix. + */ +dmnsn_matrix dmnsn_translation_matrix(dmnsn_vector d); +/** + * A left-handed rotation. + * @param[in] theta A vector representing an axis and angle. + * @f$ axis = \vec{\theta}/|\vec{\theta}| @f$, + * @f$ angle = |\vec{\theta}| @f$ + * @return The transformation matrix. + */ +dmnsn_matrix dmnsn_rotation_matrix(dmnsn_vector theta); + +/** + * An alignment matrix. + * @param[in] from The initial vector. + * @param[in] to The desired direction. + * @param[in] axis1 The first axis about which to rotate. + * @param[in] axis2 The second axis about which to rotate. + * @return A transformation matrix that will rotate \p from to \p to. + */ +dmnsn_matrix dmnsn_alignment_matrix(dmnsn_vector from, dmnsn_vector to, + dmnsn_vector axis1, dmnsn_vector axis2); + +/** Invert a matrix. */ +dmnsn_matrix dmnsn_matrix_inverse(dmnsn_matrix A); + +/** Multiply two matricies. */ +dmnsn_matrix dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs); + +/** Transform a point by a matrix. */ +DMNSN_INLINE dmnsn_vector +dmnsn_transform_point(dmnsn_matrix T, dmnsn_vector v) +{ + /* 9 multiplications, 9 additions */ + dmnsn_vector r; + r.x = T.n[0][0]*v.x + T.n[0][1]*v.y + T.n[0][2]*v.z + T.n[0][3]; + r.y = T.n[1][0]*v.x + T.n[1][1]*v.y + T.n[1][2]*v.z + T.n[1][3]; + r.z = T.n[2][0]*v.x + T.n[2][1]*v.y + T.n[2][2]*v.z + T.n[2][3]; + return r; +} + +/** Transform a direction by a matrix. */ +DMNSN_INLINE dmnsn_vector +dmnsn_transform_direction(dmnsn_matrix T, dmnsn_vector v) +{ + /* 9 multiplications, 6 additions */ + dmnsn_vector r; + r.x = T.n[0][0]*v.x + T.n[0][1]*v.y + T.n[0][2]*v.z; + r.y = T.n[1][0]*v.x + T.n[1][1]*v.y + T.n[1][2]*v.z; + r.z = T.n[2][0]*v.x + T.n[2][1]*v.y + T.n[2][2]*v.z; + return r; +} + +/** + * Transform a pseudovector by a matrix. + * @param[in] Tinv The inverse of the transformation matrix. + * @param[in] v The pseudovector to transform + * @return The transformed pseudovector. + */ +DMNSN_INLINE dmnsn_vector +dmnsn_transform_normal(dmnsn_matrix Tinv, dmnsn_vector v) +{ + /* Multiply by the transpose of the inverse + (9 multiplications, 6 additions) */ + dmnsn_vector r; + r.x = Tinv.n[0][0]*v.x + Tinv.n[1][0]*v.y + Tinv.n[2][0]*v.z; + r.y = Tinv.n[0][1]*v.x + Tinv.n[1][1]*v.y + Tinv.n[2][1]*v.z; + r.z = Tinv.n[0][2]*v.x + Tinv.n[1][2]*v.y + Tinv.n[2][2]*v.z; + return r; +} + +/** + * Transform a ray by a matrix. + * \f$ n' = T(l.\vec{x_0} + l.\vec{n}) - T(l.\vec{x_0}) \f$, + * \f$ \vec{x_0}' = T(l.\vec{x_0}) \f$ + */ +DMNSN_INLINE dmnsn_ray +dmnsn_transform_ray(dmnsn_matrix T, dmnsn_ray l) +{ + /* 18 multiplications, 15 additions */ + dmnsn_ray ret; + ret.x0 = dmnsn_transform_point(T, l.x0); + ret.n = dmnsn_transform_direction(T, l.n); + return ret; +} + +/** Transform a bounding box by a matrix. */ +dmnsn_aabb dmnsn_transform_aabb(dmnsn_matrix T, dmnsn_aabb box); + +/** Return whether a matrix contains any NaN components. */ +DMNSN_INLINE bool +dmnsn_matrix_isnan(dmnsn_matrix m) +{ + size_t i, j; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 4; ++j) { + if (dmnsn_isnan(m.n[i][j])) { + return true; + } + } + } + return false; +} diff --git a/libdimension/dimension/math/ray.h b/libdimension/dimension/math/ray.h new file mode 100644 index 0000000..1dd98f7 --- /dev/null +++ b/libdimension/dimension/math/ray.h @@ -0,0 +1,83 @@ +/************************************************************************* + * Copyright (C) 2009-2014 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Lines in 3-D space. + */ + +#ifndef DMNSN_MATH_H +#error "Please include instead of this header directly." +#endif + +/** A line, or ray. */ +typedef struct dmnsn_ray { + dmnsn_vector x0; /**< The origin of the ray. */ + dmnsn_vector n; /**< The direction of the ray. */ +} dmnsn_ray; + +/** A standard format string for rays. */ +#define DMNSN_RAY_FORMAT "(<%g, %g, %g> + t*<%g, %g, %g>)" +/** The appropriate arguements to printf() a ray. */ +#define DMNSN_RAY_PRINTF(l) \ + DMNSN_VECTOR_PRINTF((l).x0), DMNSN_VECTOR_PRINTF((l).n) + +/** + * Construct a new ray. + * @param[in] x0 The origin of the ray. + * @param[in] n The direction of the ray. + * @return The new ray. + */ +DMNSN_INLINE dmnsn_ray +dmnsn_new_ray(dmnsn_vector x0, dmnsn_vector n) +{ + dmnsn_ray l = { x0, n }; + return l; +} + +/** + * Return the point at \p t on a ray. + * The point is defined by \f$ l.\vec{x_0} + t \cdot l.\vec{n} \f$ + */ +DMNSN_INLINE dmnsn_vector +dmnsn_ray_point(dmnsn_ray l, double t) +{ + return dmnsn_vector_add(l.x0, dmnsn_vector_mul(t, l.n)); +} + +/** Add epsilon*l.n to l.x0, to avoid self-intersections. */ +DMNSN_INLINE dmnsn_ray +dmnsn_ray_add_epsilon(dmnsn_ray l) +{ + return dmnsn_new_ray( + dmnsn_vector_add( + l.x0, + dmnsn_vector_mul(1.0e3*dmnsn_epsilon, l.n) + ), + l.n + ); +} + +/** Return whether a ray contains any NaN entries. */ +DMNSN_INLINE bool +dmnsn_ray_isnan(dmnsn_ray l) +{ + return dmnsn_vector_isnan(l.x0) || dmnsn_vector_isnan(l.n); +} diff --git a/libdimension/dimension/math/scalar.h b/libdimension/dimension/math/scalar.h new file mode 100644 index 0000000..3887c14 --- /dev/null +++ b/libdimension/dimension/math/scalar.h @@ -0,0 +1,103 @@ +/************************************************************************* + * Copyright (C) 2009-2014 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Mathematical functions of one variable. + */ + +#ifndef DMNSN_MATH_H +#error "Please include instead of this header directly." +#endif + +#include +#include + +/** The smallest value considered non-zero by some numerical algorithms. */ +#define dmnsn_epsilon 1.0e-10 + +/** + * @def DMNSN_INFINITY + * Expands to floating-point infinity. + */ +#if defined(INFINITY) || DMNSN_C99 + #define DMNSN_INFINITY INFINITY +#else + #define DMNSN_INFINITY HUGE_VAL +#endif + +/** Find the minimum of two values. */ +DMNSN_INLINE double +dmnsn_min(double a, double b) +{ + return a < b ? a : b; +} + +/** Find the maximum of two values. */ +DMNSN_INLINE double +dmnsn_max(double a, double b) +{ + return a > b ? a : b; +} + +/** Clamp a value to an interval. */ +DMNSN_INLINE double +dmnsn_clamp(double n, double min, double max) +{ + return dmnsn_min(dmnsn_max(n, min), max); +} + +/** Convert degrees to radians. */ +DMNSN_INLINE double +dmnsn_radians(double degrees) +{ + return degrees*(atan(1.0)/45.0); +} + +/** Convert radians to degrees. */ +DMNSN_INLINE double +dmnsn_degrees(double radians) +{ + return radians*(45.0/atan(1.0)); +} + +/** Signum function: return the sign of a value. */ +DMNSN_INLINE int +dmnsn_sgn(double n) +{ + if (n > 0.0) { + return 1; + } else if (n < 0.0) { + return -1; + } else { + return 0; + } +} + +/** Return whether a value is NaN. */ +DMNSN_INLINE bool +dmnsn_isnan(double n) +{ +#if DMNSN_C99 + return isnan(n); +#else + return n != n; +#endif +} diff --git a/libdimension/dimension/math/vector.h b/libdimension/dimension/math/vector.h new file mode 100644 index 0000000..8eacee9 --- /dev/null +++ b/libdimension/dimension/math/vector.h @@ -0,0 +1,183 @@ +/************************************************************************* + * Copyright (C) 2009-2014 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Vectors in 3-D space. + */ + +#ifndef DMNSN_MATH_H +#error "Please include instead of this header directly." +#endif + +#include +#include + +/** A vector in 3 dimensions. */ +typedef struct dmnsn_vector { + double x; /**< The x component. */ + double y; /**< The y component. */ + double z; /**< The z component. */ +} dmnsn_vector; + +/** A standard format string for vectors. */ +#define DMNSN_VECTOR_FORMAT "<%g, %g, %g>" +/** The appropriate arguements to printf() a vector. */ +#define DMNSN_VECTOR_PRINTF(v) (v).x, (v).y, (v).z + +/* Constants */ + +/** The zero vector. */ +static const dmnsn_vector dmnsn_zero = { 0.0, 0.0, 0.0 }; +/** The x vector. */ +static const dmnsn_vector dmnsn_x = { 1.0, 0.0, 0.0 }; +/** The y vector. */ +static const dmnsn_vector dmnsn_y = { 0.0, 1.0, 0.0 }; +/** The z vector. */ +static const dmnsn_vector dmnsn_z = { 0.0, 0.0, 1.0 }; + +/* Shorthand for vector construction */ + +/** Construct a new vector. */ +DMNSN_INLINE dmnsn_vector +dmnsn_new_vector(double x, double y, double z) +{ + dmnsn_vector v = { x, y, z }; + return v; +} + +/* Vector arithmetic */ + +/** Negate a vector. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_negate(dmnsn_vector rhs) +{ + /* 3 negations */ + dmnsn_vector v = { -rhs.x, -rhs.y, -rhs.z }; + return v; +} + +/** Add two vectors. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) +{ + /* 3 additions */ + dmnsn_vector v = { lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z }; + return v; +} + +/** Subtract two vectors. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) +{ + /* 3 additions */ + dmnsn_vector v = { lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z }; + return v; +} + +/** Multiply a vector by a scalar. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_mul(double lhs, dmnsn_vector rhs) +{ + /* 3 multiplications */ + dmnsn_vector v = { lhs*rhs.x, lhs*rhs.y, lhs*rhs.z }; + return v; +} + +/** Divide a vector by a scalar. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_div(dmnsn_vector lhs, double rhs) +{ + /* 3 divisions */ + dmnsn_vector v = { lhs.x/rhs, lhs.y/rhs, lhs.z/rhs }; + return v; +} + +/** Return the dot product of two vectors. */ +DMNSN_INLINE double +dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs) +{ + /* 3 multiplications, 2 additions */ + return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; +} + +/** Return the cross product of two vectors. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) +{ + /* 6 multiplications, 3 additions */ + dmnsn_vector v = { lhs.y*rhs.z - lhs.z*rhs.y, + lhs.z*rhs.x - lhs.x*rhs.z, + lhs.x*rhs.y - lhs.y*rhs.x }; + return v; +} + +/** Return the projection of \p u onto \p d. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_proj(dmnsn_vector u, dmnsn_vector d) +{ + /* 1 division, 9 multiplications, 4 additions */ + return dmnsn_vector_mul(dmnsn_vector_dot(u, d)/dmnsn_vector_dot(d, d), d); +} + +/** Return the magnitude of a vector. */ +DMNSN_INLINE double +dmnsn_vector_norm(dmnsn_vector n) +{ + /* 1 sqrt, 3 multiplications, 2 additions */ + return sqrt(dmnsn_vector_dot(n, n)); +} + +/** Return the direction of a vector. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_normalized(dmnsn_vector n) +{ + /* 1 sqrt, 3 divisions, 3 multiplications, 2 additions */ + return dmnsn_vector_div(n, dmnsn_vector_norm(n)); +} + +/** Return the component-wise minimum of two vectors. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_min(dmnsn_vector a, dmnsn_vector b) +{ + return dmnsn_new_vector( + dmnsn_min(a.x, b.x), + dmnsn_min(a.y, b.y), + dmnsn_min(a.z, b.z) + ); +} + +/** Return the component-wise maximum of two vectors. */ +DMNSN_INLINE dmnsn_vector +dmnsn_vector_max(dmnsn_vector a, dmnsn_vector b) +{ + return dmnsn_new_vector( + dmnsn_max(a.x, b.x), + dmnsn_max(a.y, b.y), + dmnsn_max(a.z, b.z) + ); +} + +/** Return whether a vector contains any NaN components. */ +DMNSN_INLINE bool +dmnsn_vector_isnan(dmnsn_vector v) +{ + return dmnsn_isnan(v.x) || dmnsn_isnan(v.y) || dmnsn_isnan(v.z); +} -- cgit v1.2.3