Part 8 of C++ tutorial – a 3D vector & transform library
There is one other common type of vector and this is the unit vector. It is by definition of unit magnitude, and thus intended for the purposes of indicating direction only. It has distinct semantics from the general vector, and the vector represented point.
While a UnitVector class would still be represented by three doubles (x,y,z), unlike either the Vector or Point, it makes no sense to permit the elements to be individually assigned (given their magnitude must always be unity). Therefore, one creates a new representational class where the elements are read-only, thus:
class XYZ_Const
{
public:
const double x,y,z;
XYZ_Const(double a,double b,double c):x(a),y(b),z(c) { }
void Set(const XYZ_Const& xyz)
{ const_cast<double&>(x)=xyz.x;
const_cast<double&>(y)=xyz.y;
const_cast<double&>(z)=xyz.z;
}
};
It still has an assignment method, which must necessarily cast away the constness of the members in order to assign a new unit vector.
The implementation of the UnitVector is largely the same as the Vector, except that most methods are const, except for assignment.
To assure unit magnitude, constructors normalise supplied coordinates, however, they are not unity/sanity-checked, e.g. UnitVector(0.33,0.66,066)
is not the UnitVector(0.33,0.66,0.66)
that may have been intended.
Because a priori, a UnitVector has unity magnitude, an exception is thrown should it be attempted to construct one from a null vector (or null coordinates).
Typically used to represent direction, it may be helpful to provide constructors or methods that enable the creation of UnitVectors from angles of rotation, but I’ll leave these until later. However, at least the three axes can be defined as static constants.
A UnitVector is implicitly a vector, thus the implicit conversion operator is provided.
Code for the UnitVector class and an example program (with output) is below:
class UnitVector: protected VectorBase<XYZ_Const>
{
protected:
explicit UnitVector(const VectorBase<XYZ_Const>& xyz):VectorBase<XYZ_Const>(xyz) { } // NOT CHECKED FOR UNITY
public:
// Elements & Accessors
using VectorBase<XYZ_Const>::x; // READ ONLY
using VectorBase<XYZ_Const>::y; // [ Write access has unclear semantics.
using VectorBase<XYZ_Const>::z; // How can you change one element of a unit vector? ]
static const UnitVector axis_x; // |(1,0,0)|
static const UnitVector axis_y; // |(0,1,0)|
static const UnitVector axis_z; // |(0,0,1)|
explicit operator const double* () const { return array(); } // Cast to const array
const double& operator[](int i) const { return element(i); } // Const array element accessor
double* Read(double d[3]) const { return read(d); }
// Constructors
UnitVector(double a,double b,double c):VectorBase<XYZ_Const>(a,b,c) { normalise(); } // Null vector will THROW
UnitVector(const double d[3]):VectorBase<XYZ_Const>(d[0],d[1],d[2]) { normalise(); } // Null vector will THROW
explicit UnitVector(const Vector& v):VectorBase<XYZ_Const>(v.x,v.y,v.z) { normalise(); } // Null vector will THROW
// Assignment
UnitVector& operator=(const UnitVector& u) { assign(u); return *this; }
// Informational
bool operator==(const UnitVector& u) const { return is_equal_to(u); }
bool operator!=(const UnitVector& u) const { return !is_equal_to(u); }
// Conversions
operator const Vector& () const { return *reinterpret_cast<const Vector*>(this); } // Implicitly a const vector
// Scalar operations
UnitVector operator-() const { return UnitVector(negation()); } // Negation retains unity
// Scalar operations resulting in a vector
friend Vector operator*(const UnitVector& u,double s) { return Vector(u)*s; }
friend Vector operator*(double s,const UnitVector& u) { return s*Vector(u); }
friend Vector operator/(const UnitVector& u,double s) { return Vector(u)/s; } // Throws div0
friend std::ostream& operator<<(std::ostream& os,const UnitVector& u) { return os<<"|("<<u.x<<','<<u.y<<','<<u.z<<")|"; }
};
const UnitVector UnitVector::axis_x=UnitVector(1,0,0);
const UnitVector UnitVector::axis_y=UnitVector(0,1,0);
const UnitVector UnitVector::axis_z=UnitVector(0,0,1);
int main() // The program
{ const Vector u(7,3,5),v(1,2,3);
cout<<"u="<<u<<"\n";
cout<<"v="<<v<<"\n";
cout<<"u x v = "<<u.cross(v)<<"\n";
UnitVector uv(u.cross(v));
cout<<"Norm(u x v)="<<uv<<"\n";
UnitVector h(0.33,0.66,066);
cout<<"h = "<<h<<"\n";
return 0;
}
Program output:
u=(7,3,5)
v=(1,2,3)
u x v = (-4,-9,11)
Norm(u x v)=|(-0.270914,-0.609557,0.745014)|
h = |(0.00611054,0.0122211,0.999907)|
Comments
There are currently no comments on this article.
Comment