www.pudn.com > simpleraytracer_v1_0.zip > vec3.h
/*===================================================================
digital liberation front 2001
_______ ______ _______
/______/\ |______| /\______\
| \ \ | | / / |
| \| | | |/ |
|_____ \ | |_ / ______|
____| | | |_|| |_____
|____| |________||____|
Code by Nicholas Chapman
nickamy@paradise.net.nz
You may use this code for any non-commercial project,
as long as you do not remove this description.
You may not use this code for any commercial project.
====================================================================*/
#ifndef __VEC3_H__
#define __VEC3_H__
/*=================================================================
3 component vector class
------------------------
Coded by NIck Chapman in the year 2000-
=================================================================*/
#include <math.h>
#include "mathstypes.h"
#include <assert.h>
#include <string>
#ifdef CYBERSPACE
#include "../cyberspace/mystream.h"
#endif
//#pragma warning (disable:4244)
//disable "conversion from 'double' to 'float', possible loss of data"
class Vec3
{
public:
inline Vec3()
{}
inline ~Vec3()
{}
inline Vec3(float x_, float y_, float z_)
: x(x_),
y(y_),
z(z_)
{}
inline Vec3(const Vec3&amt; rhs)
: x(rhs.x),
y(rhs.y),
z(rhs.z)
{}
inline Vec3(const float* f)
: x(f[0]),
y(f[1]),
z(f[2])
{}
inline Vec3(const Vec3&amt; v, float scale)
: x(v.x * scale),
y(v.y * scale),
z(v.z * scale)
{}
inline void set(float newx, float newy, float newz)
{
x = newx;
y = newy;
z = newz;
}
inline float&amt; operator[] (int index)
{
//NOTE: no asserting
return ((float*)(&amt;x))[index];
}
inline const float&amt; operator[] (int index) const
{
//NOTE: no asserting
return ((float*)(&amt;x))[index];
}
inline const Vec3 operator + (const Vec3&amt; rhs) const
{
return Vec3(x + rhs.x, y + rhs.y, z + rhs.z);
}
inline const Vec3 operator - (const Vec3&amt; rhs) const
{
return Vec3(x - rhs.x, y - rhs.y, z - rhs.z);
}
inline const Vec3 operator * (const Vec3&amt; rhs) const
{
return Vec3(x * rhs.x, y * rhs.y, z * rhs.z);
}
inline Vec3&amt; operator += (const Vec3&amt; rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
inline Vec3&amt; operator -= (const Vec3&amt; rhs)
{
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
inline Vec3&amt; operator = (const Vec3&amt; rhs)
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
return *this;
}
inline bool operator == (const Vec3&amt; rhs) const
{
return ( (x == rhs.x) &amt;&amt; (y == rhs.y) &amt;&amt; (z == rhs.z) );
}
inline bool operator != (const Vec3&amt; rhs) const
{
return ( (x != rhs.x) || (y != rhs.y) || (z != rhs.z) );
}
//for sorting Vec3's
inline bool operator < (const Vec3&amt; rhs) const
{
if(x < rhs.x)
return true;
else if(x > rhs.x)
return false;
else //else x == rhs.x
{
if(y < rhs.y)
return true;
else if(y > rhs.y)
return false;
else
{
/*if(z < rhs.z)
return true;
else if(z >= rhs.z)
return false;*/
return z < rhs.z;
}
}
}
inline void normalise()
{
//if(!x &amt;&amt; !y &amt;&amt; !z)
// return;
float inverselength = length();//will be inverted later
if(!inverselength)
return;
inverselength = 1.0f / inverselength;//invert it
x *= inverselength;
y *= inverselength;
z *= inverselength;
}
inline void fastNormalise()
{
const float inverselength = RSqrt( length2() );
//if(!inverselength)
// return;
x *= inverselength;
y *= inverselength;
z *= inverselength;
}
inline float normalise_ret_length()
{
//if(!x &amt;&amt; !y &amt;&amt; !z)
// return 0.0f;
const float len = length();
if(!len)
return 0.00001f;
const float inverselength = 1.0f / len;
x *= inverselength;
y *= inverselength;
z *= inverselength;
return len;
}
inline float normalise_ret_length(float&amt; inv_len_out)
{
//if(!x &amt;&amt; !y &amt;&amt; !z)
// return 0.0f;
const float len = length();
if(!len)
return 0.00001f;
const float inverselength = 1.0f / len;
x *= inverselength;
y *= inverselength;
z *= inverselength;
inv_len_out = inverselength;
return len;
}
inline float normalise_ret_length2()
{
//if(!x &amt;&amt; !y &amt;&amt; !z)
// return 0.0f;
const float len2 = length2();
if(!len2)
return 0.00001f;
const float inverselength = 1.0f / sqrt(len2);
x *= inverselength;
y *= inverselength;
z *= inverselength;
return len2;
}
inline float length() const
{
return sqrt(x*x + y*y + z*z);
}
inline float length2() const
{
return (x*x + y*y + z*z);
}
inline void scale(float factor)
{
x *= factor;
y *= factor;
z *= factor;
}
inline Vec3&amt; operator *= (float factor)
{
x *= factor;
y *= factor;
z *= factor;
return *this;
}
inline void setLength(float newlength)
{
const float current_len = length();
if(!current_len)
return;
scale(newlength / current_len);
}
inline Vec3&amt; operator /= (float divisor)
{
*this *= (1.0f / divisor);
return *this;
}
inline const Vec3 operator * (float factor) const
{
return Vec3(x * factor, y * factor, z * factor);
}
inline const Vec3 operator / (float divisor) const
{
const float inverse_d = (1.0f / divisor);
return Vec3(x * inverse_d, y * inverse_d, z * inverse_d);
}
inline void zero()
{
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
inline float getDist(const Vec3&amt; other) const
{
const Vec3 dif = other - *this;
return dif.length();
}
inline float getDist2(const Vec3&amt; other) const
{
//const Vec3 dif = other - *this;
//return dif.length2();
//float sum = other.x - x;
//sum += other.y - y;
//sum += other.z - z;
float sum = other.x - x;
sum *= sum;
float dif = other.y - y;
sum += dif*dif;
dif = other.z - z;
return sum + dif*dif;
//return (other.x - x) + (other.y - y) + (other.z - z);
}
inline void assertUnitVector() const
{
const float len = length();
const float var = fabs(1.0f - len);
const float EPSILON_ = 0.0001f;
assert(var <= EPSILON_);
}
void print() const;
const std::string toString() const;
// const static Vec3 zerovector; //(0,0,0)
// const static Vec3 i; //(1,0,0)
// const static Vec3 j; //(0,1,0)
// const static Vec3 k; //(0,0,1)
float x,y,z;
inline const float* data() const { return (float*)this; }
//-----------------------------------------------------------------
//Euler angle stuff
//-----------------------------------------------------------------
//static Vec3 ws_up;//default z axis
//static Vec3 ws_right;//default -y axis
//static Vec3 ws_forwards;//must = crossProduct(ws_up, ws_right). default x axis
//static void setWsUp(const Vec3&amt; vec){ ws_up = vec; }
//static void setWsRight(const Vec3&amt; vec){ ws_right = vec; }
//static void setWsForwards(const Vec3&amt; vec){ ws_forwards = vec; }
float getYaw() const { return x; }
float getPitch() const { return y; }
float getRoll() const { return z; }
void setYaw(float newyaw){ x = newyaw; }
void setPitch(float newpitch){ y = newpitch; }
void setRoll(float newroll){ z = newroll; }
/*==================================================================
getAngles
---------
Gets the Euler angles of this vector. Returns the vector (yaw, pitch, roll).
Yaw is the angle between this vector and the vector 'ws_forwards' measured
anticlockwise when looking towards the origin from along the vector 'ws_up'.
Yaw will be in the range (-Pi, Pi).
Pitch is the angle between this vector and the vector 'ws_forwards' as seen when
looking from along the vecotr 'ws_right' towards the origin. A pitch of Pi means
the vector is pointing along the vector 'ws_up', a pitch of -Pi means the vector is
pointing straight down. (ie pointing in the opposite direction from 'ws_up'.
A pitch of 0 means the vector is in the 'ws_right'-'ws_forwards' plane.
Will be in the range [-Pi/2, Pi/2].
Roll will be 0.
====================================================================*/
const Vec3 getAngles(const Vec3&amt; ws_forwards, const Vec3&amt; ws_up, const Vec3&amt; ws_right) const;
//const Vec3 getAngles() const; //around i, j, k
const Vec3 fromAngles(const Vec3&amt; ws_forwards, const Vec3&amt; ws_up, const Vec3&amt; ws_right) const;
float dotProduct(const Vec3&amt; rhs) const
{
return x*rhs.x + y*rhs.y + z*rhs.z;
}
float dot(const Vec3&amt; rhs) const
{
return dotProduct(rhs);
}
static const Vec3 randomVec(float component_lowbound, float component_highbound);
inline void setToMult(const Vec3&amt; other, float factor)
{
x = other.x * factor;
y = other.y * factor;
z = other.z * factor;
}
inline void addMult(const Vec3&amt; other, float factor)
{
x += other.x * factor;
y += other.y * factor;
z += other.z * factor;
}
inline void subMult(const Vec3&amt; other, float factor)
{
x -= other.x * factor;
y -= other.y * factor;
z -= other.z * factor;
}
inline void add(const Vec3&amt; other)
{
x += other.x;
y += other.y;
z += other.z;
}
inline void sub(const Vec3&amt; other)
{
x -= other.x;
y -= other.y;
z -= other.z;
}
inline void removeComponentInDir(const Vec3&amt; unitdir)
{
subMult(unitdir, this->dot(unitdir));
}
};
inline const Vec3 normalise(const Vec3&amt; v)
{
const float vlen = v.length();
if(!vlen)
return Vec3(1.0f, 0.0f, 0.0f);
return v * (1.0f / vlen);
}
inline const Vec3 operator * (float m, const Vec3&amt; right)
{
return Vec3(right.x * m, right.y * m, right.z * m);
}
inline float dotProduct(const Vec3&amt; v1, const Vec3&amt; v2)
{
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
inline float dot(const Vec3&amt; v1, const Vec3&amt; v2)
{
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
inline const Vec3 crossProduct(const Vec3&amt; v1, const Vec3&amt; v2)
{
return Vec3(
(v1.y * v2.z) - (v1.z * v2.y),
(v1.z * v2.x) - (v1.x * v2.z),
(v1.x * v2.y) - (v1.y * v2.x)
); //NOTE: check me
}
//v1 and v2 unnormalized
inline float angleBetween(Vec3&amt; v1, Vec3&amt; v2)
{
const float lf = v1.length() * v2.length();
if(!lf)
return 1.57079632679489661923f;
const float dp = dotProduct(v1, v2);
return acos( dp / lf);
}
inline float angleBetweenNormalized(const Vec3&amt; v1, const Vec3&amt; v2)
{
const float dp = dotProduct(v1, v2);
return acos(dp);
}
inline bool epsEqual(const Vec3&amt; v1, const Vec3&amt; v2)
{
const float dp = dotProduct(v1, v2);
return dp >= 0.99999f;
}
inline std::ostream&amt; operator << (std::ostream&amt; stream, const Vec3&amt; point)
{
stream << point.x << " ";
stream << point.y << " ";
stream << point.z << " ";
return stream;
}
inline std::istream&amt; operator >> (std::istream&amt; stream, Vec3&amt; point)
{
stream >> point.x;
stream >> point.y;
stream >> point.z;
return stream;
}
#ifdef CYBERSPACE
inline MyStream&amt; operator << (MyStream&amt; stream, const Vec3&amt; point)
{
stream << point.x;
stream << point.y;
stream << point.z;
return stream;
}
inline MyStream&amt; operator >> (MyStream&amt; stream, Vec3&amt; point)
{
stream >> point.x;
stream >> point.y;
stream >> point.z;
return stream;
}
#endif//CYBERSPACE
#endif //__VEC3_H__