# HPoint - Homogenous Coordinates

Posted

Part 9 of C++ tutorial – a 3D vector & transform library

“Homogeneous coordinates are ubiquitous in computer graphics because they allow common vector operations such as translation, rotation, scaling and perspective projection to be represented as a matrix by which the vector is multiplied.” wikipedia.org/Homogeneous_coordinates

Thus we introduce the `HPoint` class as a 4-ordinate vector representation, i.e. `x,y,z` with a `w` divisor.

``````class XYZW_Const
{
public:
const double x,y,z,w;

XYZW_Const(double a,double b,double c,double d):x(a),y(b),z(c),w(d) { }

void Set(const XYZW_Const& xyzw)
{	const_cast<double&>(x)=xyzw.x;
const_cast<double&>(y)=xyzw.y;
const_cast<double&>(z)=xyzw.z;
const_cast<double&>(w)=xyzw.w;
}
void SetW(double ww)
{	const_cast<double&>(w)=ww;
};
};``````

Very similar to the `XYZ` triples, this representational class is very similar to `XYZ_Const` except it has a fourth double, and a dedicated method to set the fourth element, `w`.

The introduction of a fourth element means the `VectorBase` class needs tweaking to cater for it (whilst remaining compatible with triple element representations). We can do that by adding a static `w` member in the `XYZ` and `XYZ_Const` classes. Thus `XYZ` becomes:

``````class XYZ	// For Vector & Point
{
public:
double x,y,z;
static const double w;	// Dummy w

XYZ(double a,double b,double c,double d):x(a),y(b),z(c) { }
void Set(const XYZ& xyz) { *this=xyz; }
};

const double XYZ::w=0.0;``````

So, for triples, the 4 element constructor ignores the 4th element, and the `w` member exists only as a static constant. It can still be referenced as if a member variable, but without increasing the size of the object. This is one of the few examples where it is indispensable to be able to use the dot operator to access a static member (instead of the :: class scoping operator).

The `HPoint` class is similar to the `Point` class, except that while they can still be scaled by a scalar, it makes less sense to permit them to be directly translated by vectors. Translation is best left to homegenous transforms.

There are some query functions appropriate to `HPoint`, i.e. to query whether it can be converted to a `Point` (`w!=0`), whether it is a direction (point at infinity), whether it is the origin, and whether it is valid (invalid being null – origin at infinity).

The implicit conversion of an `HPoint` to a `Point` simply involves dividing `x,y,z,w` by `w`, i.e. such that `w'=1`.

Here is the code for the `HPoint` class:

``````class HPoint: protected VectorBase<XYZW_Const>
{
public:
protected:
explicit HPoint(const VectorBase<XYZW_Const>& xyzw):VectorBase<XYZW_Const>(xyzw) {  }
public:
using VectorBase<XYZW_Const>::y;	// For write access, use a Point.
using VectorBase<XYZW_Const>::z;	//
using VectorBase<XYZW_Const>::w;	//

static const HPoint origin;	// [0,0,0,1]	NB Origin is xyz=0 for any non-zero value of w

using VectorBase<XYZW_Const>::SetW;

// Constructors
HPoint(double x,double y,double z,double w=1):VectorBase<XYZW_Const>(x,y,z,w) { }
HPoint(const Point& p):VectorBase<XYZW_Const>(p.x,p.y,p.z,1) { }

// Copy & Assign
HPoint(const HPoint& p):VectorBase<XYZW_Const>(p) { }
HPoint& operator=(const HPoint& p) { assign(p); return *this; }

operator Point() const
{	if (IsPoint()) return Point(x/w,y/w,z/w);
throw std::runtime_error("Cannot convert HPoint at infinity to Point");
}

bool IsPoint() const { return w; }	// Point not at infinity simply requires non=zero w
bool IsDirection() const { return !w&&!is_null(); }	// Direction (point at infinity) requires w=0, with non-zero xyz
bool IsOrigin() const { return w&&is_null(); }	// Origin point if non-zero w, and xyz=0
bool IsValid() const { return w||!is_null(); }	// Valid if non-zero w, or w=0 && xyz!=0
explicit operator bool() const { return w||!is_null(); }	// True if any element non-zero, i.e. valid
bool operator!() const { return !w&&is_null(); }	// True if all elements zero, i.e. invalid

// HPoints may be transformed by a scalar
HPoint& operator*=(double m) { multiply_by(m); return *this; }

HPoint& operator/=(double d) { SetW(w*d); return *this; }

friend HPoint operator*(const HPoint& p,double m) { return HPoint(p.multiplication(m)); }
friend HPoint operator*(double m,const HPoint& p) { return HPoint(p.multiplication(m)); }
friend HPoint operator/(const HPoint& p,double d) { return HPoint(p)/=d; }

friend std::ostream& operator<<(std::ostream& os,const HPoint& p) { return os<<'['<<p.x<<','<<p.y<<','<<p.z<<','<<p.w<<']'; }	// E.g. [1,2,3,1]
};

const HPoint HPoint::origin=HPoint(0,0,0);``````

And here is a little test program:

``````int main()	// The program
{
const Point x(1,2,3);
const HPoint p(7,3,5,2),q(x);

cout<<"p="<<p<<"\n";
cout<<"q="<<q<<"\n";

HPoint r=p/4;

cout<<"r=p/4 -> r="<<r<<"\n";

if (r.IsPoint())
cout<<"r is point\n";
else
cout<<"r is not point\n";

r/=0;

cout<<"r/=0  -> r="<<r<<"\n";

if (r.IsDirection())
cout<<"r is direction\n";
else
cout<<"r is not direction\n";

r=p*0;

cout<<"r=p*0  -> r="<<r<<"\n";

if (r.IsOrigin())
cout<<"r is origin\n";
else
cout<<"r is not origin\n";

r/=0;

cout<<"r/=0  -> r="<<r<<"\n";

if (r.IsValid())
cout<<"r is valid\n";
else
cout<<"r is invalid\n";

Point a=static_cast<Point>(p)+Vector(1,2,3);

cout<<"p+[1,2,3]="<<a<<"\n";

return 0;
}``````

Which produces the following output:

``````p=[7,3,5,2]
q=[1,2,3,1]
r=p/4 -> r=[7,3,5,8]
r is point
r/=0  -> r=[7,3,5,0]
r is direction
r=p*0  -> r=[0,0,0,2]
r is origin
r/=0  -> r=[0,0,0,0]
r is invalid
p+[1,2,3]=[4.5,3.5,5.5]``````

Author

# UnitVector - A normalised vector - with unit magnitude

Posted

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>::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

// Constructors

UnitVector(double a,double b,double c):VectorBase<XYZ_Const>(a,b,c) { normalise(); }	// Null vector will THROW
UnitVector(const double d):VectorBase<XYZ_Const>(d,d,d) { 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)|``````

Author

# Point - Vector from origin

Posted

Part 7 of C++ tutorial – a 3D vector & transform library

A point is a position in 3D space, and can be represented by a vector from the origin.

A point has subtly different semantics from a vector. A vector can represent the translation from any point to any other, but a point represents a specific position.

Thus one can subtract one point from another to obtain the vector between them, but it makes no sense to add one position to another. Of course, you can add a vector to a point to obtain a new point, or you can add two vectors to obtain a single equivalent vector.

Therefore the addition and subtraction operations for a point are restricted accordingly. The following lists these:

``````p'=p+v  (or p+=v )
p'=p-v  (or p-=v )

v'=p'-p``````

Note that `p'=v+p` is not catered for, being less readable. However, negation, as a scaling by -1, has been provided, despite readability – thus one can have `p'=-p+v` or `v'=p - -p`

Although Point is represented by a Vector, it is not a vector per se, however, one may often wish to convert it directly to its representational Vector (rather than obtaining this by subtracting the origin from it), therefore an explicit conversion operator is provided:

``explicit operator const Vector& () const { return *reinterpret_cast<const Vector*>(this); }``

In other respects the Point class implementation is very similar to that of the Vector class.

There follows the code for the Point class, an example program, and its output:

``````class Point: protected VectorBase<XYZ>
{
protected:
explicit Point(const VectorBase<XYZ>& xyz):VectorBase<XYZ>(xyz) { }
public:
// Elements & accessors

using VectorBase<XYZ>::x;
using VectorBase<XYZ>::y;
using VectorBase<XYZ>::z;

explicit operator const double* () const { return array(); }	// Cast to const array
explicit operator double* () { return array(); }	// Cast to non-const array

const double& operator[](int i) const { return element(i); }	// Const array element accessor
double& operator[](int i) { return element(i); } // Non-const array element accessor - for assignment

// Constructors

Point(double a,double b,double c):VectorBase<XYZ>(a,b,c) { }

explicit Point(const double d):VectorBase<XYZ>(d,d,d) { }

explicit Point(const Vector& v):VectorBase<XYZ>(v.x,v.y,v.z) { }	// The point obtained by adding v to the origin

static const Point origin;	// [0,0,0] - pre-constructed null

// Assignment
Point& operator=(const Point& p) { assign(p); return *this; }

// Conversions
explicit operator const Vector& () const { return *reinterpret_cast<const Vector*>(this); }	// Can be cast to a const vector

// Informational

explicit operator bool() const { return !is_null(); }	// True if not origin
bool operator!() const { return is_null(); }

bool operator==(const Point& p) const { return is_equal_to(p); }
bool operator!=(const Point& p) const { return !is_equal_to(p); }

// Operations

// Points may be transformed by a scalar
Point operator-() const { return Point(negation()); }	// Equivalent to scaling by -1

Point& operator*=(double s) { multiply_by(s); return *this; }
Point& operator/=(double s) { divide_by(s); return *this; }	// Throws div0

friend Point operator*(const Point& p,double s) { return Point(p.multiplication(s)); }
friend Point operator*(double s,const Point& p) { return Point(p.multiplication(s)); }
friend Point operator/(const Point& p,double s) { return Point(p.division(s)); }	// Throws div0

// Transform point by vector addition
Point& operator+=(const Vector& v) { add(Point(v)); return *this; }
Point& operator-=(const Vector& v) { subtract(Point(v)); return *this; }

friend Point operator+(const Point& p,const Vector& v) { return Point(static_cast<const Vector&>(p)+v); }
friend Point operator-(const Point& p,const Vector& v) { return Point(static_cast<const Vector&>(p)-v); }

// Calculate vector between points
friend Vector operator-(const Point& p,const Point& q) { return static_cast<const Vector&>(p)-static_cast<const Vector&>(q); }

friend std::ostream& operator<<(std::ostream& os,const Point& p) { return os<<'['<<p.x<<','<<p.y<<','<<p.z<<']'; }	// E.g. [1,2,3]

};

const Point Point::origin=Point(0,0,0);

int main()	// The program
{	Point p=Point::origin;
const Vector v(1,2,3);

cout<<"p="<<p<<"\n";
cout<<"v="<<v<<"\n";

p+=v;

cout<<"p+=v: "<<p<<"\n";

p*=1.5;

cout<<"p*=1.5: "<<p<<"\n";

p-=v;

cout<<"p-=v: "<<p<<"\n";

return 0;
}``````

Program output:

``````p=[0,0,0]
v=(1,2,3)
p+=v: [1,2,3]
p*=1.5: [1.5,3,4.5]
p-=v: [0.5,1,1.5]``````

Author

# Vector - Separation of Concerns

Posted

Part 6 of C++ tutorial – a 3D vector & transform library

With the expectation that we will need other 3D data types that are vectors or very similar, such as a 3D point, it is time to separate the concerns of the Vector class into representation, helper methods, and implementation. That way we can just tweak the implementation depending upon behavioural and semantic differences.

The representation comprises three doubles, i.e. `double x,y,z;` and this can be written quite simply:

``````class XYZ
{
public:
double x,y,z;

XYZ(double a,double b,double c):x(a),y(b),z(c) { }
void Set(const XYZ& xyz) { *this=xyz; }
};``````

It just needs a constructor and a representation dependent assignment method.

The class of helper methods can then derive from this representation, but to avoid multiple definitions (per base representation), it should be a template, with the representation as the base class parameter. I’ll call the class `VectorBase`. You can see that the class is essentially identical to the set of protected methods of the non-template `Vector` class in the previous article, except that `Vector` is changed to `VectorBase` and the public member variables of the representation base class must be made visible via the `using` keyword.

``````template <class XYZ_CLASS>
class VectorBase: public XYZ_CLASS
{
public:

// Elements & accessors
using XYZ_CLASS::x;
using XYZ_CLASS::y;
using XYZ_CLASS::z;

const double* array() const { return &x; }
double* array() { return &x; }

const double& element(int i) const	// Const array element accessor
{
switch (i)
{
case 0: return x; case 1: return y; case 2: return z;
default: throw std::out_of_range("Element index");
}
}

double& element(int i) // Non-const array element accessor - for assignment
{
switch (i)
{
case 0: return x; case 1: return y;	case 2: return z;
default: throw std::out_of_range("Element index");
}
}

{
switch (i)
{
case 3: d=z;	case 2: d=y;	case 1: d=x;
case 0:	return d;
default: throw std::out_of_range("Element count");
}
}

// Constructors

VectorBase(double a,double b,double c): XYZ_CLASS(a,b,c) { }

// Const Functions - concerning xyz only
bool is_null() const { return !x&&!y&&!z; }
bool is_equal_to(const VectorBase& v) const { return x==v.x&&y==v.y&&z==v.z; }
double magnitude_squared() const { return x*x+y*y+z*z; }
double magnitude() const { return sqrt(magnitude_squared()); }
VectorBase negation() const { return VectorBase(-x,-y,-z); }
VectorBase normalisation() const { return division(magnitude()); }
VectorBase multiplication(double s) const { return VectorBase(x*s,y*s,z*s); }
VectorBase division(double s) const { if (s) return VectorBase(x/s,y/s,z/s); else throw std::runtime_error("Divide by Zero"); }
VectorBase addition(const VectorBase& v) const { return VectorBase(x+v.x,y+v.y,z+v.z); }
VectorBase subtraction(const VectorBase& v) const { return VectorBase(x-v.x,y-v.y,z-v.z); }
double dot_product(const VectorBase& v) const { return x*v.x+y*v.y+z*v.z; }
VectorBase cross_product(const VectorBase& v) const { return VectorBase(y*v.y-v.y*z,v.x*z-x*v.y,x*v.y-v.x*y); }

// Modifying transforms
using XYZ_CLASS::Set;

void assign(const VectorBase& v) { Set(v); }
void subtract(const VectorBase& v) { assign(subtraction(v)); }
void negate() { assign(negation()); }
void multiply_by(double s) { assign(multiplication(s)); }
void divide_by(double s) { assign(division(s)); }
void normalise() { assign(normalisation()); }
};``````

The Vector class is now more concise, now that the representation and helper methods can be inherited from the template base. It differs from the previous Vector class in that it now needs to have a constructor from its base (`VectorBase<XYZ>`), must also make the `XYZ` representation visible via `using`, and must initialise its base within constructors.

Note that the `VectorBase<XYZ>` base class is protected, which means it is not publicly visible, there is not a public ‘is a’ relationship between `Vector` and `VectorBase<XYZ>`. It is only visible to `Vector` (and derivatives) for implementation purposes.

``````class Vector: protected VectorBase<XYZ>
{
protected:
explicit Vector(const VectorBase<XYZ>& xyz):VectorBase<XYZ>(xyz) { }
public:
// Elements & accessors

using VectorBase<XYZ>::x;	// 'using' otherwise hidden
using VectorBase<XYZ>::y;
using VectorBase<XYZ>::z;

explicit operator const double* () const { return array(); }	// Cast to const array
explicit operator double* () { return array(); }	// Cast to non-const array

const double& operator[](int i) const { return element(i); }	// Const array element accessor
double& operator[](int i) { return element(i); } // Non-const array element accessor - for assignment

// Constructors

// Vector() { }	// Explicit initialisation de rigeur, e.g. Vector v=Vector::null;
Vector(double a,double b,double c):VectorBase<XYZ>(a,b,c) { }

explicit Vector(const double d):VectorBase<XYZ>(d,d,d) { }

static const Vector null;

// Assignment
Vector& operator=(const Vector& v) { assign(v); return *this; }

// Informational
explicit operator bool() const { return !is_null(); }	// Don't want Vector implicitly converted to int or bool
bool operator!() const { return is_null(); }

explicit operator double() const { return magnitude(); }

bool operator==(const Vector& v) const { return is_equal_to(v); }
bool operator!=(const Vector& v) const { return !is_equal_to(v); }

// Scalar operations
Vector operator-() const { return Vector(negation()); }

Vector& operator*=(double s) { multiply_by(s); return *this; }
Vector& operator/=(double s) { divide_by(s); return *this; }	// Throws div0

friend Vector operator*(const Vector& v,double s) { return Vector(v.multiplication(s)); }
friend Vector operator*(double s,const Vector& v) { return Vector(v.multiplication(s)); }
friend Vector operator/(const Vector& v,double s) { return Vector(v.division(s)); }

// Vector operations
Vector& operator+=(const Vector& v) { add(v); return *this; }
Vector& operator-=(const Vector& v) { subtract(v); return *this; }

friend Vector operator+(const Vector& u,const Vector& v) { return Vector(u.addition(v)); }
friend Vector operator-(const Vector& u,const Vector& v) { return Vector(u.subtraction(v)); }

double dot(const Vector& v) const { return dot_product(v); }
Vector cross(const Vector& v) const { return Vector(cross_product(v)); }	// NB Result is Normal vector

friend std::ostream& operator<<(std::ostream& os,const Vector& v) { return os<<'('<<v.x<<','<<v.y<<','<<v.z<<')'; }

};

const Vector Vector::null=Vector(0,0,0);	// Standard null vector (0,0,0)``````

Author

# Other Vector operations

Posted

Part 5 of C++ tutorial – a 3D vector & transform library

What remains to implement for the Vector class is rather ancillary, i.e. constructors and conversions, element access, and informational functions.

The Vector is represented by three doubles: x,y,z. However, it is also an array of three doubles, i.e. `double `. Although the Microsoft C++ compiler permits anonymous structs which would allow the use of a union to enable the superimposition of `double x,y,z` with `double`, for portability, I will use casts and conversion operators to implement this. The array is simply the address of the first element, i.e. `&x`. Accessing elements can be done by overloading the array element operator, which permits bounds checking. The helper methods are thus:

``````double* array() { return &x; }

double& element(int i)
{	switch (i)
{	case 0: return x; case 1: return y; case 2: return z;
default: throw std::out_of_range("Element index");
}
}``````

These are also implemented in const form, but note that the const element method returns a const reference rather than a value – being an accessor rather than a function returning a value.

These become public operators of the Vector class as follows:

``````explicit operator const double* () const { return array(); }
explicit operator double* () { return array(); }

const double& operator[](int i) const { return element(i); }
double& operator[](int i) { return element(i); }``````

Array conversion operators must be made explicit, otherwise invalid vector arithmetic expressions are liable to be converted into pointer arithemtic expressions. Otherwise, a Vector is just as much an array as it is x,y,z.

Another point on arrays to note is that C++ does not encode the size of the array when matching arguments, i.e. an array of 4 doubles will match an array of 3. Thus the following constructor (from an array of 3 doubles) will take any sized array or pointer-to-double.

``explicit Vector(const double p):x(p),y(p),z(p) { }``

Thus, it should be explicit to improve readability and safety, e.g. an array of three doubles (or object with an implicit conversion to such) is not necessarily a vector.

There is a special vector, which is the null vector. There are thus a few members concerned with this:

``````bool is_null() const { return !x&&!y&&!z; }
explicit operator bool() const { return !is_null(); }	// Don't want Vector implicitly converted to int
bool operator!() const { return is_null(); }
static const Vector null;``````

The ‘null’ member is initialised as `const Vector Vector::null=Vector(0,0,0);` and may sometimes be useful (referenced via Vector::null).

I have implemented an explicit cast of a vector to a double, by way of providing a means to obtaining the vector’s magnitude. I would argue that this is a valid, and unsurprising explicit conversion of a vector to a scalar.

For other methods such as equality comparison, I leave you to locate these in the code below:

``````#include <iostream>	// For console output functionality

using namespace std;	// Avoids having to use std:: scoping prefix

class Vector	// A vector class with addition and subtraction functionality
{
protected:
// Accessor helpers
const double* array() const { return &x; }
double* array() { return &x; }

const double& element(int i) const	// Const array element accessor
{	switch (i)
{	case 0: return x; case 1: return y; case 2: return z;
default: throw std::out_of_range("Element index");
}
}

double& element(int i) // Non-const array element accessor - for assignment
{	switch (i)
{	case 0: return x; case 1: return y;	case 2: return z;
default: throw std::out_of_range("Element index");
}
}

double* read(double v) const { v=x; v=y; v=z; return v; }	// Copies this vector to supplied array

// Non-modifying helpers
bool is_null() const { return !x&&!y&&!z; }
bool is_equal_to(const Vector& v) const { return x==v.x&&y==v.y&&z==v.z; }
double magnitude_squared() const { return x*x+y*y+z*z; }
double magnitude() const { return sqrt(magnitude_squared()); }
Vector negation() const { return Vector(-x,-y,-z); }
Vector normalisation() const { return division(magnitude()); }
Vector addition(const Vector& v) const { return Vector(x+v.x,y+v.y,z+v.z); }
Vector subtraction(const Vector& v) const { return Vector(x-v.x,y-v.y,z-v.z); }
Vector multiplication(double m) const { return Vector(x*m,y*m,z*m); }
Vector division(double d) const { if (d) return Vector(x/d,y/d,z/d); else throw std::runtime_error("Divide by Zero"); }
double dot_product(const Vector& v) const { return v.x*x+v.y*y+v.z*z; }
Vector cross_product(const Vector& v) const { return Vector(v.y*y-v.y*z,v.x*z-v.y*x,v.y*x-v.x*y); }

// Modifying helpers
void assign(const Vector& v) { x=v.x; y=v.y; z=v.z; }
void subtract(const Vector& v) { assign(subtraction(v)); }
void multiply_by(double m) { assign(multiplication(m)); }
void divide_by(double d) { assign(division(d)); }

public:
// Elements and accessors
double x,y,z;	// Representation

explicit operator const double* () const { return array(); }	// Cast to const array
explicit operator double* () { return array(); }	// Cast to non-const array

const double& operator[](int i) const { return element(i); }	// Const array element accessor
double& operator[](int i) { return element(i); }	// Non-const array element accessor - for assignment

// Constructors
Vector(double a,double b,double c):x(a),y(b),z(c) { }
explicit Vector(const double p):x(p),y(p),z(p) { }

static const Vector null;
// Assignment
Vector& operator=(const Vector& v) { assign(v); return *this; }

// Informational
explicit operator bool() const { return !is_null(); }	// Don't want Vector implicitly converted to int or bool
bool operator!() const { return is_null(); }

explicit operator double() const { return magnitude(); }

bool operator==(const Vector& v) const { return is_equal_to(v); }
bool operator!=(const Vector& v) const { return !is_equal_to(v); }

// Scalar operations

Vector operator-() const { return Vector(negation()); }

Vector& operator*=(double m) { multiply_by(m); return *this; }
Vector& operator/=(double d) { divide_by(d); return *this; }	// Throws div0

friend Vector operator*(const Vector& v,double m) { return Vector(v.multiplication(m)); }
friend Vector operator*(double m,const Vector& v) { return Vector(v.multiplication(m)); }
friend Vector operator/(const Vector& v,double d) { return Vector(v.division(d)); }

// Vector operations

Vector& operator+=(const Vector& v) { add(v); return *this; }
Vector& operator-=(const Vector& v) { subtract(v); return *this; }

friend Vector operator+(const Vector& u,const Vector& v) { return Vector(u.addition(v)); }
friend Vector operator-(const Vector& u,const Vector& v) { return Vector(u.subtraction(v)); }

double dot(const Vector& v) const { return dot_product(v); }
Vector cross(const Vector& v) const { return cross_product(v); }

// Output
friend ostream& operator<<(ostream& os,const Vector& v)
{ return os<<'('<<v.x<<','<<v.y<<','<<v.z<<')'; }	// Output, e.g. (1,2,3)
};

const Vector Vector::null=Vector(0,0,0);	// A standard vector

int main()	// The program
{	const Vector u(1,2,3);	// A test vector
double d={6,4,3,1};
Vector v(d);	// A test vector

cout<<"u="<<u<<"\n";
cout<<"v="<<v<<"\n";

double t0=v,t1=*(v+1);

cout<<"t0,t1="<<t0<<","<<t1<<"\n";

Vector v0=Vector::null;

cout<<"v0="<<v0<<"\n";

if (v0)
cout<<"v0 is true\n";
else
if (!v0)
cout<<"v0 is false\n";
else
cout<<"v0 is neither true nor false\n";

return 0;
}``````

Program output is:

``````u=(1,2,3)
v=(6,4,3)
t0,t1=6,4
v0=(0,0,0)
v0 is false``````

Author