|
|
1.1 root 1: /******************************Module*Header*******************************\
2: * Module Name: bndscan.c
3: *
4: * Contains the boundary scaning functions
5: *
6: * Created: 14-Apr-1992 10:59:52
7: * Author: Petrus Wong
8: *
9: * Copyright (c) 1990 Microsoft Corporation
10: *
11: * Dependencies:
12: *
13: * none
14: *
15: \**************************************************************************/
16: #include <windows.h>
17: #include <stdio.h>
18: #include "jtypes.h"
19: #include "bndscan.h"
20:
21: extern LONG lMul(LONG, LONG);
22: extern LONG lDiv(LONG, LONG);
23:
24: BOOL bBoundaryScanFix(PINFO);
25: LPPOINT pptTrace(LONG, LONG, PINFO, INT *, HDC);
26: DWORD dwGetNextBoundaryPoint(DWORD, POINT, LPPOINT, PINFO);
27: BOOL bEscape(POINT, LONG, LONG, LONG, LONG, int, RECT);
28: BOOL bDirToPt(DWORD, POINT, LPPOINT);
29: DWORD dwShift(DWORD, int, int);
30:
31: /******************************Public*Routine******************************\
32: *
33: * bBoundaryScanFix
34: *
35: * Effects: Traces the outline of the mandelbrot set. Currently,
36: * 1. Uses the old method to set the color of each pixel
37: * 2. Remember the first pixel from top that doesn't escape
38: * st we can do boundary trace later.
39: * 3. When the whole set is done, do boundary trace.
40: * 4. Store the boundary points in an array. Then build a path.
41: * 5. Converts the path to region and then select the region as
42: * current clip region.
43: *
44: * Warnings: Only traces the first non-singular pixel island from top.
45: *
46: * History:
47: * 20-Feb-1992 -by- Petrus Wong
48: * Wrote it.
49: \**************************************************************************/
50:
51: BOOL bBoundaryScanFix(PINFO pInfo)
52: {
53: DWORD dwTick1;
54: int m, n, o, p;
55: HDC hDC;
56: RECT rc;
57: LONG c1, c2;
58: LONG x0, y0;
59: int iIteration;
60: LPPOINT lpPt;
61: int iCount;
62: POINT Pt;
63: BOOL bFirstPtSet;
64:
65: pInfo->bMandel = TRUE;
66: pInfo->bDrawing = TRUE;
67: bFirstPtSet = FALSE;
68: iIteration = pInfo->iIteration;
69: hDC = GetDC(pInfo->hwnd);
70: GetClientRect(pInfo->hwnd, &rc);
71:
72: dwTick1 = GetTickCount();
73: for (n=rc.bottom/2; n<=rc.bottom; n++) {
74: c2 = y0 = XformFix(n, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
75:
76: for (m=rc.left; m<=rc.right; m++) {
77: c1 = x0 = XformFix(m, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
78: Pt.x = m;
79: Pt.y = n;
80: if (bEscape(Pt, x0, y0, c1, c2, iIteration, rc)) {
81: //SetPixel(hDC, m, n, 0x000000ff);
82: } else {
83:
84: if (!bFirstPtSet)
85: {
86: o = m;
87: p = n;
88: bFirstPtSet = TRUE;
89: }
90: goto BOUNDTRACE;
91: }
92: }
93: }
94:
95: BOUNDTRACE:
96:
97: SelectObject(hDC, hpnGreen);
98: if ((lpPt = pptTrace(o, p, pInfo, &iCount, hDC)) == NULL)
99: {
100: m = o+1;
101:
102: for (n=p; n<=rc.bottom; n++) {
103: c2 = y0 = XformFix(n, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
104:
105: while (m <= rc.right)
106: {
107: c1 = x0 = XformFix(m, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
108: Pt.x = m;
109: Pt.y = n;
110:
111: if (!bEscape(Pt, x0, y0, c1, c2, iIteration, rc))
112: {
113: o = m;
114: p = n;
115: goto BOUNDTRACE;
116: }
117:
118: m++;
119: }
120: m = rc.left;
121: }
122: }
123:
124: if (!BeginPath(hDC)) {
125: sprintf( gtext,"Failing in BeginPath!\n");
126: OutputDebugString( gtext );
127: }
128:
129: MoveToEx(hDC, m, n, NULL);
130: Polyline(hDC, lpPt, iCount);
131:
132: if (EndPath(hDC)) {
133: StrokePath(hDC);
134: }
135:
136: //
137: // Stroking discards the path
138: //
139: if (!BeginPath(hDC)) {
140: sprintf( gtext,"Failing in BeginPath!\n");
141: OutputDebugString( gtext );
142: }
143:
144: MoveToEx(hDC, m, n, NULL);
145: Polyline(hDC, lpPt, iCount);
146:
147: if (EndPath(hDC)) {
148: //
149: // Convert the path to region
150: //
151: pInfo->hRgnPath = PathToRegion(hDC);
152:
153: #if 0
154: //
155: // SelectClipPath doesn't seem to work at this time
156: //
157: if (SelectClipPath(hDC, RGN_COPY)) {
158: //
159: // Testing if the clip region is effective or not
160: //
161: //MoveToEx(hDC, 0, 0, NULL);
162: //GetClientRect(pInfo->hwnd, &rc);
163: //LineTo(hDC, rc.right, rc.bottom);
164: }
165: #endif
166: }
167:
168: if (pInfo->hRgnPath != (HRGN) NULL) {
169: if (SelectClipRgn(hDC, pInfo->hRgnPath) == ERROR) {
170: sprintf( gtext,"Error in Selecting clip region\n");
171: OutputDebugString( gtext );
172: goto EXIT;
173: }
174: //
175: // Testing if the clip region is effective or not
176: //
177: //MoveToEx(hDC, 0, 0, NULL);
178: //GetClientRect(pInfo->hwnd, &rc);
179: //LineTo(hDC, rc.right, rc.bottom);
180: }
181:
182:
183: EXIT:
184:
185: pInfo->dwElapsed = GetTickCount() - dwTick1;
186: pInfo->hBmpSaved = SaveBitmap(pInfo->hwnd);
187: pInfo->bDrawing = FALSE;
188:
189: ReleaseDC(pInfo->hwnd, hDC);
190: //
191: // GlobalAlloc was called in pptTrace for storing the boundary points
192: //
193: GlobalFree((HANDLE) lpPt);
194: ExitThread(0);
195: if (!CloseHandle(pInfo->hThrd))
196: MessageBox(ghwndMain, "Failed in CloseHandle!", "Error", MB_OK);
197:
198: return TRUE;
199: }
200:
201: /******************************Public*Routine******************************\
202: *
203: * pptTrace
204: *
205: * Effects: Given a boundary point, traces the whole boundary of the
206: * set by calling dwGetNextBoundaryPoint() repeatedly. Returns
207: * a pointer to an array of boundary points and also the count
208: * of boundary points in the array, if successful. Otherwise,
209: * returns null.
210: * m, n is the x, y coordinates of the pixel of the initial
211: * boundary point.
212: *
213: * Warnings:
214: *
215: * History:
216: * 20-Feb-1992 -by- Petrus Wong
217: * Wrote it.
218: \**************************************************************************/
219:
220: LPPOINT pptTrace(LONG m, LONG n, PINFO pInfo, INT * piCount, HDC hDC)
221: {
222: DWORD dwFace;
223: LPPOINT lpPt, lpTmpPt;
224: POINT Init;
225: int iNumPt;
226:
227: //
228: // MAXPOINT points should be enough for storing the boundary for now. If
229: // it's not enough, it is more likely that it is an error.
230: //
231: if ((lpPt = (PPOINT) GlobalAlloc(GMEM_FIXED, MAXPOINT * sizeof(POINT))) == NULL) {
232: MessageBox(ghwndMain, "Failed in Memory Allocation for lpPt!", "Error", MB_OK);
233: return (LPPOINT) NULL;
234: }
235: lpTmpPt = lpPt;
236: lpPt->x = Init.x = m;
237: lpPt->y = Init.y = n;
238: lpPt++;
239: iNumPt = 1;
240: dwFace = dwGetNextBoundaryPoint(EAST, Init, lpPt, pInfo);
241: //
242: // If can't find next boundary point, return null
243: //
244: if (dwFace == 0)
245: return((LPPOINT)NULL);
246: //#if 0
247: //
248: // remove the ifdef if we wanted to see the boundary as we trace
249: //
250: MoveToEx(hDC, Init.x, Init.y, NULL);
251: LineTo(hDC, lpPt->x, lpPt->y);
252: //#endif
253: //
254: // Keep looking for next boundary point until I get back to where I
255: // started or exceeding MAXPOINT points
256: //
257: while ((iNumPt < MAXPOINT) &&
258: ((lpPt->x != lpTmpPt->x) || (lpPt->y != lpTmpPt->y))) {
259: Init.x = lpPt->x;
260: Init.y = lpPt->y;
261: lpPt++;
262: iNumPt++;
263: dwFace = dwGetNextBoundaryPoint(dwFace, Init, lpPt, pInfo);
264: //
265: // If can't find next boundary point, return null
266: //
267: if (dwFace == 0)
268: return((LPPOINT)NULL);
269: //#if 0
270: //
271: // remove the ifdef if we wanted to see the boundary as we trace
272: //
273: MoveToEx(hDC, Init.x, Init.y, NULL);
274: LineTo(hDC, lpPt->x, lpPt->y);
275: //#endif
276:
277: }
278: //
279: // It is more likely that it is an error of the algorithm, if ever happens.
280: //
281: if (iNumPt >= MAXPOINT) {
282: MessageBox(ghwndMain, "Not enough memory!!", "Error", MB_OK);
283: }
284: *piCount = iNumPt;
285: return (LPPOINT) lpTmpPt;
286: }
287:
288:
289: /******************************Public*Routine******************************\
290: *
291: * dwGetNextBoundaryPoint
292: *
293: * Effects: Start checking the 8 neighbors in clockwise direction. Returns
294: * the first neighbor that does not escape.
295: * dwFace where we face
296: * InitPt where we are right now in pixel coordinates
297: *
298: * Warnings: assumes that we start at a boundary point. Does not trace into
299: * a bay if the entrance closed. Ie, it cuts cycle.
300: *
301: * History:
302: * 12-Feb-1992 -by- Petrus Wong
303: * Wrote it.
304: \**************************************************************************/
305:
306: DWORD dwGetNextBoundaryPoint(DWORD dwFace, POINT InitPt, LPPOINT lpPt, PINFO pInfo)
307: {
308: BOOL bEsc;
309: DWORD dwExplore;
310: DWORD dwEnd;
311: int i;
312: NODE arg[8];
313: POINT BndPt;
314: LONG lx, c1, ly, c2;
315: RECT rc;
316:
317: GetClientRect(pInfo->hwnd, &rc);
318: //
319: // Start exploring clockwise, ending at where we came from
320: //
321: dwExplore = dwShift(dwFace, RIGHT, 3);
322: dwEnd = dwShift(dwFace, LEFT, 4);
323: i = 0;
324: bDirToPt(dwExplore, InitPt, &BndPt);
325: c1 = lx = XformFix(BndPt.x, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
326: c2 = ly = XformFix(BndPt.y, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
327:
328: while (bEsc = bEscape(BndPt, lx, ly, c1, c2, pInfo->iIteration, rc)) {
329: arg[i].dwDirection = dwExplore;
330: arg[i].bEscape = TRUE;
331:
332: i++;
333:
334: if (dwExplore == dwEnd)
335: break;
336:
337: dwExplore = dwShift(dwExplore, LEFT, 1);
338: bDirToPt(dwExplore, InitPt, &BndPt);
339: c1 = lx = XformFix(BndPt.x, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
340: c2 = ly = XformFix(BndPt.y, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
341:
342: }
343:
344: if (bEsc) {
345: return 0L;
346: }
347:
348: arg[i].dwDirection = dwExplore;
349: arg[i].bEscape = FALSE;
350:
351: bDirToPt(arg[i].dwDirection, InitPt, lpPt);
352:
353: return arg[i].dwDirection;
354: }
355:
356:
357:
358: /******************************Public*Routine******************************\
359: *
360: * bEscape
361: *
362: * Effects: Test if the point excapes based on the number of iterations
363: *
364: * Warnings:
365: *
366: * History:
367: * 20-Feb-1992 -by- Petrus Wong
368: * Wrote it.
369: \**************************************************************************/
370:
371: BOOL bEscape(POINT Pt, LONG x, LONG y, LONG c1, LONG c2, int iIteration, RECT rc)
372: {
373: LONG x1, y1, z;
374: BOOL bEscape;
375: int i;
376:
377: bEscape = FALSE;
378:
379: //
380: // Treat points outside of client rect as escaping
381: //
382: if ((Pt.x < rc.left) || (Pt.x > rc.right-1) ||
383: (Pt.y > rc.bottom-1) || (Pt.y < rc.top)) {
384: return TRUE;
385: }
386: for (i=1; i<=iIteration; i++) {
387: x1 = lMul(x - y, x + y) + c1;
388: y1 = (lMul(x, y) * 2) + c2;
389: x = x1;
390: y = y1; // 2 2 2 1/2 2
391: z = lMul(x, x) + lMul(y, y); // |Z| = ((x1 + x2 ) ) > 2
392:
393: if (z > 8192) {
394: bEscape = TRUE;
395: break;
396: }
397: }
398: return bEscape;
399: }
400:
401: /******************************Public*Routine******************************\
402: *
403: * bDirToPt
404: *
405: * Effects: Returns the pixel coordinates based the direction we are facing
406: * and our current position
407: *
408: * Warnings:
409: *
410: * History:
411: * 20-Feb-1992
412: * Wrote it.
413: \**************************************************************************/
414:
415: BOOL bDirToPt(DWORD dwDirection, POINT InitPt, LPPOINT lpPt)
416: {
417: BOOL bSuccess;
418:
419: bSuccess = TRUE;
420: switch ((LONG)dwDirection) {
421: case EAST:
422: lpPt->x = InitPt.x+1;
423: lpPt->y = InitPt.y;
424: break;
425: case SOUTHEAST:
426: lpPt->x = InitPt.x+1;
427: lpPt->y = InitPt.y+1;
428: break;
429: case SOUTH:
430: lpPt->x = InitPt.x;
431: lpPt->y = InitPt.y+1;
432: break;
433: case SOUTHWEST:
434: lpPt->x = InitPt.x-1;
435: lpPt->y = InitPt.y+1;
436: break;
437: case WEST:
438: lpPt->x = InitPt.x-1;
439: lpPt->y = InitPt.y;
440: break;
441: case NORTHWEST:
442: lpPt->x = InitPt.x-1;
443: lpPt->y = InitPt.y-1;
444: break;
445: case NORTH:
446: lpPt->x = InitPt.x;
447: lpPt->y = InitPt.y-1;
448: break;
449: case NORTHEAST:
450: lpPt->x = InitPt.x+1;
451: lpPt->y = InitPt.y-1;
452: break;
453: default:
454: bSuccess = FALSE;
455: break;
456: }
457: return bSuccess;
458: }
459:
460: /******************************Public*Routine******************************\
461: *
462: * dwShift
463: * NORTH
464: * NW 0x0040 NE
465: * 0x0020 0x0080
466: * Effects: WEST 0x0010 * 0x0001 EAST
467: * 0x0008 0x0002
468: * SW 0x0004 SE
469: * SOUTH
470: *
471: * Shift dwOpnd left or right by iNum.
472: * dwOpnd contains the above values. The shift operation is
473: * closed.
474: *
475: * Warnings:
476: *
477: * History:
478: * 20-Feb-1992 -by- Petrus Wong
479: * Wrote it.
480: \**************************************************************************/
481:
482: DWORD dwShift(DWORD dwOpnd, int iDir, int iNum)
483: {
484: DWORD dwTmp;
485:
486: dwTmp = ((dwOpnd << 8) | dwOpnd);
487: switch ((LONG)iDir) {
488: case LEFT:
489: dwTmp = dwTmp << iNum;
490: dwTmp = dwTmp & 0x0ff00;
491: dwTmp = dwTmp >> 8;
492: break;
493: case RIGHT:
494: dwTmp = dwTmp >> iNum;
495: dwTmp = dwTmp & 0x0ff;
496: break;
497: default:
498: dwTmp = 0L;
499: break;
500: }
501: return dwTmp;
502: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.