Откройте файл 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;
}