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