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