#include "stdafx.h"
#include <complex>
#include <fstream>
#include "cmat.h"
#include "lu.h"
#include "EuclideanTransform.h"
#include "Vertex.h"
#include <math.h>

#define M_PI       3.14159265358979323846

const std::complex<double> M_PI_COMPLEX = std::complex<double>(1, 0) / std::complex<double>(2 * M_PI, 0);


bool Vertex::Colored = true;

Vertex::Vertex(double* x)
{
	parent = NULL;
	proj.newsize(3);
	for (int i = 0; i < 3; i++)
	{
		relative[i].newsize(3);
	}
	Set(x);
}

Vertex::Vertex(const Vertex & v)
{
	parent = NULL;
	proj.newsize(3);
	for (int i = 0; i < 3; i++)
	{
		relative[i].newsize(3);
	}
	for (int i = 0; i < 3; i++)
	{
		vertices[i] = v.vertices[i];
	}
	Init();
}

Vertex::Vertex(const VectorD & x1, const VectorD & x2, const VectorD & x3)
{
	parent = NULL;
	proj.newsize(3);
	for (int i = 0; i < 3; i++)
	{
		relative[i].newsize(3);
	}
	vertices[0] = x1;
	vertices[1] = x2;
	vertices[2] = x3;
	Init();

}




Vertex::Vertex(ID3DFace * Face)
{
	parent = NULL;
	proj.newsize(3);
	for (int i = 0; i < 3; i++)
	{
		relative[i].newsize(3);
	}
	for (int i = 0; i < 3; i++)
	{
		vertices[i] = Face->GetVertex(i);
	}
	Init();
	face = Face;
	normD = face->GetNormal();
	double nd = sqrt(normD | normD);
	normD = normD / nd;
	for (int is = 0; is < 3; is++)
	{
		norm[is] = normD[is];
	}
}




Vertex::Vertex(double s, const VectorD & position, const VectorD & Norm)
{
        parent = NULL;
		normD = Norm;
        S = s;
		area = s;
        Position = position;
		proj.newsize(3);
}

Vertex::Vertex()
{
	parent = NULL;
	normD.newsize(3);
	Position.newsize(3);
	proj.newsize(3);
	area = 1;
	for (int i = 0; i < 3; i++)
	{
		Position[i] = 0;
	}
}

Vertex::~Vertex()
{
}


void Vertex::SetFace(ID3DFace * Face)
{
	for (int i = 0; i < 3; i++)
	{
		vertices[i] = Face->GetVertex(i);
	}
	Init();
	face = Face;
	normD = face->GetNormal();
	for (int is = 0; is < 3; is++)
	{
		norm[is] = normD[is];
	}
	ownColor = Face->GetColorV();
	parent = NULL;
}

void Vertex::ResetColor()
{
	face->SetColorV(ownColor);
}

void Vertex::Reset()
{
}



TNT::Vector<double> LColor(double a)
{

	double x = a;// + 0.5 * a * a;
	TNT::Vector<double> v(4);
	if (true)
	{
		v[0] = 0.7;
		v[1] = 0.7;
		v[2] = 0.7;
		v[3] = 1 - x;
		return v;
	}
	v[3] = 1;
	int k = int(x * 5);
	if (k < 0)
	{
		k = 0;
	}
	if (k > 4)
	{
		k = 4;
	}
	double y = 5 * (x - double(k) / 5.0);
	if (k == 0)
	{
		v[0] = 1;
		v[1] = y;
		v[2] = 0;
	}
	else if (k == 1)
	{
		v[0] = 1 - y;
		v[1] = 1;
		v[2] = 0;
	}
	else if (k == 2)
	{
		v[0] = 0;
		v[1] = 1;
		v[2] = y;
	}
	else if (k == 3)
	{
		v[0] = 0;
		v[1] = 1 - y;
		v[2] = 1;
	}
	else
	{
		v[0] = y;
		v[1] = 0;
		v[2] = 1;
	}
	return v;
}


void Vertex::Draw(double a)
{
//	double b = 0;
/*	for (int i = 0; i < 3; i++)
	{
		b += J[i].real() * J[i].real() + J[i].imag() * J[i].imag();
//		ofst << J[i] << "\t";
	}
	b = sqrt(b);
	double x = b / a;
//	ofst << x << "\t";
/*	if (x < 0.0001)
	{
		ResetColor();
		return;
	}*/
	/*sum = 0;
	double x = sqrt(sum / a);
	if (x > 1)
	{
		x = 1;
	}
	face->SetColorV(LColor(1 - x));*/
	D3DFaceGL * f = (D3DFaceGL*)face;
	f->DrawGL();

}

const VectorD& Vertex::GetVertex(int i) const
{
        return vertices[i];
}

const VectorD& Vertex::GetNorm() const
{
        return normD;
}



void Vertex::LoadFromStream(std::istream& is)
{
        for (int i = 0; i < 3; i++)
        {    
			vertices[i].newsize(3);
            for (int j = 0; j < 3; j++)
            {
				is >> vertices[i][j];
            }
        }
        Init();

}


std::istream & operator >> (std::istream & is, Vertex & v)
{
        v.LoadFromStream(is);
        return is;
}



void Vertex::Init()
{
    VectorD v1(vertices[1] - vertices[0]);
    VectorD v2(vertices[2] - vertices[0]);
    VectorD v3(vertices[1] - vertices[2]);
	size = sqrt(v1 | v1);
	double a = sqrt(v2 | v2);
	if (a > size)
	{
		size = a;
	}
	a = sqrt(v3 | v3);
	if (a > size)
	{
		size = a;
	}
    Position = vertices[0] + (1.0 / 3.0) * (v1 + v2);
	for (int i = 0; i < 3; i++)
	{
		relative[i] = vertices[i] - Position;
	}
    norm = (VectorC)(v1 ^ v2);
	area = sqrt((norm | norm).real()) / 2;
	if (area < 1.0E-12)
	{
		norm = ComplexD(0);
	}
	else
	{
		norm =  ComplexD(0.5 / area) * norm;
	}
//    source = Position;
    normD.newsize(3);
    for (int i = 0; i < 3; i++)
    {
		normD[i] = norm[i].real();
    }
    parent = NULL;
    VisibleMat.newsize(3, 3);
	face = NULL;
}


void Vertex::SetVisibilityPoint(const VectorD & point)
{
        SourcePoint = point;
        for (int i = 0; i < 3; i++)
        {
                for (int j = 0; j < 3; j++)
                {
                        VisibleMat[i][j] = vertices[j][i] - point[j];
                }
        }
        VisibleMat = !VisibleMat;
        VisibleProjection = normD | vertices[0];
}

bool Vertex::isVisible(const VectorD & point)
{
        VectorD x(VisibleMat * point);
        for (int i = 0; i < 3; i++)
        {
                if (x[i] <= 0.0)
                {
                        return true;
                }
        }
        double a = (point | normD) - VisibleProjection;
        return a > 0;
}

void Vertex::ResetSum()
{
	sum = 0;
}


void Vertex::Set(double *x)
{
	for (int i = 0; i < 3; i++)
	{
		double* v = &x[3 * i];
		VectorD & vert = vertices[i];
		vertices[i].newsize(3);
		for (int j = 0; j < 3; j++)
		{
			vert[j] = v[j];
		}
	}
	Init();
}


void Vertex::SetParent(MultiVertex * Parent)
{
	parent = Parent;
}


const VectorD & Vertex::GetPosition()
{
	return Position;
}

void Vertex::SetValue(double Value)
{
	value = Value;
}

		
void Vertex::DrawValue(double min, double max)
{
	if (face == NULL)
	{
		return;
	}
	double a = (value - min) / (max - min);
	face->SetColorV(LColor(1 - a));
}



void Vertex::SetColorV(const VectorD & v)
{
	face->SetColorV(v);
}


void Vertex::SetTransitionMatrix(const MatrixD & m)
{
}

double Vertex::GetSolidAngleIntegral() const
{
	double amp = ::norm(Position);
	VectorD v[3];
	for (int i = 0; i < 3; i++)
	{
		v[i].newsize(3);
		double x = ::norm(vertices[i]);
		if (x == 0)
		{
			return 0;
		}
		v[i] = vertices[i] / ::norm(vertices[i]);
	}
	double s = ::norm((v[1] - v[0]) % (v[2] - v[0]));
	return 0.5 * s * amp;
}


std::vector<Vertex *> Vertex::barycentric()
{
	std::vector<Vertex *> v;
	VectorD center = (1.0 / 3.0) * (vertices[0] + vertices[1] + vertices[2]);
	VectorD v12 = 0.5 * (vertices[0] + vertices[1]);
	VectorD v23 = 0.5 * (vertices[1] + vertices[2]);
	VectorD v31 = 0.5 * (vertices[2] + vertices[0]);
	Vertex * v1 = new Vertex(vertices[0], v12, center);
	v.push_back(v1);
	Vertex * v2 = new Vertex(vertices[1], center, v12);
	v.push_back(v2);
	Vertex * v3 = new Vertex(vertices[1], v23, center);
	v.push_back(v3);
	Vertex * v4 = new Vertex(vertices[2], center, v23);
	v.push_back(v4);
	Vertex * v5 = new Vertex(vertices[2], v31, center);
	v.push_back(v5);
	Vertex * v6 = new Vertex(vertices[0], center, v31);
	v.push_back(v6);
	return v;
}

void Vertex::CreateCollection(double Size, std::vector<Vertex *> & collection, std::vector<Vertex *> & del)
{
	if (size < Size)
	{
		collection.push_back(this);
		return;
	}
	del.push_back(this);
	std::vector<Vertex *> v = barycentric();
	for (size_t i = 0; i < v.size(); i++)
	{
		v[i]->CreateCollection(Size, collection, del);
	}
}


