4.1.7. ПЕРВАЯ ПРОГРАММА : ДЕРЕВЬЯ АММЕРАЛА

Дополним  каркас приложения, приведенный в пп. 2.1.5 функцией (подпрограммой), выводящей на экран компьютера  дерево. Идея алгоритма построения дерева принадлежит Аммералу [1]. Сначала выводится прямоугольник, соответствующий стволу дерева. Затем на верхней стороне прямоугольника  строится прямоугольный треугольник, для которого эта сторона служит гипотенузой. Затем на каждом из катетов полученного прямоугольного треугольника будут построены прямоугольники, и этот процесс будет рекурсивно применен к каждому из этих двух прямоугольников.

            При расчету будем использовать обычную систему координат, а при выводе точку (х,у) будем записывать в позицию (x,maxY-y) , где   maxYвысота окна, т.к. начало отсчета находится в левом верхнем углу окна, а ось у направлена вниз.

            Разработаем рекурсивную функцию, осуществляющую указанное построение. Параметрами этой функции будут координаты концов отрезка (х0,у0) и (х1,у1), на котором строится прямоугольник(рис. 2.6), отношение высоты которого к основанию является случайным числом   ,.

Рис. 2.6. Ствол дерева

            Эта функция строит прямоугольник и выводит его боковые стороны. Затем она надстраивает над ним прямоугольный треугольник (рис. 2.7) и вызывает себя рекурсивно, передавая в качестве параметров координаты вершин катетов этого треугольника.

Рис. 2.7. Построение дерева

            Расчет показывает , что

где .

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

            case WM_CHAR:

            BatBlt(hdc,0,0,maxX,maxY,PATCOPY);

            piphagor(maxX/2-40,0,maxX/2+40,0);

            break;

где BatBlt() очищает окно, а piphagor() вызывает рекурсивную функцию, передавая ей координаты концов отрезка, являющегося  основанием прямоугольника, который будет «стволом» нашего дерева.

            Теперь всё готово для создания приложения, и мы можем привести текст  нашей  первой  графической программы в Windows.

            Программа

#include <windows.h>

#include <stdlib.h>

#include <math.h>

char szwinname[] = "MyWindow";

const double PI = 3.14159;

HDC hdc;

int maxX, maxY;

// функция вывода отрезка

void line(int ix0, int iy0, int ix1, int iy1)

{

MoveToEx(hdc,ix0,iy0,NULL);

   LineTo(hdc, ix1,iy1);

}

// рекурсивная функция построения дерева

void piphagor(float x0,float y0,float x1, float y1)

{

float x0s, y0s, x1s, y1s, x2s, y2s;

float lambda= 1.+(2.-1.)*(0.+rand()%10000)/10000;

float phi= PI/2 + (PI-PI/2)*(0.+rand()%10000)/10000;

if((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)<1)

{

line(x0,maxY-y0,x1,maxY-y1);

return;

}

x0s= x0-lambda*(y1-y0); y0s= y0+lambda*(x1-x0);

x1s= x1-lambda*(y1-y0); y1s= y1+lambda*(x1-x0);

line(x0, maxY-y0, x0s, maxY-y0s);

line(x1, maxY-y1, x1s, maxY-y1s);

x2s= (x0s+x1s)/2+ (x1s-x0s)/2*cos(phi)-

                   (y1s-y0s)/2*sin(phi);

y2s= (y0s+y1s)/2+ (x1s-x0s)/2*sin(phi)+(y1s-y0s)/2*cos(phi);

       piphagor(x0s,y0s,x2s,y2s);

      piphagor(x2s,y2s,x1s,y1s);

}

LRESULT CALLBACK WindowFunc(HWND hwnd,

                                     UINT message,

                                     WPARAM wParam,

                                     LPARAM lParam)

{

switch(message)

{

       case WM_CREATE:

             maxX= GetSystemMetrics(SM_CXSCREEN);

             maxY= GetSystemMetrics(SM_CYSCREEN);

             hdc = GetDC (hwnd);

             break;

      case WM_CHAR:

    randomize();

PatBlt(hdc,0,0,maxX,maxY,PATCOPY); // очистка окна

piphagor(maxX/2-40, 0, maxX/2+40, 0);

      break;

       case WM_DESTROY:

             ReleaseDC(hwnd,hdc);

             PostQuitMessage(0);

             break;

       default:

             return DefWindowProc(hwnd,message,wParam,lParam);

}

return 0;

}

int WINAPI WinMain(HINSTANCE hthisinst, HINSTANCE hprevinst,

                                     LPSTR lpszargs, int nwinmode)

{

 HWND hwnd;

 MSG msg;

 WNDCLASS wcl;

 HACCEL haccel;

 wcl.hInstance = hthisinst;

 wcl.lpszClassName = szwinname;

 wcl.lpfnWndProc= WindowFunc;

 wcl.style = 0;

 wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION);

 wcl.hCursor = LoadCursor(NULL,IDC_ARROW);

 wcl.lpszMenuName = NULL;

 wcl.cbClsExtra = 0;

 wcl.cbWndExtra = 0;

 wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

  if(!RegisterClass(&wcl)) return 0;

  hwnd = CreateWindow(szwinname, "Ammeral",

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

            CW_USEDEFAULT ,CW_USEDEFAULT,

HWND_DESKTOP, NULL, hthisinst, NULL);

        haccel=LoadAccelerators(hthisinst,NULL);

        ShowWindow(hwnd,nwinmode);

        UpdateWindow(hwnd);

        while(GetMessage(&msg,NULL,0,0))

        {

                   TranslateMessage(&msg);

                   DispatchMessage(&msg);

        }

  return msg.wParam;

}

 После нажатия клавиш  [CTRL/F9]   на  экран будут выведены результаты работы программы ( рис. 2.8).

Рис. 2.8. Дерево Аммерала