Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ООП / ООП / 3-2 / unit_stuff

.cpp
Скачиваний:
8
Добавлен:
18.02.2017
Размер:
18.17 Кб
Скачать
//---------------------------------------------------------------------------
#include "Mathem.h"
#include <vcl.h>
#include <cmath>
#include <math.hpp>
#pragma hdrstop

#include "unit_stuff.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

//---------------------------------------------------------------------------

const TColor CSupport_COLOR    = (TColor)RGB(0, 0, 0),
				CBall_COLOR[]  = {clBlue, (TColor)RGB(250, 250, 250)},
				CLine_COLOR    = (TColor)RGB(100, 100, 100),
			  CTarget_COLOR[]  = {clYellow, clRed},
			  BACKGROUND_COLOR = clWhite;

const int 	 CSupport_WIDTH = 4,
				CBall_WIDTH = 1,
				CLine_WIDTH = 4;

//---------------------------------------------------------------------------

inline double max(const double &x, const double &y){return x > y ? x : y;}
inline double min(const double &x, const double &y){return x < y ? x : y;}

inline double distance(const DPoint &p1, const DPoint &p2){
	return std::sqrt(std::pow(p1.x - p2.x, 2) + std::pow(p1.y - p2.y, 2));
}

//---------------------------------------------------------------------------
//Class DPoint---------------------------------------------------------------
//---------------------------------------------------------------------------

DPoint::DPoint(const DPoint &p){
	x = p.x;
	y = p.y;
}

//---------------------------------------------------------------------------

DPoint::DPoint(const TPoint &p){
	x = static_cast<double>(p.x);
	y = static_cast<double>(p.y);
}

//---------------------------------------------------------------------------

DPoint::DPoint(const double &X, const double &Y){
	x = X;
	y = Y;
}

//---------------------------------------------------------------------------

double DPoint::Distance(){
	return std::sqrt(std::pow(x, 2) + std::pow(y, 2));
}

//---------------------------------------------------------------------------

double DPoint::Distance(const DPoint &p){
	return std::sqrt(std::pow(x - p.x, 2) + std::pow(y - p.y, 2));
}

//---------------------------------------------------------------------------

DPoint DPoint::Normalize(){
	return DPoint(x / Distance(), y / Distance());
}

//---------------------------------------------------------------------------

DPoint& operator+=(DPoint &left, const DPoint &right){
	left.x += right.x;
	left.y += right.y;
	return left;
}

//---------------------------------------------------------------------------

bool DPoint::operator==(const DPoint &other) const{
	if(this->x == other.x)
		if(this->y == other.y) return true;
	return false;
}

//---------------------------------------------------------------------------

const DPoint operator+(const DPoint &left, const DPoint &right){
	return DPoint(left.x + right.x, left.y + right.y);
}

//---------------------------------------------------------------------------

const DPoint operator-(const DPoint &left, const DPoint &right){
	return DPoint(left.x - right.x, left.y - right.y);
}

//---------------------------------------------------------------------------

bool DPoint::operator!=(const DPoint &other) const{
    return !(*this == other);
}


//---------------------------------------------------------------------------
//Class CSupport-------------------------------------------------------------
//---------------------------------------------------------------------------

CSupport::CSupport(const DPoint &C, const double &A, const double &B, const double &T){
	center = C;
	a = max(0., A);
	b = max(0., B);

	t = T;

	while(t >= 2.*M_PI) t -= 2.*M_PI;
	while(t < 0.) t += 2.*M_PI;

	t = M_PI - t;

	angle = 0.;
}

//---------------------------------------------------------------------------

void CSupport::Draw(Graphics::TCanvas *cnv){

	using namespace std;

	XFORM xfrm;

	xfrm.eM11 = static_cast<FLOAT>(cos(angle));
	xfrm.eM12 = static_cast<FLOAT>(-sin(angle));
	xfrm.eM21 = static_cast<FLOAT>(sin(angle));
	xfrm.eM22 = static_cast<FLOAT>(cos(angle));

	xfrm.eDx  = static_cast<FLOAT>(center.x - a - (center.x - a)*xfrm.eM11 - center.y*xfrm.eM21);
	xfrm.eDy  = static_cast<FLOAT>(center.y - (center.x - a)*xfrm.eM12 - center.y*xfrm.eM22);

	SetGraphicsMode(cnv->Handle, GM_ADVANCED);
	SetWorldTransform(cnv->Handle, &xfrm);

    cnv->Pen->Style = psSolid;
	cnv->Pen->Color = CSupport_COLOR;
	cnv->Pen->Width = CSupport_WIDTH;
	cnv->Brush->Style = bsClear;
	
	cnv->Arc(center.x - a, center.y - b, center.x + a, center.y + b,
			 center.x - a, center.y, center.x + a*cos(t), center.y + b*sin(t));
	cnv->Ellipse(center.x - a - CSupport_WIDTH, center.y - CSupport_WIDTH,
				 center.x - a + CSupport_WIDTH, center.y + CSupport_WIDTH);

	ModifyWorldTransform(cnv->Handle, NULL, MWT_IDENTITY);
}

//---------------------------------------------------------------------------

void CSupport::Move(const DPoint &ds){
	center.x += ds.x;
	center.y += ds.y;
}

//---------------------------------------------------------------------------

void CSupport::Rotate(const double &d){
	angle = d;
}

//---------------------------------------------------------------------------

void CSupport::Resize(const double &A, const double &B, const double &T){
	a = max(0, A);
	b = max(0, B);

	t = T;

	while(t > 2*M_PI){
		t -= 2*M_PI;
	}
	while(t <= 0.0){
		t += 2*M_PI;
	}

	t = M_PI - t;
}

//---------------------------------------------------------------------------

DPoint CSupport::GetNormal(CBall *ball){
	using namespace std;

	DPoint b0;

	DPoint Ncenter = DPoint(center.x - a, center.y);

	b0.x = (ball->center.x - Ncenter.x)*cos(angle) - (ball->center.y - Ncenter.y)*sin(angle) - a;
	b0.y = (ball->center.x - Ncenter.x)*sin(angle) + (ball->center.y - Ncenter.y)*cos(angle);

	double x[4], Z = b*b + b0.y * b0.y + b0.x * b0.x - ball->r * ball->r;
	unsigned root_count;

	if(a==b){
		if(b0.Distance() < 1.e-10){
			return DPoint(0., 0.);
		}
		else{
			double A = -Z*b0.x / (b0.x * b0.x + b0.y * b0.y),
				   B = (Z*Z - 4. * b0.y * b0.y * b* b) / (4.*(b0.x * b0.x + b0.y * b0.y));

			root_count = root2(A, B, x);
		}
	}
	else{
		if(b0.Distance() < 1.e-10){
		double s = (b*b - ball->r*ball->r) / (b*b - a*a);
			if(s >= 0.){
				x[0] = a * sqrt(s);
				x[1] = -x[0];
				root_count = 2;
			}
			else{
				return DPoint(0., 0.);
			}
		}
		else{
			double W = (1. - b*b/(a*a)),
			A = -4.*b0.x / W,
			B = (4.*b0.x*b0.x + 2.*Z*W + 4.*b0.y *b0.y * b*b/(a*a)) / (W*W),
			C = -4.*b0.x*Z/(W*W),
			D = (Z*Z - 4. * b0.y*b0.y * b *b) / (W*W);
			root_count = root4(A, B, C, D, x);
		}
	}

	if(!root_count) return DPoint(0., 0.);

	DPoint temp, result;
	result.x = 0.;
	result.y = 0.;

	int k = 0;

	for(unsigned i = 0; i < root_count; ++i){

		if(abs(x[i]) > a) continue;

		temp.x = x[i];
		temp.y = b*sqrt(abs(1 - temp.x * temp.x / (a*a)));

		for(int j = 0; j < 2; ++j){
			if(abs(temp.Distance(b0) - ball->r) <= 1.e-10){
				double p = atan2(temp.y, temp.x);
					if((p <= M_PI) && (p >= t)){
					   result.x += (b0.x - temp.x)/temp.Distance(b0);
					   result.y += (b0.y - temp.y)/temp.Distance(b0);
					   ++k;
					}
			}
			temp.y *= -1.;
		}
	}

	temp = DPoint(center.x - a, center.y);

	if(abs(b0.Distance(temp) - ball->r) <= 1.e-10){
		result.x += (b0.x - temp.x)/temp.Distance(b0) ;
		result.y += (b0.y - temp.y)/temp.Distance(b0);
		++k;
	}

	temp = DPoint(a*cos(t), b*sin(t));

	if(abs(b0.Distance(temp) - ball->r) <= 1.e-10){
		result.x += (b0.x - temp.x)/temp.Distance(b0);
		result.y += (b0.y - temp.y)/temp.Distance(b0);
		++k;
	}

	if(k){

		temp.x = (result.x) * cos(angle) + (result.y)* sin(angle);
		temp.y = -(result.x) * sin(angle) + (result.y)* cos(angle);

		return temp.Normalize();
	}
	return DPoint(0., 0.);
}


//---------------------------------------------------------------------------
//Class CBall----------------------------------------------------------------
//---------------------------------------------------------------------------

CBall::CBall(const DPoint &C, const double &R){
	center = C;
	r = max(.5, R);
	v = DPoint(0., 0.);
}

//---------------------------------------------------------------------------

void CBall::Draw(Graphics::TCanvas *cnv){
	cnv->Pen->Color = CBall_COLOR[0];
	cnv->Pen->Width = CBall_WIDTH;
	cnv->Brush->Color = CBall_COLOR[0];
	cnv->Ellipse(center.x - r, center.y - r, center.x + r, center.y + r);

	cnv->Pen->Color = CBall_COLOR[1];
	cnv->Brush->Color = CBall_COLOR[1];
	cnv->Ellipse(center.x - .5*r, center.y - .5*r, center.x + .5*r, center.y + .5*r);
}

//---------------------------------------------------------------------------

void CBall::Move(const DPoint &ds){
	center.x += ds.x;
	center.y += ds.y;
}

//---------------------------------------------------------------------------

DPoint CBall::GetNormal(CBall*){
	return DPoint(0., 0);
}


//---------------------------------------------------------------------------
//Class CLine----------------------------------------------------------------
//---------------------------------------------------------------------------

CLine::CLine(const DPoint &P1, const DPoint &P2){
	p1 = P1;
	p2 = P2;

	if(P1 == P2)
		p2.x += 1;
}

//---------------------------------------------------------------------------

void CLine::Draw(Graphics::TCanvas *cnv){
	cnv->Pen->Style = psSolid;
	cnv->Pen->Color = CLine_COLOR;
	cnv->Pen->Width = CLine_WIDTH;
	cnv->Brush->Style = bsClear;

	cnv->PenPos = TPoint(p1.x, p1.y);
	cnv->LineTo(p2.x, p2.y);
}

//---------------------------------------------------------------------------

void CLine::Move(const DPoint&){
	return;
}

//---------------------------------------------------------------------------

DPoint CLine::GetNormal(CBall *ball){
	using namespace std;

	if(p1.x == p2.x){
		if(ball->r >= abs(p1.x - ball->center.x)){
			return ball->center.x > p1.x ? DPoint(1., 0.) : DPoint(-1., 0.);
		}
	}
	
	if(p1.y == p2.y){
		if(ball->r >= abs(p1.y - ball->center.y)){
			return ball->center.y > p1.y ? DPoint(0., 1.) : DPoint(0., -1.);
		}
	}

	// если наклонная линия
	// ...

	return DPoint(0., 0.);

}


//---------------------------------------------------------------------------
//Class CTarget--------------------------------------------------------------
//---------------------------------------------------------------------------

CTarget::CTarget(const DPoint &P1, const DPoint &P2, const int &C){
	p1 = P1;
	p2 = P2;
	count = C ? abs(C) : 1;
}

//---------------------------------------------------------------------------

void CTarget::Draw(Graphics::TCanvas *cnv){
	cnv->Pen->Style = psClear;

	double h = (abs(p1.y - p2.y)) / (2 * count - 1);

	for(int i = 0; i < count; ++i){
		cnv->Brush->Color = CTarget_COLOR[i%2];
		cnv->Rectangle(p1.x, p1.y + h * i, p2.x, p2.y - h * i);
	}
}

//---------------------------------------------------------------------------

void CTarget::Move(const DPoint &ds){
	p1 += ds;
	p2 += ds;
}

//---------------------------------------------------------------------------

double CTarget::getHeight(){
	return std::abs(p1.y - p2.y);
}

//---------------------------------------------------------------------------

double CTarget::getWidth(){
	return std::abs(p1.x - p2.x);
}

//---------------------------------------------------------------------------

DPoint CTarget::GetNormal(CBall *ball){
	DPoint pc = DPoint((p1.x + p2.x) / 2., (p1.y + p2.y) / 2.);
	double h = abs(p1.y - p2.y) / 2.,
		   w = abs(p1.x - p2.x) / 2.;

	if((ball->center.y <= pc.y + h) && (ball->center.y >= pc.y - h))
    	if((ball->center.x <= pc.x + w + ball->r) && (ball->center.x >= pc.x - w - ball->r)){
			throw (static_cast<int>(RoundTo(count - (abs(ball->center.y - pc.y) / (2. * h / (2. * static_cast<double>(count) - 1) )), 0)));
		}

	return DPoint(0., 0.);
}

//---------------------------------------------------------------------------

Elements* FindItem(Graphics::TCanvas *cnv, const TPoint &pt, vector<Elements*> &arr){
	using namespace std;

	if((cnv->Pixels[pt.x][pt.y] == BACKGROUND_COLOR) ||
	   (cnv->Pixels[pt.x][pt.y] == CLine_COLOR)){
        	return NULL;
	   }

	if(arr.empty()) return NULL; 

	if((cnv->Pixels[pt.x][pt.y] == CBall_COLOR[0])||
	   (cnv->Pixels[pt.x][pt.y] == CBall_COLOR[1])){
			CBall *ball;
			for(vector<Elements*>:: iterator p = arr.begin(); p < arr.end(); ++p){
				if((ball = dynamic_cast<CBall*>(*p)) != NULL){
					if(distance(DPoint(pt), ball->center) <= ball->r + CBall_WIDTH){
						return *p;
					}
				}
			}
	}

	if(cnv->Pixels[pt.x][pt.y] == CSupport_COLOR){
			CSupport *support;
			for(vector<Elements*>:: iterator p = arr.begin(); p < arr.end(); ++p){

				if((support = dynamic_cast<CSupport*>(*p)) != NULL){
					//!!
					if(distance(DPoint(pt), DPoint(support->center.x - support->a, support->center.y)) <= CSupport_WIDTH){
						return *p;
					}
				}
			}
		}

	if((cnv->Pixels[pt.x][pt.y] == CTarget_COLOR[0]) ||
	   (cnv->Pixels[pt.x][pt.y] == CTarget_COLOR[1])){
			CTarget *target;

			for(vector<Elements*>:: iterator p = arr.begin(); p < arr.end(); ++p){
				if((target = dynamic_cast<CTarget*>(*p)) != NULL){
					DPoint c;
					c.x = (target->p1.x + target->p2.x) / 2;
					c.y = (target->p1.y + target->p2.y) / 2;
						if((static_cast<double>(pt.x) >= c.x - target->getWidth() / 2) &&
						   (static_cast<double>(pt.x) <= c.x + target->getWidth() / 2)  &&
						   (static_cast<double>(pt.y) >= c.y - target->getHeight() / 2) &&
						   (static_cast<double>(pt.y) <= c.y + target->getHeight() / 2)){
								return *p;
						   }
				}
			}
	}
	return NULL;
}

//---------------------------------------------------------------------------

void MoveItem(Elements *item, const TPoint &ds){
	item->Move(DPoint(ds));
}

//---------------------------------------------------------------------------

void DrawAll(Graphics::TCanvas *cnv, vector <Elements*>  &arr){
	Graphics::TBitmap *bitmp = new Graphics::TBitmap;
	
	bitmp->SetSize(cnv->ClipRect.Width(), cnv->ClipRect.Height());

	bitmp->Canvas->Brush->Color = BACKGROUND_COLOR;
	bitmp->Canvas->FillRect(cnv->ClipRect);

	for(vector<Elements*>:: iterator p = arr.end() - 1; p >= arr.begin(); --p)
		(*p)->Draw(bitmp->Canvas);

	cnv->CopyRect(cnv->ClipRect, bitmp->Canvas, bitmp->Canvas->ClipRect);

	delete(bitmp);
}

//---------------------------------------------------------------------------

bool AddBall(vector<Elements*> &arr, const DPoint &center, const double &R){
	CBall *ball = new CBall(center, R);
	if(ball){
		arr.push_back(ball);
		return true;
	}

	return false;
}

//---------------------------------------------------------------------------

bool AddSupport(vector<Elements*> &arr, const DPoint &center, const double &A, const double &B, const double &T){
	CSupport *support = new CSupport(center, A, B, T);
	if(support){
		arr.push_back(support);
		return true;
	}

	return false;
}

//---------------------------------------------------------------------------

bool AddBorder(vector<Elements*> &arr, const DPoint &P1, const DPoint &P2){
	CLine *line = new CLine(P1, DPoint(P2.x, P1.y));
	if(line) arr.push_back(line);
	else return false;

	line = new CLine(P2, DPoint(P2.x, P1.y));
	if(line) arr.push_back(line);
	else return false;

	line = new CLine(P1, DPoint(P1.x, P2.y));
	if(line) arr.push_back(line);
	else return false;

	line = new CLine(P2, DPoint(P1.x, P2.y));
	if(line) arr.push_back(line);
	else return false;

	return true;
}

//---------------------------------------------------------------------------

bool AddTarget(vector<Elements*> &arr, const DPoint &P1, const DPoint &P2, const int &count){
	CTarget *target = new CTarget(P1, P2, count);
	if(target){
		arr.push_back(target);
		return true;
	}
	return false;
}

//---------------------------------------------------------------------------

void MoveIt(Graphics::TCanvas *cnv, CBall *ball, vector<Elements*> &arr, const double &gravity,
const double &bounce, const double &friction){

bool flag = false;

DPoint ds,
	   destination = ball->center + ball->v;
if(ball->v != DPoint(0., 0.))
	ds = DPoint(0.005*ball->r * ball->v.x / ball->v.Distance(), 0.005*ball->r * ball->v.y / ball->v.Distance());
else
	ds = DPoint(0.,0.);

do{
	ball->center += ds;

	DPoint n = DPoint(0., 0.);
	
	for(vector<Elements*>:: iterator t = arr.begin(); t < arr.end(); ++t){
		n += (*t)->GetNormal(ball);
	}


	if(n != DPoint(0., 0.)){
		flag = true;

		n = n.Normalize();

		DPoint  p = DPoint(-n.y, n.x),
			   vn = DPoint((ball->v.x * n.x + ball->v.y * n.y) * n.x,
					   (ball->v.x * n.x + ball->v.y * n.y) * n.y),
			   vp = DPoint((ball->v.x * p.x + ball->v.y * p.y) * p.x,
					   (ball->v.x * p.x + ball->v.y * p.y) * p.y);

//		if((ball->v.x * n.x + ball->v.y * n.y) < 0){
			vn.x = -vn.x;
			vn.y = -vn.y;
			ball->v = DPoint(vn.x * bounce + vp.x * friction, vn.y * bounce + vp.y * friction);

			if(gravity > 0.)
				if(abs(ball->v.y) > gravity)
				ball->v.y +=  + gravity * (ball->v.Distance() - ball->center.Distance(destination))/ball->v.Distance();
//		}
//		else{
//			ball->v = DPoint(vn.x + vp.x, vn.y + vp.y);
//			if(ball->v.Distance() > 0)
//				ball->v.y +=  + gravity * (ball->v.Distance() - ball->center.Distance(destination))/ball->v.Distance();
//		}

			DPoint h = n;
			h.x *= 0.005 * ball->r + 0.1*(ball->v.Distance() > 1.e-10 ? ball->v.Distance() : 1.e-10);
			h.y *= 0.005 * ball->r + 0.1*(ball->v.Distance() > 1.e-10 ? ball->v.Distance() : 1.e-10);
			ball->center += h;

		break;
	}

if(ball->center.Distance(destination) < 0.005*ball->r) ball->center = destination;

}while(ball->center.Distance(destination) > 0);

if(!flag){
	ball->v.y += gravity;
}

DrawAll(cnv, arr);
}

Соседние файлы в папке 3-2