复数集合,详情见各种百科全书。
下面做了个示例,附件内有 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.70
typedef 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 fld qword 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));
}