Mandelbrot 集合。
复数集合,详情见各种百科全书。
下面做了个示例,附件内有 vc6 工程。
#include <windows.h>#include <tchar.h>#define MANDELBROT_ITER 2000#define MANDELBROT_COLORS 128#define MANDELBROT_VW 400#define MANDELBROT_VH 300 // MANDELBROT_VW * .75#define MANDELBROT_CW MANDELBROT_VW / 2#define MANDELBROT_CH MANDELBROT_VH / 2#define MANDELBROT_L -2.50#define MANDELBROT_T +1.35#define MANDELBROT_W +3.60#define MANDELBROT_H -2.70typedef struct {double r;double i;} complex;typedef struct {void *hwnd;int l;int t;int r;int b;RECT rect;} region;struct {struct {void *himg;void *pixs;int w;int h;} simg;int iter;double setx;double sety;double setw;double seth;int cunt;} sdata;struct {int x;int y;double w;double h;int move;} scoor;unsigned int palet[] = {0xff000086, 0xff01018c, 0xff040491, 0xff070797, 0xff0c0c9c, 0xff1212a1, 0xff1919a7, 0xff2020ac,0xff2929b1, 0xff3333b6, 0xff3d3dbb, 0xff4747bf, 0xff5252c4, 0xff5e5ec8, 0xff6a6acc, 0xff7676d1,0xff8181d4, 0xff8d8dd8, 0xff9999dc, 0xffa5a5df, 0xffb0b0e2, 0xffbbbbe5, 0xffc5c5e8, 0xffcfcfea,0xffd8d8ec, 0xffe1e1ee, 0xffe8e8f0, 0xffefeff2, 0xfff5f5f3, 0xfffafaf4, 0xfffdfdf5, 0xfffffff5,0xfffffff5, 0xfffffff4, 0xfffffff2, 0xfffffeee, 0xfffffee9, 0xfffffde4, 0xfffffcdd, 0xfffffcd6,0xffffface, 0xfffff9c4, 0xfffff8bb, 0xfffff6b0, 0xfffff5a6, 0xfffff39b, 0xfffff190, 0xffffef84,0xffffed79, 0xffffeb6d, 0xffffe862, 0xffffe557, 0xffffe34c, 0xffffe041, 0xffffdc37, 0xffffd92e,0xffffd625, 0xffffd21d, 0xffffce16, 0xffffca0f, 0xffffc60a, 0xffffc205, 0xffffbd02, 0xffffb900,0xffffb400, 0xffffaf00, 0xfffea900, 0xfffea400, 0xfffd9d00, 0xfffc9700, 0xfffb9000, 0xfff98900,0xfff88200, 0xfff67a00, 0xfff47300, 0xfff16b00, 0xffef6400, 0xffec5c00, 0xffe95500, 0xffe64d00,0xffe34600, 0xffe03f00, 0xffdc3800, 0xffd93100, 0xffd52b00, 0xffd12400, 0xffcd1f00, 0xffc81900,0xffc41400, 0xffbf0f00, 0xffba0b00, 0xffb60800, 0xffb00500, 0xffab0300, 0xffa60100, 0xffa10000,0xff9b0000, 0xff950000, 0xff8f0001, 0xff890002, 0xff830004, 0xff7d0006, 0xff760008, 0xff70000a,0xff69000d, 0xff630010, 0xff5c0014, 0xff560017, 0xff4f001b, 0xff49001f, 0xff430024, 0xff3d0028,0xff37002d, 0xff310032, 0xff2b0037, 0xff26003c, 0xff210042, 0xff1c0047, 0xff17004d, 0xff130052,0xff0f0058, 0xff0c005e, 0xff090063, 0xff060069, 0xff04006f, 0xff020075, 0xff01007b, 0xff000080,};unsigned int templ[] = { WS_MINIMIZEBOX | WS_SYSMENU, WS_EX_DLGMODALFRAME, 0, 0, 0, 0, };__declspec(naked) double __cdecl sqrt(double x) {__asm fldqword ptr [esp+4]__asm fsqrt__asm ret}double complex_abs(complex *a) {return sqrt(a->r * a->r + a->i * a->i);}void complex_sub(complex *a, complex *b, complex *o) {o->i = a->i - b->i;o->r = a->r - b->r;}void complex_mul(complex *a, complex *b, complex *o) {double r = a->r * b->r - a->i * b->i;o->i = a->i * b->r + a->r * b->i;o->r = r;}unsigned int __stdcall mandelbrot_thread_proc(region *rptr) {int x, y, i;complex c, z, t, n;unsigned char *pixs;void *hwnd = rptr->hwnd;n.r = -.9;n.i = +.0;for (y = rptr->t; y < rptr->b; ++y) {pixs = (unsigned char*)sdata.simg.pixs + y * sdata.simg.w + rptr->l;for (x = rptr->l; x < rptr->r; ++x) {i = 0;t.r = sdata.setx + x * (sdata.setw / sdata.simg.w);t.i = sdata.sety + y * (sdata.seth / sdata.simg.h);complex_mul(&n, &t, &c);z.r = .0;z.i = .0;while (i++ < sdata.iter - 1 && complex_abs(&z) < 2.0) {complex_mul(&z, &z, &z);complex_sub(&z, &c, &z);}*pixs++ = (i == sdata.iter) ? MANDELBROT_COLORS : (i % MANDELBROT_COLORS);}if (!(y % 20)) InvalidateRect(hwnd, &rptr->rect, 1);}InvalidateRect(hwnd, 0, 1);free(rptr);--sdata.cunt;return 0;}void mandelbrot_create_image(int w, int h) {void *hmdc;BITMAPINFO *bmif = calloc(sizeof(char), sizeof(BITMAPINFOHEADER) + sizeof(int) * 256);sdata.simg.w = w;sdata.simg.h = h;bmif->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmif->bmiHeader.biWidth = w;bmif->bmiHeader.biHeight = -h;bmif->bmiHeader.biPlanes = 1;bmif->bmiHeader.biBitCount = 8;for (w = 0; w < MANDELBROT_COLORS; ++w) *(int*)(bmif->bmiColors + w) = palet[w];hmdc = CreateCompatibleDC(0);sdata.simg.himg = CreateDIBSection(hmdc, bmif, DIB_RGB_COLORS, &sdata.simg.pixs, 0, 0);DeleteDC(hmdc);free(bmif);}void mandelbrot_update(void *hwnd) {int x, y;double n;void *hthr;region *rptr;n = (double)MANDELBROT_VW / sdata.simg.w;for (y = 0; y < sdata.simg.h; y = y + MANDELBROT_CH)for (x = 0; x < sdata.simg.w; x = x + MANDELBROT_CW) {rptr = calloc(1, sizeof(region));rptr->hwnd = hwnd;rptr->l = x;rptr->t = y;rptr->r = MANDELBROT_CW <= sdata.simg.w - x ? x + MANDELBROT_CW : sdata.simg.w;rptr->b = MANDELBROT_CH <= sdata.simg.h - y ? y + MANDELBROT_CH : sdata.simg.h;SetRect(&rptr->rect, (int)(rptr->l * n), (int)(rptr->t * n), (int)(rptr->r * n), (int)(rptr->b * n));hthr = CreateThread(0, 0, mandelbrot_thread_proc, rptr, 0, 0);CloseHandle(hthr);if (hthr) ++sdata.cunt;}}void mandelbrot_draw_image(void *htdc) {void *himg, *hmdc;hmdc = CreateCompatibleDC(0);himg = SelectObject(hmdc, sdata.simg.himg);SetStretchBltMode(htdc, HALFTONE);StretchBlt(htdc, 0, 0, MANDELBROT_VW, MANDELBROT_VH, hmdc, 0, 0, sdata.simg.w, sdata.simg.h, SRCCOPY);SelectObject(hmdc, himg);DeleteDC(hmdc);}void mandelbrot_rbuttonup(void *hwnd) {if (sdata.cunt) return;if (scoor.move) return;sdata.setx = MANDELBROT_L;sdata.sety = MANDELBROT_T;sdata.setw = MANDELBROT_W;sdata.seth = MANDELBROT_H;mandelbrot_update(hwnd);}void mandelbrot_activate(void *hwnd, int code) {if (WA_INACTIVE != code) return;SetCapture(0);scoor.move = 0;InvalidateRect(hwnd, 0, 1);}void mandelbrot_initdialog(void *hwnd) {RECT rect = { 0, 0, MANDELBROT_VW, MANDELBROT_VH, };AdjustWindowRect(&rect, WS_CAPTION, 0);OffsetRect(&rect, -rect.left, -rect.top);MoveWindow(hwnd,(GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2,(GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2, rect.right, rect.bottom, 1);sdata.iter = MANDELBROT_ITER;mandelbrot_create_image(800, 600);mandelbrot_rbuttonup(hwnd);}void mandelbrot_lbuttondown(void *hwnd, int x, int y) {if (sdata.cunt) return;scoor.x = x;scoor.y = y;scoor.w = .0;scoor.h = .0;SetCapture(hwnd);scoor.move = 1;}void mandelbrot_lbuttonup(void *hwnd, int x, int y) {if (sdata.cunt) return;if (!scoor.move) return;SetCapture(0);scoor.move = 0;if (.0 >= scoor.w || .0 >= scoor.h) return;sdata.setx = sdata.setx + (scoor.x - scoor.w) / MANDELBROT_VW * sdata.setw;sdata.sety = sdata.sety + (scoor.y - scoor.h) / MANDELBROT_VH * sdata.seth;sdata.setw = sdata.setw / MANDELBROT_VW * (scoor.w * 2.0);sdata.seth = sdata.seth / MANDELBROT_VH * (scoor.h * 2.0);mandelbrot_update(hwnd);}void mandelbrot_mousemove(void *hwnd, int code, int x, int y) {if (!scoor.move) return;x = abs(x - scoor.x);y = abs(y - scoor.y);if (x < y) {scoor.w = y / .75;scoor.h = y;} else {scoor.w = x;scoor.h = x * .75;}InvalidateRect(hwnd, 0, 1);}void mandelbrot_paint(void *hwnd) {PAINTSTRUCT ps;int l, t, r, b;RECT rect = { 0, 0, MANDELBROT_VW, MANDELBROT_VH, };void *himg, *hmdc, *hwdc = BeginPaint(hwnd, &ps);hmdc = CreateCompatibleDC(0);himg = SelectObject(hmdc, CreateCompatibleBitmap(hwdc, MANDELBROT_VW, MANDELBROT_VH));FillRect(hmdc, &rect, GetSysColorBrush(COLOR_3DFACE));mandelbrot_draw_image(hmdc);if (scoor.move) {l = (int)(scoor.x - scoor.w);t = (int)(scoor.y - scoor.h);r = (int)(scoor.x + scoor.w);b = (int)(scoor.y + scoor.h);SetROP2(hmdc, R2_NOT);MoveToEx(hmdc, l, t, 0);LineTo(hmdc, r, t);LineTo(hmdc, r, b);LineTo(hmdc, l, b);LineTo(hmdc, l, t);}BitBlt(hwdc, 0, 0, rect.right, rect.bottom, hmdc, 0, 0, SRCCOPY);DeleteObject(SelectObject(hmdc, himg));DeleteDC(hmdc);EndPaint(hwnd, &ps);}int __stdcall mandelbrot_proc(void *hwnd, unsigned int umsg, unsigned int wprm, long lprm) {switch (umsg) {case WM_ACTIVATE: mandelbrot_activate(hwnd, wprm); break;case WM_ERASEBKGND: break;case WM_INITDIALOG: mandelbrot_initdialog(hwnd); break;case WM_LBUTTONDOWN: mandelbrot_lbuttondown(hwnd, (short)lprm, lprm >> 16); break;case WM_LBUTTONUP: mandelbrot_lbuttonup(hwnd, (short)lprm, lprm >> 16); break;case WM_MOUSEMOVE: mandelbrot_mousemove(hwnd, wprm, (short)lprm, lprm >> 16); break;case WM_PAINT: mandelbrot_paint(hwnd); break;case WM_RBUTTONUP: mandelbrot_rbuttonup(hwnd); break;case WM_SYSCOMMAND: if (SC_CLOSE == wprm) EndDialog(hwnd, 0); // break;default: return 0;}return 1;}void mandelbrot() {ExitProcess(DialogBoxIndirectParam(GetModuleHandle(0), (void*)templ, 0, mandelbrot_proc, 0));}