//#  eulerN -- program for statistical estimation of Euler characteristic of a 3-dimensional body
//#  given as a sufficiently dense "volumetric" point sampling
//#
//#  Copyright (c) 2005-2007 Bradford Jones, Konstantin Rybnikov, Karen Daniels, Daniel Klain
//#  Release 2: 1 June 2007 
//#
//#  This program is free software; you can redistribute it and/or modify it
//#  under the terms of the GNU General Public License as published by the
//#  Free Software Foundation; either version 2, or (at your option) any
//#  later version: http://www.gnu.org/licenses/gpl.txt.
//#
//#  This program is distributed in the hope that it will be useful,
//#  but WITHOUT ANY WARRANTY; without even the implied warranty of
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//#  GNU General Public License for more details.
//#-----------------------------------------------------------------------------


#include "math_vector.h"
SeedRandomNumberGenerator math_vector::seedRandomGenerator; // ensures the random number generator is seeded
/*--------------------------------------*/
/// constructors
/*--------------------------------------*/
math_vector::math_vector()
{

	dimension = 0;
}
math_vector::math_vector(int d)
{
	assert(d > 0);

	dimension = d;
	for (int i = 0; i < dimension; i++)
		data[dimension] = 0;
}
math_vector::math_vector(double x, double y)
{

	dimension = 2;
	data[0] = x; data[1] = y;
}
math_vector::math_vector(double x, double y, double z)
{

	dimension = 3;
	data[0] = x; data[1] = y; data[2] = z;
}
math_vector::math_vector(const math_vector& copy)
{
	dimension = copy.dim();
	for (int i = 0; i < dimension; i++)
		data[i] = copy[i];
}
math_vector::~math_vector()
{
}
/*--------------------------------------*/
/// class functions
/*--------------------------------------*/

double math_vector::xcoord()
{
	assert(dimension > 0);
	return data[0];
}
double math_vector::ycoord()
{
	assert(dimension > 1);
	return data[1];
}
double math_vector::zcoord()
{
	assert(dimension > 2);
	return data[2];
}
int math_vector::dim() const
{
	return dimension;
}
math_vector math_vector::norm()
{
	math_vector temp = *this;
	double mag = temp.length();

	assert(mag != 0);

	for (int i = 0; i < dimension; i++)
		temp[i] = data[i] / mag;
	return temp;
}
double math_vector::length()
{
	double total = 0;
	for (int i = 0; i < dimension; i++)
		total = total + data[i] * data[i];
	return sqrt(total);
}
double math_vector::sqr_length()
{
	double total = 0;
	for (int i = 0; i < dimension; i++)
	{
		total = total + data[i]*data[i];
	}
	return total;
}
math_vector math_vector::getRandomUnitVector(int dimension)
{
	double total;
	math_vector outputVector = *this;
	outputVector.dimension = dimension;
	while (true)
	{
		for (int i = 0; i < dimension; i++)
		{
			total = 0;
			for (int j = 0; j < 30; j++)
			{
				total = total +  ((double) rand()/RAND_MAX );
			}
			total = total - 15;
			outputVector[i] = total;
		}

		if (outputVector[0] != 0 || outputVector[1] != 0 || outputVector[2] != 0)
		{
			// the probability is extremely high that this IF condition passes
			outputVector = outputVector.norm();
			return outputVector;
		}

	}
}
/*--------------------------------------*/
/// overloaded operators
/*--------------------------------------*/
math_vector& math_vector::operator = (const math_vector &rhs)
{
	if (this == &rhs)
		return *this;

	dimension = rhs.dim();
	for (int i = 0; i < dimension; i++)
		data[i] = rhs[i];

	return *this;
}
bool math_vector::operator == (const math_vector &rhs)
{
	if (dimension != rhs.dim())
		return false;

	for (int i = 0; i < dimension; i++)
		if ( data[i] != rhs[i])
			return false;

	return true;
}
bool math_vector::operator != (const math_vector &rhs)
{
	if (dimension != rhs.dim())
		return true;

	for (int i = 0; i < dimension; i++)
		if ( data[i] != rhs[i])
			return true;

	return false;
}
double& math_vector::operator[] (int index)
{
	return data[index];
}

const double& math_vector::operator[] (int index) const
{
	return data[index];
}

math_vector math_vector::operator + (const math_vector &rhs)
{
	assert(dimension == rhs.dim()); //dimension must be same for addition
	math_vector temp = *this;

	for (int i = 0; i < dimension; i++)
		temp[i] = data[i] + rhs[i];

	return temp;
}
math_vector math_vector::operator - (const math_vector &rhs)
{
	assert(dimension == rhs.dim()); //dimension must be same for subtraction

	math_vector temp = *this;

	for (int i = 0; i < dimension; i++)
		temp[i] = data[i] - rhs[i];

	return temp;
}
math_vector math_vector::operator / (double scale)
{
	assert(scale != 0); //no divide by zero

	math_vector temp = *this;
	for (int i = 0; i < dimension; i++)
		temp[i] = data[i] / scale;
	return temp;
}
/*--------------------------------------*/
/// friend functions / binary operators
/*--------------------------------------*/
double operator * (const math_vector &lhs, const math_vector &rhs)//dot product
{

	assert(lhs.dim() == rhs.dim()); //dimension must be same for addition

	double total = 0;
	for (int i = 0; i < rhs.dim(); i++)
		total = total + ( lhs[i] * rhs[i] );
	return total;
}
math_vector operator * (const math_vector &lhs, double scale) // scale vector
{
	math_vector temp(lhs.dim());
	for (int i = 0; i < lhs.dim(); i++)
		temp[i] = lhs[i] * scale;
	return temp;
}
math_vector operator * (double scale, const math_vector &rhs) // scale vector
{
	math_vector temp(rhs.dim());
	for (int i = 0; i < rhs.dim(); i++)
		temp[i] = rhs[i] * scale;
	return temp;
}
ostream& operator << (ostream &os, const math_vector &v)
{
	os << '<';
	for (int i = 0; i < (v.dim() -1); i++)
		os << v[i] << ',';
	os << v[v.dim() -1] << '>';
	return os;
}



