Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Алгоритмическое обеспечение

Лабораторная работа №5

 

Цель лабораторной работы - получить навыки реализации решения физических задач в среде Visual C++ 6.0.

Задачи лабораторной работы:

— сформулировать требования к программе;

— разработать алгоритмическое обеспечение;

— реализовать алгоритмы в програмном коде;

— провести тестирование программы.

 

Спецификация требований

 

1) Условие задачи.

Из пункта А в пункт Б вышел товарный поезд, идущий со скоростью:

 

(1)

 

Скорость в данной задаче будем выражать в км/ч, а время – в часах.

Через время час по тому же пути вышел экспресс, скорость которого описывается зависимостью:

 

(2)

Расстояние между пунктами км.

Обгонит ли экспресс товарный поезд? Если да, то через какое время после выхода товарного поезда и на каком расстоянии от пункта А?

2) Пользовательский интерфейс должен позволять задавать уравнения скоростей для товарного и пасажирского поездов в виде полиномов 2 степени.

3) Пользовательский интерфейс должен позволять задавать время .

4) Пользовательский интерфейс должен визуализировать процесс движения поездов с соблюдением масштаба времени.

5) Пользовательский интерфейс должен позволять изменять коэффициент масштабирования по времени.

 

Алгоритмическое обеспечение

 

Для аналитического решения задачи запишем выражение для перемещения материальной точки за промежуток времени от 0 до t:

 

(3)

 

Отметим, что по условию задачи экспресс вышел на час позже товарного поезда. Поэтому при записи интеграла (3) для экспресса нижний предел интегрирования по времени будет равен , тогда как для товарного поезда нижний предел интегрирования равен 0.

После подстановки (1) и (2) в (3), получаем следующие выражения для координат товарного поезда и экспресса в момент времени t:

 

(4)

 

(5)

 

Условие встречи товарного поезда и экспресса описывается соотношением:

 

(6)

 

После подстановки (4) и (5) в (6) получим квадратное уравнение относительно t:

 

(7)

 

Квадратное уравнение (7) имеет два решения: (ч) и (ч).

Не имеющее физического смысла отрицательное решение отбрасываем, после чего остается единственное решение:

 

 

Подставив в (4), с учетом (6), получим для :

 

 

Так как, пассажирский поезд обгонит товарный. Это произойдет в момент времени на расстоянии от пункта А.

 

Следует отметить, что в общем случае, далеко не всегда система соотношений, описывающих ту или иную физическую задачу, поддается прямому аналитическому решению.

Например, в нашей задаче “о поездах” функции и имеют достаточно простой вид. Это позволило нам легко решить квадратное уравнение (7) относительно t.

Но, если выражения для скоростей и имели бы вид алгебраического многочлена 5-го порядка, то выражение относительно t, аналогичное (7), имело бы вид алгебраического уравнения 6-го порядка. А поскольку не существует универсальных методов прямого аналитического решения алгебраических уравнений высокого порядка, то решение задачи “о поездах” стало бы возможным только с использованием численных методов. Поэтому будем условно считать, что выражение (7) относительно t решить прямым аналитическим путем невозможно.

Тогда нам остается единственный путь — реализовать численное решение рассматриваемой динамической задачи.

В лабораторных работах 1-го семестра Вы познакомились с методом правых прямоугольников и методом левых прямоугольников для вычисления определенного интеграла.

В данном случае не имеет значения, какой метод (правых или левых прямоугольников) использовать для вычислений.

Выражение для определенного интеграла рассчитанному по методу левых прямоугольников для нашего случая имеет вид:

 

, (8)

 

где n — количество прямоугольников, равное числу шагов интегрирования Δ t.

Для решения задачи нужно вычислять с шагом Δ t значения интегралов (4) и (5) по выражению (8) до тех пор, пока на n -м шаге интегрирования не будет выполняться условие прекращения итераций:

 

(9)

 

При выполнении условия (9), на n -м шаге интегрирования можно найти искомые величины:

 

(10)

 

(11)

 

Итак, алгоритм решения нам известен. Переходим к реализации программного обеспечения.

 

Реализация

 

Начнем с разработки пользовательского интерфейса. В отличие от предыдущих создадим данный проект на основе класса CView.

Запустите среду Visual C++. В меню File укажите New\MFC AppWizard (exe). В окне “Project name” укажите имя вашего проекта. В окне “Location” укажите путь, по которому будет храниться ваш проект. Нажмите кнопку OK (рис. 46).

Рис. 46

 

В первом окне (Step1) укажите тип вашего приложения “Single document” и нажмите “Next” (Рис. 47).

 

Рис. 47

 

Нажмите “Next” для шагов 2 и 3.

На шаге 4 отключите пункты «Docking toolbar», «Initial status bar» и «Printing and print preview» (рис. 48). Нажмите кнопку “Advanced”. В появившемся окне расширенных настроек (рис. 49) выберите закладку «Window styles» и отметьте пункт «Maximazed». После этого закройте окно расширенных настроек и нажмите кнопку «Finish», а затем «ОК».

После этого на экране появится рабочее пространство созданного проекта.

 

Рис. 48 Рис. 49

 

Итак, проект создан. Пристапаем к формированию пользовательского интерфейса.

Начнем формирование интерфейса с модификации меню. В окне “Workspace” выберите закладку ResourceView. Далее в папке Menu выберите IDR_MAINFRAME (рис. 50).

 

Рис. 50

 

Выделите пункт меню “Edit” и удалите его нажав клавишу “Delete”. Аналогичным образом удалите пункт «View». Удалите также все кроме “Exit” из пункта меню “File”.

Выберите пункт “Help” и нажмите клавишу «Insert». При этом в меню добавится пустой пункт. Нажмите на нем правой кнопкой мыши и выберите “Properties”.

Укажите в поле “Caption” название данного пункта меню “Модель”. Добавьте в меню “Модель” пункты подменю «Настройки», «Пуск» и «Стоп». Присвойте этим пунктам подменю идентификаторы ID_SETTINGS, ID_START и ID_STOP соответственно (рис. 51) и закройте окно с меню.

Рис. 51

 

Теперь саздадим обработчики событий меню. Запустите ClassWizard (рис. 52). В поле Class name укажите класс CLesson5View.

 

Рис. 52

 

В поле Object IDs выберите пункт соответствующий созданным вами элементам меню (ID_SETTINGS). В поле Message укажите строку COMMAND. Нажмите кнопку Add Function. Подтвердите создание нового метода.

Создайте аналогичным образом обработчики для элементов меню ID_START, ID_STOP. Новые обработчики должны появиться в поле Member function (рис. 53). Кроме этого добавте обработчики событий WM_TIMER и WM_PAINT.

 

Рис. 53

 

Далее создадим окно настроек в котором будем задавать полиномы определяющие законы изменения скоростей для каждого поезда и время выхода пассажирского экспресса.

Окно настроек сделаем на основе уже известного вам класса CDialog. Откройте закладку ресурсов, выберите папку Dialog, правой кнопкой мыши вызовите контекстное меню и выберите пункт Insert Dialog (рис. 54).

 

Рис. 54

 

На экране появится знакомая вам заготовка диалогового окна. Измените идентификатор окна и его заголовок так как это показано на рис. 55.

 

Рис. 55

 

Теперь, используя элементы Static Text и Edit Box, придайте диалогу вид представленный на рис. 56.

 

Рис. 56.

 

Посредством этого диалога мы будем задавать скорости поездов в виде:

 

,

 

а также время выхода пассажирского поезда.

Итак, у нас есть ресурс для диалогового окна, но нет класса необходимого для его работы. Убедитесь, что в окне ресурсов у вас выбран созданный вами диалог и откройте окно ClassWizard. В данном случае поверх окна ClassWizard появится окно Adding a class в котором вам необходимо выбрать пункт Create a new class и нажать кнопку ОК рис. 57.

 

Рис. 57

 

В появившемся окне New Class рис. 58, в поле Name укажите имя нового класса CSettingsDlg и нажмите ОК. Нажмите ОК в окне ClassWizard.

 

Рис. 58

 

Теперь у нас есть класс необходимый для работы с диалоговым окном. Еще раз проверте, какие элементы Edit Box соответсвуют коэффициентам A, B, C для каждого поезда и свяжите с ними соответствующие вещественные переменные рис. 59.

 

Рис. 59

 

Также свяжите целочисленную переменную m_T0 с полем «Время выхода второго поезда».

Завершите работу над окном настроек созданием обработчиков событий нажатия на кнопки Default и Ok.

Осталось создать картинки поездов, которые будут двигаться по экрану. Это можно сделать двумя способами.

Первый способ заключается в том, что вы можете подготовить изображение поезда в любом графическом редакторе, например Photoshop. На изображение накладывается два ограничения. Оно должно быть сохранено в формате BMP. Оно должно содержать не более 256 цветов.

Предположим, что изображение у вас подготовлено. Тогда в окне ресурсов среды Visual C++ вам надо выбрать папку Lesson5 resources, вызвать правой кнопкой мыши контекстное меню и выбрать пункт Import рис. 60.

 

Рис. 60

 

В появившемся окне рис. 61 выберите тип файлов All Files (*.*), найдите BMP-файл который вы подгтовили и нажмите кнопку Import.

 

Рис. 61

 

Перед вами появится редактор графических ресурсов рис. 62.

 

Рис. 62

 

Рассмотрим альтернативный вариант создания изображения поезда. Для этого воспользуемся встроенным редактором графических ресурсов.

Вызовите контекстное меню рис. 60 и выберите пункт Insert. В появившемся окне выберите пункт Bitmap и нажмите New рис. 63.

 

Рис. 63

 

Перед вам снова откроется окно редактора графических ресурсов аналогичное рис. 62, но с пустой картинкой. Используя панели для рисования нарисуйте свой вариант поезда (рис. 64). Поле для рисования может быть несколько больше вашей картинки. Дважды клацнув мышкой на идентификаторе битмапа слева в окне ресурсов добейтесь чтобы вокруг картинки появилась рамка (рис. 64). Изменяя размеры этой рамки вы можете соответственно изменять размеры вашей картинки.

 

Рис. 64

 

Мы рассмотрели два варианта добавления в проект графических ресурсов. В лабораторной работе можно использовать любой из них.

Итак, у нас есть все необходимые ресурсы. Мы создали обработчики необходимых событий и работу над интерфейсом можно считать завершенной. Перейдем к программной реализации.

Начнем с модификации обработчиков события диалогового окна настроек. Измените конструктор (cpp-файл) класса CSettingsDlg и обработчики нажатия на кнопки так как это показано в листинге 18:

 

Листинг 18

CSettingsDlg::CSettingsDlg(CWnd* pParent /*=NULL*/)

: CDialog(CSettingsDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CSettingsDlg)

m_A1 = 0.0;

m_B1 = 2.0;

m_C1 = 36.0;

m_A2 = 0.0;

m_B2 = 4.0;

m_C2 = 72.0;

m_T0 = 60;

//}}AFX_DATA_INIT

}

void CSettingsDlg::OnBtnDefault()

{

// TODO: Add your control notification handler code here

m_A1 = 0.;

m_B1 = 2.;

m_C1 = 36;

m_A2 = 0.;

m_B2 = 4.;

m_C2 = 72.;

m_T0 = 60;

UpdateData(false);

}

 

void CSettingsDlg::OnBtnOk()

{

// TODO: Add your control notification handler code here

UpdateData(true);

CDialog::OnOK();

}

 

 

Как видите в конструкторе и обработчике OnBtnDefault() мы присваиваем коэффициентам полиномов и времени выхода второго поезда исходные значения. Обработчик OnBtnOk() в пояснениях не нуждается.

Диалог настроек готов. Теперь займемся модификацией класса CLesson5View. Добавте в h-файл этого класса объявление необходимых атрибутов и функций (листинг 19). Назначение каждого атрибута и функции приведены в комментариях.

 

Листинг 19

class CLesson5View: public CView

{

protected: // create from serialization only

CLesson5View();

DECLARE_DYNCREATE(CLesson5View)

 

// Attributes

public:

CLesson5Doc* GetDocument();

 

CBitmap m_Train; // Битмап для хранения картинки поезда

 

double m_dPos1; // Координата товарного поезда

double m_dPos2; // Координата пассажирского поезда

 

// Коэффициенты полиномов

double m_A1;

double m_B1;

double m_C1;

double m_A2;

double m_B2;

double m_C2;

 

int m_T0; // Время выхода пассажирского поезда

int m_nIterCount; // Количество проведенных итераций моделирования

double m_DeltaTime; // Шаг моделирования по врмени

 

void ResetModel(); // Функция сбросов параментров моделирования в исходное состояние

void Draw(double dPos1, double dPos2); // Функция рисования модели

void Calc(double* pPos1, double* pPos2); // Функция пересчета модели

 

 

Осталось внести в класс CLesson5View начальную инициализацию, модифицировать обработчики событий и добавить описания собственных функций (ResetModel(), Draw() и Calc()).

Прежде всего, подключим необходимые библиотеки. Обратите внимание на то, что новый диалог CSettingDlg также является своего рода библиотекой и нам необходимо подключить файл-заголовков (h-файл) данного класса. Кроме того нам понадобится библиотека math. Таким образом, в начало файла Lesson5View.cpp (там где происходит подключение библиотек) необходимо добавить следующие строки:

 

#include "SettingsDlg.h"

#include <math.h>

 

Измените конструктор класса следующим образом:

 

CLesson5View::CLesson5View()

{

// TODO: add construction code here

m_Train.LoadBitmap(IDB_BITMAP1);

ResetModel();

}

 

Здесь мы загружаем в переменную m_Train, являющуюся объектом класса CBitmap, изображение поезда которое мы ранее создали в ресурсах. Функция ResetModel() наша собственная. Она будет производить сброс параметров нашей модели движения поездов в начальное состояние. Пока еще мы не внесли в код описание этой функции и при попытке компиляции будет возникать ошибка. Пока не обращайте на это внимание.

Модифицируйте стандартные обработчики событий так, как это показано в листинге 20.

 

Листинг 20

void CLesson5View::OnSettings()

{

// TODO: Add your command handler code here

CSettingsDlg dlg; // Создаем диалог настроек

dlg.DoModal(); // выводим диалог на экран

// Переносим параметры введенные в диалоге нестроек в нашу модель

m_A1 = dlg.m_A1;

m_B1 = dlg.m_B1;

m_C1 = dlg.m_C1;

m_A2 = dlg.m_A2;

m_B2 = dlg.m_B2;

m_C2 = dlg.m_C2;

m_T0 = dlg.m_T0;

}

 

void CLesson5View::OnStart()

{

// TODO: Add your command handler code here

SetTimer(1, 100, NULL);

}

 

void CLesson5View::OnStop()

{

// TODO: Add your command handler code here

KillTimer(1);

ResetModel();

Draw(m_dPos1, m_dPos2); // Рисуем на экране поезда в позициях m_dPos1, m_dPos2

}

 

void CLesson5View::OnTimer(UINT nIDEvent)

{

// TODO: Add your message handler code here and/or call default

Calc(&m_dPos1, &m_dPos2); // Производим очередную итерацию расчета модели

Draw(m_dPos1, m_dPos2);

 

CView::OnTimer(nIDEvent);

}

 

void CLesson5View::OnPaint()

{

CPaintDC dc(this); // device context for painting

 

// TODO: Add your message handler code here

Draw(m_dPos1, m_dPos2);

 

// Do not call CView::OnPaint() for painting messages

}

 

 

Тепрь займемся собственными. Их описания приведены в листинге 21.

 

Листинг 21

void CLesson5View::ResetModel()

{

// Начальная инициализация модели

m_dPos1 = 0;

m_dPos2 = 0;

m_A1 = 0.;

m_B1 = 2.;

m_C1 = 36;

m_A2 = 0.;

m_B2 = 4.;

m_C2 = 72.;

m_T0 = 60;

m_DeltaTime = 0.01;

m_nIterCount = 0;

}

 

void CLesson5View::Calc(double* pPos1, double* pPos2)

{

m_nIterCount++; // Увеличиваем счетчик итераций

double dTime1 = m_nIterCount * m_DeltaTime; // Определяем текущее время движения

 

// Определяем положение товарного поезда

*pPos1 = *pPos1 + (m_A1 * pow(dTime1, 2) + m_B1 * dTime1 + m_C1) * m_DeltaTime;

 

// Если прошло время выхода экспресса

if (dTime1 > (m_T0 / 60.))

{

// Определяем положение экспресса

*pPos2 = *pPos2 + (m_A2 * pow(dTime1, 2) + m_B2 * dTime1 + m_C2) * m_DeltaTime;

}

// Проверяем критерии прекращения итераций

/* Мы останавливаемся если координата любого из поездов стала равной или превысила значение 100 км, а также если координата экспресса стала равной либо превысила координату товарного поезда (экспресс нагнал товарняк) */

if ((*pPos1 >= 100) || (*pPos2 >= 100) || (*pPos2 >= *pPos1))

{

KillTimer(1);

}

}

 

void CLesson5View::Draw(double dPos1, double dPos2)

{

if ((dPos1 > 100.) || (dPos2 > 100.))

{

KillTimer(1);

return;

}

 

CRect rect;

GetClientRect(&rect);

 

int nWidth = rect.right - rect.left;

int nHeight = rect.bottom - rect.top;

 

CClientDC dc(this);

 

CBitmap bm;

bm.CreateCompatibleBitmap(&dc, nWidth, nHeight);

 

CDC memDC;

memDC.CreateCompatibleDC(&dc);

memDC.SelectObject(&bm);

memDC.FillRect(&rect, NULL);

memDC.MoveTo(50, 0);

memDC.LineTo(50, nHeight);

memDC.MoveTo(nWidth - 50, 0);

memDC.LineTo(nWidth - 50, nHeight);

 

char szBuf[128];

sprintf(szBuf, "Время моделирования Т = %g ч", m_nIterCount * m_DeltaTime);

memDC.TextOut(100, 300, szBuf);

sprintf(szBuf, "Пройденый путь S = %g км", dPos1);

memDC.TextOut(100, 320, szBuf);

sprintf(szBuf, "Дистанция между поездами L = %g км", dPos1 - dPos2);

memDC.TextOut(100, 340, szBuf);

 

CDC trainDC;

trainDC.CreateCompatibleDC(&dc);

trainDC.SelectObject(&m_Train);

 

BITMAP bminfo;

m_Train.GetBitmap(&bminfo);

 

int nPos1 = 50 - bminfo.bmWidth + ceil((nWidth - 100) * dPos1 / 100);

int nPos2 = 50 - bminfo.bmWidth + ceil((nWidth - 100) * dPos2 / 100);

 

memDC.BitBlt(nPos1, 100, nWidth, nHeight, &trainDC, 0, 0, SRCCOPY);

memDC.BitBlt(nPos2, 200, nWidth, nHeight, &trainDC, 0, 0, SRCCOPY);

dc.BitBlt(0, 0, nWidth, nHeight, &memDC, 0, 0, SRCCOPY);

}

 

 

На этом работу над программной реализацией можно считать завершенной.

 

Для самостоятельной работы необходимо решить дополнительные задачи:

1) Реализовать п. 5 спецификации требований.

2) Решить задачу тестирования.

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...