Данная программа осуществляет построение и отрисовку трех наиболее известных «классических» фракталов –Kam Torus, множество Джулии и множество Мандельброта. Фрактал – математическое понятие, обозначающее абстрактный образ, построенный по принципу самоподобия с помощью алгебраических уравнений. Фрактал Kam Torus Множество Джулии Множество Мандельброта Ниже прилагается исходный код файла, содержащий функции для непосредственного рисования фракталов в окне с помощью GDI. Полный же код проекта со скомпилированном exe-файлом находится в прикрепленном архиве. #include "stdafx.h" #include "DrawFract.h" void DrawKamTorus (HWND hwnd, HDC hdc) // Процедура рисования фрактала Kam Torus. // Принимает в качестве параметров дескриптор окна // и указатель на контекст устройства. { int a, c, nx, ny; time_t t; unsigned long k; double an, can, san, can1, san1, e, r, ax, ay; double x, xa, x1, x2, x3, y, y1, y2, y3, rand1, rand2; HPEN DrawPen; // Указатель на перо, которым будет производиться рисование. RECT rect; // Прямоугольник, необходимый для снятия размеров с клиентской области. DrawPen = CreatePen(PS_SOLID, 1, RGB(0,0,0)); // Создание пера (черное, 1 пиксель). GetClientRect(hwnd, &rect); // Узнаем размер клиентской области. nx = rect.right / 2; // Задаем опорные точки (середина окна). ny = rect.bottom / 2; ax = 400.0; // Некоторые начальные значения, которые можно менять в последствии. ay = ax; c = 1; // Генерация случайных значений, служащих основой для вычмсления фрактала. srand((unsigned) time(&t)); rand1 = rand() % 20000; rand2 = rand() % 20000; rand1 = 5.0e-5*rand1; rand2 = 5.0e-5*rand2; // Вычисление пары косинусов и синусов. an = 10.0*(rand1-rand2); can = 0.99*cos(an); san = 0.99*sin(an); can1 = 1.01*cos(an); san1 = 1.01*sin(an); // Начальные значения для х3 и у3. x3 = 0.01; y3 = 0.01; e = 0.0; // Главный цикл. do { xa = x3*x3 - y3; x2 = x3*can1 + xa*san1; y2 = x3*san1 - xa*can1; x3 = x2; y3 = y2; x = x2; y = y2; a = 0; do { xa = x*x - y; // Расчет текущей точки. x1 = x*can + xa*san; y1 = x*san - xa*can; x = x1; y = y1; a++; MoveToEx(hdc, (int)(ax*x+nx), (int)(ay*y+ny), NULL); LineTo(hdc, (int)(ax*x+nx) - 1, (int)(ay*y+ny) + 1); } while ((fabs(x1)<=2.0e3) && (fabs(y1)<=2.0e3) && a <=100); e = e + 0.075; c = (int)e % 5 + 1; } while ((fabs(x2) <= 2.0e3) && (fabs(y2) <= 2.0e3)); } void DrawJulia (HWND hwnd, HDC hdc) // Процедура рисования Множества Джулии. // Принимает в качестве параметров дескриптор окна // и указатель на контекст устройства. { // Объявление переменных для внутреннего использования при вычислениях. double xmin, xmax, ymin, ymax, fact = 1.0; double ypy, x, y, x0, y0, xp, yp, const_scr = 1.0; double deltax, deltay, pmin, qmin, ya, xkp1, ykp1, r; int npix, npiy, kcolor; int k, np, nq, npy, ipen; RECT rect; GetClientRect(hwnd, &rect); // Получение размеров клиентской области окна и npix = rect.right; // задание внешних границ области рисования. npiy = rect.bottom; pmin = -0.74356; qmin = 0.11135; xmin = -2.0; xmax = 2.0; ymin = -2.0; ymax = 2.0; kcolor = 255; if (fact >= 1.0 || fact <= 0.0) fact = 1.0; else { npix = (int)(npix * fact); npiy = (int)(npiy * fact); } ypy = (double)npiy - 0.5; // Переменные deltax и deltay соответсвуют разности максимальных и // минимальных значений х и у, поделенной на длину экрана. deltax = (xmax-xmin) / (npix-1); deltay = (ymax-ymin) / (npiy-1); // Программа в двух циклах for - по х и у проходит по всем пикселам рисунка. // Переменная np будет соответствовать текущему значению х, а переменная nq - значению у. // При каждом проходе внешнего цикла переменной х0 присваивается значение, равное // минимальному значению х плюс текущее значение счетчика, умноженное на приращение х. for (np = 0; np <= npix - 1; np++) { x0 = xmin + (double)np * deltax; // Аналогично и во внутреннем цикле вычисляется значение у0. // Далее идет установка вычисленных значений в х и у и обнуление k. for (nq = 0; nq <= npiy - 1; nq++) { y0 = ymin + (double)nq * deltay; x = x0; y = y0; k = 0; // Цикл do, рисующий составляющие фрактал точки. // Повторяется, пока пока значения r и k не превосходят kcolor, // установленного ранее равным 255. do { // Вычисление действительной и мнимой части комплексного числа Z, // для представления которого мы двумя переменными типа double. // Переменная xkp1 содержит действительную часть комплексного числа, // а ykp1 - мнимую. xkp1 = (x+y)*(x-y) + pmin; ya = x * y; ykp1 = ya + ya + qmin; r = xkp1*xkp1 + ykp1*ykp1; // Возведение обеих частей в квадрат и сложение. k++; // Если r больше максимального значения, то точка фрактала стремится // к бесконечности и закрашивается цветом, определяемым значением k // и выводится в позиции, заданной координатами np и nq. if (r <= kcolor) { ipen = k; xp = const_scr * (double)np; yp = (double)nq; SetPixel(hdc, xp, yp, ipen); } // Если значение k равно максимальному, то точка стремится к центру, // она рисуется синим. if (k == kcolor) { ipen = RGB(0, 0, 255); xp = const_scr * (double)np; yp = (double)nq; SetPixel(hdc, xp, yp, ipen); } x = xkp1; y = ykp1; } while (r <= kcolor && k <= kcolor); } } } double MandelSetPoten (double cx, double cy, int maxiter) // Функция, служащая для измерения // потенциала точки множества Мандельброта, // заданной параметрами cx и cy. { double x, y, x2, y2, temp, potential; int iter; x = cx; x2 = x * x; y = cy; y2 = y * y; iter = 0; do { temp = x2 - y2 + cx; y = 2.0*x*y + cy; x = temp; x2 = x * x; y2 = y * y; iter++; } while ((iter < maxiter) && ((x2+y2) < 10000.0)); if (iter < maxiter) potential = 0.5*log(x2+y2) / powl(2.0, iter); else potential = 0.0; return potential; } void DrawMandelbrot (HWND hwnd, HDC hdc) // Процедура рисования Множества Мандельброта. // Принимает в качестве параметров дескриптор окна // и указатель на контекст устройства. { int nx, ny, iy, ix, ipen, maxiter = 16000, iflag = 0, iset = 1; std::complex<double> c; double xmin = -2.25, ymin = -1.25, xmax = 0.75, ymax = 1.25; double cx, cy, potent; double diff = 0.6482801, test1, test2; if ((maxiter >= 16000) || (maxiter <= 0)) maxiter = 16000; RECT rect; GetClientRect(hwnd, &rect); nx = rect.right; ny = rect.bottom; ymin = -1.125; ymax = 1.125; for (iy = 0; iy <= ny - 1; iy++) { cy = ymin + iy*(ymax-ymin)/(ny-1); for (ix = 0; ix <= nx - 1; ix++) { cx = xmin + ix*(xmax-xmin)/(nx-1); c.real(cx); c.imag(cy); test1 = 2.0; if ((cx >= -7.55e-1) && (cx <= 4.0e-1)) { if ((cy >= -6.6e-1) && (cy <= 6.6e-1)) test1 = abs(1.0 - sqrt(1.0-4.0*c)); } test2 = 2.0; if ((cx >= -1.275e0) && (cx <= -7.45e-1)) { if ((cy >= -2.55e-1) && (cy <= 2.55e-1)) test2 = abs(4.0*(c+1.0)); } if (test1 <= 1.0) { potent = 0; iflag = 1; if (iset != 0) ipen = 126; else ipen = 64; } else if (test2 <= 1.0) { potent = 0; iflag = 1; if (iset != 0) ipen = 104; else ipen = 64; } else { potent = MandelSetPoten(cx, cy, maxiter); iflag = 0; } if ((potent == 0.0) && (iflag == 0)) ipen = 64; else if ((potent != 0) && (iflag == 0)) ipen = (int)(33.0 + 15.0*(potent-33.0)/diff); SetPixel(hdc, ix, iy, ipen); } } }
Ключевые слова:
Рисование фракталов, Kam Torus, множество Джулии, множество Мандельброта
|
|||||||