Скачиваний:
20
Добавлен:
28.06.2014
Размер:
14.07 Кб
Скачать
/*---------------------------------------------------------------------------
	Курсовая работа "Автоколебания в химических реакциях"
	Автор: Захаров А. Е.
	Московский Энергетический Институт (Технический Университет), 2011 г.
  ---------------------------------------------------------------------------*/
#include <vcl.h>
#include <math.h>
#pragma hdrstop

#include "MainUnit.h"
#include "EditUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "sPageControl"
#pragma link "sSkinManager"
#pragma link "sLabel"
#pragma link "sBitBtn"
#pragma link "sGroupBox"
#pragma link "sCheckBox"
#pragma link "sPanel"
#pragma link "sSkinProvider"
#pragma link "sUpDown"
#pragma link "sPageControl"
#pragma link "sColorSelect"
#pragma link "sSpeedButton"
#pragma link "acPNG"
#pragma link "sTrackBar"
#pragma link "sRadioButton"
#pragma link "sStatusBar"
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
TMainForm *MainForm;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner)
{
	recount();
}

/*--- Заданные функции правых частей системы --------------------------------
 * x, y - концентрации реагентов X и Y
 */
double TMainForm::f1(double x, double y)
{
	return Options.b * x - x * x * y;
}

double TMainForm::f2(double x, double y)
{
	return Options.a - (Options.b + 1) * x + x * x * y;
}

/*--- Поиск численных решений системы методом Рунге-Кутты 3-его порядка -----
 * y_prev, x_prev - предыдущие значения функций
 * Результат: Значение функции в точке t + h
 */
double TMainForm::y(double x_prev, double y_prev)
{
	double k1 = f1(x_prev, y_prev);
	double k2 = f1(x_prev + Options.h * Options.b2 * k1, y_prev + Options.h * Options.b2 * k1);
	double k3 = f1(x_prev + Options.h * (Options.b31 * k1 + Options.b32 * k2), y_prev + Options.h * (Options.b31 * k1 + Options.b32 * k2));

	return y_prev + Options.h * (Options.c1 * k1 + Options.c2 * k2 + Options.c3 * k3);
}

double TMainForm::x(double x_prev, double y_prev)
{
	double k1 = f2(x_prev, y_prev);
	double k2 = f2(x_prev + Options.h * Options.b2 * k1, y_prev + Options.h * Options.b2 * k1);
	double k3 = f2(x_prev + Options.h * (Options.b31 * k1 + Options.b32 * k2), y_prev + Options.h * (Options.b31 * k1 + Options.b32 * k2));

	return x_prev + Options.h * (Options.c1 * k1 + Options.c2 * k2 + Options.c3 * k3);
}

/*--- Поиск минимума и максимума в векторе точек функции на плоскости ------
 * P - вектор точкек (x,y)
 */
double maxy(vector<point> P)
{
	double max = 0;
	if(P.size())
	{
		max = P.front().y;
		for(int t = 1; t < P.size(); t++)
			if(P[t].y > max) max = P[t].y;
	}
	return max;
}

double miny(vector<point> P)
{
	double min = 0;
	if(P.size())
	{
		min = P.front().y;
		for(int t = 1; t < P.size(); t++)
			if(P[t].y < min) min = P[t].y;
	}
	return min;
}

double maxx(vector<point> P)
{
	double max = 0;
	if(P.size())
	{
		max = P.front().x;
		for(int t = 1; t < P.size(); t++)
			if(P[t].x > max) max = P[t].x;
	}
	return max;
}

double minx(vector<point> P)
{
	double min = 0;
	if(P.size())
	{
		min = P.front().x;
		for(int t = 1; t < P.size(); t++)
			if(P[t].x < min) min = P[t].x;
	}
	return min;
}

//--- Расчёт задачи --------------------------------------------------------
void TMainForm::recount()
{
	double ta = Options.ta;
	double tb = Options.tb;
	double h = Options.h;
	double x0 = Options.x0;
	double y0 = Options.y0;

	// Коррекция шага
	h = (tb - ta) / (int((tb - ta) / h) + 1.);

	// Начальные условия
	Fpoints[0].clear();
	Fpoints[1].clear();
	Fpoints[2].clear();
	point P1 = {ta, y0};
	point P2 = {ta, x0};
	point P3 = {y0, x0};
	Fpoints[0].push_back(P1);
	Fpoints[1].push_back(P2);
	Fpoints[2].push_back(P3);

	// Поиск точек семейства решений
	vector<point> T;
	int j = 0, v = -1;
	Fpoints2.clear();
	for (int i = 0; j < 10; i++)
		if(((y0 - 1) + i * 0.2) > 0)
		{
			if(v == -1)
				v = i;
			T.clear();
			point P = {ta, (y0 - 1) + double(i) * 0.2};
			if(fabs(P.y) < 0.00000001)
				P.y = 0;
			if(fabs(P.y - y0) < 0.00000001)
				P.y = y0;
			T.push_back(P);
			if(Fpoints2.size() < 10)
				Fpoints2.push_back(T);
			j++;
		}
	j = 0;
	for (int i = v; j < 10; i++)
		if(((x0 - 1) + i * 0.2) > 0)
		{
			T.clear();
			point P = {ta, (x0 - 1) + i * 0.2};
			if(fabs(P.y) < 0.00000001)
				P.y = 0;
			if(fabs(P.y - x0) < 0.00000001)
				P.y = x0;
			T.push_back(P);
			if(Fpoints2.size() < 20)
				Fpoints2.push_back(T);
			j++;
		}
	for (int i = 0; i < 10; i++)
	{
		T.clear();
		point P = {Fpoints2[i].front().y, Fpoints2[i+10].front().y};
		T.push_back(P);
		Fpoints2.push_back(T);
	}
	for(int i = 0; i < 10; i++)
	{
		int j = 1;
		for(double t = ta + h; t <= tb; t = ta + j * h)
		{
			point P1 = {t, y(Fpoints2[i + 10].back().y, Fpoints2[i].back().y)};
			point P2 = {t, x(Fpoints2[i + 10].back().y, Fpoints2[i].back().y)};
			point P3 = {P1.y, P2.y};
			Fpoints2[i].push_back(P1);
			Fpoints2[i + 10].push_back(P2);
			Fpoints2[i + 20].push_back(P3);
			j++;
		}
	}

	paint();
	MainForm->Refresh();
}

/*--- Построение графиков функций на компаненте TImage ---------------------
 * Image     - указатель на объект типа TImage
 * Functions - вектор структур, определяющих точки графиков функции
 *             и задающих параметры отрисовки графиков (цвет, стиль и т. п.)
 * showGrid  - определяет, рисовать сетку или нет
 * zoom      - координата центра области для увеличения
 * zoomed    - определяет, увеличивать область или нет
 */
void TMainForm::functionPaint(TImage *Image, vector<functionOptions> Functions,
						point zoom, bool zoomed = false, bool showGrid = true)
{
	int i, j, x, y, labelpos;
	vector<point> F;
	TColor color;

	int width, height, gridNumX, gridNumY, gridStepX, gridStepY;
	double minY, maxY, minX, maxX, kx, ky;

	minX = minx(Functions.front().points);
	maxX = maxx(Functions.front().points);
	minY = miny(Functions.front().points);
	maxY = maxy(Functions.front().points);

	if(minY == maxY)
	{
		minY = minY - 2;
		maxY = maxY + 5;
	}

	width = Image->Width;
	height = Image->Height;
	gridNumX = 10;
	gridNumY = 16;
	gridStepX = width / gridNumX;
	gridStepY = height / gridNumY;

	kx = double((maxX - minX) / (width  - 2 * gridStepX));
	ky = double((maxY - minY) / (height - 2 * gridStepY));

	if(zoomed)
	{
		minX = (zoom.x - 2 * gridStepX) * kx;
		maxX = zoom.x * kx;
		minY = (height - zoom.y - 2.5 * gridStepY)* ky;
		maxY = (height - zoom.y + 0.5 * gridStepY)* ky;
		kx = double((maxX - minX) / (width  - 2 * gridStepX));
		ky = double((maxY - minY) / (height - 2 * gridStepY));
	}

	// Фон
	Image->Picture->Bitmap->Height = Image->Height;
	Image->Picture->Bitmap->Width = Image->Width;
	Image->Canvas->Pen->Color = clBlack;
	Image->Canvas->Brush->Color = clWhite;
	Image->Canvas->Rectangle(0, 0, width, height);

	// Сетка
	if(showGrid)
	{
		Image->Canvas->Pen->Color = clInactiveCaption;
		Image->Canvas->Pen->Style = psDot;
		for(i = 1; i < gridNumX; i++)
		{
			Image->Canvas->MoveTo(i * gridStepX, 1);
			Image->Canvas->LineTo(i * gridStepX, height - 1);
		}
		for(i = gridNumY - 1; i >= 1 ; i--)
		{
			Image->Canvas->MoveTo(1, i * gridStepY);
			Image->Canvas->LineTo(width - 1, i * gridStepY);
		}
	}

    Image->Canvas->Pen->Color = clBlack;
	Image->Canvas->Pen->Style = psSolid;
    for(i = 1; i < gridNumX; i++)
	{
		Image->Canvas->MoveTo(i * gridStepX, height - gridStepY + 3);
		Image->Canvas->LineTo(i * gridStepX, height - gridStepY - 4);
	}
	for(i = gridNumY - 1; i >= 1 ; i--)
	{
		Image->Canvas->MoveTo(gridStepX - 3, i * gridStepY);
		Image->Canvas->LineTo(gridStepX + 4, i * gridStepY);
	}
	Image->Canvas->MoveTo(gridStepX - 3, 23); Image->Canvas->LineTo(gridStepX, 10);
	Image->Canvas->MoveTo(gridStepX + 3, 23); Image->Canvas->LineTo(gridStepX, 10);
	Image->Canvas->LineTo(gridStepX, height - 11);
	Image->Canvas->MoveTo(10, (gridNumY - 1) * gridStepY);
	Image->Canvas->LineTo(width - 11, (gridNumY - 1) * gridStepY);
	Image->Canvas->MoveTo(width - 11, (gridNumY - 1) * gridStepY); Image->Canvas->LineTo(width - 24, (gridNumY - 1) * gridStepY - 3);
	Image->Canvas->MoveTo(width - 11, (gridNumY - 1) * gridStepY); Image->Canvas->LineTo(width - 24, (gridNumY - 1) * gridStepY + 3);

	Image->Canvas->Pen->Width = 1;

	// Масштаб
	AnsiString xLabel, yLabel;

	Image->Canvas->Pen->Color = clBlack;
	Image->Canvas->Brush->Style = bsClear;
	Image->Canvas->Font->Color = clBlack;

	for(i = (minY != minX) ? 1 : 3; i < gridNumX; i+= 2)
	{
		xLabel = FloatToStrF(minX + double((fabs(minX) + fabs(maxX)) * (i - 1) / (gridNumX - 2)), ffGeneral, 6, 0);
		Image->Canvas->TextOutW(i * gridStepX + 1, height - gridStepY, xLabel);
	}
	for(i = gridNumY - 1; i >= 1; i-= 2)
	{
		yLabel = FloatToStrF(maxY - double((maxY - minY) * (i - 1) / (gridNumY - 2)), ffGeneral, 6, 0);
		Image->Canvas->TextOutW(gridStepX - 6.5 * strlen(yLabel.c_str()), i * gridStepY + 1, yLabel);
	}

	// Графики функций
	for(i = 0; i < Functions.size(); i++)
	{
		if(Functions[i].enabled)
		{
			F = Functions[i].points;
			color = Functions[i].color;
			AnsiString label = Functions[i].label;
			labelpos = Functions[i].labelpos;

			Image->Canvas->Pen->Color = color;
			Image->Canvas->Brush->Color = color;
			Image->Canvas->Font->Color = color;

			for(j = 0; j < F.size(); j++)
			{
				x = gridStepX + (F[j].x - minX) / kx;
				y = height - gridStepY - (F[j].y - minY) / ky;
				if (Functions[i].style == psDot)
					Image->Canvas->Ellipse(x - 3, y - 3, x + 3, y + 3);
				else
				{
					if (j == 0)
						Image->Canvas->MoveTo(x, y);
					else
						Image->Canvas->LineTo(x, y);
				}
				if (label != ' ' && labelpos <= j * 100 / F.size())
				{
					Image->Canvas->Brush->Style = bsClear;
					Image->Canvas->TextOutW(x + 15, y + 5, label);
					Image->Canvas->Brush->Color = color;
					Image->Canvas->MoveTo(x, y);
					label = ' ';
				}
			}
		}
	}

	// Область для увеличения
	if(zoom.x > 0 && zoom.y > 0 && !zoomed)
	{
		Image->Canvas->Brush->Style = bsClear;
		Image->Canvas->Pen->Color = clSkyBlue;
		Image->Canvas->Pen->Width = 2;
		Image->Canvas->Rectangle(zoom.x - gridStepX, zoom.y - 1.5 * gridStepY, zoom.x + gridStepX, zoom.y + 1.5 * gridStepY);
		Image->Canvas->Pen->Width = 1;
		Image->Cursor = crCross;
	}
	else
		Image->Cursor = crDefault;

	Image->Refresh();
}
//---------------------------------------------------------------------------
void TMainForm::addFunction(vector<functionOptions> &F, vector<point> P, TColor C, bool enabled = true, TPenStyle style = psDash, AnsiString label = ' ', int labelpos = 0)
{
	functionOptions O;

	O.points = P;
	O.color = C;
	O.label = label;
	O.labelpos = labelpos;
	O.enabled = enabled;
	O.style = style;

	F.push_back(O);
}

//--- Перерисовка графиков функций для заданных точек -----------------------
void TMainForm::paint()
{
	vector<functionOptions> F;

	if(sRadioButton1->Checked)
	{
		for (int i = 0; i < 10; i++)
			addFunction(F, Fpoints2[i], (Fpoints2[i].front().y != Options.y0) ? sColorSelect1->ColorValue : clGreen, (Options.show_all || Fpoints2[i].front().y == Options.y0));
		addFunction(F, Fpoints[0], clBlack, true, psDot);
	}
	if(sRadioButton2->Checked)
	{
		for (int i = 10; i < 20; i++)
			addFunction(F, Fpoints2[i], (Fpoints2[i].front().y != Options.x0) ? sColorSelect1->ColorValue : clGreen, (Options.show_all || Fpoints2[i].front().y == Options.x0));
		addFunction(F, Fpoints[1], clBlack, true, psDot);
	}
	if(sRadioButton3->Checked)
	{
		for (int i = 20; i < 30; i++)
			addFunction(F, Fpoints2[i], (Fpoints2[i].front().y != Options.x0 && Fpoints2[i].front().x != Options.y0) ? sColorSelect1->ColorValue : clGreen, (Options.show_all || (Fpoints2[i].front().y == Options.x0 && Fpoints2[i].front().x == Options.y0)));
	}

	if(sRadioButton1->Checked || sRadioButton2->Checked || sRadioButton3->Checked)
		functionPaint(Image1, F, zoom, zoomed, Options.show_grid);
}

//--- Открыть окно настроек программы ------------------------------------------------------------------------
void __fastcall TMainForm::sBitBtn1Click(TObject *Sender)
{
	Application->CreateForm(__classid(TEditForm1), &EditForm1);
	EditForm1->ShowModal();
}

//--- Выбор графиков для отображения ----------------------------------------
void __fastcall TMainForm::check(TObject *Sender)
{
	paint();
}

//--- Область для увеличения графика ----------------------------------------
void __fastcall TMainForm::Image1MouseMove(TObject *Sender, TShiftState Shift, int X,
		  int Y)
{
    if(!zoomed)
	{
		zoom.x = X;
		zoom.y = Y;
		sStatusBar1->Panels->Items[0]->Text = "  Щёлкните мышью, чтобы увеличить график";
		paint();
	}
	else
		sStatusBar1->Panels->Items[0]->Text = "  Щёлкните мышью, чтобы уменьшить график";
}

void __fastcall TMainForm::Image1MouseLeave(TObject *Sender)
{
    if(!zoomed)
	{
		zoom.x = zoom.y = 0;
		paint();
	}
	sStatusBar1->Panels->Items[0]->Text = "  Курсовая работа \"Автоколебания в химических реакциях\"";
}

void __fastcall TMainForm::Image1Click(TObject *Sender)
{
	zoomed = !zoomed;
	paint();
}

//--- Смена цвета графиков функций ------------------------------------------
void __fastcall TMainForm::sColorSelectChange1(TObject *Sender)
{
	paint();
}

void __fastcall TMainForm::sColorSelect1MouseEnter(TObject *Sender)
{
	sStatusBar1->Panels->Items[0]->Text = "  Нажмите, чтобы изменить цвет графиков функций";
}

void __fastcall TMainForm::sColorSelect1MouseLeave(TObject *Sender)
{
	sStatusBar1->Panels->Items[0]->Text = "  Курсовая работа \"Автоколебания в химических реакциях\"";
}
//---------------------------------------------------------------------------

Соседние файлы в папке Исходные коды