//
//	Copyright © 2005 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#include "StdAfx.h"
//#include "VWPoint3D.h"

using namespace VWFC::Math;



// default epsilon for operator==
double	VWPoint3D::sEpsilon		= 0.0000001;

VWPoint3D::VWPoint3D()
{
	this->x	= 0;
	this->y	= 0;
	this->z	= 0;
}

VWPoint3D::VWPoint3D(const WorldPt3& pt)
{
	this->x	= pt.x;
	this->y	= pt.y;
	this->z	= pt.z;
}

VWPoint3D::VWPoint3D(double x, double y, double z)
{
	this->x	= x;
	this->y	= y;
	this->z	= z;
}

VWPoint3D::VWPoint3D(const VWPoint2D& pt, double z)
{
	this->x	= pt.x;
	this->y	= pt.y;
	this->z	= z;
}

VWPoint3D::VWPoint3D(const VWPoint3D& src)
{
	this->x	= src.x;
	this->y	= src.y;
	this->z	= src.z;
}

VWPoint3D::~VWPoint3D()
{
}

void VWPoint3D::SetPoint(double x, double y, double z)
{
	this->x	= x;
	this->y	= y;
	this->z	= z;
}

void VWPoint3D::SetPoint(const VWPoint2D& pt, double z)
{
	this->x	= pt.x;
	this->y	= pt.y;
	this->z	= z;
}

void VWPoint3D::SetPoint(const WorldPt3& pt)
{
	this->x	= pt.x;
	this->y	= pt.y;
	this->z	= pt.z;
}

bool VWPoint3D::operator==(const VWPoint3D& p) const
{
	return	this->Equal( p, VWPoint3D::sEpsilon );
}

bool VWPoint3D::operator!=(const VWPoint3D& p) const
{
	return	! this->Equal( p, VWPoint3D::sEpsilon );
}

bool VWPoint3D::operator==(const VWPoint2D& p) const
{
	return	this->Equal( p, VWPoint3D::sEpsilon );
}

bool VWPoint3D::operator!=(const VWPoint2D& p) const
{
	return	! this->Equal( p, VWPoint3D::sEpsilon );
}

VWPoint3D VWPoint3D::operator+(const VWPoint3D& p) const
{
	return VWPoint3D( x + p.x, y + p.y, z + p.z );
}

VWPoint3D VWPoint3D::operator-(const VWPoint3D& p) const
{
	return VWPoint3D( x - p.x, y - p.y, z - p.z );
}

VWPoint3D VWPoint3D::operator*(double scalar) const
{
	return VWPoint3D( x * scalar, y * scalar, z * scalar );
}

VWPoint3D VWPoint3D::operator/(double scalar) const
{
	return VWPoint3D( x / scalar, y / scalar, z / scalar );
}

VWPoint3D VWPoint3D::operator-(void) const
{
	return VWPoint3D( -x, -y, -z );
}

VWPoint3D& VWPoint3D::operator=(const WorldPt3& p)
{
	x	= p.x;
	y	= p.y;
	z	= p.z;
	return *this;
}

VWPoint3D& VWPoint3D::operator=(const VWPoint3D& p)
{
	x	= p.x;
	y	= p.y;
	z	= p.z;
	return *this;
}

VWPoint3D& VWPoint3D::operator=(const VWPoint2D& p)
{
	x	= p.x;
	y	= p.y;
	z	= 0;
	return *this;
}

VWPoint3D& VWPoint3D::operator+=(const VWPoint3D& p)
{
	x	+= p.x;
	y	+= p.y;
	z	+= p.z;
	return *this;
}

VWPoint3D& VWPoint3D::operator+=(const VWPoint2D& p)
{
	x	+= p.x;
	y	+= p.y;
	return *this;
}

VWPoint3D& VWPoint3D::operator-=(const VWPoint3D& p)
{
	x	-= p.x;
	y	-= p.y;
	z	-= p.z;
	return *this;
}

VWPoint3D& VWPoint3D::operator-=(const VWPoint2D& p)
{
	x	-= p.x;
	y	-= p.y;
	return *this;
}


VWPoint3D& VWPoint3D::operator*=(double s)
{
	x	*= s;
	y	*= s;
	z	*= s;
	return *this;
}

VWPoint3D& VWPoint3D::operator/=(double s)
{
	x	/= s;
	y	/= s;
	z	/= s;
	return *this;
}

// cross product
VWPoint3D VWPoint3D::operator*(const VWPoint3D& p) const
{
	return VWPoint3D(	this->y * p.z - this->z * p.y,
						this->z * p.x - this->x * p.z,
						this->x * p.y - this->y * p.x	);
}

VWPoint3D& VWPoint3D::operator*=(const VWPoint3D& p)
{
	this->SetPoint(	this->y * p.z - this->z * p.y,
					this->z * p.x - this->x * p.z,
					this->x * p.y - this->y * p.x	);
	return *this;
}

// dot product
double VWPoint3D::operator%(const VWPoint3D& p) const
{
	return this->x * p.x + this->y * p.y + this->z * p.z;
}

// compatibility with SDK
VWPoint3D::operator const WorldPt3&() const
{
	// fool the compiler
	// to allow us modify member variable
	WorldPt3*	pPt	= (WorldPt3*) & fPoint;
	pPt->Set( x, y, z );
	return (*pPt);
}

VWPoint3D::operator VWPoint2D() const
{
	return VWPoint2D( x, y );
}

//////////////////////////////////////////////////////////////////////////////////////
// Math functions
//////////////////////////////////////////////////////////////////////////////////////

// return the distance from (0,0,0) to this point
double VWPoint3D::Magnitude() const
{
	return sqrt( x*x + y*y + z*z );
}

// return the squared distance from (0,0,0) to this point
double VWPoint3D::MagnitudeSquared() const
{
	return x*x + y*y + z*z;
}

// return true if the specified point is equal within the given epsilon to this point
bool VWPoint3D::Equal(const VWPoint3D& pt, double dEpsilon) const
{
	double	xx	= (x - pt.x);
	double	yy	= (y - pt.y);
	double	zz	= (z - pt.z);
	return ((xx*xx) + (yy*yy) + (zz*zz)) < dEpsilon*dEpsilon;
}

bool VWPoint3D::Equal(const VWPoint2D& pt, double dEpsilon) const
{
	double	xx	= (x - pt.x);
	double	yy	= (y - pt.y);
	return ((xx*xx) + (yy*yy)) < dEpsilon*dEpsilon;
}

// calculate the distance from the specified point to this point
double VWPoint3D::DistanceTo(double x, double y, double z)
{
	double	xx	= this->x - x;
	double	yy	= this->y - y;
	double	zz	= this->z - z;
	return sqrt( xx*xx + yy*yy + zz*zz );
}

double VWPoint3D::DistanceTo(const VWPoint3D& pt) const
{
	return ( (*this) - pt ).Magnitude();
}

// calculate the distance from the specified point to this point
double VWPoint3D::DistanceSquaredTo(double x, double y, double z)
{
	double	xx	= this->x - x;
	double	yy	= this->y - y;
	double	zz	= this->z - z;
	return xx*xx + yy*yy + zz*zz ;
}

double VWPoint3D::DistanceSquaredTo(const VWPoint3D& pt) const
{
	return ( (*this) - pt ).MagnitudeSquared();
}

// cross product
VWPoint3D VWPoint3D::Cross(const VWPoint3D& pt) const
{
	return VWPoint3D(	this->y * pt.z - this->z * pt.y,
						this->z * pt.x - this->x * pt.z,
						this->x * pt.y - this->y * pt.x	);
}

// dot product
double VWPoint3D::DotProduct(const VWPoint3D& pt) const
{
	return this->x * pt.x + this->y * pt.y + this->z * pt.z;
}

// normalize this vector
VWPoint3D& VWPoint3D::Normalize()
{      
	double		len	= this->Magnitude();
	if ( len > 0.0 )
	{
		this->x	/= len;
		this->y	/= len;
		this->z	/= len;
	}
	return *this;
}

double VWPoint3D::TriArea(const VWPoint3D& pt1, const VWPoint3D& pt2, const VWPoint3D& pt3)
{
	// The area of a 3D triangle defined by the vertex P1, P2, P3 is half the magnitude of the cross product of the two edge vectors:
	// 0.5 * | P1P2 * P1P3 |

	VWPoint3D	cross	= (pt2 - pt1).Cross( pt3 - pt1 );
	
	return cross.Magnitude() / 2;
}

double VWPoint3D::TriArea(	double pt1x, double pt1y, double pt1z,
							double pt2x, double pt2y, double pt2z,
							double pt3x, double pt3y, double pt3z)
{
	// The area of a 3D triangle defined by the vertex P1, P2, P3 is half the magnitude of the cross product of the two edge vectors:
	// 0.5 * | P1P2 * P1P3 |

	double	P1P2x	= pt2x - pt1x;
	double	P1P2y	= pt2y - pt1y;
	double	P1P2z	= pt2z - pt1z;

	double	P1P3x	= pt3x - pt1x;
	double	P1P3y	= pt3y - pt1y;
	double	P1P3z	= pt3z - pt1z;

	double	crossX	= P1P2y * P1P3z - P1P2z * P1P3y;
	double	crossY	= P1P2z * P1P3x - P1P2x * P1P3z;
	double	crossZ	= P1P2x * P1P3y - P1P2y * P1P3x;

	double	sign	= crossZ < 0 ? -1 : 1;

	return sign * sqrt( crossX*crossX + crossY*crossY + crossZ*crossZ ) / 2;
}
