Добавил:
sergey123
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
//---------------------------------------------------------------------------
#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 ¢er, 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 ¢er, 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