123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Math.h>
- #include <algorithm>
- #include <array>
- #include <initializer_list>
- namespace WwiseGTE
- {
- template <int N, typename Real>
- class Vector
- {
- public:
- // The tuple is uninitialized.
- Vector() = default;
- // The tuple is fully initialized by the inputs.
- Vector(std::array<Real, N> const& values)
- :
- mTuple(values)
- {
- }
- // At most N elements are copied from the initializer list, setting
- // any remaining elements to zero. Create the zero vector using the
- // syntax
- // Vector<N,Real> zero{(Real)0};
- // WARNING: The C++ 11 specification states that
- // Vector<N,Real> zero{};
- // will lead to a call of the default constructor, not the initializer
- // constructor!
- Vector(std::initializer_list<Real> values)
- {
- int const numValues = static_cast<int>(values.size());
- if (N == numValues)
- {
- std::copy(values.begin(), values.end(), mTuple.begin());
- }
- else if (N > numValues)
- {
- std::copy(values.begin(), values.end(), mTuple.begin());
- std::fill(mTuple.begin() + numValues, mTuple.end(), (Real)0);
- }
- else // N < numValues
- {
- std::copy(values.begin(), values.begin() + N, mTuple.begin());
- }
- }
- // For 0 <= d < N, element d is 1 and all others are 0. If d is
- // invalid, the zero vector is created. This is a convenience for
- // creating the standard Euclidean basis vectors; see also
- // MakeUnit(int) and Unit(int).
- Vector(int d)
- {
- MakeUnit(d);
- }
- // The copy constructor, destructor, and assignment operator are
- // generated by the compiler.
- // Member access. The first operator[] returns a const reference
- // rather than a Real value. This supports writing via standard file
- // operations that require a const pointer to data.
- inline int GetSize() const
- {
- return N;
- }
- inline Real const& operator[](int i) const
- {
- return mTuple[i];
- }
- inline Real& operator[](int i)
- {
- return mTuple[i];
- }
- // Comparisons for sorted containers and geometric ordering.
- inline bool operator==(Vector const& vec) const
- {
- return mTuple == vec.mTuple;
- }
- inline bool operator!=(Vector const& vec) const
- {
- return mTuple != vec.mTuple;
- }
- inline bool operator< (Vector const& vec) const
- {
- return mTuple < vec.mTuple;
- }
- inline bool operator<=(Vector const& vec) const
- {
- return mTuple <= vec.mTuple;
- }
- inline bool operator> (Vector const& vec) const
- {
- return mTuple > vec.mTuple;
- }
- inline bool operator>=(Vector const& vec) const
- {
- return mTuple >= vec.mTuple;
- }
- // Special vectors.
- // All components are 0.
- void MakeZero()
- {
- std::fill(mTuple.begin(), mTuple.end(), (Real)0);
- }
- // All components are 1.
- void MakeOnes()
- {
- std::fill(mTuple.begin(), mTuple.end(), (Real)1);
- }
- // Component d is 1, all others are zero.
- void MakeUnit(int d)
- {
- std::fill(mTuple.begin(), mTuple.end(), (Real)0);
- if (0 <= d && d < N)
- {
- mTuple[d] = (Real)1;
- }
- }
- static Vector Zero()
- {
- Vector<N, Real> v;
- v.MakeZero();
- return v;
- }
- static Vector Ones()
- {
- Vector<N, Real> v;
- v.MakeOnes();
- return v;
- }
- static Vector Unit(int d)
- {
- Vector<N, Real> v;
- v.MakeUnit(d);
- return v;
- }
- protected:
- // This data structure takes advantage of the built-in operator[],
- // range checking, and visualizers in MSVS.
- std::array<Real, N> mTuple;
- };
- // Unary operations.
- template <int N, typename Real>
- Vector<N, Real> operator+(Vector<N, Real> const& v)
- {
- return v;
- }
- template <int N, typename Real>
- Vector<N, Real> operator-(Vector<N, Real> const& v)
- {
- Vector<N, Real> result;
- for (int i = 0; i < N; ++i)
- {
- result[i] = -v[i];
- }
- return result;
- }
- // Linear-algebraic operations.
- template <int N, typename Real>
- Vector<N, Real> operator+(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
- {
- Vector<N, Real> result = v0;
- return result += v1;
- }
- template <int N, typename Real>
- Vector<N, Real> operator-(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
- {
- Vector<N, Real> result = v0;
- return result -= v1;
- }
- template <int N, typename Real>
- Vector<N, Real> operator*(Vector<N, Real> const& v, Real scalar)
- {
- Vector<N, Real> result = v;
- return result *= scalar;
- }
- template <int N, typename Real>
- Vector<N, Real> operator*(Real scalar, Vector<N, Real> const& v)
- {
- Vector<N, Real> result = v;
- return result *= scalar;
- }
- template <int N, typename Real>
- Vector<N, Real> operator/(Vector<N, Real> const& v, Real scalar)
- {
- Vector<N, Real> result = v;
- return result /= scalar;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator+=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
- {
- for (int i = 0; i < N; ++i)
- {
- v0[i] += v1[i];
- }
- return v0;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator-=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
- {
- for (int i = 0; i < N; ++i)
- {
- v0[i] -= v1[i];
- }
- return v0;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator*=(Vector<N, Real>& v, Real scalar)
- {
- for (int i = 0; i < N; ++i)
- {
- v[i] *= scalar;
- }
- return v;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator/=(Vector<N, Real>& v, Real scalar)
- {
- if (scalar != (Real)0)
- {
- Real invScalar = (Real)1 / scalar;
- for (int i = 0; i < N; ++i)
- {
- v[i] *= invScalar;
- }
- }
- else
- {
- for (int i = 0; i < N; ++i)
- {
- v[i] = (Real)0;
- }
- }
- return v;
- }
- // Componentwise algebraic operations.
- template <int N, typename Real>
- Vector<N, Real> operator*(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
- {
- Vector<N, Real> result = v0;
- return result *= v1;
- }
- template <int N, typename Real>
- Vector<N, Real> operator/(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
- {
- Vector<N, Real> result = v0;
- return result /= v1;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator*=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
- {
- for (int i = 0; i < N; ++i)
- {
- v0[i] *= v1[i];
- }
- return v0;
- }
- template <int N, typename Real>
- Vector<N, Real>& operator/=(Vector<N, Real>& v0, Vector<N, Real> const& v1)
- {
- for (int i = 0; i < N; ++i)
- {
- v0[i] /= v1[i];
- }
- return v0;
- }
- // Geometric operations. The functions with 'robust' set to 'false' use
- // the standard algorithm for normalizing a vector by computing the length
- // as a square root of the squared length and dividing by it. The results
- // can be infinite (or NaN) if the length is zero. When 'robust' is set
- // to 'true', the algorithm is designed to avoid floating-point overflow
- // and sets the normalized vector to zero when the length is zero.
- template <int N, typename Real>
- Real Dot(Vector<N, Real> const& v0, Vector<N, Real> const& v1)
- {
- Real dot = v0[0] * v1[0];
- for (int i = 1; i < N; ++i)
- {
- dot += v0[i] * v1[i];
- }
- return dot;
- }
- template <int N, typename Real>
- Real Length(Vector<N, Real> const& v, bool robust = false)
- {
- if (robust)
- {
- Real maxAbsComp = std::fabs(v[0]);
- for (int i = 1; i < N; ++i)
- {
- Real absComp = std::fabs(v[i]);
- if (absComp > maxAbsComp)
- {
- maxAbsComp = absComp;
- }
- }
- Real length;
- if (maxAbsComp > (Real)0)
- {
- Vector<N, Real> scaled = v / maxAbsComp;
- length = maxAbsComp * std::sqrt(Dot(scaled, scaled));
- }
- else
- {
- length = (Real)0;
- }
- return length;
- }
- else
- {
- return std::sqrt(Dot(v, v));
- }
- }
- template <int N, typename Real>
- Real Normalize(Vector<N, Real>& v, bool robust = false)
- {
- if (robust)
- {
- Real maxAbsComp = std::fabs(v[0]);
- for (int i = 1; i < N; ++i)
- {
- Real absComp = std::fabs(v[i]);
- if (absComp > maxAbsComp)
- {
- maxAbsComp = absComp;
- }
- }
- Real length;
- if (maxAbsComp > (Real)0)
- {
- v /= maxAbsComp;
- length = std::sqrt(Dot(v, v));
- v /= length;
- length *= maxAbsComp;
- }
- else
- {
- length = (Real)0;
- for (int i = 0; i < N; ++i)
- {
- v[i] = (Real)0;
- }
- }
- return length;
- }
- else
- {
- Real length = std::sqrt(Dot(v, v));
- if (length > (Real)0)
- {
- v /= length;
- }
- else
- {
- for (int i = 0; i < N; ++i)
- {
- v[i] = (Real)0;
- }
- }
- return length;
- }
- }
- // Gram-Schmidt orthonormalization to generate orthonormal vectors from
- // the linearly independent inputs. The function returns the smallest
- // length of the unnormalized vectors computed during the process. If
- // this value is nearly zero, it is possible that the inputs are linearly
- // dependent (within numerical round-off errors). On input,
- // 1 <= numElements <= N and v[0] through v[numElements-1] must be
- // initialized. On output, the vectors v[0] through v[numElements-1]
- // form an orthonormal set.
- template <int N, typename Real>
- Real Orthonormalize(int numInputs, Vector<N, Real>* v, bool robust = false)
- {
- if (v && 1 <= numInputs && numInputs <= N)
- {
- Real minLength = Normalize(v[0], robust);
- for (int i = 1; i < numInputs; ++i)
- {
- for (int j = 0; j < i; ++j)
- {
- Real dot = Dot(v[i], v[j]);
- v[i] -= v[j] * dot;
- }
- Real length = Normalize(v[i], robust);
- if (length < minLength)
- {
- minLength = length;
- }
- }
- return minLength;
- }
- return (Real)0;
- }
- // Construct a single vector orthogonal to the nonzero input vector. If
- // the maximum absolute component occurs at index i, then the orthogonal
- // vector U has u[i] = v[i+1], u[i+1] = -v[i], and all other components
- // zero. The index addition i+1 is computed modulo N.
- template <int N, typename Real>
- Vector<N, Real> GetOrthogonal(Vector<N, Real> const& v, bool unitLength)
- {
- Real cmax = std::fabs(v[0]);
- int imax = 0;
- for (int i = 1; i < N; ++i)
- {
- Real c = std::fabs(v[i]);
- if (c > cmax)
- {
- cmax = c;
- imax = i;
- }
- }
- Vector<N, Real> result;
- result.MakeZero();
- int inext = imax + 1;
- if (inext == N)
- {
- inext = 0;
- }
- result[imax] = v[inext];
- result[inext] = -v[imax];
- if (unitLength)
- {
- Real sqrDistance = result[imax] * result[imax] + result[inext] * result[inext];
- Real invLength = ((Real)1) / std::sqrt(sqrDistance);
- result[imax] *= invLength;
- result[inext] *= invLength;
- }
- return result;
- }
- // Compute the axis-aligned bounding box of the vectors. The return value
- // is 'true' iff the inputs are valid, in which case vmin and vmax have
- // valid values.
- template <int N, typename Real>
- bool ComputeExtremes(int numVectors, Vector<N, Real> const* v,
- Vector<N, Real>& vmin, Vector<N, Real>& vmax)
- {
- if (v && numVectors > 0)
- {
- vmin = v[0];
- vmax = vmin;
- for (int j = 1; j < numVectors; ++j)
- {
- Vector<N, Real> const& vec = v[j];
- for (int i = 0; i < N; ++i)
- {
- if (vec[i] < vmin[i])
- {
- vmin[i] = vec[i];
- }
- else if (vec[i] > vmax[i])
- {
- vmax[i] = vec[i];
- }
- }
- }
- return true;
- }
- return false;
- }
- // Lift n-tuple v to homogeneous (n+1)-tuple (v,last).
- template <int N, typename Real>
- Vector<N + 1, Real> HLift(Vector<N, Real> const& v, Real last)
- {
- Vector<N + 1, Real> result;
- for (int i = 0; i < N; ++i)
- {
- result[i] = v[i];
- }
- result[N] = last;
- return result;
- }
- // Project homogeneous n-tuple v = (u,v[n-1]) to (n-1)-tuple u.
- template <int N, typename Real>
- Vector<N - 1, Real> HProject(Vector<N, Real> const& v)
- {
- static_assert(N >= 2, "Invalid dimension.");
- Vector<N - 1, Real> result;
- for (int i = 0; i < N - 1; ++i)
- {
- result[i] = v[i];
- }
- return result;
- }
- // Lift n-tuple v = (w0,w1) to (n+1)-tuple u = (w0,u[inject],w1). By
- // inference, w0 is a (inject)-tuple [nonexistent when inject=0] and w1 is
- // a (n-inject)-tuple [nonexistent when inject=n].
- template <int N, typename Real>
- Vector<N + 1, Real> Lift(Vector<N, Real> const& v, int inject, Real value)
- {
- Vector<N + 1, Real> result;
- int i;
- for (i = 0; i < inject; ++i)
- {
- result[i] = v[i];
- }
- result[i] = value;
- int j = i;
- for (++j; i < N; ++i, ++j)
- {
- result[j] = v[i];
- }
- return result;
- }
- // Project n-tuple v = (w0,v[reject],w1) to (n-1)-tuple u = (w0,w1). By
- // inference, w0 is a (reject)-tuple [nonexistent when reject=0] and w1 is
- // a (n-1-reject)-tuple [nonexistent when reject=n-1].
- template <int N, typename Real>
- Vector<N - 1, Real> Project(Vector<N, Real> const& v, int reject)
- {
- static_assert(N >= 2, "Invalid dimension.");
- Vector<N - 1, Real> result;
- for (int i = 0, j = 0; i < N - 1; ++i, ++j)
- {
- if (j == reject)
- {
- ++j;
- }
- result[i] = v[j];
- }
- return result;
- }
- }
|