//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2013 Ceetron AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: // // GNU General Public License Usage // This library is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This 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 General Public License at <> // for more details. // // GNU Lesser General Public License Usage // This 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 2.1 of the License, or // (at your option) any later version. // // This 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 at <> // for more details. // //################################################################################################## namespace cvf { //================================================================================================== /// /// \class cvf::Vector3 /// \ingroup Core /// /// Templated vector class for a 3 component vector. /// /// Three ready-to-use typedefs are defined:\n /// - cvf::Vec3f (Vector3) /// - cvf::Vec3d (Vector3) /// - cvf::Vec3i (Vector3) /// //================================================================================================== template Vector3 const Vector3::X_AXIS(1,0,0); template Vector3 const Vector3::Y_AXIS(0,1,0); template Vector3 const Vector3::Z_AXIS(0,0,1); template Vector3 const Vector3::ZERO(0,0,0); //-------------------------------------------------------------------------------------------------- /// Set the vector to //-------------------------------------------------------------------------------------------------- template Vector3::Vector3(S x, S y, S z) { m_v[0] = x; m_v[1] = y; m_v[2] = z; } //-------------------------------------------------------------------------------------------------- /// Set the vector to the same as other //-------------------------------------------------------------------------------------------------- template Vector3::Vector3(const Vector3& other) { *this = other; } //-------------------------------------------------------------------------------------------------- /// An explicit cast constructor to convert from one vector type to another. //-------------------------------------------------------------------------------------------------- template template Vector3::Vector3(const T& other) { m_v[0] = static_cast(other.x()); m_v[1] = static_cast(other.y()); m_v[2] = static_cast(other.z()); } //-------------------------------------------------------------------------------------------------- /// Explicit constructor from 2D vector. /// /// Will initialize x and y components from the 2D vector, z will be set to 0. //-------------------------------------------------------------------------------------------------- template Vector3::Vector3(const Vector2& other) { m_v[0] = other.x(); m_v[1] = other.y(); m_v[2] = 0.0; } //-------------------------------------------------------------------------------------------------- /// Constructor //-------------------------------------------------------------------------------------------------- template Vector3::Vector3(const Vector2& other, S z) { m_v[0] = other.x(); m_v[1] = other.y(); m_v[2] = z; } //-------------------------------------------------------------------------------------------------- /// Assign the vector to the contents of other //-------------------------------------------------------------------------------------------------- template Vector3& Vector3::operator=(const Vector3& other) { m_v[0] = other.m_v[0]; m_v[1] = other.m_v[1]; m_v[2] = other.m_v[2]; return *this; } //-------------------------------------------------------------------------------------------------- /// Check if two vectors are equal. An exact match is required. //-------------------------------------------------------------------------------------------------- template bool Vector3::equals(const Vector3& other) const { return (*this == other); } //-------------------------------------------------------------------------------------------------- /// Check if two vectors are equal. An exact match is required. //-------------------------------------------------------------------------------------------------- template inline bool Vector3::operator==(const Vector3& rhs) const { return (m_v[0] == rhs.m_v[0]) && (m_v[1] == rhs.m_v[1]) && (m_v[2] == rhs.m_v[2]); } //-------------------------------------------------------------------------------------------------- /// Check if two vectors are different. Returns true if not an exact match //-------------------------------------------------------------------------------------------------- template inline bool Vector3::operator!=(const Vector3& rhs) const { return !operator==(rhs); } //-------------------------------------------------------------------------------------------------- /// Adds the vector \a other to this vector //-------------------------------------------------------------------------------------------------- template void cvf::Vector3::add(const Vector3& other) { (*this) += other; } //-------------------------------------------------------------------------------------------------- /// Subtracts the vector \a other from this vector //-------------------------------------------------------------------------------------------------- template void cvf::Vector3::subtract(const Vector3& other) { (*this) -= other; } //-------------------------------------------------------------------------------------------------- /// Returns the sum of this vector and the rhs vector //-------------------------------------------------------------------------------------------------- template inline const Vector3 Vector3::operator+(const Vector3& rhs) const { return Vector3(m_v[0]+rhs.m_v[0], m_v[1]+rhs.m_v[1], m_v[2]+rhs.m_v[2]); } //-------------------------------------------------------------------------------------------------- /// Compute this-rhs and return the result. //-------------------------------------------------------------------------------------------------- template inline const Vector3 Vector3::operator-(const Vector3& rhs) const { return Vector3(m_v[0] - rhs.m_v[0], m_v[1] - rhs.m_v[1], m_v[2] - rhs.m_v[2]); } //-------------------------------------------------------------------------------------------------- /// Scale this vector by the given scalar //-------------------------------------------------------------------------------------------------- template void Vector3::scale(S scalar) { (*this) *= scalar; } //-------------------------------------------------------------------------------------------------- /// Return this vector scaled by the given scalar //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::operator*(S scalar) const { return Vector3(m_v[0]*scalar, m_v[1]*scalar, m_v[2]*scalar); } //-------------------------------------------------------------------------------------------------- /// Return vector scaled by the given scalar //-------------------------------------------------------------------------------------------------- template const Vector3 operator*(T scalar, const Vector3& rhs) { // Note that this is a friend function return Vector3(rhs.m_v[0]*scalar, rhs.m_v[1]*scalar, rhs.m_v[2]*scalar); } //-------------------------------------------------------------------------------------------------- /// Return a vector where each component is the corresponding component in this divided by scalar //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::operator/(S scalar) const { return Vector3(m_v[0]/scalar, m_v[1]/scalar, m_v[2]/scalar); } //-------------------------------------------------------------------------------------------------- /// Return a vector which is the negation of this //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::operator-() const { return Vector3(-m_v[0], -m_v[1], -m_v[2]); } //-------------------------------------------------------------------------------------------------- /// Add the given vector to this //-------------------------------------------------------------------------------------------------- template inline Vector3& Vector3::operator+=(const Vector3& v) { m_v[0] += v.x(); m_v[1] += v.y(); m_v[2] += v.z(); return *this; } //-------------------------------------------------------------------------------------------------- /// Subtract the given vector from this //-------------------------------------------------------------------------------------------------- template inline Vector3& Vector3::operator-=(const Vector3& v) { m_v[0] -= v.x(); m_v[1] -= v.y(); m_v[2] -= v.z(); return *this; } //-------------------------------------------------------------------------------------------------- /// Scale this with the given scalar. Each component is multiplied with the given value //-------------------------------------------------------------------------------------------------- template inline Vector3& Vector3::operator*=(S scalar) { m_v[0] *= scalar; m_v[1] *= scalar; m_v[2] *= scalar; return *this; } //-------------------------------------------------------------------------------------------------- /// Divide this with the given scalar. Each component is divided by the given scalar //-------------------------------------------------------------------------------------------------- template inline Vector3& Vector3::operator/=(S scalar) { m_v[0] /= scalar; m_v[1] /= scalar; m_v[2] /= scalar; return *this; } //-------------------------------------------------------------------------------------------------- /// Get component 0,1,2. E.g. x = v[0]; //-------------------------------------------------------------------------------------------------- template inline const S& Vector3::operator[](int index) const { CVF_TIGHT_ASSERT(index >= 0); CVF_TIGHT_ASSERT(index < 3); return m_v[index]; } //-------------------------------------------------------------------------------------------------- /// Set component 0,1,2. E.g. v[0] = x; //-------------------------------------------------------------------------------------------------- template inline S& Vector3::operator[](int index) { CVF_TIGHT_ASSERT(index >= 0); CVF_TIGHT_ASSERT(index < 3); return m_v[index]; } //-------------------------------------------------------------------------------------------------- /// Compute the dot product of this and \a other //-------------------------------------------------------------------------------------------------- template S Vector3::dot(const Vector3& other) const { return (*this)*other; } //-------------------------------------------------------------------------------------------------- /// Compute the dot product of this and rhs and return the result (scalar) /// /// Formula: /// \code /// S = tx*rx + ty*ry + tz*rz /// \endcode //-------------------------------------------------------------------------------------------------- template inline S Vector3::operator*(const Vector3& rhs) const { return m_v[0]*rhs.m_v[0] + m_v[1]*rhs.m_v[1] + m_v[2]*rhs.m_v[2]; } //-------------------------------------------------------------------------------------------------- /// Sets this vector to the cross product of vectors \a v1 and \a v2 //-------------------------------------------------------------------------------------------------- template void cvf::Vector3::cross(const Vector3& v1, const Vector3& v2) { *this = v1 ^ v2; } //-------------------------------------------------------------------------------------------------- /// Compute the cross product of this and rhs and return the result (vector) /// /// Formula: /// \code /// vec = /// \endcode //-------------------------------------------------------------------------------------------------- template inline const Vector3 Vector3::operator^(const Vector3& rhs) const { return Vector3(m_v[1]*rhs.m_v[2] - m_v[2]*rhs.m_v[1], m_v[2]*rhs.m_v[0] - m_v[0]*rhs.m_v[2], m_v[0]*rhs.m_v[1] - m_v[1]*rhs.m_v[0]); } //-------------------------------------------------------------------------------------------------- /// Set the vector from the other vector (of different type). Cast each component to convert it. //-------------------------------------------------------------------------------------------------- template template void Vector3::set(const T& other) { m_v[0] = static_cast(other.x()); m_v[1] = static_cast(other.y()); m_v[2] = static_cast(other.z()); } //-------------------------------------------------------------------------------------------------- /// Get the length of the vector /// /// Formula: /// \code /// len = sqrt(x*x + y*y + z*z) /// \endcode //-------------------------------------------------------------------------------------------------- template inline S Vector3::length() const { return Math::sqrt(m_v[0]*m_v[0] + m_v[1]*m_v[1] + m_v[2]*m_v[2]); } //-------------------------------------------------------------------------------------------------- /// Get the squared length (L2) of the vector /// /// Formula: /// \code /// len = x*x + y*y + z*z /// \endcode //-------------------------------------------------------------------------------------------------- template inline S Vector3::lengthSquared() const { return m_v[0]*m_v[0] + m_v[1]*m_v[1] + m_v[2]*m_v[2]; } //-------------------------------------------------------------------------------------------------- /// Set the length of the vector to \a newLength. /// /// \return The method returns true if scaling was a success. Returns false if the vector was of /// zero length and \a newLength was different from 0. /// /// This is the same as calling normalize() and then scaling with \a newLength. /// If the current vector length is 0 or \a newLength is 0, the vector is set to all zeros. //-------------------------------------------------------------------------------------------------- template bool Vector3::setLength(S newLength) { CVF_ASSERT(newLength >= 0); S currLen = length(); if (currLen > std::numeric_limits::epsilon() && newLength > 0) { S scale = newLength/currLen; m_v[0] *= scale; m_v[1] *= scale; m_v[2] *= scale; return true; } else { setZero(); return (newLength == 0) ? true : false; } } //-------------------------------------------------------------------------------------------------- /// Get the distance between this point and the point specified in \a otherPoint //-------------------------------------------------------------------------------------------------- template inline S Vector3::pointDistance(const Vector3& otherPoint) const { return Math::sqrt(pointDistanceSquared(otherPoint)); } //-------------------------------------------------------------------------------------------------- /// Get the squared distance between this point and the point specified in \a otherPoint //-------------------------------------------------------------------------------------------------- template inline S Vector3::pointDistanceSquared(const Vector3& otherPoint) const { S x = otherPoint.m_v[0] - m_v[0]; S y = otherPoint.m_v[1] - m_v[1]; S z = otherPoint.m_v[2] - m_v[2]; return (x*x + y*y + z*z); } //-------------------------------------------------------------------------------------------------- /// Normalize the vector (make sure the length is 1.0). /// /// \return Returns true if normalization was possible. Returns false if length is zero or a NaN vector. //-------------------------------------------------------------------------------------------------- template bool Vector3::normalize() { S len = length(); if (len > 0.0) { // Precompute 1/length and do multiplication instead of division S oneOverLen = (static_cast(1.0)/len); m_v[0] *= oneOverLen; m_v[1] *= oneOverLen; m_v[2] *= oneOverLen; return true; } else { // Might be NaN, so set it to zero m_v[0] = 0; m_v[1] = 0; m_v[2] = 0; return false; } } //-------------------------------------------------------------------------------------------------- /// Returns a normalized version of the current vector. The vector is unchanged. //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::getNormalized(bool* normalizationOK) const { S len = length(); if (len > 0.0) { if (normalizationOK) *normalizationOK = true; S oneOverLen = (static_cast(1.0)/len); return Vector3(m_v[0]*oneOverLen, m_v[1]*oneOverLen, m_v[2]*oneOverLen); } else { if (normalizationOK) *normalizationOK = false; return Vector3::ZERO; } } //-------------------------------------------------------------------------------------------------- /// Set all components to 0 //-------------------------------------------------------------------------------------------------- template inline void Vector3::setZero() { m_v[0] = 0; m_v[1] = 0; m_v[2] = 0; } //-------------------------------------------------------------------------------------------------- /// Check if all components are zero (exact match) //-------------------------------------------------------------------------------------------------- template inline bool Vector3::isZero() const { return (m_v[0] == 0) && (m_v[1] == 0) && (m_v[2] == 0); } //-------------------------------------------------------------------------------------------------- /// Check if vector is undefined /// /// \return Returns true if any one of the components is undefined //-------------------------------------------------------------------------------------------------- template inline bool Vector3::isUndefined() const { if (Math::isUndefined(m_v[0]) || Math::isUndefined(m_v[1]) || Math::isUndefined(m_v[2])) { return true; } else { return false; } } //-------------------------------------------------------------------------------------------------- /// Set the components of the vector //-------------------------------------------------------------------------------------------------- template inline void Vector3::set(S x, S y, S z) { m_v[0] = x; m_v[1] = y; m_v[2] = z; } //-------------------------------------------------------------------------------------------------- /// Transforms this vector as a point. /// /// Transforms this vector as a point by multiplying it with the passed matrix. /// This will both rotate and translate this. /// Assumes the matrix m doesn't contain any perspective projection //-------------------------------------------------------------------------------------------------- template void Vector3::transformPoint(const Matrix4& m) { const S* pV = m.ptr(); S valX = pV[0]*x() + pV[4]*y() + pV[8]*z() + pV[12]; S valY = pV[1]*x() + pV[5]*y() + pV[9]*z() + pV[13]; S valZ = pV[2]*x() + pV[6]*y() + pV[10]*z() + pV[14]; x() = valX; y() = valY; z() = valZ; } //-------------------------------------------------------------------------------------------------- /// Return this vector transformed as a point (rotation and translation) with the given matrix. /// \sa /// transformPoint //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::getTransformedPoint(const Matrix4& m) const { Vector3 pt(*this); pt.transformPoint(m); return pt; } //-------------------------------------------------------------------------------------------------- /// Transforms this vector as a vector. /// /// Transforms this vector as a vector by multiplying it with the passed matrix. /// This will only rotate the vector, but not consider the translation part of the matrix. /// Assumes the matrix m doesn't contain any perspective projection. //-------------------------------------------------------------------------------------------------- template void Vector3::transformVector(const Matrix4& m) { const S* pV = m.ptr(); S valX = pV[0]*x() + pV[4]*y() + pV[8]*z(); S valY = pV[1]*x() + pV[5]*y() + pV[9]*z(); S valZ = pV[2]*x() + pV[6]*y() + pV[10]*z(); x() = valX; y() = valY; z() = valZ; } //-------------------------------------------------------------------------------------------------- /// Return this vector transformed as a vector (rotation only) with the given matrix. /// \sa /// transformVector //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::getTransformedVector(const Matrix4& m) const { Vector3 vec(*this); vec.transformVector(m); return vec; } //-------------------------------------------------------------------------------------------------- /// Transforms this vector. /// /// Transforms this vector by multiplying it with the passed matrix. //-------------------------------------------------------------------------------------------------- template void Vector3::transformVector(const Matrix3& m) { const S* pV = m.ptr(); S valX = pV[0]*x() + pV[3]*y() + pV[6]*z(); S valY = pV[1]*x() + pV[4]*y() + pV[7]*z(); S valZ = pV[2]*x() + pV[5]*y() + pV[8]*z(); x() = valX; y() = valY; z() = valZ; } //-------------------------------------------------------------------------------------------------- /// Return this vector transformed with the given matrix. /// \sa /// transformVector //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::getTransformedVector(const Matrix3& m) const { Vector3 vec(*this); vec.transformVector(m); return vec; } //---------------------------------------------------------------------------------------------------- /// Create an orthonormal basis from this vector /// /// \param mapToAxis Specifies which axis this vector should be mapped onto (0=u, 1=v, 2=w) /// \param uAxis Output u vector /// \param vAxis Output v vector /// \param wAxis Output w vector /// /// Will create an orthonormal basis from this vector. The returned u, v and w axes will all be unit /// length and will be perpendicular to each other. /// The vector does not have to be normalized before calling this function. //---------------------------------------------------------------------------------------------------- template bool Vector3::createOrthonormalBasis(int mapToAxis, Vector3* uAxis, Vector3* vAxis, Vector3* wAxis) const { bool normalizedOK = false; Vector3 W = getNormalized(&normalizedOK); if (!normalizedOK) { return false; } Vector3 U(0, 0, 0); if (Math::abs(W.x()) >= Math::abs(W.y())) { // W.x or W.z component has largest magnitude S length = Math::sqrt(W.x()*W.x() + W.z()*W.z()); U.x() = -W.z()/length; U.y() = 0.0; U.z() = +W.x()/length; } else { // W.y or W.z component has largest magnitude S length = Math::sqrt(W.y()*W.y() + W.z()*W.z()); U.x() = 0.0; U.y() = +W.z()/length; U.z() = -W.y()/length; } // Get V as cross product of WxU // Could be optimized by taking into account the fact that either the y or x component of U will be 0 Vector3 V = W^U; // Algorithm above maps our vector onto W axis // If another axis is requested, we need to shuffle the vectors if (mapToAxis == 0) { if (uAxis) *uAxis = W; if (vAxis) *vAxis = U; if (wAxis) *wAxis = V; } else if (mapToAxis == 1) { if (uAxis) *uAxis = V; if (vAxis) *vAxis = W; if (wAxis) *wAxis = U; } else { if (uAxis) *uAxis = U; if (vAxis) *vAxis = V; if (wAxis) *wAxis = W; } return true; } //-------------------------------------------------------------------------------------------------- /// Return a unit length perpendicular vector //-------------------------------------------------------------------------------------------------- template const Vector3 Vector3::perpendicularVector(bool* perpendicularOK) const { Vector3 perpendic(0, 0, 0); bool ok = createOrthonormalBasis(0, NULL, &perpendic, NULL); if (perpendicularOK) { *perpendicularOK = ok; } return perpendic; } } // namespace cvf