pcb 4.1.1
An interactive printed circuit board layout editor.

decompose.c

Go to the documentation of this file.
00001 
00018 /* decompose.c 146 2007-04-09 00:43:46Z selinger */
00019 
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <limits.h>
00024 
00025 #include "potracelib.h"
00026 #include "curve.h"
00027 #include "lists.h"
00028 #include "auxiliary.h"
00029 #include "bitmap.h"
00030 #include "decompose.h"
00031 //#include "progress.h"
00032 
00036 static void
00037 bm_clearexcess (potrace_bitmap_t * bm)
00038 {
00039   potrace_word mask;
00040   int y;
00041 
00042   if (bm->w % BM_WORDBITS != 0)
00043     {
00044       mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
00045       for (y = 0; y < bm->h; y++)
00046         {
00047           *bm_index (bm, bm->w, y) &= mask;
00048         }
00049     }
00050 }
00051 
00052 struct bbox_s
00053 {
00054   int x0, x1, y0, y1;           /* bounding box */
00055 };
00056 typedef struct bbox_s bbox_t;
00057 
00063 static void
00064 clear_bm_with_bbox (potrace_bitmap_t * bm, bbox_t * bbox)
00065 {
00066   int imin = (bbox->x0 / BM_WORDBITS);
00067   int imax = ((bbox->x1 + BM_WORDBITS - 1) / BM_WORDBITS);
00068   int i, y;
00069 
00070   for (y = bbox->y0; y < bbox->y1; y++)
00071     {
00072       for (i = imin; i < imax; i++)
00073         {
00074           bm_scanline (bm, y)[i] = 0;
00075         }
00076     }
00077 }
00078 
00079 /* ---------------------------------------------------------------------- */
00080 /* auxiliary functions */
00081 
00086 static inline int
00087 detrand (int x, int y)
00088 {
00089   unsigned int z;
00090   static const unsigned char t[256] = {
00091     /* non-linear sequence: constant term of inverse in GF(8), 
00092        mod x^8+x^4+x^3+x+1 */
00093     0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
00094     0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
00095     0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
00096     1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
00097     0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
00098     0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
00099     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
00100     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
00101     1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
00102     0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
00103     1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
00104   };
00105 
00106   /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
00107      5-bit sequence */
00108   z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
00109   z =
00110     t[z & 0xff] ^ t[(z >> 8) & 0xff] ^ t[(z >> 16) & 0xff] ^ t[(z >> 24) &
00111                                                                0xff];
00112   return z & 1;
00113 }
00114 
00121 static int
00122 majority (potrace_bitmap_t * bm, int x, int y)
00123 {
00124   int i, a, ct;
00125 
00126   for (i = 2; i < 5; i++)
00127     {                           /* check at "radius" i */
00128       ct = 0;
00129       for (a = -i + 1; a <= i - 1; a++)
00130         {
00131           ct += BM_GET (bm, x + a, y + i - 1) ? 1 : -1;
00132           ct += BM_GET (bm, x + i - 1, y + a - 1) ? 1 : -1;
00133           ct += BM_GET (bm, x + a - 1, y - i) ? 1 : -1;
00134           ct += BM_GET (bm, x - i, y + a) ? 1 : -1;
00135         }
00136       if (ct > 0)
00137         {
00138           return 1;
00139         }
00140       else if (ct < 0)
00141         {
00142           return 0;
00143         }
00144     }
00145   return 0;
00146 }
00147 
00148 /* ---------------------------------------------------------------------- */
00149 /* decompose image into paths */
00150 
00156 static void
00157 xor_to_ref (potrace_bitmap_t * bm, int x, int y, int xa)
00158 {
00159   int xhi = x & -BM_WORDBITS;
00160   int xlo = x & (BM_WORDBITS - 1);      /* = x % BM_WORDBITS */
00161   int i;
00162 
00163   if (xhi < xa)
00164     {
00165       for (i = xhi; i < xa; i += BM_WORDBITS)
00166         {
00167           *bm_index (bm, i, y) ^= BM_ALLBITS;
00168         }
00169     }
00170   else
00171     {
00172       for (i = xa; i < xhi; i += BM_WORDBITS)
00173         {
00174           *bm_index (bm, i, y) ^= BM_ALLBITS;
00175         }
00176     }
00177   /* note: the following "if" is needed because x86 treats a<<b as
00178      a<<(b&31). I spent hours looking for this bug. */
00179   if (xlo)
00180     {
00181       *bm_index (bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo));
00182     }
00183 }
00184 
00196 static void
00197 xor_path (potrace_bitmap_t * bm, path_t * p)
00198 {
00199   int xa, x, y, k, y1;
00200 
00201   if (p->priv->len <= 0)
00202     {                           /* a path of length 0 is silly, but legal */
00203       return;
00204     }
00205 
00206   y1 = p->priv->pt[p->priv->len - 1].y;
00207 
00208   xa = p->priv->pt[0].x & -BM_WORDBITS;
00209   for (k = 0; k < p->priv->len; k++)
00210     {
00211       x = p->priv->pt[k].x;
00212       y = p->priv->pt[k].y;
00213 
00214       if (y != y1)
00215         {
00216           /* efficiently invert the rectangle [x,xa] x [y,y1] */
00217           xor_to_ref (bm, x, min (y, y1), xa);
00218           y1 = y;
00219         }
00220     }
00221 }
00222 
00228 static void
00229 setbbox_path (bbox_t * bbox, path_t * p)
00230 {
00231   int x, y;
00232   int k;
00233 
00234   bbox->y0 = INT_MAX;
00235   bbox->y1 = 0;
00236   bbox->x0 = INT_MAX;
00237   bbox->x1 = 0;
00238 
00239   for (k = 0; k < p->priv->len; k++)
00240     {
00241       x = p->priv->pt[k].x;
00242       y = p->priv->pt[k].y;
00243 
00244       if (x < bbox->x0)
00245         {
00246           bbox->x0 = x;
00247         }
00248       if (x > bbox->x1)
00249         {
00250           bbox->x1 = x;
00251         }
00252       if (y < bbox->y0)
00253         {
00254           bbox->y0 = y;
00255         }
00256       if (y > bbox->y1)
00257         {
00258           bbox->y1 = y;
00259         }
00260     }
00261 }
00262 
00273 static path_t *
00274 findpath (potrace_bitmap_t * bm, int x0, int y0, int sign, int turnpolicy)
00275 {
00276   int x, y, dirx, diry, len, size, area;
00277   int c, d, tmp;
00278   point_t *pt, *pt1;
00279   path_t *p = NULL;
00280 
00281   x = x0;
00282   y = y0;
00283   dirx = 0;
00284   diry = -1;
00285 
00286   len = size = 0;
00287   pt = NULL;
00288   area = 0;
00289 
00290   while (1)
00291     {
00292       /* add point to path */
00293       if (len >= size)
00294         {
00295           size += 100;
00296           size = (int) (1.3 * size);
00297           pt1 = (point_t *) realloc (pt, size * sizeof (point_t));
00298           if (!pt1)
00299             {
00300               goto error;
00301             }
00302           pt = pt1;
00303         }
00304       pt[len].x = x;
00305       pt[len].y = y;
00306       len++;
00307 
00308       /* move to next point */
00309       x += dirx;
00310       y += diry;
00311       area += x * diry;
00312 
00313       /* path complete? */
00314       if (x == x0 && y == y0)
00315         {
00316           break;
00317         }
00318 
00319       /* determine next direction */
00320       c = BM_GET (bm, x + (dirx + diry - 1) / 2, y + (diry - dirx - 1) / 2);
00321       d = BM_GET (bm, x + (dirx - diry - 1) / 2, y + (diry + dirx - 1) / 2);
00322 
00323       if (c && !d)
00324         {                       /* ambiguous turn */
00325           if (turnpolicy == POTRACE_TURNPOLICY_RIGHT
00326               || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
00327               || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
00328               || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand (x, y))
00329               || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY
00330                   && majority (bm, x, y))
00331               || (turnpolicy == POTRACE_TURNPOLICY_MINORITY
00332                   && !majority (bm, x, y)))
00333             {
00334               tmp = dirx;       /* right turn */
00335               dirx = diry;
00336               diry = -tmp;
00337             }
00338           else
00339             {
00340               tmp = dirx;       /* left turn */
00341               dirx = -diry;
00342               diry = tmp;
00343             }
00344         }
00345       else if (c)
00346         {                       /* right turn */
00347           tmp = dirx;
00348           dirx = diry;
00349           diry = -tmp;
00350         }
00351       else if (!d)
00352         {                       /* left turn */
00353           tmp = dirx;
00354           dirx = -diry;
00355           diry = tmp;
00356         }
00357     }                           /* while this path */
00358 
00359   /* allocate new path object */
00360   p = path_new ();
00361   if (!p)
00362     {
00363       goto error;
00364     }
00365 
00366   p->priv->pt = pt;
00367   p->priv->len = len;
00368   p->area = area;
00369   p->sign = sign;
00370 
00371   return p;
00372 
00373 error:
00374   free (pt);
00375   return NULL;
00376 }
00377 
00399 static void
00400 pathlist_to_tree (path_t * plist, potrace_bitmap_t * bm)
00401 {
00402   path_t *p, *p1;
00403   path_t *heap, *heap1;
00404   path_t *cur;
00405   path_t *head;
00406   path_t **hook, **hook_in, **hook_out; /* for fast appending to linked list */
00407   bbox_t bbox;
00408 
00409   bm_clear (bm, 0);
00410 
00411   /* save original "next" pointers */
00412   list_forall (p, plist)
00413   {
00414     p->sibling = p->next;
00415     p->childlist = NULL;
00416   }
00417 
00418   heap = plist;
00419 
00420   /* the heap holds a list of lists of paths. Use "childlist" field
00421      for outer list, "next" field for inner list. Each of the sublists
00422      is to be turned into a tree. This code is messy, but it is
00423      actually fast. Each path is rendered exactly once. We use the
00424      heap to get a tail recursive algorithm: the heap holds a list of
00425      pathlists which still need to be transformed. */
00426 
00427   while (heap)
00428     {
00429       /* unlink first sublist */
00430       cur = heap;
00431       heap = heap->childlist;
00432       cur->childlist = NULL;
00433 
00434       /* unlink first path */
00435       head = cur;
00436       cur = cur->next;
00437       head->next = NULL;
00438 
00439       /* render path */
00440       xor_path (bm, head);
00441       setbbox_path (&bbox, head);
00442 
00443       /* now do insideness test for each element of cur; append it to
00444          head->childlist if it's inside head, else append it to
00445          head->next. */
00446       hook_in = &head->childlist;
00447       hook_out = &head->next;
00448       list_forall_unlink (p, cur)
00449       {
00450         if (p->priv->pt[0].y <= bbox.y0)
00451           {
00452             list_insert_beforehook (p, hook_out);
00453             /* append the remainder of the list to hook_out */
00454             *hook_out = cur;
00455             break;
00456           }
00457         if (BM_GET (bm, p->priv->pt[0].x, p->priv->pt[0].y - 1))
00458           {
00459             list_insert_beforehook (p, hook_in);
00460           }
00461         else
00462           {
00463             list_insert_beforehook (p, hook_out);
00464           }
00465       }
00466 
00467       /* clear bm */
00468       clear_bm_with_bbox (bm, &bbox);
00469 
00470       /* now schedule head->childlist and head->next for further
00471          processing */
00472       if (head->next)
00473         {
00474           head->next->childlist = heap;
00475           heap = head->next;
00476         }
00477       if (head->childlist)
00478         {
00479           head->childlist->childlist = heap;
00480           heap = head->childlist;
00481         }
00482     }
00483 
00484   /* copy sibling structure from "next" to "sibling" component */
00485   p = plist;
00486   while (p)
00487     {
00488       p1 = p->sibling;
00489       p->sibling = p->next;
00490       p = p1;
00491     }
00492 
00493   /* reconstruct a new linked list ("next") structure from tree
00494      ("childlist", "sibling") structure. This code is slightly messy,
00495      because we use a heap to make it tail recursive: the heap
00496      contains a list of childlists which still need to be
00497      processed. */
00498   heap = plist;
00499   if (heap)
00500     {
00501       heap->next = NULL;        /* heap is a linked list of childlists */
00502     }
00503   plist = NULL;
00504   hook = &plist;
00505   while (heap)
00506     {
00507       heap1 = heap->next;
00508       for (p = heap; p; p = p->sibling)
00509         {
00510           /* p is a positive path */
00511           /* append to linked list */
00512           list_insert_beforehook (p, hook);
00513 
00514           /* go through its children */
00515           for (p1 = p->childlist; p1; p1 = p1->sibling)
00516             {
00517               /* append to linked list */
00518               list_insert_beforehook (p1, hook);
00519               /* append its childlist to heap, if non-empty */
00520               if (p1->childlist)
00521                 {
00522                   list_append (path_t, heap1, p1->childlist);
00523                 }
00524             }
00525         }
00526       heap = heap1;
00527     }
00528 
00529   return;
00530 }
00531 
00542 static int
00543 findnext (potrace_bitmap_t * bm, int *xp, int *yp)
00544 {
00545   int x;
00546   int y;
00547 
00548   for (y = *yp; y >= 0; y--)
00549     {
00550       for (x = 0; x < bm->w; x += BM_WORDBITS)
00551         {
00552           if (*bm_index (bm, x, y))
00553             {
00554               while (!BM_GET (bm, x, y))
00555                 {
00556                   x++;
00557                 }
00558               /* found */
00559               *xp = x;
00560               *yp = y;
00561               return 0;
00562             }
00563         }
00564     }
00565   /* not found */
00566   return 1;
00567 }
00568 
00577 int
00578 bm_to_pathlist (const potrace_bitmap_t * bm, path_t ** plistp,
00579                 const potrace_param_t * param)
00580 {
00581   int x;
00582   int y;
00583   path_t *p;
00584   path_t *plist = NULL;         /* linked list of path objects */
00585   path_t **hook = &plist;       /* used to speed up appending to linked list */
00586   potrace_bitmap_t *bm1 = NULL;
00587   int sign;
00588 
00589   bm1 = bm_dup (bm);
00590   if (!bm1)
00591     {
00592       goto error;
00593     }
00594 
00595   /* be sure the byte padding on the right is set to 0, as the fast
00596      pixel search below relies on it */
00597   bm_clearexcess (bm1);
00598 
00599   /* iterate through components */
00600   y = bm1->h - 1;
00601   while (findnext (bm1, &x, &y) == 0)
00602     {
00603       /* calculate the sign by looking at the original */
00604       sign = BM_GET (bm, x, y) ? '+' : '-';
00605 
00606       /* calculate the path */
00607       p = findpath (bm1, x, y + 1, sign, param->turnpolicy);
00608       if (p == NULL)
00609         {
00610           goto error;
00611         }
00612 
00613       /* update buffered image */
00614       xor_path (bm1, p);
00615 
00616       /* if it's a turd, eliminate it, else append it to the list */
00617       if (p->area <= param->turdsize)
00618         {
00619           path_free (p);
00620         }
00621       else
00622         {
00623           list_insert_beforehook (p, hook);
00624         }
00625 
00626       if (bm1->h > 0)
00627         {                       /* to be sure */
00628           //progress_update(1-y/(double)bm1->h, progress);
00629         }
00630     }
00631 
00632   pathlist_to_tree (plist, bm1);
00633   bm_free (bm1);
00634   *plistp = plist;
00635 
00636 //  progress_update(1.0, progress);
00637 
00638   return 0;
00639 
00640 error:
00641   bm_free (bm1);
00642   list_forall_unlink (p, plist)
00643   {
00644     path_free (p);
00645   }
00646   return -1;
00647 }