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

#include "StdAfx.h"
//#include "VWLine3D.h"

using namespace VWFC::Math;

VWLine3D::VWLine3D()
{
}

VWLine3D::VWLine3D(const VWPoint3D& begPt, const VWPoint3D& endPt)
{
	m_ptStart	= begPt;
	m_ptEnd		= endPt;
}

VWLine3D::VWLine3D(const VWLine3D& src)
{
	m_ptStart	= src.m_ptStart;
	m_ptEnd		= src.m_ptEnd;
}

VWLine3D::~VWLine3D()
{
}

VWLine3D& VWLine3D::operator=(const VWLine3D& src)
{
	m_ptStart	= src.m_ptStart;
	m_ptEnd		= src.m_ptEnd;
	return *this;
}

const VWPoint3D& VWLine3D::GetStart() const
{
	return m_ptStart;
}

VWPoint3D& VWLine3D::GetStart()
{
	return m_ptStart;
}

const VWPoint3D& VWLine3D::GetEnd() const
{
	return m_ptEnd;
}

VWPoint3D& VWLine3D::GetEnd()
{
	return m_ptEnd;
}

void VWLine3D::GetLine(VWPoint3D& outPtStart, VWPoint3D& outPtEnd) const
{
	outPtStart		= m_ptStart;
	outPtEnd		= m_ptEnd;
}

void VWLine3D::SetStart(const VWPoint3D& pt)
{
	m_ptStart	= pt;
}

void VWLine3D::SetEnd(const VWPoint3D& pt)
{
	m_ptEnd		= pt;
}

void VWLine3D::SetLine(const VWPoint3D& ptStart, const VWPoint3D& ptEnd)
{
	m_ptStart	= ptStart;
	m_ptEnd		= ptEnd;
}

void VWLine3D::ReverseSides()
{
	VWPoint3D	pt	= m_ptStart;
	m_ptStart		= m_ptEnd;
	m_ptEnd			= pt;
}

VWLine3D VWLine3D::operator+(const VWPoint3D& p) const
{
	VWLine3D	line	= *this;
	line				+= p;
	return line;
}

VWLine3D VWLine3D::operator-(const VWPoint3D& p) const
{
	VWLine3D	line	= *this;
	line				-= p;
	return line;
}

VWLine3D VWLine3D::operator*(double scalar) const
{
	VWLine3D	line	= *this;
	line				*= scalar;
	return line;
}

VWLine3D VWLine3D::operator/(double scalar) const
{
	VWLine3D	line	= *this;
	line				/= scalar;
	return line;
}

VWLine3D& VWLine3D::operator+=(const VWPoint3D& p)
{
	m_ptStart		+= p;
	m_ptEnd			+= p;
	return *this;
}

VWLine3D& VWLine3D::operator-=(const VWPoint3D& p)
{
	m_ptStart		-= p;
	m_ptEnd			-= p;
	return *this;
}

VWLine3D& VWLine3D::operator*=(double scalar)
{
	m_ptStart		*= scalar;
	m_ptEnd			*= scalar;
	return *this;
}

VWLine3D& VWLine3D::operator/=(double scalar)
{
	m_ptStart		/= scalar;
	m_ptEnd			/= scalar;
	return *this;
}

////////////////////////////////////////////////////////////////////
// math functions
////////////////////////////////////////////////////////////////////
// return the center point of the line
VWPoint2D VWLine3D::CenterPt() const
{
	return ( m_ptStart + m_ptEnd ) / 2;
}

// return the length of the line
double VWLine3D::GetLength() const
{
	return m_ptStart.DistanceTo( m_ptEnd );
}

// min distance from a point to this line
// this is the distance from the point to the nearest point on the line
// which is the line perpendicular to the given one trough the specified point
double VWLine3D::GetDistance(const VWPoint3D& pt) const
{
/*	VWPoint3D	tangent	= (m_ptEnd - m_ptStart).Normalize();

	VWPoint3D	diff	= pt - m_ptStart;
	double		f		= diff % tangent;
	
	return diff.DistanceTo( tangent * f );
*/

	double	a	= ((m_ptEnd - m_ptStart) * (m_ptStart - pt)).Magnitude();
	double	b	= (m_ptEnd - m_ptStart).Magnitude();

	return a / b;
/*
	VWPoint3D	diff( pt - m_ptStart );
	VWPoint3D	m	= (m_ptEnd - m_ptStart).Normalize();

    double l = (m % m);
    if (l > 0.0f)
	{
        double t	= (m % diff) / l;
        diff		= diff - m*t;

        return diff.Magnitude();
    }
	else
	{
        // line is really a point...
        VWPoint3D v( pt - m_ptStart );
        return v.Magnitude();
    }
*/
}

// return the direction vector of the line (end - start)
VWPoint3D VWLine3D::GetDirectionVector() const
{
	return (m_ptEnd - m_ptStart).Normalize();
}

// get vertical distance from the point to the line
// NOTE! no check if the point is on the projection of the line is check
double VWLine3D::GetVerticalDistance(const VWPoint3D& pt) const
{
	return  VWLine3D::GetVerticalDistance( m_ptStart.x, m_ptStart.y, m_ptStart.x, m_ptEnd.x, m_ptEnd.y, m_ptEnd.x, pt.x, pt.y );
}


double VWLine3D::GetVerticalDistance(double ax, double ay, double az, double bx, double by, double bz, double px, double py)
{
	double		d		= VWPoint2D::Distance( ax, ay, bx, by );
	double		dp		= VWPoint2D::Distance( ax, ay, px, py );

	if ( Abs(d) == VWPoint2D::sEpsilon )
		return 0;

	double		pz		= 0;
	if ( az <= bz ) {
		pz		= ( bz - az ) * ( dp / d ) + az;
	}
	else {
		pz		= ( az - bz ) * ( (d - dp) / d ) + bz;
	}

	return pz;
}
