BNDSCAN.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:13k
源码类别:

Windows编程

开发平台:

Visual C++

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