This class should have been posted long ago. So, seeing how popular my C++ Vector2 class page has been, I've decided to finally post this for your needs. This version is similar to the "improvements" on the Vector2 class, supposedly helping encapsulation; frankly, that's up for you to decide.
Remember, you can hover over the source area and click the "<>" looking image (top right) to pop the source code into a new window to more easily view and copy the code.
Vector3.h
/* __ __ ___ _____ ____
* \ \ / / / _ \ | __ \ | |
* \ \/\/ / / / \ \ | | / / | __|
* \_/\_/ /_/ \_\ |_| \_\ |_|
* Take it to the next Level
*
* Copyright (c) 2009 Brian Ernst.
*/
#ifndef w_Vector3
#define w_Vector3
#include <cmath>
namespace _Warp
{
typedef float Scalar;
typedef int Bool;
class Vector3
{
public:
Scalar X;
Scalar Y;
Scalar Z;
Vector3();
Vector3(Scalar x, Scalar y, Scalar z);
Vector3 operator+(const Vector3& vector) const;
Vector3 operator-(const Vector3& vector) const;
Vector3 operator-() const;
Vector3 operator*(Scalar num) const;
Vector3 operator/(Scalar num) const;
Vector3& operator+=(const Vector3& vector);
Vector3& operator-=(const Vector3& vector);
Vector3& operator*=(Scalar num);
Vector3& operator/=(Scalar num);
Bool operator==(const Vector3& vector) const;
Bool operator!=(const Vector3& vector) const;
static const Vector3 Zero;
static const Scalar Epsilon;
};
inline Bool Vector3::operator==(const Vector3& vector) const
{
return X == vector.X && Y == vector.Y && Z == vector.Z;
}
inline Bool Vector3::operator!=(const Vector3& vector) const
{
return X != vector.X || Y != vector.Y || Z != vector.Z;
}
inline Vector3 Vector3::operator+(const Vector3& vector) const
{
return Vector3(X + vector.X, Y + vector.Y, Z + vector.Z);
}
inline Vector3 Vector3::operator-(const Vector3& vector) const
{
return Vector3(X - vector.X, Y - vector.Y, Z - vector.Z);
}
inline Vector3 Vector3::operator-() const
{
return Vector3(-X,-Y,-Z);
}
inline Vector3 Vector3::operator*(Scalar num) const
{
return Vector3(X * num, Y * num, Z * num);
}
inline Vector3 Vector3::operator/(Scalar num) const
{
return Vector3(X / num, Y / num, Z / num);
}
}
#endif
Vector3.cpp:
#include "Vector3.h"
#include
namespace _Warp
{
const Vector3 Vector3::Zero = Vector3(0,0,0);
const Scalar Vector3::Epsilon = std::numeric_limits::epsilon();
Vector3::Vector3()
{
}
Vector3::Vector3(Scalar x, Scalar y, Scalar z)
: X( x )
, Y( y )
, Z( z )
{
}
Vector3& Vector3::operator+=(const Vector3& vector)
{
X += vector.X;
Y += vector.Y;
Z += vector.Z;
return *this;
}
Vector3& Vector3::operator-=(const Vector3& vector)
{
X -= vector.X;
Y -= vector.Y;
Z -= vector.Z;
return *this;
}
Vector3& Vector3::operator*=(Scalar num)
{
X *= num;
Y *= num;
Z *= num;
return *this;
}
Vector3& Vector3::operator/=(Scalar num)
{
this->X /= num;
this->Y /= num;
this->Z /= num;
return *this;
}
}
Vector3Util.h
/* __ __ ___ _____ ____
* \ \ / / / _ \ | __ \ | |
* \ \/\/ / / / \ \ | | / / | __|
* \_/\_/ /_/ \_\ |_| \_\ |_|
* Take it to the next Level
*
* Copyright (c) 2009 Brian Ernst.
*/
#ifndef w_Vector3Util
#define w_Vector3Util
#include "Vector3.h"
// These two files are not detailed out in this blog post.
#include "Quaternion.h"
#include "TMatrixUtil.h"
namespace _Warp
{
Scalar len(const Vector3& vect);
Scalar len2(const Vector3& vect);
void Clamp(Vector3& vect,Scalar length);
void Normalize(Vector3& vect);
void Normalize_s(Vector3& vect);
void SetLength(Vector3& vect, Scalar length);
void SetLength_s(Vector3& vect, Scalar length);
Scalar Dot(const Vector3& vec1, const Vector3& vec2);
Scalar GetAngle(Vector3 vec1, Vector3 vec2);
Vector3 ToNormalized(const Vector3& vect);
Vector3 ToNormalized_s(const Vector3& vect);
Vector3 ToPolar(Scalar x, Scalar y, Scalar z);
Vector3 ToCartesian(Scalar radius, Scalar angle, Scalar z);
Vector3 Cross(const Vector3& vec1, const Vector3& vec2);
Vector3 Rotate(const Vector3& vec1, Scalar angle, const Vector3& axis);
Vector3 ToEuler(Vector3 axis, Scalar angle);
inline Scalar len(const Vector3& vect)
{
return sqrt(vect.X * vect.X + vect.Y * vect.Y + vect.Z * vect.Z);
}
inline Scalar len2(const Vector3& vect)
{
return vect.X * vect.X + vect.Y * vect.Y + vect.Z * vect.Z;
}
inline void Normalize(Vector3& vect)
{
vect /= len(vect);
}
inline void SetLength(Vector3& vect, Scalar length)
{
vect *= length / len(vect);
}
inline Scalar Dot(const Vector3& vec1, const Vector3& vec2)
{
return vec1.X * vec2.X + vec1.Y * vec2.Y + vec1.Z * vec2.Z;
}
inline Vector3 ToNormalized(const Vector3& vect)
{
return vect / len(vect);
}
// This uses a Quaternion combined with the Matrix Utility, neither of which are detailed out in this post.
inline Vector3 Rotate(const Vector3& vec1, Scalar angle, const Vector3& axis)
{
return TransformCoord(Quaternion::FromAxis(axis.X,axis.Y,axis.Z,angle).Get_RotationMatrix(),vec1);
}
inline Vector3 ToPolar(Scalar x, Scalar y, Scalar z)
{
return Vector3(
atan2(y,x),
sqrt(x * x + y * y),
z);
}
inline Vector3 ToCartesian(Scalar radius, Scalar angle, Scalar z)
{
return Vector3(
radius * cos(angle),
radius * sin(angle),
z);
}
inline Vector3 Cross(const Vector3& vec1, const Vector3& vec2)
{
return Vector3(
vec1.Y * vec2.Z - vec1.Z * vec2.Y,
vec1.Z * vec2.X - vec1.X * vec2.Z,
vec1.X * vec2.Y - vec1.Y * vec2.X);
}
}
#endif
Vector3Util.cpp
#include "Vector3Util.h"
#include "../Constants.h"
namespace _Warp
{
void Clamp(Vector3& vect,Scalar length)
{
Scalar vecLength = len2(vect);
if(vecLength <= length * length)
{
return;
}
vect *= length / sqrt(vecLength);
}
void Normalize_s(Vector3& vect)
{
Scalar vecLength = len2(vect);
if(vecLength == 0)
{
return;
}
vect /= sqrt(vecLength);
}
void SetLength_s(Vector3& vect, Scalar length)
{
Scalar vecLength = len2(vect);
if(vecLength == 0)
{
return;
}
vect *= length / sqrt(vecLength);
}
inline Scalar GetAngle(Vector3 vec1, Vector3 vec2)
{
if(vec1 == vec2)
{
return 0.0f;
}
Normalize_s(vec1);
Normalize_s(vec2);
Scalar dot = Dot(vec1, vec2) / (len(vec1) * len(vec2));
dot = dot > 1.0f ? 1.0f : ( dot < -1.0f ? -1.0f : dot );
return std::acos(dot);
}
Vector3 ToNormalized_s(const Vector3& vect)
{
Scalar vecLength = len2(vect);
if(vecLength == 0)
{
return vect;
}
vecLength = sqrt(vecLength);
return Vector3(vect.X / vecLength, vect.Y / vecLength, vect.Z / vecLength);
}
// Thanks to Martin Baker for this solution
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToEuler/index.htm
Vector3 ToEuler(Vector3 axis, Scalar angle)
{
Vector3 out = Vector3();
Scalar s = sin(angle);
Scalar c = cos(angle);
Scalar t = (Scalar)1.0 - c;
if ((axis.X * axis.Y * t + axis.Z * s) > (Scalar)0.998)// north pole singularity detected
{
out.Y = 2 * atan2(axis.X * sin(angle/2), cos(angle/2));
out.Z = static_cast(W_PI_2);
out.X = 0;
return out;
}
if ((axis.X * axis.Y * t + axis.Z * s) < (Scalar)-0.998)// south pole singularity detected
{
out.Y = (Scalar)-2.0 * atan2(axis.X * sin(angle / (Scalar)2.0), cos(angle / (Scalar)2.0));
out.Z = -static_cast(W_PI_2);;
out.X = 0;
return out;
}
out.Y = atan2(axis.Y * s - axis.X * axis.Z * t , 1 - (axis.Y * axis.Y + axis.Z * axis.Z ) * t);
out.Z = asin(axis.X * axis.Y * t + axis.Z * s) ;
out.X = atan2(axis.X * s - axis.Y * axis.Z * t , 1 - (axis.X * axis.X + axis.Z * axis.Z) * t);
return out;
}
}
You'll notice in the Vector3Util I have some functions ending with "_s", like "Noramlize_s"; this is a notation I'm trying to mean, in this case, a safe normalize function call (won't result in a divide by zero error). So, if you know the vector you're using can't possibly be zero, use the standard Normalize function, if not, then feel free to use Normalize_s. Please let me know if you have a comment on the notation!
Anyway, this Vector3 class and utility are code I use in my personal game development, and in other school projects that I may have, and have used it and my personal math libs in a ray tracer. Concerning the util, I'm still tweaking it, making decisions on how to wrap it in a namespace (like it's own _Math namespace, which was taken out for this post), or perhaps on whether I feel I really need a separate util instead of having them as member functions, which would be more convenient with intellisense at hand. If you're wondering what I'm talking about, check out this article at Dr Dobbs on encapsulation. I personally have to give it another read and determine if I agree with it or not and really want to stick with that methodology.
Please leave your thoughts and suggestions! [I'll be uploading the upgraded version of this Vector3 class sometime soon, I realize there are parts of this version that may be a little rough/unfinished, and after that I'll include the source files for you to download]
Comments