#ifndef GAME_Vertex3D_H
#define GAME_Vertex3D_H
#include "stdafx.h"
#include "math.h"
// Vertex3D: Шаблон класса "точка" (или "вектор", что одно и то же) в трехмерной
// декартовой системе координат.
// Поддерживает примитивные операции над векторами в пространстве.
// Основан на коде Алексея В. Борескова (http://s...content-available-to-author-only...d.ru)
template < class T >
class Vertex3D
{
private:
// max3: возвращает максимальное значение из трех переданных
static T max3( T a, T b, T c )
{
return a > b ? (a > c ? a : (b > c ? b : c)) :
(b > c ? b : (a > c ? a : c));
};
// sqr: возвращает квадрат аргумента
static T sqr( T x )
{
return x * x;
};
public:
T x, y, z; // Координаты точки (вектора) в трехмерном пространстве
// Конструктор по умолчанию создаёт "нулевой" вектор
Vertex3D(): x( 0 ), y( 0 ), z( 0 ) {};
// Конструкто из трех координат
Vertex3D( T px, T py, T pz )
{
x = px;
y = py;
z = pz;
};
// Конструкто из массива трех координат
Vertex3D( const T *pt )
{
x = pt[ 0 ];
y = pt[ 1 ];
z = pt[ 2 ];
};
// Конструктор копирования из другой точки
Vertex3D( const Vertex3D< T > &v )
{
x = v.x;
y = v.y;
z = v.z;
};
// operator=: оператор копирования из массива трех координат точки
const Vertex3D< T > &operator=( const T *pt )
{
x = pt[ 0 ];
y = pt[ 1 ];
z = pt[ 2 ];
return *this;
};
// operator=: оператор копирования из другой точки
const Vertex3D< T > &operator=( const Vertex3D< T > &v )
{
x = v.x;
y = v.y;
z = v.z;
return *this;
};
// operator+: унарный плюс возвращает копию объекта
Vertex3D< T > operator+() const
{
return *this;
};
// operator-: Унарный минус возвращает инвертированную копию объекта
Vertex3D< T > operator-() const
{
return Vertex3D< T >( -x, -y, -z );
};
// operator+=: прибавляет к координатам текущей точки координаты аргумента
Vertex3D< T > &operator+=( const Vertex3D< T > &v )
{
x += v.x;
y += v.y;
z += v.z;
return *this;
};
// operator-=: вычитает из координат текущей точки координаты аргумента
Vertex3D< T > &operator-=( const Vertex3D< T > &v )
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
};
// operator*=: умножает координаты текущей точки на координаты аргумента
Vertex3D< T > &operator*=( const Vertex3D< T > &v )
{
x *= v.x;
y *= v.y;
z *= v.z;
return *this;
};
// operator*=: умножает координаты текущей точки на параметр
Vertex3D< T > &operator*=( T f )
{
x *= f;
y *= f;
z *= f;
return *this;
};
// operator/=: делит координаты текущей точки на координаты аргумента
Vertex3D< T > &operator/=( const Vertex3D< T > &v )
{
x /= v.x;
y /= v.y;
z /= v.z;
return *this;
};
// operator/=: делит координаты текущей точки на параметр
Vertex3D< T > &operator/=( T f )
{
x /= f;
y /= f;
z /= f;
return *this;
};
// operator[]: доступ к i-ому элементу координат в стиле массива (индекс x = 0)
T &operator[]( int index )
{
return *( index + &x );
};
// operator[] const: доступ к i-ому элементу координат в стиле массива (индекс x = 0)
T &operator[]( int index ) const
{
return *( index + &x );
};
// operator==: сравнение на равенство с аргументом
bool operator==( const Vertex3D< T > &v ) const
{
return (x == v.x) && (y == v.y) && (z == v.z);
};
// operator!=: сравнение на неравенство с аргументом
bool operator!=( const Vertex3D< T > &v ) const
{
return (x != v.x) || (y != v.y) || (z != v.z);
};
// Length: возвращает длину вектора (длину линии, соединяющей точку с началом координат)
T Length() const
{
return (T) sqrt( x * x + y * y + z * z );
};
// LengthSqr: возвращает квадрат длины вектора (длины линии, соединяющей точку
// с началом координат). В отличие от length() не использует вычисление квадратного
// корня, поэтому предпочтительнее использовать этот метод там, где возможно, например:
// Vertex3D a, b;
// ...
// if ( a.length() < b.length() ) ...
// будет выполнятся существенно медленнее чем
// if ( a.lengthSqr() < b.lengthSqr() ) ...
// но результат будет такой же, поэтому последняя форма предпочтительнее.
T LengthSqr() const
{
return x * x + y * y + z * z;
};
// Normalize: нормализует вектор, т.е. приводит его длину к единице (1).
Vertex3D< T > &Normalize()
{
return (*this) /= Length();
};
// MaxLength: возвращает величину максимальной координаты точки (вектора)
T MaxLength() const
{
return max3( (T)fabs(x), (T)fabs(y), (T)fabs(z) );
};
// DistanceTo: возвращает расстояние от текущей точки до аргумента
T DistanceTo( const Vertex3D< T > &p ) const
{
return (T) sqrt( sqr( x - p.x ) + sqr( y - p.y ) + sqr( z - p.z ) );
};
// DistanceToSqr: возвращает квадрат расстояния от текущей точки до аргумента
T DistanceToSqr( const Vertex3D< T > &p ) const
{
return sqr( x - p.x ) + sqr( y - p.y ) + sqr( z - p.z );
};
// DistanceToAlongAxis: возвращает расстояние (всегда > 0) между соответствующими
// координатами текущей точки с аргументом вдоль оси axis
// (0 - ось X, 1 - ось Y, 2 - ось Z).
T DistanceToAlongAxis( const Vertex3D< T > &p, int axis ) const
{
return (T) fabs( (*this)[ axis ] - p[ axis ] );
};
// GetMainAxis: возвращает индекс оси, координата по которой имеет максимальное
// абсолютное значение (0 - ось X, 1 - ось Y, 2 - ось Z).
int GetMainAxis() const
{
int axis = 0;
T val = (T) fabs ( x );
for ( register int i = 1; i < 3; i++ )
{
T vNew = (T) fabs( (*this)[ i ] );
if ( vNew > val )
{
val = vNew;
axis = i;
};
};
return axis;
};
// Lerp: возвращает точку, лежащую на прямой проходящей через текущую точку
// и точку b, отстоящую от текущей на t единиц вдоль прямой, начиная с неё и в
// направлении к точке b (если t > 0, или в обратном направлении, если t < 0).
// Единицей считается расстояние между этими точками
// (т.е. при t = 1 результат будет равен точке b).
Vertex3D< T > Lerp( const Vertex3D< T > &b, T t )
{
return *this + t * (b - *this);
};
// MixedProduct: выполняет векторное перемножение агрументов b и с, результат
// которого скалярно помножается на текущую точку (вектор).
// Результатом будет скаляр, величина которого равна объему
// параллелепипеда построенного на данных трёх векторах.
// Результат может быть отрицателен, в зависимости от того в каком
// (левостороннем или правостороннем) стоят вектора.
T MixedProduct( const Vertex3D< T > &b, const Vertex3D< T > &c ) const
{
return ( *this & ( b ^ c ) );
};
// operator+: бинарное сложение двух точек (векторов).
// Возвращает точку координаты которой являются суммой
// соответствующих координат аргументов.
Vertex3D< T > operator+( const Vertex3D< T > &v ) const
{
return Vertex3D< T >( x + v.x, y + v.y, z + v.z );
};
// operator-: бинарное вычитание двух точек (векторов).
// Возвращает точку координаты которой являются разницей
// соответствующих координат аргументов.
Vertex3D< T > operator-( const Vertex3D< T > &v ) const
{
return Vertex3D< T >( x - v.x, y - v.y, z - v.z );
};
// operator*: бинарное умножение двух точек (векторов).
// Возвращает точку координаты которой являются произведением
// соответствующих координат аргументов.
Vertex3D< T > operator*( const Vertex3D< T > &v ) const
{
return Vertex3D< T >( x * v.x, y * v.y, z * v.z );
};
// operator*: бинарное умножение точеки (вектора) на скаляр.
// Возвращает точку координаты которой являются произведением
// соответствующей координаты на аргумент.
Vertex3D< T > operator*( T a ) const
{
return Vertex3D< T >( x * a, y * a, z * a );
};
// operator/: бинарное деление точки (вектора) на скаляр.
// Возвращает точку координаты которой являются результатом деления
// соответствующей координаты на аргумент.
Vertex3D< T > operator/( T a ) const
{
return Vertex3D< T >( x / a, y / a, z / a );
};
// operator&: скалярное умножение векторов (dot product).
// Возвращает результат скалярного умножения аргументов
// (скаляр, величина которого равна произведению длин векторов на косинус угла между ними).
T operator&( const Vertex3D< T > &v ) const
{
return x * v.x + y * v.y + z * v.z;
};
// operator^: векторное умножение векторов (cross product).
// Возвращает результат векторного умножения аргументов
// (вектор, перпендикулярный плоскости, образованной u и v, длина которого
// равна произведению длин векторов на синус угла между ними).
Vertex3D< T > operator^( const Vertex3D< T > &v ) const
{
return Vertex3D< T >( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x );
};
};
template< class T >
Vertex3D<T> operator*( T a, const Vertex3D< T > & v )
{
return Vertex3D< T >( a * v.x, a * v.y, a * v.z );
}
template< class T >
Vertex3D<T> operator*( const Vertex3D< T > & v, T a )
{
return Vertex3D< T >( a * v.x, a * v.y, a * v.z );
}
typedef Vertex3D< float > Vertex3Df;
typedef Vertex3D< double > Vertex3Dd;
#endif