//---------------------------------------------------------------------------
//#pragma hdrstop //Управление пред компиляцией
//#include "stdafx.h"
//---------------------------------------------------------------------------
#include <stdexcept>      // std::invalid_argument
#include <stdlib.h> //rand
#include <math.h>

//---------------------------------------------------------------------------
#include "mathTools.h"
#include "object3d.h"
//---------------------------------------------------------------------------
//Большее из 2х интеджеров
int MaxI4(int v1,int v2)
{	if(v1>v2) return v1; else return v2;
}
//---------------------------------------------------------------------------
/*int MaxI4_2(int v1,int v2)
{	if(v1>v2) return v1; else return v2;
}*/
//------------------------------------------------------------------------------
//Преобразовать HEX символ в число
int hexCharToInt(char input)
{
  if(input >= '0' && input <= '9')
    return input - '0';
  if(input >= 'A' && input <= 'F')
    return input - 'A' + 10;
  if(input >= 'a' && input <= 'f')
    return input - 'a' + 10;
  throw std::invalid_argument("Invalid input string");
}
//------------------------------------------------------------------------------
//проверка значения бита в массиве (нумерация с лева на право) pos - 0..n
bool testBit(const unsigned char *mas,const unsigned char pos)
{
	unsigned char mask=128;
	unsigned char loc=pos/8;
	mask=mask >> (pos-loc*8);
	return (mask & mas[loc])==mask;
}
//------------------------------------------------------------------------------
//установить заданный бит в 1 или в 0
void setBit(unsigned char *mas,const unsigned char pos,bool val)
{
	unsigned char mask=128;
	unsigned char loc=pos/8;
	mask=mask >> (pos-loc*8);
	if(val) mas[loc]=mas[loc] | mask;
	else
	{
		mask=~mask; //Отрицание
		mas[loc]=mas[loc] & mask;
	}
}
//---------------------------------------------------------------------------
//Установит знначение бита в заданную позицию
///pos - Позиция 7..0
uint1 setBitVal(uint1 bit,uint1 pos,bool val)
{
	uint1 v=1;
	v=0x1<<pos;
	if(val)
	{
		bit=bit | v;
	}else
	{
		v=v ^ 0xFF;
		bit=bit & v;
	}
	return bit;
}
//---------------------------------------------------------------------------
//Вернёт значение бита на заданной позиции
///pos - Позиция 7..0
bool getBitVal(uint1 bit,uint1 pos)
{
	uint1 v=1;
	v=v<<pos;
	return (bit & v) == v;
}
//---------------------------------------------------------------------------
//Скорость ком порта по номеру
long getBaudRate(long s)
{	
	if(s==0) return 1200;
	if(s==1) return 2400;
	if(s==2) return 4800;
	if(s==3) return 9600;
	if(s==4) return 19200;
	if(s==5) return 38400;
	if(s==6) return 57600;
	if(s==7) return 115200;
	return 0;
}
//---------------------------------------------------------------------------
//Шифровать XOR
void Encrypt(unsigned char* key, unsigned short keylen, unsigned char* data, unsigned short datalen)
{
	for(int i=0;i<datalen;i++)
		for(int j=0;j<keylen;j++)
			data[i]= data[i] ^ key[j];
}
//---------------------------------------------------------------------------
//Дешифровать XOR
void Decrypt(unsigned char* key, unsigned short keylen, unsigned char* data, unsigned short datalen)
{
  /*res = "";
  // побайтное шифрование без ключа
  for(int i = 1; i <= key.Length(); i++)
    res += " ";
  res[1] = key[1] ^ key[key.Length()];
  for(int i = 1; i < key.Length();i++){
    res[i + 1] = key[i+1] ^ res[i];
  }*/
}
//------------------------------------------------------------------------------
//Простое вычисление CRC (как для GPS)
unsigned char CRC8(const char *pcBlock, unsigned char len, unsigned char crc)
{
	for(unsigned char i=0; i < len; i++)
		crc^=pcBlock[i];
	return crc;
}
// ----------------------------------------------------------------------------
/*
  Name  : CRC-16 CCITT
  Poly  : 0x1021    x^16 + x^12 + x^5 + 1
  Init  : 0xFFFF
  Revert: false
  XorOut: 0x0000
  Check : 0x29B1 ("123456789")
  MaxLen: 4095 байт (32767 бит) - обнаружение
    одинарных, двойных, тройных и всех нечетных ошибок
*/
unsigned short Crc16(unsigned char ch, unsigned short crc)
{
	unsigned char i;
	crc ^= ch << 8;
	for (i = 0; i < 8; i++)
		crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
	return crc;
}
// ----------------------------------------------------------------------------
/*
  Name  : CRC-16 CCITT
  Poly  : 0x1021    x^16 + x^12 + x^5 + 1
  Init  : 0xFFFF
  Revert: false
  XorOut: 0x0000
  Check : 0x29B1 ("123456789")
  MaxLen: 4095 байт (32767 бит) - обнаружение
    одинарных, двойных, тройных и всех нечетных ошибок
*/
unsigned short Crc16(const char *pcBlock, unsigned short len, unsigned short crc)
{
    //unsigned short crc = 0xFFFF;
    unsigned char i;
 
    while (len--)
    {
        crc ^= *pcBlock++ << 8;
        for (i = 0; i < 8; i++)
            crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
    }
 
    return crc;
}
//------------------------------------------------------------------------------
int RandInt(int a, int b)
{
	return a + rand() % (b - a + 1);
}
//------------------------------------------------------------------------------
//Расстояние от начала декартовых координат до заданной точки
float fnGetDistans(RfPointXYZ p)
{
	return sqrt(sqr(p.x) + sqr(p.y) + sqr(p.z));
}
//------------------------------------------------------------------------------
//Расстояние между 2мя точками на плоскости в декартовых координатах
float fnGetDistans2d(RfPointXY PointXY1, RfPointXY PointXY2)
{
	return sqrt(fabs(sqr(PointXY1.x - PointXY2.x) + sqr(PointXY1.y - PointXY2.y)));
}
//------------------------------------------------------------------------------
//Расстояние между 2мя точками в пространстве в декартовых координатах
float fnGetDistans3d(RfPointXYZ PointXYZ1, RfPointXYZ PointXYZ2)
{
	return sqrt(fabs(sqr(PointXYZ1.x - PointXYZ2.x) + sqr(PointXYZ1.y - PointXYZ2.y) + sqr(PointXYZ1.z - PointXYZ2.z)));
}
//------------------------------------------------------------------------------
float sqr(float val)
{
	return val*val;
}
//------------------------------------------------------------------------------
double sqr(double val)
{
	return val*val;
}
//------------------------------------------------------------------------------
int roundf2(float val)
{
	if (val>0)
	{
		if (val - floor(val) >= 0.5) return (int)floor(val) + 1; else return (int)floor(val);
	}
	else
		if (val <= 0)
		{
			if (val - floor(val) <= 0.5) return (int)floor(val) - 1; else return (int)floor(val);
		}
	return 0;
}
//------------------------------------------------------------------------------
//Чтоб угол был в пределах 0..2PI градусов
double fnCorrectAngle(double angle)
{
	double num;
	if (angle>2 * M_PI)
	{
		num = floor(angle / (2.0*M_PI));
		angle = (angle - 2.0*M_PI*num);
	};
	if (angle<0)
	{
		num = floor(-angle / (2.0*M_PI)) + 1;
		angle = ((2.0*M_PI)*num + angle);
	}
	return angle;
};
//------------------------------------------------------------------------------
//Корректировать угол не дает превысить 2PI, приводит к положительному значению если оно отрицательно -45°=360°-45°=315°
double CorrectAngleRad(double angle)
{
	int num; //количество оборотов
	if (angle>2 * PI)
	{
		num = (int)floor(angle / (2 * PI));
		angle = (angle - 2 * PI*num);
	}
	else
		if (angle<0)
		{
			num = (int)floor(-angle / (2 * PI)) + 1;
			angle = ((2 * PI)*num + angle);
		}
	return angle;
}
/*************************************************************************
Проверка лежат ли две точки по одну сторону от прямой.
Если одна или обе точки лежат на прямой, функция возвращает True.

function IsPointsOnOneSide(
x1,y1,x2,y2:real;
xL1,yL1,xL2,yL2:real):Boolean

This function check is 2 points lies on same side from line
(x1,y1),(x2,y2) checked points
(xL1,yL1),(xL2,yL2)-two points for definition line;
*************************************************************************/
bool isPointsOnOneSide(const float x1,
	const float y1,
	const float x2,
	const float y2,
	const float xL1,
	const float yL1,
	const float xL2,
	const float yL2)
{
	if ((xL1<xL2) || (xL1>xL2))
	{
		return (y1 - yL1 + (yL1 - yL2)*(x1 - xL1) / (xL2 - xL1))*(y2 - yL1 + (yL1 - yL2)*(x2 - xL1) / (xL2 - xL1)) >= 0;
	}
	else
	{
		return (x1 - xL1)*(x2 - xL2) >= 0;
	}
}
//------------------------------------------------------------------------------
//Просчитать нормаль к плоскости плоскость заданна 3мя точками против часовой стрелки
void CalcNormals(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float &xr, float &yr, float &zr)
{
	float a, b, c, r;
	a = (y1 - y0)*(z2 - z0) - (y2 - y0)*(z1 - z0);
	b = (x2 - x0)*(z1 - z0) - (x1 - x0)*(z2 - z0);
	c = (x1 - x0)*(y2 - y0) - (y1 - y0)*(x2 - x0);
	r = sqrt(a*a + b*b + c*c);
	if (r != 0) r = 1 / r;
	xr = a*r;
	yr = b*r;
	zr = c*r;
}
//------------------------------------------------------------------------------
//уравнение окружности по 3м точкам
// a - x, b - y, r - радиус
void fnCalcCircle(RfPointXYZ p1, RfPointXYZ p2, RfPointXYZ p3, float &a, float &b, float &r)
{
	double a1, b1, a2, b2, c1, c2;
	double k1, k2;

	a1 = 2 * (p1.x - p2.x);
	b1 = 2 * (p2.y - p1.y);
	c1 = ((p2.y - p1.y)*p2.y + (p2.y - p1.y)*p1.y) - ((p1.x - p2.x)*p1.x + (p1.x - p2.x)*p2.x);
	a2 = 2 * (p3.x - p2.x);
	b2 = 2 * (p2.y - p3.y);
	c2 = ((p2.y - p3.y)*p2.y + (p2.y - p3.y)*p3.y) - ((p3.x - p2.x)*p3.x + (p3.x - p2.x)*p2.x);
	if (b1 != 0)
	{
		k1 = (b2*a1) / b1 - a2;
		if (k1 == 0) //3 точки в 1 линии
		{
			r = 0;
			return;
		}
		a = (float)((c2 - (b2*c1) / b1) / k1);
		b = (float)((c1 + a1*a) / b1);
	}
	else
		if (b2 != 0)
		{
			k2 = (b1*a2) / b2 - a1;
			if (k2 == 0) //3 точки в 1 линии
			{
				r = 0;
				return;
			}
			a = (float)((c1 - (b1*c2) / b2) / k2);
			b = (float)((c2 + a2*a) / b2);
		}
		else
		{ //всё в 1 точке
			r = 0;
		}
	r = sqrt((a - p1.x)*(a - p1.x) + (b - p1.y)*(b - p1.y));
}
//------------------------------------------------------------------------------
/** Из декартовых в полярные
x,y,z - вектор исходящий из 0,0,0 координат
AngleH - угол в плоскости XY по часовой в радианах начиная с +X
AngleV - угол по вертикали от плоскости XY до Z, +Z плюсовые значения -Z минусовые
r - радиус
*/
void NormalInPolar3d(float x, float y, float z, float &AngleH, float &AngleV, float &r)
{
	if (x == 0.0) x = 0.0000001f;
	r = sqrt(x*x + y*y + z*z);
	AngleH = fabs(atan(y / x));
	if ((x <= 0) && (y <= 0)) AngleH = (float)(PI - AngleH);
	if ((x<0) && (y>0)) AngleH = (float)(AngleH + PI);
	if ((x >= 0) && (y >= 0)) AngleH = (float)(2.0f*PI - AngleH);
	if (AngleH>PI*2.0f) AngleH = (float)(AngleH - PI*2.0f);
	AngleV = fabs(atan(z / sqrt(x*x + y*y)));
	if (z<0) AngleV = -AngleV;
}
//------------------------------------------------------------------------------
/** Из декартовых в полярные
x,y - вектор исходящий из 0,0 координат
Angle - угол в плоскости XY по часовой в радианах начиная с +X
r - радиус
*/
void NormalInPolar2d(float x, float y, float &Angle, float &r)
{
	if (x == 0.0) x = 0.0000001f;
	r = sqrt(x*x + y*y);
	Angle = fabs(atan(y / x));
	if ((x <= 0) && (y <= 0)) Angle = (float)(PI - Angle);
	if ((x<0) && (y>0)) Angle = (float)(Angle + PI);
	if ((x >= 0) && (y >= 0)) Angle = (float)(2.0f*PI - Angle);
	if (Angle>PI*2.0f) Angle = (float)(Angle - PI*2.0f);
}
//------------------------------------------------------------------------------
void PolarInNormal3d(double AngleH, double AngleV, double r, float &x, float &y, float &z)
{
	AngleH = fnCorrectAngle(AngleH);
	AngleV = fnCorrectAngle(AngleV);

	double r2, a;
	char nx, ny;
	nx = 1; ny = 1; a = 0;
	z = (float)(r*sin(AngleV));
	r2 = r*sin(M_PI / 2.0 - fabs(AngleV));
	if (AngleH == 0) AngleH = 0.000000001;
	if (AngleH <= M_PI / 2.0)
	{
		a = AngleH; nx = 1; ny = -1;
	}
	if ((AngleH>M_PI / 2.0) && (AngleH <= M_PI))
	{
		a = M_PI - AngleH; nx = -1; ny = -1;
	}
	if ((AngleH>M_PI) && (AngleH <= 3.0 / 2.0*M_PI))
	{
		a = AngleH - M_PI; nx = -1; ny = 1;
	}
	if ((AngleH>3.0 / 2.0*M_PI) && (AngleH<2.0*M_PI))
	{
		a = 2.0*M_PI - AngleH; nx = 1; ny = 1;
	}
	x = (float)(r2*sin(M_PI / 2.0 - a)*nx);
	y = (float)(r2*sin(a)*ny);
}
//------------------------------------------------------------------------------
void PolarInNormal3d(double AngleH, double AngleV, double r, double &x, double &y, double &z)
{
	AngleH = fnCorrectAngle(AngleH);
	AngleV = fnCorrectAngle(AngleV);

	double r2, a;
	char nx, ny;
	nx = 1; ny = 1; a = 0;
	z = r*sin(AngleV);
	r2 = r*sin(M_PI / 2.0 - fabs(AngleV));
	if (AngleH == 0) AngleH = 0.000000001;
	if (AngleH <= M_PI / 2.0)
	{
		a = AngleH; nx = 1; ny = -1;
	}
	if ((AngleH>M_PI / 2.0) && (AngleH <= M_PI))
	{
		a = M_PI - AngleH; nx = -1; ny = -1;
	}
	if ((AngleH>M_PI) && (AngleH <= 3.0 / 2.0*M_PI))
	{
		a = AngleH - M_PI; nx = -1; ny = 1;
	}
	if ((AngleH>3.0 / 2.0*M_PI) && (AngleH<2.0*M_PI))
	{
		a = 2.0*M_PI - AngleH; nx = 1; ny = 1;
	}
	x = r2*sin(M_PI / 2.0 - a)*nx;
	y = r2*sin(a)*ny;
}
//------------------------------------------------------------------------------
/* уравнение плоскости по 3м точкам
P0,P1,P2 -предпологаемые точки на плоскости
a,b,c,d - коэфициенты уравнения плоскости
*/
void CalcPlane(RfPointXYZ p0, RfPointXYZ p1, RfPointXYZ p2, float &a, float &b, float &c, float &d)
{
	//просчитаем коефициенты в уравнении плоскости треугольника
	a = ((p1.y - p0.y)*(p2.z - p0.z) - (p2.y - p0.y)*(p1.z - p0.z));
	b = ((p2.x - p0.x)*(p1.z - p0.z) - (p1.x - p0.x)*(p2.z - p0.z));
	c = ((p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x));
	d = -(p1.y - p0.y)*(p2.z - p0.z)*p0.x - (p1.x - p0.x)*(p2.y - p0.y)*p0.z - (p2.x - p0.x)*(p1.z - p0.z)*p0.y;
	d = d + (p1.y - p0.y)*(p2.x - p0.x)*p0.z + (p1.x - p0.x)*(p2.z - p0.z)*p0.y + (p2.y - p0.y)*(p1.z - p0.z)*p0.x;
	//  d=-a*p0.x-b*p0.y-c*p0.z;
}
//------------------------------------------------------------------------------
/*уравнение плоскости по вектору и точке на плоскости
v - вектор
p - точка на плоскости
a,b,c,d - коэфициенты уравнения плоскости
*/
void CalcPlane2(RfPointXYZ v, RfPointXYZ p, float &a, float &b, float &c, float &d)
{
	normalized(v); //В единичный вектор
	a = v.x;
	b = v.y;
	c = v.z;//c=v.x;
	d = -a*p.x - b*p.y - c*p.z;
}
//------------------------------------------------------------------------------
/*уравнение плоскости по вектору и точке на плоскости
v - вектор
p - точка на плоскости
a,b,c,d - коэфициенты уравнения плоскости
*/
void CalcPlane2(RdPointXYZ v, RdPointXYZ p, double &a, double &b, double &c, double &d)
{
	normalized(v);
	a = v.x;
	b = v.y;
	c = v.z;//c=v.x;
	d = -a*p.x - b*p.y - c*p.z;
}
//------------------------------------------------------------------------------
float Max(float val1, float val2)
{
	if (val1>val2)
		return val1;
	else
		return val2;
}
//------------------------------------------------------------------------------
float Min(float val1, float val2)
{
	if (val1<val2)
		return val1;
	else
		return val2;
}
//------------------------------------------------------------------------------
RfPointXYZ getMaxPoint(RfPointXYZ point1, RfPointXYZ point2, RfPointXYZ point3)
{
	RfPointXYZ result;
	result.x = Max(Max(point1.x, point2.x), point3.x);
	result.y = Max(Max(point1.y, point2.y), point3.y);
	result.z = Max(Max(point1.z, point2.z), point3.z);
	return result;
}
//------------------------------------------------------------------------------
RfPointXYZ getMinPoint(RfPointXYZ point1, RfPointXYZ point2, RfPointXYZ point3)
{
	RfPointXYZ result;
	result.x = Min(Min(point1.x, point2.x), point3.x);
	result.y = Min(Min(point1.y, point2.y), point3.y);
	result.z = Min(Min(point1.z, point2.z), point3.z);
	return result;
}
//------------------------------------------------------------------------------
//Находиться ли точка внутри куба заданного минимальной и максимальной точками включая эти точки
bool inBox(RfPointXYZ pMin, RfPointXYZ pMax, RfPointXYZ p)
{
	if (pMin.x <= p.x && pMin.y <= p.y && pMin.z <= p.z && pMax.x >= p.x && pMax.y >= p.y && pMax.z >= p.z) return true;
	return false;
}
//------------------------------------------------------------------------------
//Неходиться ли точка в нутри куба заданного минимальной и максимальной точками
bool inBox(RfPointXYZ pMin, RfPointXYZ pMax, RdPointXYZ p)
{
	if (pMin.x <= p.x && pMin.y <= p.y && pMin.z <= p.z && pMax.x >= p.x && pMax.y >= p.y && pMax.z >= p.z) return true;
	return false;
}
//------------------------------------------------------------------------------
//Перевести из градусов в радианы
double DegToRad(double deg)
{
	return CorrectAngleRad(deg / 180.0*M_PI);
}
//------------------------------------------------------------------------------
//Перевести из радиан в градусы
double RadToDeg(double deg)
{
	return CorrectAngleRad(deg) / M_PI*180.0;
}
//------------------------------------------------------------------------------
RfPointXYZ getMaxPointXYZ(RfPointXYZ poiny1, RfPointXYZ poiny2, RfPointXYZ poiny3)
{
	RfPointXYZ PointXYZ;
	PointXYZ.x = Max(Max(poiny1.x, poiny2.x), poiny3.x);
	PointXYZ.y = Max(Max(poiny1.y, poiny2.y), poiny3.y);
	PointXYZ.z = Max(Max(poiny1.z, poiny2.z), poiny3.z);
	return PointXYZ;
};
//------------------------------------------------------------------------------
RfPointXYZ getMinPointXYZ(RfPointXYZ poiny1, RfPointXYZ poiny2, RfPointXYZ poiny3)
{
	RfPointXYZ PointXYZ;
	PointXYZ.x = Min(Min(poiny1.x, poiny2.x), poiny3.x);
	PointXYZ.y = Min(Min(poiny1.y, poiny2.y), poiny3.y);
	PointXYZ.z = Min(Min(poiny1.z, poiny2.z), poiny3.z);
	return PointXYZ;
};
//------------------------------------------------------------------------------
//Приблизить либо отдалить первую точку ко второй на заданное растояние
RfPointXY ApproachPoint2d(RfPointXY PointXY1, RfPointXY PointXY2, float Distans)
{
	float dist;
	RfPointXY LengthXY;

	LengthXY.x = fabs(PointXY1.x - PointXY2.x);
	LengthXY.y = fabs(PointXY1.y - PointXY2.y);
	dist = sqrt(sqr(LengthXY.x) + sqr(LengthXY.y));

	dist = Distans / dist;
	PointXY2.x = PointXY1.x*(1 - dist) + PointXY2.x*dist;
	PointXY2.y = PointXY1.y*(1 - dist) + PointXY2.y*dist;

	return PointXY2;
}
//------------------------------------------------------------------------------
//Приблизить или отдолить первую точку ко второй на указанное растояние
RfPointXYZ ApproachPoint3d(RfPointXYZ PointXYZ1, RfPointXYZ PointXYZ2, float Distans)
{
	float dist;
	RfPointXYZ LengthXYZ;

	LengthXYZ.x = fabs(PointXYZ1.x - PointXYZ2.x);
	LengthXYZ.y = fabs(PointXYZ1.y - PointXYZ2.y);
	LengthXYZ.z = fabs(PointXYZ1.z - PointXYZ2.z);

	dist = sqrt(sqr(LengthXYZ.x) + sqr(LengthXYZ.y) + sqr(LengthXYZ.z));
	dist = Distans / dist;
	PointXYZ2.x = PointXYZ1.x*(1 - dist) + PointXYZ2.x*dist;
	PointXYZ2.y = PointXYZ1.y*(1 - dist) + PointXYZ2.y*dist;
	PointXYZ2.z = PointXYZ1.z*(1 - dist) + PointXYZ2.z*dist;

	return PointXYZ2;
}
//------------------------------------------------------------------------------
//задать расстояние на которой должна находиться первая точка относительно второй
RfPointXYZ setDistancePoint3d(RfPointXYZ PointXYZ1, RfPointXYZ PointXYZ2, float Distans)
{
	float dist;
	RfPointXYZ LengthXYZ;

	LengthXYZ.x = fabs(PointXYZ1.x - PointXYZ2.x);
	LengthXYZ.y = fabs(PointXYZ1.y - PointXYZ2.y);
	LengthXYZ.z = fabs(PointXYZ1.z - PointXYZ2.z);

	dist = sqrt(sqr(LengthXYZ.x) + sqr(LengthXYZ.y) + sqr(LengthXYZ.z));
	dist = 1 - Distans / dist;
	PointXYZ2.x = PointXYZ1.x*(1 - dist) + PointXYZ2.x*dist;
	PointXYZ2.y = PointXYZ1.y*(1 - dist) + PointXYZ2.y*dist;
	PointXYZ2.z = PointXYZ1.z*(1 - dist) + PointXYZ2.z*dist;

	return PointXYZ2;
}
//------------------------------------------------------------------------------
//Угол между 2мя точкам и X координатой против часовой в радианах
float fnGetAngle(RfPointXY CenterPoint, RfPointXY ResearchedPoint)
{
	double A, B, C, Angle;
	Angle = 0;
	A = fabs(ResearchedPoint.y - CenterPoint.y)*1.0;
	B = fabs(ResearchedPoint.x - CenterPoint.x)*1.0;
	C = sqrt(A*A + B*B);
	if (C>0)
	{
		Angle = asin(1.00*B / C);
		if ((ResearchedPoint.x>CenterPoint.x) && (ResearchedPoint.y <= CenterPoint.y)) Angle = M_PI / 2.0 - Angle; else
			if ((ResearchedPoint.x <= CenterPoint.x) && (ResearchedPoint.y<CenterPoint.y)) Angle = M_PI / 2.0 + Angle; else
				if ((ResearchedPoint.x<CenterPoint.x) && (ResearchedPoint.y >= CenterPoint.y)) Angle = 3.0 / 2.0*M_PI - Angle; else
					if ((ResearchedPoint.x >= CenterPoint.x) && (ResearchedPoint.y>CenterPoint.y)) Angle = 3.0 / 2.0*M_PI + Angle;
	}
	return (float)Angle;
}
//------------------------------------------------------------------------------
//Угол между 2мя точкам и X координатой против часовой в радианах
float fnGetAngleXY(RfPointXYZ CenterPoint, RfPointXYZ ResearchedPoint)
{
	double A, B, C, Angle;
	Angle = 0;
	A = fabs(ResearchedPoint.y - CenterPoint.y)*1.0;
	B = fabs(ResearchedPoint.x - CenterPoint.x)*1.0;
	C = sqrt(A*A + B*B);
	if (C>0)
	{
		Angle = asin(1.00*B / C);
		if ((ResearchedPoint.x>CenterPoint.x) && (ResearchedPoint.y <= CenterPoint.y)) Angle = M_PI / 2.0 - Angle; else
			if ((ResearchedPoint.x <= CenterPoint.x) && (ResearchedPoint.y<CenterPoint.y)) Angle = M_PI / 2.0 + Angle; else
				if ((ResearchedPoint.x<CenterPoint.x) && (ResearchedPoint.y >= CenterPoint.y)) Angle = 3.0 / 2.0*M_PI - Angle; else
					if ((ResearchedPoint.x >= CenterPoint.x) && (ResearchedPoint.y>CenterPoint.y)) Angle = 3.0 / 2.0*M_PI + Angle;
	}
	return (float)Angle;
}
//------------------------------------------------------------------------------
//Угол между 2мя точкам и X координатой против часовой в радианах
float fnGetAngle(float cx, float cy, float x, float y)
{
	RfPointXY CenterPoint, ResearchedPoint;
	CenterPoint.x = cx;
	CenterPoint.y = cy;
	ResearchedPoint.x = x;
	ResearchedPoint.y = y;
	return fnGetAngle(CenterPoint, ResearchedPoint);
}
//------------------------------------------------------------------------------
//разбить поверхность на треугольники в плоскости XY
//inPos - позиция с которой начинаем читать count точек из PointsXYZ
//count - количество точек читаемых из в PointsXYZ
//PointsXYZ - ссылка на массив точек
//outPos - позиция с которой надо записывать в Vector3i
//Vector3i - ссылка на созданный вектор в который будем писать count-2 треугольников
bool Tessellated2d(unsigned int inPos, unsigned int count, RfPointXYZ *PointsXYZ, unsigned int outPos, RsFacesABC *Vector3i)
{
	unsigned int i;
	struct TessTri
	{
		TessTri *next; //ссылка на следующую точку
		unsigned int n; //номер точки
	};
	TessTri *tessTri0, *tessTri1, *tessTri2;
	//точки по которым мы собираемся пройтись представляем в виде связанного списка
	tessTri0 = new TessTri;
	tessTri0->n = inPos;
	tessTri1 = tessTri0;
	for (i = inPos + 1; i<inPos + count; i++)
	{
		tessTri2 = new TessTri;
		tessTri2->n = i;
		tessTri1->next = tessTri2;
		tessTri1 = tessTri2;
	}
	tessTri1->next = tessTri0;
	//алгоритм работает пока не будут открыты 3 точки
	int p[3];
	unsigned int pos = 0; //найденно треугольников
	i = 0;
	while (tessTri0 != tessTri0->next->next) //пока текущйй и следующий не ссылаються друг на друга (протреангулированно)
	{
		if (i >= count) break;//если сделали круг и не создали ни одного треугольника то дело дрянь выходим из цикла
							  //выбираем 3 точки которые пытаемся соеденить
		p[0] = tessTri0->n;
		p[1] = tessTri0->next->n;
		p[2] = tessTri0->next->next->n;
		//проверка на вогнутость
		float Angle1 = fnGetAngleXY(PointsXYZ[p[1]], PointsXYZ[p[0]]);
		float Angle2 = fnGetAngleXY(PointsXYZ[p[1]], PointsXYZ[p[2]]);
		//вогнутые и лижащие на одной линии пропускаем
		if (fnCorrectAngle(Angle2 - Angle1) <= PI)
		{
			//проверка на вхождение остальных точек в этот 3х угольник
			//максимальная и минимальная точки треугольника
			RfPointXYZ PointMax = getMaxPoint(PointsXYZ[p[0]], PointsXYZ[p[1]], PointsXYZ[p[2]]);
			RfPointXYZ PointMin = getMinPoint(PointsXYZ[p[0]], PointsXYZ[p[1]], PointsXYZ[p[2]]);
			//точка в не 3х угольника
			bool bool1 = false; bool bool2 = false; bool bool3 = false;
			tessTri1 = tessTri0->next->next->next; //первая точка за пределпми проверяемого треугольника
			while (tessTri0 != tessTri1)
			{
				RfPointXY Point;
				Point.x = PointsXYZ[tessTri1->n].x; //сравниваем каждую точку
				Point.y = PointsXYZ[tessTri1->n].y;
				if (!((PointMin.x <= Point.x) && (PointMax.x >= Point.x) && (PointMin.y <= Point.y) && (PointMax.y >= Point.y)))
				{
					bool1 = false; bool2 = false; bool3 = false;
					tessTri1 = tessTri1->next;
					continue;
				}
				bool1 = isPointsOnOneSide(Point.x, Point.y, PointsXYZ[p[0]].x, PointsXYZ[p[0]].y, PointsXYZ[p[1]].x, PointsXYZ[p[1]].y, PointsXYZ[p[2]].x, PointsXYZ[p[2]].y);
				bool2 = isPointsOnOneSide(Point.x, Point.y, PointsXYZ[p[1]].x, PointsXYZ[p[1]].y, PointsXYZ[p[2]].x, PointsXYZ[p[2]].y, PointsXYZ[p[0]].x, PointsXYZ[p[0]].y);
				bool3 = isPointsOnOneSide(Point.x, Point.y, PointsXYZ[p[2]].x, PointsXYZ[p[2]].y, PointsXYZ[p[0]].x, PointsXYZ[p[0]].y, PointsXYZ[p[1]].x, PointsXYZ[p[1]].y);
				if (bool1 && bool2 && bool3) break; //попалась точка в нутри 3х угольника
				tessTri1 = tessTri1->next;
			}
			if (!(bool1 && bool2 && bool3))
			{
				//удаляем точку из списка и в следующий раз её не брать
				tessTri1 = tessTri0->next;
				tessTri0->next = tessTri0->next->next;
				delete tessTri1;

				i = 0; //обнуляем счётчик круга без новых треугольников
				count--; //точек стало меньше

				Vector3i[outPos + pos].a = p[0];
				Vector3i[outPos + pos].b = p[1];
				Vector3i[outPos + pos].c = p[2];
				pos++;
				continue; //если удачный треугольник то не двигаемся вероятно что с этого положения можно найти ещё
			}
		}
		i++;
		tessTri0 = tessTri0->next; //если не удачный треугольник то двигаемся на 1 точку в перёд
	}
	//осталось 2 не использованные точки значит всё OK
	if (count == 2)
	{
		delete tessTri0->next;
		delete tessTri0;
		return true;
	}
	else //не использованные будут ссылаться на 0ю точку
	{
		while (tessTri0 != tessTri0->next)
		{
			tessTri1 = tessTri0->next;
			tessTri0->next = tessTri0->next->next;
			delete tessTri1;
		}
		delete tessTri0;
		for (i = outPos + pos; i<outPos + pos + count - 2; i++)
		{
			Vector3i[i].a = 0;
			Vector3i[i].b = 0;
			Vector3i[i].c = 0;
		}
		return false;
	}
}
//------------------------------------------------------------------------------
//Триангуляция набора точек по делоне
void TrianglesDeloneXY(unsigned int countP, RfPointXYZ *points, TSimpleList<RTriangle*>* ListEdge)
{
	RTriangle *Triangle;
	RSotrPoint *sp, *sp1, *sp2;
	RfPointXYZ addpoint, rez;
	bool b;
	unsigned int i, j, k;

	if (countP<3) return;
	TSimpleList<RSotrPoint*>* listsort = new TSimpleList<RSotrPoint*>(10, true); //список открытых отсортированных точек по часовой стрелки

																				 //первоначальный 3х угольник
	Triangle = new RTriangle;
	Triangle->del = false;
	Triangle->pnt[0] = 0;
	Triangle->pnt[1] = 1;
	Triangle->pnt[2] = 2;
	Triangle->center.z = 0;
	fnCalcCircle(points[Triangle->pnt[0]], points[Triangle->pnt[1]], points[Triangle->pnt[2]], Triangle->center.x, Triangle->center.y, Triangle->r);
	ListEdge->add(Triangle);
	for (i = 3; i<countP; i++)
	{
		addpoint = points[i];
		//помечаем на удаление те треугольники в писанную окружность которых попала новая точка
		for (j = 0; j<ListEdge->count(); j++)
		{
			if ((ListEdge->get(j)->center.x + ListEdge->get(j)->r>addpoint.x) && (ListEdge->get(j)->center.x - ListEdge->get(j)->r<addpoint.x) &&
				(ListEdge->get(j)->center.y + ListEdge->get(j)->r>addpoint.y) && (ListEdge->get(j)->center.y - ListEdge->get(j)->r<addpoint.y) &&
				(fnGetDistans3d(ListEdge->get(j)->center, addpoint)<ListEdge->get(j)->r))
			{
				ListEdge->get(j)->del = true;
			}
		}
		//вычисляем градус до каждой открытой(нет пересичения с существующими рёбрами) точки из новой
		listsort->clear();
		for (j = 0; j<i; j++)
		{
			//проверяем на пересичение с существующими треугольниками
			b = false;
			for (k = 0; k<ListEdge->count(); k++)
			{
				if (!ListEdge->get(k)->del)
				{
					if (!((j == ListEdge->get(k)->pnt[0]) || (j == ListEdge->get(k)->pnt[1])))
						b = CrossingLineXY(addpoint, points[j], points[ListEdge->get(k)->pnt[0]], points[ListEdge->get(k)->pnt[1]], rez);
					if (b) break;
					if (!((j == ListEdge->get(k)->pnt[1]) || (j == ListEdge->get(k)->pnt[2])))
						b = CrossingLineXY(addpoint, points[j], points[ListEdge->get(k)->pnt[1]], points[ListEdge->get(k)->pnt[2]], rez);
					if (b) break;
					if (!((j == ListEdge->get(k)->pnt[2]) || (j == ListEdge->get(k)->pnt[0])))
						b = CrossingLineXY(addpoint, points[j], points[ListEdge->get(k)->pnt[2]], points[ListEdge->get(k)->pnt[0]], rez);
					if (b) break;
				}
			}
			if (!b)
			{
				sp = new RSotrPoint;
				sp->n = j; //номер точки в массиве
				sp->angle = fnGetAngleXY(addpoint, points[j]); //её градус в радианах
				listsort->add(sp);
			}
		}
		//сортируем все открытые точки по углу (пузырьком)
		for (j = 0; j<listsort->count(); j++)
		{
			for (k = j; k<listsort->count(); k++)
			{
				if (listsort->get(j)->angle > listsort->get(k)->angle)
				{
					sp = listsort->get(j);
					listsort->get(j) = listsort->get(k);
					listsort->get(k) = sp;
				}
			}
		}
		//строим треугольники по откр. оточкам пропускаем те где улог >180 градусов
		for (j = 0; j<listsort->count(); j++)
		{
			if (j<listsort->count() - 1)
			{
				sp1 = listsort->get(j);
				sp2 = listsort->get(j + 1);
			}
			else
			{
				sp1 = listsort->get(listsort->count() - 1);
				sp2 = listsort->get(0);
			}
			if (fnCorrectAngle(sp2->angle + (2 * PI) - sp1->angle)>PI) continue; //потому что область выпуклая
			Triangle = new RTriangle;
			Triangle->del = false;
			Triangle->pnt[0] = i;
			Triangle->pnt[1] = sp1->n;
			Triangle->pnt[2] = sp2->n;
			Triangle->center.z = 0;
			fnCalcCircle(points[Triangle->pnt[0]], points[Triangle->pnt[1]], points[Triangle->pnt[2]], Triangle->center.x, Triangle->center.y, Triangle->r);
			ListEdge->add(Triangle);
		}
		//удаляем помечанные на удаление
		j = 0;
		while (j<ListEdge->count())
		{
			if (ListEdge->get(j)->del)
			{
				ListEdge->del(j);
				j--;
			}
			j++;
		}
	}

	//вычисляем центр треугольника и растояние каждой точки до центра треугольника
	for (i = 0; i<ListEdge->count(); i++)
	{
		ListEdge->get(i)->center.x = (points[ListEdge->get(i)->pnt[0]].x + points[ListEdge->get(i)->pnt[1]].x + points[ListEdge->get(i)->pnt[2]].x) / 3;
		ListEdge->get(i)->center.y = (points[ListEdge->get(i)->pnt[0]].y + points[ListEdge->get(i)->pnt[1]].y + points[ListEdge->get(i)->pnt[2]].y) / 3;
		ListEdge->get(i)->center.z = 0;
		ListEdge->get(i)->cr[0] = fnGetDistans3d(points[ListEdge->get(i)->pnt[0]], ListEdge->get(i)->center);
		ListEdge->get(i)->cr[1] = fnGetDistans3d(points[ListEdge->get(i)->pnt[1]], ListEdge->get(i)->center);
		ListEdge->get(i)->cr[2] = fnGetDistans3d(points[ListEdge->get(i)->pnt[2]], ListEdge->get(i)->center);
	}
	delete listsort;
}
//------------------------------------------------------------------------------
//Подвинуть точку на заданный угол
void MovePointOnAngle(float Angle, RfPointXY CenterPointXY, RfPointXY PointXY, RfPointXY & RezPointXY)
{
	PointXY.x = PointXY.x - CenterPointXY.x;
	PointXY.y = PointXY.y - CenterPointXY.y;
	RezPointXY.x = PointXY.x*cos(Angle) + PointXY.y*sin(Angle);
	RezPointXY.y = PointXY.y*cos(Angle) - PointXY.x*sin(Angle);
	RezPointXY.x = RezPointXY.x + CenterPointXY.x;
	RezPointXY.y = RezPointXY.y + CenterPointXY.y;
}
/*------------------------------------------------------------------------------
PHead0,PTail0 - координаты первой линии (отрезка)
PHead1,PTail1 - координаты второй линии (отрезка)
PRez - точка пересичения
*/
bool CrossingLine(RfPointXY PHead0, RfPointXY PTail0, RfPointXY PHead1, RfPointXY PTail1, RfPointXY & PRez)
{
	float a0, b0, c0, a1, b1, c1;
	a0 = PTail0.y - PHead0.y;
	b0 = PHead0.x - PTail0.x;
	c0 = PTail0.x*PHead0.y - PHead0.x*PTail0.y;

	a1 = PTail1.y - PHead1.y;
	b1 = PHead1.x - PTail1.x;
	c1 = PTail1.x*PHead1.y - PHead1.x*PTail1.y;

	if ((b1 == 0) || ((b0*a1 / b1) - a0 == 0)) PRez.x = PHead1.x;
	else PRez.x = (-(b0*c1 / b1) + c0) / ((b0*a1 / b1) - a0);
	if ((a1 == 0) || ((a0*b1 / a1) - b0 == 0)) PRez.y = PHead1.y;
	else PRez.y = (-(c1*a0 / a1) + c0) / ((a0*b1 / a1) - b0);

	if ((PRez.x<Min(PHead0.x, PTail0.x)) || (PRez.x>Max(PHead0.x, PTail0.x))) return false;
	if ((PRez.x<Min(PHead1.x, PTail1.x)) || (PRez.x>Max(PHead1.x, PTail1.x))) return false;

	if ((PRez.y<Min(PHead0.y, PTail0.y)) || (PRez.y>Max(PHead0.y, PTail0.y))) return false;
	if ((PRez.y<Min(PHead1.y, PTail1.y)) || (PRez.y>Max(PHead1.y, PTail1.y))) return false;
	return true;
}
//------------------------------------------------------------------------------
//Точка пересечения 2х линий
bool CrossingLineXY(RfPointXYZ PHead0, RfPointXYZ PTail0, RfPointXYZ PHead1, RfPointXYZ PTail1, RfPointXYZ & PRez)
{
	RfPointXY qPHead0;
	qPHead0.x = PHead0.x;
	qPHead0.y = PHead0.y;
	RfPointXY qPTail0;
	qPTail0.x = PTail0.x;
	qPTail0.y = PTail0.y;
	RfPointXY qPHead1;
	qPHead1.x = PHead1.x;
	qPHead1.y = PHead1.y;
	RfPointXY qPTail1;
	qPTail1.x = PTail1.x;
	qPTail1.y = PTail1.y;
	RfPointXY qPRez;
	bool rez = CrossingLine(qPHead0, qPTail0, qPHead1, qPTail1, qPRez);
	PRez.x = qPRez.x;
	PRez.y = qPRez.y;
	PRez.z = PHead0.z;
	return rez;
}
//------------------------------------------------------------------------------
/*пересичение сферы и линии
r - радиус, p0 - центр шара
p1,p2 - координаты линии
rp1,rp2 - 2 точки пересичения с шаром*/
bool CrossingLineAndSphere(double r, RdPointXYZ p0, RdPointXYZ p1, RdPointXYZ p2, RdPointXYZ &rp1, RdPointXYZ &rp2)
{
	double a1, a2, b1, b2;
	double d, b, a, c;
	double rz1, rz2;

	if (p1.z == p2.z) return false;
	a1 = (p2.x - p1.x) / (p2.z - p1.z);
	a2 = (p2.y - p1.y) / (p2.z - p1.z);
	b1 = (-p1.z*p2.x + p1.z*p1.x) / (p2.z - p1.z) + p1.x - p0.x;
	b2 = (-p1.z*p2.y + p1.z*p1.y) / (p2.z - p1.z) + p1.y - p0.y;
	//дискриминант
	b = 2.0*a1*b1 + 2 * a2*b2 + 2.0*p0.z;
	a = a1*a1 + a2*a2 + 1;
	c = b1*b1 + b2*b2 - r*r + p0.z*p0.z;
	d = sqr(b) - 4.0*a*c;
	if (d<0) return false;
	d = sqrt(d);
	rz1 = (-(2.0*a1*b1 + 2 * a2*b2 + 2 * p0.z) - d) / (2.0*(a1*a1 + a2*a2 + 1));
	rz2 = (-(2.0*a1*b1 + 2 * a2*b2 + 2 * p0.z) + d) / (2.0*(a1*a1 + a2*a2 + 1));
	//подставляем уравнения и находим ответы
	rp1.x = (rz2 - p1.z) / (p2.z - p1.z)*(p2.x - p1.x) + p1.x;
	rp1.y = (rz2 - p1.z) / (p2.z - p1.z)*(p2.y - p1.y) + p1.y;
	rp1.z = rz2;
	rp2.x = (rz1 - p1.z) / (p2.z - p1.z)*(p2.x - p1.x) + p1.x;
	rp2.y = (rz1 - p1.z) / (p2.z - p1.z)*(p2.y - p1.y) + p1.y;
	rp2.z = rz1;
	return true;
}
//------------------------------------------------------------------------------
/*пересичение сферы и линии
r - радиус, p0 - центр шара
p1,p2 - координаты линии
rp1,rp2 - 2 точки пересичения с шаром*/
bool CrossingLineAndSphere(float r, RfPointXYZ p0, RfPointXYZ p1, RfPointXYZ p2, RfPointXYZ &rp1, RfPointXYZ &rp2)
{
	double rr;
	RdPointXYZ p00, p11, p22, rp11, rp22;
	bool b = true;
	rr = r;
	p00.x = p0.x; p00.y = p0.y; p00.z = p0.z;
	p11.x = p1.x; p11.y = p1.y; p11.z = p1.z;
	p22.x = p2.x; p22.y = p2.y; p22.z = p2.z;
	CrossingLineAndSphere(rr, p00, p11, p22, rp11, rp22);
	rp1.x = (float)rp11.x; rp1.y = (float)rp11.y; rp1.z = (float)rp11.z;
	rp2.x = (float)rp22.x; rp2.y = (float)rp22.y; rp2.z = (float)rp22.z;
	return b;
}
//------------------------------------------------------------------------------
/*пересичении линии и плоскости (линия заданна 2мя точками)
p1,p2 - точки линии
a,b,c,d - коэфициенты в уранении плоскости*/
RdPointXYZ CrossingLineAndPlane(RdPointXYZ p1, RdPointXYZ p2, double a, double b, double c, double d)
{
	double buf;
	RdPointXYZ result;
	// вычисляем расстояния между концами отрезка и плоскостью треугольника.
	//float r1,r2;
	//  r1 = PHead0.x*a+PHead0.y*b+PHead0.z*c+d;
	//  r2 = PTail0.x*a+PTail0.y*b+PTail0.z*c+d;
	//  if(((r1<0) and (r2<0))or((r1>0) or (r2>0))) then Exit; // если оба конца отрезка лежат по одну сторону от плоскости, то отрезок не пересекает треугольник.
	// вычисляем точку пересечения отрезка с плоскостью
	buf = p2.x*a - p1.x*a + p2.z*c - p1.z*c + p2.y*b - p1.y*b; //надо выяснить что означает геометрически buf=0 TODO
	if ((p1.y == p2.y) || (buf == 0.0)) result.y = p1.y; else result.y = (float)(((p1.y*p2.x*a - p1.y*p1.x*a + p1.y*p2.z*c - p1.y*p1.z*c) / (p2.y - p1.y) - a*p1.x - c*p1.z - d) / (buf / (p2.y - p1.y)));
	if (p1.x == p2.x) result.x = p1.x; else
	{
		if (p1.y == p2.y) result.x = p1.x / (p2.x - p1.x)*(p2.x - p1.x);
		else result.x = ((result.y - p1.y) / (p2.y - p1.y) + p1.x / (p2.x - p1.x))*(p2.x - p1.x);
	}
	if (p1.z == p2.z) result.z = p1.z; else
	{
		if (p1.y == p2.y) result.z = p1.z / (p2.z - p1.z)*(p2.z - p1.z);
		else result.z = ((result.y - p1.y) / (p2.y - p1.y) + p1.z / (p2.z - p1.z))*(p2.z - p1.z);
	}
	return result;
}
//------------------------------------------------------------------------------
/*пересичении линии и плоскости (линия заданна 2мя точками)
p1,p2 - точки линии
a,b,c,d - коэфициенты в уранении плоскости*/
RfPointXYZ CrossingLineAndPlane(RfPointXYZ p1, RfPointXYZ p2, float a, float b, float c, float d)
{
	RfPointXYZ result;
	RdPointXYZ r, p11, p22;
	double aa, bb, cc, dd;
	p11.x = p1.x; p11.y = p1.y; p11.z = p1.z;
	p22.x = p2.x; p22.y = p2.y; p22.z = p2.z;
	aa = a; bb = b; cc = c; dd = d;
	r = CrossingLineAndPlane(p11, p22, aa, bb, cc, dd);
	result.x = (float)r.x; result.y = (float)r.y; result.z = (float)r.z;
	return result;
}
//------------------------------------------------------------------------------
//точка пересичения 3х плоскостей
RfPointXYZ CrossingPlanes(RfPlaneABCD p1, RfPlaneABCD p2, RfPlaneABCD p3)
{
	float a1, a2, a3, a4;
	a1 = (p1.a*p2.b*p3.c + p1.b*p2.c*p3.a + p2.a*p3.b*p1.c) - (p1.c*p2.b*p3.a + p2.a*p1.b*p3.c + p1.a*p2.c*p3.b);
	a2 = (p1.d*p2.b*p3.c + p1.b*p2.c*p3.d + p2.d*p3.b*p1.c) - (p1.c*p2.b*p3.d + p1.b*p3.c*p2.d + p1.d*p2.c*p3.b);
	a3 = (p1.a*p2.d*p3.c + p2.a*p3.d*p1.c + p3.a*p2.c*p1.d) - (p1.c*p2.d*p3.a + p2.a*p3.c*p1.d + p1.a*p3.d*p2.c);
	a4 = (p1.a*p2.b*p3.d + p1.b*p2.d*p3.a + p2.a*p3.b*p1.d) - (p1.d*p2.b*p3.a + p1.b*p3.d*p2.a + p1.a*p2.d*p3.b);
	RfPointXYZ result;
	result.x = -a2 / a1;
	result.y = -a3 / a1;
	result.z = -a4 / a1;
	return result;
}
//------------------------------------------------------------------------------
//Для определения проходит ли линия в нутри заданого радиуса
//r - радиус
//cx,cy - центр радиуса
//lx1, ly1 - начало линии
//lx2, ly2 - конец линии
//Coincides - Проходит или нет
//x, y - Ближайшая точка на линии к центру радиуса
void Distance(float r, float cx, float cy, float lx1, float ly1, float lx2, float ly2, bool& Coincides, float& x, float& y)
{
	double ang, angcos, angsin;
	double ncx, ncy, nlx2, nr;

	x = 0.0; y = 0.0;

	cx = cx - lx1;
	cy = cy - ly1;
	lx2 = lx2 - lx1;
	ly2 = ly2 - ly1;
	ang = atan(ly2 / lx2);
	if (lx2<0) ang = ang + M_PI;
	if ((lx2>0) && (ly2<0)) ang = ang + (2 * M_PI);
	angcos = cos(ang);
	angsin = sin(ang);
	ncx = cx*angcos + cy*angsin;
	ncy = cy*angcos - (cx*angsin);
	nlx2 = lx2*angcos + ly2*angsin;
	nr = fabs(ncy);
	Coincides = false;
	if (nr<r)
	{
		Coincides = true;
		if (ncx<0)
		{
			if (ncx<-r)
			{
				Coincides = false;
				return;
			}
			nr = sqrt(ncx*ncx + ncy*ncy);
			if (nr<r)
			{
				x = lx1;
				y = ly1;
				return;
			}
			Coincides = false;
			return;
		}
		else
			if (ncx>nlx2)
			{
				if (ncx>nlx2 + r)
				{
					Coincides = false;
					return;
				}
				nr = sqrt((ncx - nlx2)*(ncx - nlx2) + ncy*ncy);
				if (nr<r)
				{
					x = lx2 + lx1;
					y = ly2 + ly1;
					return;
				}
				Coincides = false;
				return;
			}
			else
			{
				angcos = cos(2 * M_PI - ang);
				angsin = sin(2 * M_PI - ang);
				x = (float)(ncx*angcos + lx1);
				y = (float)(-(ncx*angsin) + ly1);
				return;
			}
	}
}
//------------------------------------------------------------------------------
//умножение векторов
float ScalarProduct(RfPointXYZ t, RfPointXYZ p)
{
	return p.x*t.x + p.y*t.y + p.z*t.z;
}
//------------------------------------------------------------------------------
//нормализовать точку сделать еденичной длины
void normalized(RfPointXYZ &p)
{
	float l = sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
	if (l == 0)
	{
		p.x = 0.0;
		p.y = 0.0;
		p.z = 1.0;
		return;
	}
	p.x = p.x / l;
	p.y = p.y / l;
	p.z = p.z / l;
}
//------------------------------------------------------------------------------
//нормализовать точку сделать еденичной длины
void normalized(RdPointXYZ &p)
{
	double l = sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
	if (l == 0)
	{
		p.x = 0.0;
		p.y = 0.0;
		p.z = 1.0;
		return;
	}
	p.x = p.x / l;
	p.y = p.y / l;
	p.z = p.z / l;
}
//------------------------------------------------------------------------------
//пересичение векторов
RfPointXYZ CrossProduct(RfPointXYZ p, RfPointXYZ t)
{
	RfPointXYZ result;
	result.x = p.y*t.z - p.z*t.y;
	result.y = t.x*p.z - p.x*t.z;
	result.z = p.x*t.y - p.y*t.x;
	return result;
}
//------------------------------------------------------------------------------
//пересичение векторов
RdPointXYZ CrossProduct(RdPointXYZ p, RdPointXYZ t)
{
	RdPointXYZ result;
	result.x = p.y*t.z - p.z*t.y;
	result.y = t.x*p.z - p.x*t.z;
	result.z = p.x*t.y - p.y*t.x;
	return result;
}
//------------------------------------------------------------------------------
//dot product умножить вектор на значение
RfPointXYZ dotProduct(RfPointXYZ p, float t)
{
	RfPointXYZ result;
	result.x = p.x*t;
	result.y = p.y*t;
	result.z = p.z*t;
	return result;
}
//------------------------------------------------------------------------------
/*умножение 2х видовых матриц 4x4
dest - матрица из 16 элементов результат
left, float - умножаемые матрицы из 16 элементов
*/
void quatnext(float* dest, float* left, float* right)
{
	dest[0] = left[0] * right[0] + left[1] * right[4] + left[2] * right[8];
	dest[1] = left[0] * right[1] + left[1] * right[5] + left[2] * right[9];
	dest[2] = left[0] * right[2] + left[1] * right[6] + left[2] * right[10];
	dest[4] = left[4] * right[0] + left[5] * right[4] + left[6] * right[8];
	dest[5] = left[4] * right[1] + left[5] * right[5] + left[6] * right[9];
	dest[6] = left[4] * right[2] + left[5] * right[6] + left[6] * right[10];
	dest[8] = left[8] * right[0] + left[9] * right[4] + left[10] * right[8];
	dest[9] = left[8] * right[1] + left[9] * right[5] + left[10] * right[9];
	dest[10] = left[8] * right[2] + left[9] * right[6] + left[10] * right[10];
}
//------------------------------------------------------------------------------
//reset the rotation matrix
void quatidentity(float* q)
{
	q[0] = 1;  q[1] = 0;  q[2] = 0;  q[3] = 0;
	q[4] = 0;  q[5] = 1;  q[6] = 0;  q[7] = 0;
	q[8] = 0;  q[9] = 0;  q[10] = 1; q[11] = 0;
	q[12] = 0; q[13] = 0; q[14] = 0; q[15] = 1;
}
//------------------------------------------------------------------------------
//reset the rotation matrix
void quatidentity(double* q)
{	//0,5,10 - масштаб
	q[0] = 1;  q[1] = 0;  q[2] = 0;  q[3] = 0;
	q[4] = 0;  q[5] = 1;  q[6] = 0;  q[7] = 0;
	q[8] = 0;  q[9] = 0;  q[10] = 1; q[11] = 0;
	q[12] = 0; q[13] = 0; q[14] = 0; q[15] = 1; // <-сдвиг
}
//------------------------------------------------------------------------------
//длина от начала коордионат
float pythagoreanlength(RfPointXYZ p)
{
	return sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
}
//------------------------------------------------------------------------------
/*умножить точку на матрицу поворота
point - точка
mas - матрица из 16 элементов
*/
RfPointXYZ MultPointOnRotArray(RfPointXYZ point, double* mas)
{
	RfPointXYZ result;
	result.x = (float)(point.x*mas[0] + point.y*mas[1] + point.z*mas[2]);
	result.y = (float)(point.x*mas[4] + point.y*mas[5] + point.z*mas[6]);
	result.z = (float)(point.x*mas[8] + point.y*mas[9] + point.z*mas[10]);
	return result;
}
//------------------------------------------------------------------------------
/*умножить точку на матрицу поворота
point - точка
mas - матрица из 16 элементов
*/
RdPointXYZ MultPointOnRotArray(RdPointXYZ point, double* mas)
{
	RdPointXYZ result;
	result.x = point.x*mas[0] + point.y*mas[1] + point.z*mas[2];
	result.y = point.x*mas[4] + point.y*mas[5] + point.z*mas[6];
	result.z = point.x*mas[8] + point.y*mas[9] + point.z*mas[10];
	return result;
}
//------------------------------------------------------------------------------
/* Транспонировать только матрицу вращения (=обратной)
q - матрица 4x4
*/
void TransposeRotMat(double* q)
{
	double buf;
	buf = q[1]; q[1] = q[4]; q[4] = buf;
	buf = q[2]; q[2] = q[8]; q[8] = buf;
	buf = q[6]; q[6] = q[9]; q[9] = buf;
}
//------------------------------------------------------------------------------
//заполнить матрицу поворота по заданному вектору  q[16]
void LookAt(RfPointXYZ vecEye, RfPointXYZ vecTop, double* q)
{
	normalized(vecEye);
	normalized(vecTop);
	//float m[16];
	double x[3], y[3], z[3];
	//double mag;
	/* Make rotation matrix */
	/* Z vector */
	z[0] = vecEye.x;
	z[1] = vecEye.y;
	z[2] = vecEye.z;

	/* Y vector */
	y[0] = vecTop.x;
	y[1] = vecTop.y;
	y[2] = vecTop.z;

	/* X vector = Y cross Z */
	x[0] = y[1] * z[2] - y[2] * z[1];
	x[1] = -y[0] * z[2] + y[2] * z[0];
	x[2] = y[0] * z[1] - y[1] * z[0];

	/* Recompute Y = Z cross X */
	y[0] = z[1] * x[2] - z[2] * x[1];
	y[1] = -z[0] * x[2] + z[2] * x[0];
	y[2] = z[0] * x[1] - z[1] * x[0];

	/* mpichler, 19950515 */
	/* cross product gives area of parallelogram, which is < 1.0 for
	* non-perpendicular unit-length vectors; so normalize x, y here
	*/
	/*mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
	if (mag) {
	x[0] /= mag;
	x[1] /= mag;
	x[2] /= mag;
	}

	mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
	if (mag) {
	y[0] /= mag;
	y[1] /= mag;
	y[2] /= mag;
	}*/

#define M(row,col)  q[col*4+row]
	M(0, 0) = x[0];
	M(0, 1) = x[1];
	M(0, 2) = x[2];
	M(0, 3) = 0.0;
	M(1, 0) = y[0];
	M(1, 1) = y[1];
	M(1, 2) = y[2];
	M(1, 3) = 0.0;
	M(2, 0) = z[0];
	M(2, 1) = z[1];
	M(2, 2) = z[2];
	M(2, 3) = 0.0;
	M(3, 0) = 0.0;
	M(3, 1) = 0.0;
	M(3, 2) = 0.0;
	M(3, 3) = 1.0;
#undef M
	//glMultMatrixf(m);       
	/* Translate Eye to Origin */
	//glTranslatef(-eyex, -eyey, -eyez);
}
//------------------------------------------------------------------------------
//Построить: икосандр 12 точек 20 граней
void buildIcosahedron(double r, TSimpleList2<RdPointXYZ>* Points, TSimpleList2<RsFacesABC>* Faces)
{
	const double vX = 0.525731112119133606*r;
	const double vZ = 0.850650808352039932*r;

	RdPointXYZ vPoints;
	RsFacesABC vFaces;

	vPoints.x = -vX; vPoints.y = 0.0; vPoints.z = vZ;
	Points->add(vPoints);
	vPoints.x = vX; vPoints.y = 0.0; vPoints.z = vZ;
	Points->add(vPoints);
	vPoints.x = -vX; vPoints.y = 0.0; vPoints.z = -vZ;
	Points->add(vPoints);
	vPoints.x = vX; vPoints.y = 0.0; vPoints.z = -vZ;
	Points->add(vPoints);
	vPoints.x = 0.0; vPoints.y = vZ; vPoints.z = vX;
	Points->add(vPoints);
	vPoints.x = 0.0; vPoints.y = vZ; vPoints.z = -vX;
	Points->add(vPoints);
	vPoints.x = 0.0; vPoints.y = -vZ; vPoints.z = vX;
	Points->add(vPoints);
	vPoints.x = 0.0; vPoints.y = -vZ; vPoints.z = -vX;
	Points->add(vPoints);
	vPoints.x = vZ; vPoints.y = vX; vPoints.z = 0.0;
	Points->add(vPoints);
	vPoints.x = -vZ; vPoints.y = vX; vPoints.z = 0.0;
	Points->add(vPoints);
	vPoints.x = vZ; vPoints.y = -vX; vPoints.z = 0.0;
	Points->add(vPoints);
	vPoints.x = -vZ; vPoints.y = -vX; vPoints.z = 0.0;
	Points->add(vPoints);

	vFaces.a = 0; vFaces.c = 4; vFaces.b = 1;
	Faces->add(vFaces);
	vFaces.a = 0; vFaces.c = 9; vFaces.b = 4;
	Faces->add(vFaces);
	vFaces.a = 9; vFaces.c = 5; vFaces.b = 4;
	Faces->add(vFaces);
	vFaces.a = 4; vFaces.c = 5; vFaces.b = 8;
	Faces->add(vFaces);
	vFaces.a = 4; vFaces.c = 8; vFaces.b = 1;
	Faces->add(vFaces);
	vFaces.a = 8; vFaces.c = 10; vFaces.b = 1;
	Faces->add(vFaces);
	vFaces.a = 8; vFaces.c = 3; vFaces.b = 10;
	Faces->add(vFaces);
	vFaces.a = 5; vFaces.c = 3; vFaces.b = 8;
	Faces->add(vFaces);
	vFaces.a = 5; vFaces.c = 2; vFaces.b = 3;
	Faces->add(vFaces);
	vFaces.a = 2; vFaces.c = 7; vFaces.b = 3;
	Faces->add(vFaces);
	vFaces.a = 7; vFaces.c = 10; vFaces.b = 3;
	Faces->add(vFaces);
	vFaces.a = 7; vFaces.c = 6; vFaces.b = 10;
	Faces->add(vFaces);
	vFaces.a = 7; vFaces.c = 11; vFaces.b = 6;
	Faces->add(vFaces);
	vFaces.a = 11; vFaces.c = 0; vFaces.b = 6;
	Faces->add(vFaces);
	vFaces.a = 0; vFaces.c = 1; vFaces.b = 6;
	Faces->add(vFaces);
	vFaces.a = 6; vFaces.c = 1; vFaces.b = 10;
	Faces->add(vFaces);
	vFaces.a = 9; vFaces.c = 0; vFaces.b = 11;
	Faces->add(vFaces);
	vFaces.a = 9; vFaces.c = 11; vFaces.b = 2;
	Faces->add(vFaces);
	vFaces.a = 9; vFaces.c = 2; vFaces.b = 5;
	Faces->add(vFaces);
	vFaces.a = 7; vFaces.c = 2; vFaces.b = 11;
	Faces->add(vFaces);
}
//------------------------------------------------------------------------------
//Построить: октаэдр 6 точек 8 граней
void buildOctahedron(double r, TSimpleList2<RdPointXYZ>* Points, TSimpleList2<RsFacesABC>* Faces)
{
	RdPointXYZ vPoints;
	RsFacesABC vFaces;

	vPoints.x = r; vPoints.y = 0; vPoints.z = 0; //0
	Points->add(vPoints);
	vPoints.x = -r; vPoints.y = 0; vPoints.z = 0; //1
	Points->add(vPoints);
	vPoints.x = 0; vPoints.y = r; vPoints.z = 0; //2
	Points->add(vPoints);
	vPoints.x = 0; vPoints.y = -r; vPoints.z = 0; //3
	Points->add(vPoints);
	vPoints.x = 0; vPoints.y = 0; vPoints.z = r; //4
	Points->add(vPoints);
	vPoints.x = 0; vPoints.y = 0; vPoints.z = -r; //5
	Points->add(vPoints);

	vFaces.a = 0; vFaces.c = 4; vFaces.b = 2;
	Faces->add(vFaces);
	vFaces.a = 2; vFaces.c = 4; vFaces.b = 1;
	Faces->add(vFaces);
	vFaces.a = 1; vFaces.c = 4; vFaces.b = 3;
	Faces->add(vFaces);
	vFaces.a = 3; vFaces.c = 4; vFaces.b = 0;
	Faces->add(vFaces);

	vFaces.a = 2; vFaces.c = 5; vFaces.b = 0;
	Faces->add(vFaces);
	vFaces.a = 1; vFaces.c = 5; vFaces.b = 2;
	Faces->add(vFaces);
	vFaces.a = 3; vFaces.c = 5; vFaces.b = 1;
	Faces->add(vFaces);
	vFaces.a = 0; vFaces.c = 5; vFaces.b = 3;
	Faces->add(vFaces);
}
//------------------------------------------------------------------------------
//Переместить шпиндель на заданое количество точек по линии
// От LONG_MIN до LONG_MAX -2,147,483,648 до 2,147,483,647
// xDis, yDis, zDis - количество шагов в ту или другую сторону
TSimpleList2<RcPointXYZ>* Line3D(signed long int xDis, signed long int yDis, signed long int zDis)
{
	TSimpleList2<RcPointXYZ>* result = new TSimpleList2<RcPointXYZ>();

	signed long int i, l, m, n, dx2, dy2, dz2, err_1, err_2;
	signed char x_inc, y_inc, z_inc;
	RcPointXYZ pixel;

	pixel.x = 0;
	pixel.y = 0;
	pixel.z = 0;

	if (xDis < 0) x_inc = -1; else x_inc = 1;
	if (xDis < 0) xDis = -xDis;
	l = xDis;

	if (yDis < 0) y_inc = -1; else 	y_inc = 1;
	if (yDis < 0) yDis = -yDis;
	m = yDis;

	if (zDis < 0) z_inc = -1; else 	z_inc = 1;
	if (zDis < 0) zDis = -zDis;
	n = zDis;

	dx2 = l << 1;
	dy2 = m << 1;
	dz2 = n << 1;

	if ((l >= m) && (l >= n))
	{
		err_1 = dy2 - l;
		err_2 = dz2 - l;
		for (i = 0; i < l; i++)
		{
			// step here
			//StepMotors(pixel[0], pixel[1], pixel[2]);
			result->add(pixel);

			pixel.x = 0;
			pixel.y = 0;
			pixel.z = 0;

			if (err_1 > 0)
			{
				pixel.y = y_inc;
				err_1 -= dx2;
			}
			if (err_2 > 0)
			{
				pixel.z = z_inc;
				err_2 -= dx2;
			}
			err_1 += dy2;
			err_2 += dz2;

			pixel.x = x_inc;
		}
	}
	else if ((m >= l) && (m >= n))
	{
		err_1 = dx2 - m;
		err_2 = dz2 - m;
		for (i = 0; i < m; i++)
		{
			// step here
			//StepMotors(pixel[0], pixel[1], pixel[2]);
			result->add(pixel);

			pixel.x = 0;
			pixel.y = 0;
			pixel.z = 0;

			if (err_1 > 0)
			{
				pixel.x = x_inc;
				err_1 -= dy2;
			}
			if (err_2 > 0)
			{
				pixel.z = z_inc;
				err_2 -= dy2;
			}
			err_1 += dx2;
			err_2 += dz2;

			pixel.y = y_inc;
		}
	}
	else
	{
		err_1 = dy2 - n;
		err_2 = dx2 - n;
		for (i = 0; i < n; i++)
		{
			// step here
			//StepMotors(pixel[0], pixel[1], pixel[2]);
			result->add(pixel);

			pixel.x = 0;
			pixel.y = 0;
			pixel.z = 0;

			if (err_1 > 0)
			{
				pixel.y = y_inc;
				err_1 -= dz2;
			}
			if (err_2 > 0)
			{
				pixel.x = x_inc;
				err_2 -= dz2;
			}
			err_1 += dy2;
			err_2 += dx2;

			pixel.z = z_inc;
		}
	}
	// step here
	//StepMotors(pixel[0], pixel[1], pixel[2]);
	result->add(pixel);

	return result;
}
//------------------------------------------------------------------------------
