Класс
окна для отображения графика
Откройте файл
ChildView.cpp, который содержит коды реализации методов класса CChildView. Его
имя содержит ложный намек на происхождение от CView. На самом деле он происходит
от класса CWnd и инкапсулирует функциональность окна, оккупирующего клиентскую
область окна рамки, которое управляется классом CMainFrame. Простое окно, как
вы помните, для перерисовки своего содержимого, вместо метода OnDraw использует
метод OnPaint. Найдите этот метод в классе CChildView и убедитесь, что в нем
контекст устройства создается, а не приходит в качестве параметра от каркаса
приложения, как это было в приложениях, поддерживающих архитектуру документ
— представление. Вставьте внутрь этого метода вызов конструктора класса CGraph
с последующим сообщением Draw:
void
CChildView::OnPaint()
{
CPaintDC
dc(this);
CGraph(m_Points,
"Field Distribution", "x[m]","Field").Draw(&dc); }
Класс CGraph
разработаем позже. Он будет создавать двухмерный график функции — решения краевой
задачи, автоматически масштабируемый и подстраивающийся под текущий размер окна
CChildView. Перейдите к файлу с определением оконного класса (ChildFrame.h)
и введите следующие коррективы:
#
pragma once
#include
"Graph.h"
Class
CChildView :
public CWnd
{
//
Вспомогательные классы будут пользоваться данными
friend
class CParamDlg;
friend
class CGraph;
private:
//=====
Контейнер координат точек графика
vector<CDPoint>
m_Points;
//=====
Вектор источников и свойств среды (см. f и р)
vector<double>
m_f, m_r;
//=====
Размерность задачи (см. N)
int
m_n;
//=====
Параметры
double
m_k, // Коэффициент k
m_L,
// Протяженность расчетной области
m_g0,
// Коэффициенты, задающие ГУ слева
m_d0,
m_gn,
// Коэффициенты, задающие ГУ справа m_dn ;
CParamDlg
*m_pDlg; // Немодальный диалог параметров
public:
CChildView();
virtual
-CChildViewO;
virtual
BOOL PreCreateWindow(CREATESTRUCT& cs);
//=====
Изменение размерности задачи
void
Resize();
//=====
Решение системы методом прогонки
void
Solve();
protected:
afx_msg
void OnPaint();
DECLARE_MESSAGE_MAP()
};
Точки графика
будем хранить в контейнере объектов класса CDPoint, который мы неоднократно
использовали, так как исследователи реальных систем работают с вещественными
координатами. Переход к экранным координатам будет произведен в классе CGraph.
Инициализацию данных проведите в конструкторе оконного класса:
CChildView:
:CChildView()
{
m_n
= 200;
m_k
= -0.0005;
m_L
= 200.;
//======
Слева ГУ первого рода Uo=100
m_g0
= 0.;
m_d0
=100.;
m_gn
= 0.;
m_dn
= 0.;
Resize
() ;
m_pDlg
= 0;
}
В деструктор
вставьте коды освобождения памяти, занимаемой контейнерами:
CChildView::~CChildView()
{
m_Points.clear();
m_f.clear();
m_r.clear();
}
При работе
с диалогом по управлению параметрами пользователь будет иметь возможность изменять
количество узлов разбиения расчетной области, поэтому мы должны изменять размерность
используемых контейнеров:
void
CChildView::Resize
()
{
//=====
Число узлов равно N+1 (с учетом 0-го узла)
int
n = m n + 1;
m_Points.resize(n,
CDPoint(0.,0.));
m_f.resize(n,
0.);
m_r.resize(n,
1.); }
Функция
Solve решает систему уравнений методом прогонки:
void
CChildView::Solve()
{
Resize
() ;
int
n = m_n + 1;
//=======
Коэффициенты разностных уравнений
vector<double>
a(n), b(n), c(n);
//=======
Коэффициенты прогонки
vector<double>
d(n), e(n);
double
h = m L / m_n, // Размер шага вдоль оси х
hh
= h * h;
//
Квадрат шага
//=======
Коэффициенты с 0-м индексом не используются
а[0]
= 0.;
b[0]
= 0.;
с[0]
= 0.;
//===
Вычисляем координаты х и коэффициенты уравнений
m_Points[0].х
= 0.;
for
(
int i=1; i < m_n; i++)
{
m_Points[i],x
= i * h;
//=======
Смотри формулы (4)
a[i]
= m_r[i-l]/hh;
c[i]
= m_r[i]/hh;
b[i]
= - a[i] - c[i] + m_k;
}
m_Points[m_n].x
= m_L;
//========
-Прямой ходпрогонки
d[0]
= m_gO; //ГУ слева e[0] * m_d0; double den;
for
(i=1; i < m_n; 1++)
{
//=======
Общий знаменатель
den
= a[i) * d[i-l] + b[i] ; d[i] = -c[i] / den;
e[i]
= <m_f[i] - a[i] * e[i-l]) / den;
}
//=======
Готовимся к обратному ходу
den
= 1. - m_gn * d[m_n-l];
//=======
Случай некорректно поставленной задачи
if
(den==0.)
{
MessageBox
("ГУ заданы некорректно", "Ошибка-",МВ_ОК) ;
return;
}
//======
Два последних узла используют ГУ справа
//=======
Смотри формулы (13)
m_Points[m_n-l].у
= (e[m_n-l] + m_dn * d[m_n-l])/den;
m_Points[m_n].y
= (m_dn + m_gn* e[m_n-l])/den;
//=======
Обратный ход прогонки
for
(i = m_n-2; i >= 0; i--)
m_Points[i].y
= d[i) * m_Points[i+1].у + e[i]; Invalidate();
}
С помощью инструментов
Studio.Net введите в класс CChildView реакцию на сообщение о создании окна WM_CREATE
и вставьте в нее единственную строку, которая вызывает функцию Solve. Она формирует
и решает систему разностных уравнений, определенную данными по умолчанию. Позже
мы создадим диалог по изменению этих данных:
int
CChildView::OnCreate(LPCREATESTRUCT
IpCreateStruct)
{
if
(CWnd::OnCreate(IpCreateStruct) == -1)
return
-1;
//=======
Решаем систему, определенную по умолчанию
Solved;
return
0;
}