Список можно продолжить и дальше: нечеткие деревья решений, нечеткие сети Петри, нечеткая ассоциативная память, нечеткие самоорганизующиеся карты и другие гибридные методы.
3. ПРОЕКТИРОВАНИЕ ФУНКЦИОНАЛЬНОЙ СТРУКТУРЫ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
Проектирование приложений с использованием библиотеки MFC основывается на предопределенной структуре иерархии взаимодействия стандартных классов (рисунок 2.1). Для реализации необходимой функциональности приложения достаточным является использование обычного диалогового окна. При этом основная структура приложения будет определяться двумя классами:
- класс CFuzzyApp, обеспечивающий функциональность динамического исполнения приложения в целом, порожденный от базового MFC-классаCWinApp;
- класс CFuzzyDlg, обеспечивающий работу с визуальными компонентами операционной среды MicrosoftWindows, порожденный от базового MFC-классаCDialog;
Класс CFuzzyApp наследуется от класса приложения CWinApp. Основной перегружаемым виртуальным методом данного класса является метод CFuzzyApp::InitInstance(). Перегрузка метода необходима для инициализации вспомогательных компонент приложения, а также для реализации связи визуального окна компонентов MSWindows с исполняемым приложением. В целом, метод CFuzzyApp::InitInstance() готовит приложение к работе.
Как известно [3], программы, работающие в среде MSWindows, имеют графический интерфейс пользователя (GUI – GraphicalUserInterface). Исходные данные поступают в программу через диалоговое окно. Например, пользователь может сообщить приложению о выборе функции, включив один из переключателей (класс CButton(BS_RADIOBUTTON, …)) или выполнив некоторое действие с другими элементами управления. Для каждого диалогового окна в приложении есть две вещи, которые необходимо разработать, – ресурсы окна и класс окна.
Ресурсы окна используются программой для того, чтобы вывести на экран его изображение и изображения элементов управления, которые входят в него. В класс окна включены его параметры и методы, ответственные за вывод окна на экран. Они работают совместно для достижения общей цели – обеспечить максимально эффективное взаимодействие пользователя и программы.
Ресурсы диалогового окна создаются посредством редактора ресурсов, с помощью которого возможно включать в состав окна необходимые элементы управления и размещать их в пространстве окна желаемым образом. Помощь в создании класс окна может оказать ClassWizard, встроенный в стандартом наборе MSVisualStudio. Как правило, класс конкретного диалогового окна в проекте является производным от базового класса CDialog, имеющегося в составе MFC. Обычно каждый элемент управления, включенный в состав ресурсов окна, имеет в классе окна соответствующий член класса. Для того чтобы вывести диалоговое окно на экран, необходимо вызвать метод его класса. Для того, чтобы установить значения по умолчанию для элементов управления перед выводом окна на экран или считать состояние элементов управления после завершения работы пользователя, необходимо обращаться к членам класса.
Таким образом, первым шагом проектирования MFC-приложения является формирование ресурса окна, который служит своего рода шаблоном для MSWindows. Когда MSWindows обнаруживает ресурс окна в программе, она использует команды из этого ресурса для конструирования работающего окна.
Далее в редакторе ресурсов в диалоговое окно должны быть добавлены необходимые элементы управления – кнопки, радиокнопки, поля ввода, текстовые метки, декоративные элементы (GroupBox) и элемент Picture.
Проектируемый интерфейс изображен на рисунке 3.1.
Рисунок 3.1 – Проектируемый интерфейс
Когда сформированы ресурсы окна и подготовлен класс CFuzzyDlg для окна приложения, можно создавать объект этого класса в самой программе и выводить на экран связанное с ним диалоговое окно. В рассматриваемом случае, достаточно в методе CFuzzyApp::InitInstance() вывести диалоговое окно на экран сразу после запуска приложения, используя базовый метод CDialog::DoModal() класса диалогового окна CDialog.
Отображение результатов построения функции производится в элемент Picture. Для вывода графики в Windows и в Visual C++ используется понятие контекста устройства (device context). Контекст устройства ‑ это объект класса CDC, содержащий все методы для построения изображения в окне.
Таким образом спроектированная структура программного обеспечения является адекватной решению поставленной в техническом задании задачи.
4. ПРОГРАММНАЯ РЕАЛИЗАЦИЯ ПОСТАВЛЕННОЙ ЗАДАЧИ
Программная реализация разработанной выше структуры приложения состоит в разработке исполняемого Win32-приложения в среде визуального программирования MSVisualStudio. Проект программного обеспечения состоит из трех классов – CFuzzyApp, CFuzzyDlg, CFuzzy_.
В классе CFuzzy_ выполняются непосредственные расчеты значений функций неопределенности. Расчеты выполняются функциями-членами[6] этого класса:
- CFuzzy_::fisTriangleMf (double x, double *params) – вычисление значений треугольной функции принадлежности;
- CFuzzy_::fisTrapezoidMf(doublex, double *params) – вычисление значений трапециидальной функции принадлежности;
- CFuzzy_::fisGaussianMf(doublex, double *params) – вычисление значений гауссовской функции принадлежности;
- CFuzzy_::fisGaussian2Mf(doublex, double *params) – вычисление значений расширенной гауссовской функции принадлежности;
- CFuzzy_::fisSigmoidMf(doublex, double *params) – вычисление значений сигмоидальной функции принадлежности.
Например, функция CFuzzy_::fisTrapezoidMf(double x, double *params):
/* Trapezpoidal membership function */
double CFuzzy_::fisTrapezoidMf(double x, double *params)
{
double a = params[0], b = params[1], c = params[2], d = params[3];
double y1 = 0, y2 = 0;
if (a>b) {
fisError("Illegal parameters in fisTrapezoidMf() --> a > b");
}
if (b>c)
{
fisError("Illegal parameters in fisTrapezoidMf() --> b > c");
}
if (c>d) {
fisError("Illegal parameters in fisTrapezoidMf() --> c > d");
}
if (b <= x)
y1 = 1;
else if (x < a)
y1 = 0;
else if (a != b)
y1 = (x-a)/(b-a);
if (x <= c)
y2 = 1;
else if (d < x)
y2 = 0;
else if (c != d)
y2 = (d-x)/(d-c);
return(MIN(y1, y2));
}
Так же в классе CFuzzy_ находится функция-член fisError(char *msg), которая реализует выдачу сообщения об ошибке, если пользователь ввел неправильные данные. Само сообщение передается в функцию fisError(char *msg) в качестве параметра из функций, вычисляющих значение функций принадлежности.
В классе CFuzzyApp реализована базовая функциональность стандартного MFC-приложения. В частности, переопределен виртуальный метод базового класса CWinApp::InitInstance():
BOOL CFuzzyApp::InitInstance()
{
AfxEnableControlContainer();
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
CFuzzyDlg dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
returnFALSE;
}
В результате исполняемый код приложения был связан со спроектированным ранее визуальным интерфейсом (рисунок 3.1). В качестве члена в классе CFuzzyApp была введена переменная[6] dlg типа CFuzzyDlg. Она обеспечивает непосредственную связь приложения с интерфейсом, предоставляемого пользователю.
В классе CFuzzyDlg выполняется инициализация диалога и элементов управления.
BOOL CFuzzyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
par_a.SetWindowText("1");
par_b.SetWindowText("3");
par_c.SetWindowText("5");
par_d.SetWindowText("9");
R_Tri=(CButton*)GetDlgItem(IDC_RADIO1);
R_Tra=(CButton*)GetDlgItem(IDC_RADIO2);
R_Ga=(CButton*)GetDlgItem(IDC_RADIO3);
R_Ga2=(CButton*)GetDlgItem(IDC_RADIO4);
R_Sig=(CButton*)GetDlgItem(IDC_RADIO5);
param = new double[3];
WIDTH = 600;
HEIGHT = 400;
return TRUE;
}
С помощью элементов управления, являющимися объектами класса CEdit – par_a, par_b, par_c, par_d реализуется ввод параметров для функций принадлежности.
В классе CFuzzyDlgимеются функции для построения координатных осей (функция CFuzzyDlg::Axis()) и отображения графика функции принадлежности (одна из функций CFuzzyDlg::PlotTriangle(), CFuzzyDlg::PlotTrapezoid(), CFuzzyDlg::PlotGaussian(),CFuzzyDlg::PlotGaussian2(), CFuzzyDlg::PlotSigmoid() в зависимости от типа функции, выбранной пользователем). Вывод графика осуществляется с помощью класса CDC, который
При нажатии пользователем кнопки «Построить!!» происходит выполнение функции CFuzzyDlg::OnButton1(), из которой вызываются функции построения осей и функции принадлежности, выбранной пользователем или, если не был выбран тип функции, выдается сообщение «Выберите тип функции!!».
Функции для построения координатных осей (функция CFuzzyDlg::Axis()) и отображения графика функции принадлежности (одна из функций CFuzzyDlg::PlotTriangle(), CFuzzyDlg::PlotTrapezoid(), CFuzzyDlg::PlotGaussian(),CFuzzyDlg::PlotGaussian2(), CFuzzyDlg::PlotSigmoid() в зависимости от типа функции, выбранной пользователем) вызываются так же при перерисовке окна (обработка сообщения WM_PAINT с помощью функции CFuzzyDlg::OnPaint()).
void CFuzzyDlg::OnPaint()
{
CDialog::OnPaint();
Axis();
if (function==GAUSSIAN)
PlotGaussian();
else
if (function==TRIANGLE)
PlotTriangle();
else
if (function==TRAPEZOID)
PlotTrapezoid();
else
if (function==GAUSSIAN2)
PlotGaussian2();
else
if (function==SIGMOID)
PlotSigmoid();
}
Для того чтобы определить значение данной функции распределения в конкретной точке, в класс CFuzzyDlg была добавлена функция обработки сообщения перемещения манипулятора «Мышь» WM_MOUSEMOVE ‑ CFuzzyDlg::OnMouseMove(UINT nFlags, CPoint point). При перемещении мыши выводится значение точки x (с учетом масштаба) и степень принадлежности (значение данной функции принадлежности) этой точки x.
void CFuzzyDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if (point.x>10 && point.x<WIDTH && point.y>10 && point.y<HEIGHT)
{
CDC *dc = m_grapho.GetDC();
CPen SolidPen;
SolidPen.CreatePen(PS_SOLID,1,RGB(255,255,255));
CBrush brush;
brush.CreateSolidBrush(RGB(255,255,255));
dc->SelectObject(brush);
dc->SelectObject(SolidPen);
dc->Rectangle(350,10,580,30);
double _tmp;
char crds[15];
CString coords;
_tmp=(point.x-36)*1000/kX+_par;
itoa((int)(_tmp),crds,10);
coords=crds;
itoa(ABS((int)(_tmp*100)%100),crds,10);
(ABS((int)(_tmp*100)%100)<10)?coords+=".0":coords+=".";
coords+=crds;
if (function==GAUSSIAN)
gcvt(fuzzy.fisGaussianMf(_tmp,param),2,crds);
else
if (function==TRIANGLE)
gcvt(fuzzy.fisTriangleMf(_tmp,param),2,crds);
else
if (function==TRAPEZOID)
gcvt(fuzzy.fisTrapezoidMf(_tmp,param),2,crds);
else
if (function==GAUSSIAN2)
gcvt(fuzzy.fisGaussian2Mf(_tmp,param),2,crds);
else
if (function==SIGMOID)
gcvt(fuzzy.fisSigmoidMf(_tmp,param),2,crds);