pcb 4.1.1
An interactive printed circuit board layout editor.

polygon1.c

Go to the documentation of this file.
00001 
00075 #include        <assert.h>
00076 #include        <stdlib.h>
00077 #include        <stdio.h>
00078 #include        <setjmp.h>
00079 #include        <math.h>
00080 #include        <string.h>
00081 
00082 #include "global.h"
00083 #include "pcb-printf.h"
00084 #include "rtree.h"
00085 #include "heap.h"
00086 
00087 #define ROUND(a) (long)((a) > 0 ? ((a) + 0.5) : ((a) - 0.5))
00088 
00089 #define EPSILON (1E-8)
00090 #define IsZero(a, b) (fabs((a) - (b)) < EPSILON)
00091 
00092 /*              L o n g   V e c t o r   S t u f f                    */
00093 
00094 #define Vcopy(a,b) {(a)[0]=(b)[0];(a)[1]=(b)[1];}
00095 int vect_equal (Vector v1, Vector v2);
00096 void vect_init (Vector v, double x, double y);
00097 void vect_sub (Vector res, Vector v2, Vector v3);
00098 
00099 void vect_min (Vector res, Vector v2, Vector v3);
00100 void vect_max (Vector res, Vector v2, Vector v3);
00101 
00102 double vect_dist2 (Vector v1, Vector v2);
00103 double vect_det2 (Vector v1, Vector v2);
00104 double vect_len2 (Vector v1);
00105 
00106 int vect_inters2 (Vector A, Vector B, Vector C, Vector D, Vector S1,
00107                   Vector S2);
00108 
00109 /* note that a vertex v's Flags.status represents the edge defined by
00110  * v to v->next (i.e. the edge is forward of v)
00111  */
00112 #define ISECTED 3
00113 #define UNKNWN  0
00114 #define INSIDE  1
00115 #define OUTSIDE 2
00116 #define SHARED 3
00117 #define SHARED2 4
00118 
00119 #define TOUCHES 99
00120 
00121 #define NODE_LABEL(n)  ((n)->Flags.status)
00122 #define LABEL_NODE(n,l) ((n)->Flags.status = (l))
00123 
00124 #define error(code)  longjmp(*(e), code)
00125 
00126 #define MemGet(ptr, type) \
00127   if (UNLIKELY (((ptr) = (type *)malloc(sizeof(type))) == NULL))        \
00128     error(err_no_memory);
00129 
00130 #undef DEBUG_LABEL
00131 #undef DEBUG_ALL_LABELS
00132 #undef DEBUG_JUMP
00133 #undef DEBUG_GATHER
00134 #undef DEBUG_ANGLE
00135 #undef DEBUG
00136 #ifdef DEBUG
00137 #define DEBUGP(...) pcb_fprintf(stderr, ## __VA_ARGS__)
00138 #else
00139 #define DEBUGP(...)
00140 #endif
00141 
00142 /* 2-Dimentional stuff */
00143 
00144 #define Vsub2(r,a,b)    {(r)[0] = (a)[0] - (b)[0]; (r)[1] = (a)[1] - (b)[1];}
00145 #define Vadd2(r,a,b)    {(r)[0] = (a)[0] + (b)[0]; (r)[1] = (a)[1] + (b)[1];}
00146 #define Vsca2(r,a,s)    {(r)[0] = (a)[0] * (s); (r)[1] = (a)[1] * (s);}
00147 #define Vcpy2(r,a)              {(r)[0] = (a)[0]; (r)[1] = (a)[1];}
00148 #define Vequ2(a,b)              ((a)[0] == (b)[0] && (a)[1] == (b)[1])
00149 #define Vadds(r,a,b,s)  {(r)[0] = ((a)[0] + (b)[0]) * (s); (r)[1] = ((a)[1] + (b)[1]) * (s);}
00150 #define Vswp2(a,b) { long t; \
00151         t = (a)[0], (a)[0] = (b)[0], (b)[0] = t; \
00152         t = (a)[1], (a)[1] = (b)[1], (b)[1] = t; \
00153 }
00154 
00155 #ifdef DEBUG
00156 static char *theState (VNODE * v);
00157 
00158 static void
00159 pline_dump (VNODE * v)
00160 {
00161   VNODE *s, *n;
00162 
00163   s = v;
00164   do
00165     {
00166       n = v->next;
00167       pcb_fprintf (stderr, "Line [%#mS %#mS %#mS %#mS 10 10 \"%s\"]\n",
00168                v->point[0], v->point[1],
00169                n->point[0], n->point[1], theState (v));
00170     }
00171   while ((v = v->next) != s);
00172 }
00173 
00174 static void
00175 poly_dump (POLYAREA * p)
00176 {
00177   POLYAREA *f = p;
00178   PLINE *pl;
00179 
00180   do
00181     {
00182       pl = p->contours;
00183       do
00184         {
00185           pline_dump (&pl->head);
00186           fprintf (stderr, "NEXT PLINE\n");
00187         }
00188       while ((pl = pl->next) != NULL);
00189       fprintf (stderr, "NEXT POLY\n");
00190     }
00191   while ((p = p->f) != f);
00192 }
00193 #endif
00194 
00195 /* routines for processing intersections */
00196 
00210 static VNODE *
00211 node_add_single (VNODE * dest, Vector po)
00212 {
00213   VNODE *p;
00214 
00215   if (vect_equal (po, dest->point))
00216     return dest;
00217   if (vect_equal (po, dest->next->point))
00218     return dest->next;
00219   p = poly_CreateNode (po);
00220   if (p == NULL)
00221     return NULL;
00222   p->cvc_prev = p->cvc_next = NULL;
00223   p->Flags.status = UNKNWN;
00224   return p;
00225 }                               /* node_add */
00226 
00227 #define ISECT_BAD_PARAM (-1)
00228 #define ISECT_NO_MEMORY (-2)
00229 
00230 
00236 static CVCList *
00237 new_descriptor (VNODE * a, char poly, char side)
00238 {
00239   CVCList *l = (CVCList *) malloc (sizeof (CVCList));
00240   Vector v;
00241   register double ang, dx, dy;
00242 
00243   if (!l)
00244     return NULL;
00245   l->head = NULL;
00246   l->parent = a;
00247   l->poly = poly;
00248   l->side = side;
00249   l->next = l->prev = l;
00250   if (side == 'P')              /* previous */
00251     vect_sub (v, a->prev->point, a->point);
00252   else                          /* next */
00253     vect_sub (v, a->next->point, a->point);
00254   /* Uses slope/(slope+1) in quadrant 1 as a proxy for the angle.
00255    * It still has the same monotonic sort result
00256    * and is far less expensive to compute than the real angle.
00257    */
00258   if (vect_equal (v, vect_zero))
00259     {
00260       if (side == 'P')
00261         {
00262           if (a->prev->cvc_prev == (CVCList *) - 1)
00263             a->prev->cvc_prev = a->prev->cvc_next = NULL;
00264           poly_ExclVertex (a->prev);
00265           vect_sub (v, a->prev->point, a->point);
00266         }
00267       else
00268         {
00269           if (a->next->cvc_prev == (CVCList *) - 1)
00270             a->next->cvc_prev = a->next->cvc_next = NULL;
00271           poly_ExclVertex (a->next);
00272           vect_sub (v, a->next->point, a->point);
00273         }
00274     }
00275   assert (!vect_equal (v, vect_zero));
00276   dx = fabs ((double) v[0]);
00277   dy = fabs ((double) v[1]);
00278   ang = dy / (dy + dx);
00279   /* now move to the actual quadrant */
00280   if (v[0] < 0 && v[1] >= 0)
00281     ang = 2.0 - ang;            /* 2nd quadrant */
00282   else if (v[0] < 0 && v[1] < 0)
00283     ang += 2.0;                 /* 3rd quadrant */
00284   else if (v[0] >= 0 && v[1] < 0)
00285     ang = 4.0 - ang;            /* 4th quadrant */
00286   l->angle = ang;
00287   assert (ang >= 0.0 && ang <= 4.0);
00288 #ifdef DEBUG_ANGLE
00289   DEBUGP ("node on %c at %#mD assigned angle %g on side %c\n", poly,
00290           a->point[0], a->point[1], ang, side);
00291 #endif
00292   return l;
00293 }
00294 
00306 static CVCList *
00307 insert_descriptor (VNODE * a, char poly, char side, CVCList * start)
00308 {
00309   CVCList *l, *newone, *big, *small;
00310 
00311   if (!(newone = new_descriptor (a, poly, side)))
00312     return NULL;
00313   /* search for the CVCList for this point */
00314   if (!start)
00315     {
00316       start = newone;           /* return is also new, so we know where start is */
00317       start->head = newone;     /* circular list */
00318       return newone;
00319     }
00320   else
00321     {
00322       l = start;
00323       do
00324         {
00325           assert (l->head);
00326           if (l->parent->point[0] == a->point[0]
00327               && l->parent->point[1] == a->point[1])
00328             {                   /* this CVCList is at our point */
00329               start = l;
00330               newone->head = l->head;
00331               break;
00332             }
00333           if (l->head->parent->point[0] == start->parent->point[0]
00334               && l->head->parent->point[1] == start->parent->point[1])
00335             {
00336               /* this seems to be a new point */
00337               /* link this cvclist to the list of all cvclists */
00338               for (; l->head != newone; l = l->next)
00339                 l->head = newone;
00340               newone->head = start;
00341               return newone;
00342             }
00343           l = l->head;
00344         }
00345       while (1);
00346     }
00347   assert (start);
00348   l = big = small = start;
00349   do
00350     {
00351       if (l->next->angle < l->angle)    /* find start/end of list */
00352         {
00353           small = l->next;
00354           big = l;
00355         }
00356       else if (newone->angle >= l->angle && newone->angle <= l->next->angle)
00357         {
00358           /* insert new cvc if it lies between existing points */
00359           newone->prev = l;
00360           newone->next = l->next;
00361           l->next = l->next->prev = newone;
00362           return newone;
00363         }
00364     }
00365   while ((l = l->next) != start);
00366   /* didn't find it between points, it must go on an end */
00367   if (big->angle <= newone->angle)
00368     {
00369       newone->prev = big;
00370       newone->next = big->next;
00371       big->next = big->next->prev = newone;
00372       return newone;
00373     }
00374   assert (small->angle >= newone->angle);
00375   newone->next = small;
00376   newone->prev = small->prev;
00377   small->prev = small->prev->next = newone;
00378   return newone;
00379 }
00380 
00391 static VNODE *
00392 node_add_single_point (VNODE * a, Vector p)
00393 {
00394   VNODE *next_a, *new_node;
00395 
00396   next_a = a->next;
00397 
00398   new_node = node_add_single (a, p);
00399   assert (new_node != NULL);
00400 
00401   new_node->cvc_prev = new_node->cvc_next = (CVCList *) - 1;
00402 
00403   if (new_node == a || new_node == next_a)
00404     return NULL;
00405 
00406   return new_node;
00407 }                               /* node_add_point */
00408 
00414 static unsigned int
00415 node_label (VNODE * pn)
00416 {
00417   CVCList *first_l, *l;
00418   char this_poly;
00419   int region = UNKNWN;
00420 
00421   assert (pn);
00422   assert (pn->cvc_next);
00423   this_poly = pn->cvc_next->poly;
00424   /* search counter-clockwise in the cross vertex connectivity (CVC) list
00425    *
00426    * check for shared edges (that could be prev or next in the list since the angles are equal)
00427    * and check if this edge (pn -> pn->next) is found between the other poly's entry and exit
00428    */
00429   if (pn->cvc_next->angle == pn->cvc_next->prev->angle)
00430     l = pn->cvc_next->prev;
00431   else
00432     l = pn->cvc_next->next;
00433 
00434   first_l = l;
00435   while ((l->poly == this_poly) && (l != first_l->prev))
00436     l = l->next;
00437   assert (l->poly != this_poly);
00438 
00439   assert (l && l->angle >= 0 && l->angle <= 4.0);
00440   if (l->poly != this_poly)
00441     {
00442       if (l->side == 'P')
00443         {
00444           if (l->parent->prev->point[0] == pn->next->point[0] &&
00445               l->parent->prev->point[1] == pn->next->point[1])
00446             {
00447               region = SHARED2;
00448               pn->shared = l->parent->prev;
00449             }
00450           else
00451             region = INSIDE;
00452         }
00453       else
00454         {
00455           if (l->angle == pn->cvc_next->angle)
00456             {
00457               assert (l->parent->next->point[0] == pn->next->point[0] &&
00458                       l->parent->next->point[1] == pn->next->point[1]);
00459               region = SHARED;
00460               pn->shared = l->parent;
00461             }
00462           else
00463             region = OUTSIDE;
00464         }
00465     }
00466   if (region == UNKNWN)
00467     {
00468       for (l = l->next; l != pn->cvc_next; l = l->next)
00469         {
00470           if (l->poly != this_poly)
00471             {
00472               if (l->side == 'P')
00473                 region = INSIDE;
00474               else
00475                 region = OUTSIDE;
00476               break;
00477             }
00478         }
00479     }
00480   assert (region != UNKNWN);
00481   assert (NODE_LABEL (pn) == UNKNWN || NODE_LABEL (pn) == region);
00482   LABEL_NODE (pn, region);
00483   if (region == SHARED || region == SHARED2)
00484     return UNKNWN;
00485   return region;
00486 }                               /* node_label */
00487 
00493 static CVCList *
00494 add_descriptors (PLINE * pl, char poly, CVCList * list)
00495 {
00496   VNODE *node = &pl->head;
00497 
00498   do
00499     {
00500       if (node->cvc_prev)
00501         {
00502           assert (node->cvc_prev == (CVCList *) - 1
00503                   && node->cvc_next == (CVCList *) - 1);
00504           list = node->cvc_prev = insert_descriptor (node, poly, 'P', list);
00505           if (!node->cvc_prev)
00506             return NULL;
00507           list = node->cvc_next = insert_descriptor (node, poly, 'N', list);
00508           if (!node->cvc_next)
00509             return NULL;
00510         }
00511     }
00512   while ((node = node->next) != &pl->head);
00513   return list;
00514 }
00515 
00516 static inline void
00517 cntrbox_adjust (PLINE * c, Vector p)
00518 {
00519   c->xmin = min (c->xmin, p[0]);
00520   c->xmax = max (c->xmax, p[0] + 1);
00521   c->ymin = min (c->ymin, p[1]);
00522   c->ymax = max (c->ymax, p[1] + 1);
00523 }
00524 
00525 /* some structures for handling segment intersections using the rtrees */
00526 
00527 typedef struct seg
00528 {
00529   BoxType box;
00530   VNODE *v;
00531   PLINE *p;
00532   int intersected;
00533 } seg;
00534 
00535 typedef struct _insert_node_task insert_node_task;
00536 
00537 struct _insert_node_task
00538 {
00539   insert_node_task *next;
00540   seg * node_seg;
00541   VNODE *new_node;
00542 };
00543 
00544 typedef struct info
00545 {
00546   double m, b;
00547   rtree_t *tree;
00548   VNODE *v;
00549   struct seg *s;
00550   jmp_buf *env, sego, *touch;
00551   int need_restart;
00552   insert_node_task *node_insert_list;
00553 } info;
00554 
00555 typedef struct contour_info
00556 {
00557   PLINE *pa;
00558   jmp_buf restart;
00559   jmp_buf *getout;
00560   int need_restart;
00561   insert_node_task *node_insert_list;
00562 } contour_info;
00563 
00564 
00573 static int
00574 adjust_tree (rtree_t * tree, struct seg *s)
00575 {
00576   struct seg *q;
00577 
00578   q = (seg *)malloc (sizeof (struct seg));
00579   if (!q)
00580     return 1;
00581   q->intersected = 0;
00582   q->v = s->v;
00583   q->p = s->p;
00584   q->box.X1 = min (q->v->point[0], q->v->next->point[0]);
00585   q->box.X2 = max (q->v->point[0], q->v->next->point[0]) + 1;
00586   q->box.Y1 = min (q->v->point[1], q->v->next->point[1]);
00587   q->box.Y2 = max (q->v->point[1], q->v->next->point[1]) + 1;
00588   r_insert_entry (tree, (const BoxType *) q, 1);
00589   q = (seg *)malloc (sizeof (struct seg));
00590   if (!q)
00591     return 1;
00592   q->intersected = 0;
00593   q->v = s->v->next;
00594   q->p = s->p;
00595   q->box.X1 = min (q->v->point[0], q->v->next->point[0]);
00596   q->box.X2 = max (q->v->point[0], q->v->next->point[0]) + 1;
00597   q->box.Y1 = min (q->v->point[1], q->v->next->point[1]);
00598   q->box.Y2 = max (q->v->point[1], q->v->next->point[1]) + 1;
00599   r_insert_entry (tree, (const BoxType *) q, 1);
00600   r_delete_entry (tree, (const BoxType *) s);
00601   return 0;
00602 }
00603 
00611 static int
00612 seg_in_region (const BoxType * b, void *cl)
00613 {
00614   struct info *i = (struct info *) cl;
00615   double y1, y2;
00616   /* for zero slope the search is aligned on the axis so it is already pruned */
00617   if (i->m == 0.)
00618     return 1;
00619   y1 = i->m * b->X1 + i->b;
00620   y2 = i->m * b->X2 + i->b;
00621   if (min (y1, y2) >= b->Y2)
00622     return 0;
00623   if (max (y1, y2) < b->Y1)
00624     return 0;
00625   return 1;                     /* might intersect */
00626 }
00627 
00631 static insert_node_task *
00632 prepend_insert_node_task (insert_node_task *list, seg *seg, VNODE *new_node)
00633 {
00634   insert_node_task *task = (insert_node_task *)malloc (sizeof (*task));
00635   task->node_seg = seg;
00636   task->new_node = new_node;
00637   task->next = list;
00638   return task;
00639 }
00640 
00658 static int
00659 seg_in_seg (const BoxType * b, void *cl)
00660 {
00661   struct info *i = (struct info *) cl;
00662   struct seg *s = (struct seg *) b;
00663   Vector s1, s2;
00664   int cnt;
00665   VNODE *new_node;
00666 
00667   /* When new nodes are added at the end of a pass due to an intersection
00668    * the segments may be altered. If either segment we're looking at has
00669    * already been intersected this pass, skip it until the next pass.
00670    */
00671   if (s->intersected || i->s->intersected)
00672     return 0;
00673 
00674   cnt = vect_inters2 (s->v->point, s->v->next->point,
00675                       i->v->point, i->v->next->point, s1, s2);
00676   if (!cnt)
00677     return 0;
00678   if (i->touch)                 /* if checking touches one find and we're done */
00679     longjmp (*i->touch, TOUCHES);
00680   i->s->p->Flags.status = ISECTED;
00681   s->p->Flags.status = ISECTED;
00682   for (; cnt; cnt--)
00683     {
00684       bool done_insert_on_i = false;
00685       new_node = node_add_single_point (i->v, cnt > 1 ? s2 : s1);
00686       if (new_node != NULL)
00687         {
00688 #ifdef DEBUG_INTERSECT
00689           DEBUGP ("new intersection on segment \"i\" at %#mD\n",
00690                   cnt > 1 ? s2[0] : s1[0], cnt > 1 ? s2[1] : s1[1]);
00691 #endif
00692           i->node_insert_list =
00693             prepend_insert_node_task (i->node_insert_list, i->s, new_node);
00694           i->s->intersected = 1;
00695           done_insert_on_i = true;
00696         }
00697       new_node = node_add_single_point (s->v, cnt > 1 ? s2 : s1);
00698       if (new_node != NULL)
00699         {
00700 #ifdef DEBUG_INTERSECT
00701           DEBUGP ("new intersection on segment \"s\" at %#mD\n",
00702                   cnt > 1 ? s2[0] : s1[0], cnt > 1 ? s2[1] : s1[1]);
00703 #endif
00704           i->node_insert_list =
00705             prepend_insert_node_task (i->node_insert_list, s, new_node);
00706           s->intersected = 1;
00707           return 0; /* Keep looking for intersections with segment "i" */
00708         }
00709       /* Skip any remaining r_search hits against segment i, as any futher
00710        * intersections will be rejected until the next pass anyway.
00711        */
00712       if (done_insert_on_i)
00713         longjmp (*i->env, 1);
00714     }
00715   return 0;
00716 }
00717 
00718 static void *
00719 make_edge_tree (PLINE * pb)
00720 {
00721   struct seg *s;
00722   VNODE *bv;
00723   rtree_t *ans = r_create_tree (NULL, 0, 0);
00724   bv = &pb->head;
00725   do
00726     {
00727       s = (seg *)malloc (sizeof (struct seg));
00728       s->intersected = 0;
00729       if (bv->point[0] < bv->next->point[0])
00730         {
00731           s->box.X1 = bv->point[0];
00732           s->box.X2 = bv->next->point[0] + 1;
00733         }
00734       else
00735         {
00736           s->box.X2 = bv->point[0] + 1;
00737           s->box.X1 = bv->next->point[0];
00738         }
00739       if (bv->point[1] < bv->next->point[1])
00740         {
00741           s->box.Y1 = bv->point[1];
00742           s->box.Y2 = bv->next->point[1] + 1;
00743         }
00744       else
00745         {
00746           s->box.Y2 = bv->point[1] + 1;
00747           s->box.Y1 = bv->next->point[1];
00748         }
00749       s->v = bv;
00750       s->p = pb;
00751       r_insert_entry (ans, (const BoxType *) s, 1);
00752     }
00753   while ((bv = bv->next) != &pb->head);
00754   return (void *) ans;
00755 }
00756 
00757 static int
00758 get_seg (const BoxType * b, void *cl)
00759 {
00760   struct info *i = (struct info *) cl;
00761   struct seg *s = (struct seg *) b;
00762   if (i->v == s->v)
00763     {
00764       i->s = s;
00765       longjmp (i->sego, 1);
00766     }
00767   return 0;
00768 }
00769 
00792 static int
00793 contour_bounds_touch (const BoxType * b, void *cl)
00794 {
00795   contour_info *c_info = (contour_info *) cl;
00796   PLINE *pa = c_info->pa;
00797   PLINE *pb = (PLINE *) b;
00798   PLINE *rtree_over;
00799   PLINE *looping_over;
00800   VNODE *av;                    /* node iterators */
00801   struct info info;
00802   BoxType box;
00803   jmp_buf restart;
00804 
00805   /* Have seg_in_seg return to our desired location if it touches */
00806   info.env = &restart;
00807   info.touch = c_info->getout;
00808   info.need_restart = 0;
00809   info.node_insert_list = c_info->node_insert_list;
00810 
00811   /* Pick which contour has the fewer points, and do the loop
00812    * over that. The r_tree makes hit-testing against a contour
00813    * faster, so we want to do that on the bigger contour.
00814    */
00815   if (pa->Count < pb->Count)
00816     {
00817       rtree_over = pb;
00818       looping_over = pa;
00819     }
00820   else
00821     {
00822       rtree_over = pa;
00823       looping_over = pb;
00824     }
00825 
00826   av = &looping_over->head;
00827   do                            /* Loop over the nodes in the smaller contour */
00828     {
00829       /* check this edge for any insertions */
00830       double dx;
00831       info.v = av;
00832       /* compute the slant for region trimming */
00833       dx = av->next->point[0] - av->point[0];
00834       if (dx == 0)
00835         info.m = 0;
00836       else
00837         {
00838           info.m = (av->next->point[1] - av->point[1]) / dx;
00839           info.b = av->point[1] - info.m * av->point[0];
00840         }
00841       box.X2 = (box.X1 = av->point[0]) + 1;
00842       box.Y2 = (box.Y1 = av->point[1]) + 1;
00843 
00844       /* fill in the segment in info corresponding to this node */
00845       if (setjmp (info.sego) == 0)
00846         {
00847           r_search (looping_over->tree, &box, NULL, get_seg, &info);
00848           assert (0);
00849         }
00850 
00851       /* If we're going to have another pass anyway, skip this */
00852       if (info.s->intersected && info.node_insert_list != NULL)
00853         continue;
00854 
00855       if (setjmp (restart))
00856         continue;
00857 
00858       /* NB: If this actually hits anything, we are teleported back to the beginning */
00859       info.tree = rtree_over->tree;
00860       if (info.tree)
00861         if (UNLIKELY (r_search (info.tree, &info.s->box,
00862                                 seg_in_region, seg_in_seg, &info)))
00863           assert (0); /* XXX: Memory allocation failure */
00864     }
00865   while ((av = av->next) != &looping_over->head);
00866 
00867   c_info->node_insert_list = info.node_insert_list;
00868   if (info.need_restart)
00869     c_info->need_restart = 1;
00870   return 0;
00871 }
00872 
00873 static int
00874 intersect_impl (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
00875 {
00876   POLYAREA *t;
00877   PLINE *pa;
00878   contour_info c_info;
00879   int need_restart = 0;
00880   insert_node_task *task;
00881   c_info.need_restart = 0;
00882   c_info.node_insert_list = NULL;
00883 
00884   /* Search the r-tree of the object with most contours
00885    * We loop over the contours of "a". Swap if necessary.
00886    */
00887   if (a->contour_tree->size > b->contour_tree->size)
00888     {
00889       t = b;
00890       b = a;
00891       a = t;
00892     }
00893 
00894   for (pa = a->contours; pa; pa = pa->next)     /* Loop over the contours of POLYAREA "a" */
00895     {
00896       BoxType sb;
00897       jmp_buf out;
00898       int retval;
00899 
00900       c_info.getout = NULL;
00901       c_info.pa = pa;
00902 
00903       if (!add)
00904         {
00905           retval = setjmp (out);
00906           if (retval)
00907             {
00908               /* The intersection test short-circuited back here,
00909                * we need to clean up, then longjmp to jb */
00910               longjmp (*jb, retval);
00911             }
00912           c_info.getout = &out;
00913         }
00914 
00915       sb.X1 = pa->xmin;
00916       sb.Y1 = pa->ymin;
00917       sb.X2 = pa->xmax + 1;
00918       sb.Y2 = pa->ymax + 1;
00919 
00920       r_search (b->contour_tree, &sb, NULL, contour_bounds_touch, &c_info);
00921       if (c_info.need_restart)
00922         need_restart = 1;
00923     }
00924 
00925   /* Process any deferred node insersions */
00926   task = c_info.node_insert_list;
00927   while (task != NULL)
00928     {
00929       insert_node_task *next = task->next;
00930 
00931       /* Do insersion */
00932       task->new_node->prev = task->node_seg->v;
00933       task->new_node->next = task->node_seg->v->next;
00934       task->node_seg->v->next->prev = task->new_node;
00935       task->node_seg->v->next = task->new_node;
00936       task->node_seg->p->Count++;
00937 
00938       cntrbox_adjust (task->node_seg->p, task->new_node->point);
00939       if (adjust_tree (task->node_seg->p->tree, task->node_seg))
00940         assert (0); /* XXX: Memory allocation failure */
00941 
00942       need_restart = 1; /* Any new nodes could intersect */
00943 
00944       free (task);
00945       task = next;
00946     }
00947 
00948   return need_restart;
00949 }
00950 
00951 static int
00952 intersect (jmp_buf * jb, POLYAREA * b, POLYAREA * a, int add)
00953 {
00954   int call_count = 1;
00955   while (intersect_impl (jb, b, a, add))
00956     call_count++;
00957   return 0;
00958 }
00959 
00960 static void
00961 M_POLYAREA_intersect (jmp_buf * e, POLYAREA * afst, POLYAREA * bfst, int add)
00962 {
00963   POLYAREA *a = afst, *b = bfst;
00964   PLINE *curcA, *curcB;
00965   CVCList *the_list = NULL;
00966 
00967   if (a == NULL || b == NULL)
00968     error (err_bad_parm);
00969   do
00970     {
00971       do
00972         {
00973           if (a->contours->xmax >= b->contours->xmin &&
00974               a->contours->ymax >= b->contours->ymin &&
00975               a->contours->xmin <= b->contours->xmax &&
00976               a->contours->ymin <= b->contours->ymax)
00977             {
00978               if (UNLIKELY (intersect (e, a, b, add)))
00979                 error (err_no_memory);
00980             }
00981         }
00982       while (add && (a = a->f) != afst);
00983       for (curcB = b->contours; curcB != NULL; curcB = curcB->next)
00984         if (curcB->Flags.status == ISECTED)
00985           {
00986             the_list = add_descriptors (curcB, 'B', the_list);
00987             if (UNLIKELY (the_list == NULL))
00988               error (err_no_memory);
00989           }
00990     }
00991   while (add && (b = b->f) != bfst);
00992   do
00993     {
00994       for (curcA = a->contours; curcA != NULL; curcA = curcA->next)
00995         if (curcA->Flags.status == ISECTED)
00996           {
00997             the_list = add_descriptors (curcA, 'A', the_list);
00998             if (UNLIKELY (the_list == NULL))
00999               error (err_no_memory);
01000           }
01001     }
01002   while (add && (a = a->f) != afst);
01003 }                               /* M_POLYAREA_intersect */
01004 
01005 static inline int
01006 cntrbox_inside (PLINE * c1, PLINE * c2)
01007 {
01008   assert (c1 != NULL && c2 != NULL);
01009   return ((c1->xmin >= c2->xmin) &&
01010           (c1->ymin >= c2->ymin) &&
01011           (c1->xmax <= c2->xmax) && (c1->ymax <= c2->ymax));
01012 }
01013 
01014 /* Routines for making labels */
01015 
01016 static int
01017 count_contours_i_am_inside (const BoxType * b, void *cl)
01018 {
01019   PLINE *me = (PLINE *) cl;
01020   PLINE *check = (PLINE *) b;
01021 
01022   if (poly_ContourInContour (check, me))
01023     return 1;
01024   return 0;
01025 }
01026 
01032 static int
01033 cntr_in_M_POLYAREA (PLINE * poly, POLYAREA * outfst, BOOLp test)
01034 {
01035   POLYAREA *outer = outfst;
01036   heap_t *heap;
01037 
01038   assert (poly != NULL);
01039   assert (outer != NULL);
01040 
01041   heap = heap_create ();
01042   do
01043     {
01044       if (cntrbox_inside (poly, outer->contours))
01045         heap_insert (heap, outer->contours->area, (void *) outer);
01046     }
01047   /* if checking touching, use only the first polygon */
01048   while (!test && (outer = outer->f) != outfst);
01049   /* we need only check the smallest poly container
01050    * but we must loop in case the box containter is not
01051    * the poly container */
01052   do
01053     {
01054       if (heap_is_empty (heap))
01055         break;
01056       outer = (POLYAREA *) heap_remove_smallest (heap);
01057 
01058       switch (r_search
01059               (outer->contour_tree, (BoxType *) poly, NULL,
01060                count_contours_i_am_inside, poly))
01061         {
01062         case 0:         /* Didn't find anything in this piece, Keep looking */
01063           break;
01064         case 1:         /* Found we are inside this piece, and not any of its holes */
01065           heap_destroy (&heap);
01066           return TRUE;
01067         case 2:         /* Found inside a hole in the smallest polygon so far. No need to check the other polygons */
01068           heap_destroy (&heap);
01069           return FALSE;
01070         default:
01071           printf ("Something strange here\n");
01072           break;
01073         }
01074     }
01075   while (1);
01076   heap_destroy (&heap);
01077   return FALSE;
01078 }                               /* cntr_in_M_POLYAREA */
01079 
01080 #ifdef DEBUG
01081 
01082 static char *
01083 theState (VNODE * v)
01084 {
01085   static char u[] = "UNKNOWN";
01086   static char i[] = "INSIDE";
01087   static char o[] = "OUTSIDE";
01088   static char s[] = "SHARED";
01089   static char s2[] = "SHARED2";
01090 
01091   switch (NODE_LABEL (v))
01092     {
01093     case INSIDE:
01094       return i;
01095     case OUTSIDE:
01096       return o;
01097     case SHARED:
01098       return s;
01099     case SHARED2:
01100       return s2;
01101     default:
01102       return u;
01103     }
01104 }
01105 
01106 #ifdef DEBUG_ALL_LABELS
01107 static void
01108 print_labels (PLINE * a)
01109 {
01110   VNODE *c = &a->head;
01111 
01112   do
01113     {
01114       DEBUGP ("%#mD->%#mD labeled %s\n", c->point[0], c->point[1],
01115               c->next->point[0], c->next->point[1], theState (c));
01116     }
01117   while ((c = c->next) != &a->head);
01118 }
01119 #endif
01120 #endif
01121 
01132 static BOOLp
01133 label_contour (PLINE * a)
01134 {
01135   VNODE *cur = &a->head;
01136   VNODE *first_labelled = NULL;
01137   int label = UNKNWN;
01138 
01139   do
01140     {
01141       if (cur->cvc_next)        /* examine cross vertex */
01142         {
01143           label = node_label (cur);
01144           if (first_labelled == NULL)
01145             first_labelled = cur;
01146           continue;
01147         }
01148 
01149       if (first_labelled == NULL)
01150         continue;
01151 
01152       /* This labels nodes which aren't cross-connected */
01153       assert (label == INSIDE || label == OUTSIDE);
01154       LABEL_NODE (cur, label);
01155     }
01156   while ((cur = cur->next) != first_labelled);
01157 #ifdef DEBUG_ALL_LABELS
01158   print_labels (a);
01159   DEBUGP ("\n\n");
01160 #endif
01161   return FALSE;
01162 }                               /* label_contour */
01163 
01164 static BOOLp
01165 cntr_label_POLYAREA (PLINE * poly, POLYAREA * ppl, BOOLp test)
01166 {
01167   assert (ppl != NULL && ppl->contours != NULL);
01168   if (poly->Flags.status == ISECTED)
01169     {
01170       label_contour (poly);     /* should never get here when BOOLp is true */
01171     }
01172   else if (cntr_in_M_POLYAREA (poly, ppl, test))
01173     {
01174       if (test)
01175         return TRUE;
01176       poly->Flags.status = INSIDE;
01177     }
01178   else
01179     {
01180       if (test)
01181         return false;
01182       poly->Flags.status = OUTSIDE;
01183     }
01184   return FALSE;
01185 }                               /* cntr_label_POLYAREA */
01186 
01187 static BOOLp
01188 M_POLYAREA_label_separated (PLINE * afst, POLYAREA * b, BOOLp touch)
01189 {
01190   PLINE *curc = afst;
01191 
01192   for (curc = afst; curc != NULL; curc = curc->next)
01193     {
01194       if (cntr_label_POLYAREA (curc, b, touch) && touch)
01195         return TRUE;
01196     }
01197   return FALSE;
01198 }
01199 
01200 static BOOLp
01201 M_POLYAREA_label (POLYAREA * afst, POLYAREA * b, BOOLp touch)
01202 {
01203   POLYAREA *a = afst;
01204   PLINE *curc;
01205 
01206   assert (a != NULL);
01207   do
01208     {
01209       for (curc = a->contours; curc != NULL; curc = curc->next)
01210         if (cntr_label_POLYAREA (curc, b, touch))
01211           {
01212             if (touch)
01213               return TRUE;
01214           }
01215     }
01216   while (!touch && (a = a->f) != afst);
01217   return FALSE;
01218 }
01219 
01220 
01224 static void
01225 InsCntr (jmp_buf * e, PLINE * c, POLYAREA ** dst)
01226 {
01227   POLYAREA *newp;
01228 
01229   if (*dst == NULL)
01230     {
01231       MemGet (*dst, POLYAREA);
01232       (*dst)->f = (*dst)->b = *dst;
01233       newp = *dst;
01234     }
01235   else
01236     {
01237       MemGet (newp, POLYAREA);
01238       newp->f = *dst;
01239       newp->b = (*dst)->b;
01240       newp->f->b = newp->b->f = newp;
01241     }
01242   newp->contours = c;
01243   newp->contour_tree = r_create_tree (NULL, 0, 0);
01244   r_insert_entry (newp->contour_tree, (BoxType *) c, 0);
01245   c->next = NULL;
01246 }                               /* InsCntr */
01247 
01248 static void
01249 PutContour (jmp_buf * e, PLINE * cntr, POLYAREA ** contours, PLINE ** holes,
01250             POLYAREA * owner, POLYAREA * parent, PLINE * parent_contour)
01251 {
01252   assert (cntr != NULL);
01253   assert (cntr->Count > 2);
01254   cntr->next = NULL;
01255 
01256   if (cntr->Flags.orient == PLF_DIR)
01257     {
01258       if (owner != NULL)
01259         r_delete_entry (owner->contour_tree, (BoxType *) cntr);
01260       InsCntr (e, cntr, contours);
01261     }
01262   /* put hole into temporary list */
01263   else
01264     {
01265       /* if we know this belongs inside the parent, put it there now */
01266       if (parent_contour)
01267         {
01268           cntr->next = parent_contour->next;
01269           parent_contour->next = cntr;
01270           if (owner != parent)
01271             {
01272               if (owner != NULL)
01273                 r_delete_entry (owner->contour_tree, (BoxType *) cntr);
01274               r_insert_entry (parent->contour_tree, (BoxType *) cntr, 0);
01275             }
01276         }
01277       else
01278         {
01279           cntr->next = *holes;
01280           *holes = cntr;        /* let cntr be 1st hole in list */
01281           /* We don't insert the holes into an r-tree,
01282            * they just form a linked list */
01283           if (owner != NULL)
01284             r_delete_entry (owner->contour_tree, (BoxType *) cntr);
01285         }
01286     }
01287 }                               /* PutContour */
01288 
01289 static inline void
01290 remove_contour (POLYAREA * piece, PLINE * prev_contour, PLINE * contour,
01291                 int remove_rtree_entry)
01292 {
01293   if (piece->contours == contour)
01294     piece->contours = contour->next;
01295   else if (prev_contour != NULL)
01296     {
01297       assert (prev_contour->next == contour);
01298       prev_contour->next = contour->next;
01299     }
01300 
01301   contour->next = NULL;
01302 
01303   if (remove_rtree_entry)
01304     r_delete_entry (piece->contour_tree, (BoxType *) contour);
01305 }
01306 
01307 struct polyarea_info
01308 {
01309   BoxType BoundingBox;
01310   POLYAREA *pa;
01311 };
01312 
01313 static int
01314 heap_it (const BoxType * b, void *cl)
01315 {
01316   heap_t *heap = (heap_t *) cl;
01317   struct polyarea_info *pa_info = (struct polyarea_info *) b;
01318   PLINE *p = pa_info->pa->contours;
01319   if (p->Count == 0)
01320     return 0;                   /* how did this happen? */
01321   heap_insert (heap, p->area, pa_info);
01322   return 1;
01323 }
01324 
01325 struct find_inside_info
01326 {
01327   jmp_buf jb;
01328   PLINE *want_inside;
01329   PLINE *result;
01330 };
01331 
01332 static int
01333 find_inside (const BoxType * b, void *cl)
01334 {
01335   struct find_inside_info *info = (struct find_inside_info *) cl;
01336   PLINE *check = (PLINE *) b;
01337   /* Do test on check to see if it inside info->want_inside */
01338   /* If it is: */
01339   if (check->Flags.orient == PLF_DIR)
01340     {
01341       return 0;
01342     }
01343   if (poly_ContourInContour (info->want_inside, check))
01344     {
01345       info->result = check;
01346       longjmp (info->jb, 1);
01347     }
01348   return 0;
01349 }
01350 
01351 static void
01352 InsertHoles (jmp_buf * e, POLYAREA * dest, PLINE ** src)
01353 {
01354   POLYAREA *curc;
01355   PLINE *curh, *container;
01356   heap_t *heap;
01357   rtree_t *tree;
01358   int i;
01359   int num_polyareas = 0;
01360   struct polyarea_info *all_pa_info, *pa_info;
01361 
01362   if (*src == NULL)
01363     return;                     /* empty hole list */
01364   if (dest == NULL)
01365     error (err_bad_parm);       /* empty contour list */
01366 
01367   /* Count dest polyareas */
01368   curc = dest;
01369   do
01370     {
01371       num_polyareas++;
01372     }
01373   while ((curc = curc->f) != dest);
01374 
01375   /* make a polyarea info table */
01376   /* make an rtree of polyarea info table */
01377   all_pa_info = (struct polyarea_info *) malloc (sizeof (struct polyarea_info) * num_polyareas);
01378   tree = r_create_tree (NULL, 0, 0);
01379   i = 0;
01380   curc = dest;
01381   do
01382     {
01383       all_pa_info[i].BoundingBox.X1 = curc->contours->xmin;
01384       all_pa_info[i].BoundingBox.Y1 = curc->contours->ymin;
01385       all_pa_info[i].BoundingBox.X2 = curc->contours->xmax;
01386       all_pa_info[i].BoundingBox.Y2 = curc->contours->ymax;
01387       all_pa_info[i].pa = curc;
01388       r_insert_entry (tree, (const BoxType *) &all_pa_info[i], 0);
01389       i++;
01390     }
01391   while ((curc = curc->f) != dest);
01392 
01393   /* loop through the holes and put them where they belong */
01394   while ((curh = *src) != NULL)
01395     {
01396       *src = curh->next;
01397 
01398       container = NULL;
01399       /* build a heap of all of the polys that the hole is inside its bounding box */
01400       heap = heap_create ();
01401       r_search (tree, (BoxType *) curh, NULL, heap_it, heap);
01402       if (heap_is_empty (heap))
01403         {
01404 #ifndef NDEBUG
01405 #ifdef DEBUG
01406           poly_dump (dest);
01407 #endif
01408 #endif
01409           poly_DelContour (&curh);
01410           error (err_bad_parm);
01411         }
01412       /* Now search the heap for the container. If there was only one item
01413        * in the heap, assume it is the container without the expense of
01414        * proving it.
01415        */
01416       pa_info = (struct polyarea_info *) heap_remove_smallest (heap);
01417       if (heap_is_empty (heap))
01418         {                       /* only one possibility it must be the right one */
01419           assert (poly_ContourInContour (pa_info->pa->contours, curh));
01420           container = pa_info->pa->contours;
01421         }
01422       else
01423         {
01424           do
01425             {
01426               if (poly_ContourInContour (pa_info->pa->contours, curh))
01427                 {
01428                   container = pa_info->pa->contours;
01429                   break;
01430                 }
01431               if (heap_is_empty (heap))
01432                 break;
01433               pa_info = (struct polyarea_info *) heap_remove_smallest (heap);
01434             }
01435           while (1);
01436         }
01437       heap_destroy (&heap);
01438       if (container == NULL)
01439         {
01440           /* bad input polygons were given */
01441 #ifndef NDEBUG
01442 #ifdef DEBUG
01443           poly_dump (dest);
01444 #endif
01445 #endif
01446           curh->next = NULL;
01447           poly_DelContour (&curh);
01448           error (err_bad_parm);
01449         }
01450       else
01451         {
01452           /* Need to check if this new hole means we need to kick out any old ones for reprocessing */
01453           while (1)
01454             {
01455               struct find_inside_info info;
01456               PLINE *prev;
01457 
01458               info.want_inside = curh;
01459 
01460               /* Set jump return */
01461               if (setjmp (info.jb))
01462                 {
01463                   /* Returned here! */
01464                 }
01465               else
01466                 {
01467                   info.result = NULL;
01468                   /* Rtree search, calling back a routine to longjmp back with data about any hole inside the added one */
01469                   /*   Be sure not to bother jumping back to report the main contour! */
01470                   r_search (pa_info->pa->contour_tree, (BoxType *) curh, NULL,
01471                             find_inside, &info);
01472 
01473                   /* Nothing found? */
01474                   break;
01475                 }
01476 
01477               /* We need to find the contour before it, so we can update its next pointer */
01478               prev = container;
01479               while (prev->next != info.result)
01480                 {
01481                   prev = prev->next;
01482                 }
01483 
01484               /* Remove hole from the contour */
01485               remove_contour (pa_info->pa, prev, info.result, TRUE);
01486 
01487               /* Add hole as the next on the list to be processed in this very function */
01488               info.result->next = *src;
01489               *src = info.result;
01490             }
01491           /* End check for kicked out holes */
01492 
01493           /* link at front of hole list */
01494           curh->next = container->next;
01495           container->next = curh;
01496           r_insert_entry (pa_info->pa->contour_tree, (BoxType *) curh, 0);
01497 
01498         }
01499     }
01500   r_destroy_tree (&tree);
01501   free (all_pa_info);
01502 }                               /* InsertHoles */
01503 
01504 
01505 /* routines for collecting result */
01506 
01507 typedef enum
01508 {
01509   FORW, BACKW
01510 } DIRECTION;
01511 
01515 typedef int (*S_Rule) (VNODE *, DIRECTION *);
01516 
01520 typedef int (*J_Rule) (char, VNODE *, DIRECTION *);
01521 
01522 static int
01523 UniteS_Rule (VNODE * cur, DIRECTION * initdir)
01524 {
01525   *initdir = FORW;
01526   return (NODE_LABEL (cur) == OUTSIDE) || (NODE_LABEL (cur) == SHARED);
01527 }
01528 
01529 static int
01530 IsectS_Rule (VNODE * cur, DIRECTION * initdir)
01531 {
01532   *initdir = FORW;
01533   return (NODE_LABEL (cur) == INSIDE) || (NODE_LABEL (cur) == SHARED);
01534 }
01535 
01536 static int
01537 SubS_Rule (VNODE * cur, DIRECTION * initdir)
01538 {
01539   *initdir = FORW;
01540   return (NODE_LABEL (cur) == OUTSIDE) || (NODE_LABEL (cur) == SHARED2);
01541 }
01542 
01543 static int
01544 XorS_Rule (VNODE * cur, DIRECTION * initdir)
01545 {
01546   if (cur->Flags.status == INSIDE)
01547     {
01548       *initdir = BACKW;
01549       return TRUE;
01550     }
01551   if (cur->Flags.status == OUTSIDE)
01552     {
01553       *initdir = FORW;
01554       return TRUE;
01555     }
01556   return FALSE;
01557 }
01558 
01559 static int
01560 IsectJ_Rule (char p, VNODE * v, DIRECTION * cdir)
01561 {
01562   assert (*cdir == FORW);
01563   return (v->Flags.status == INSIDE || v->Flags.status == SHARED);
01564 }
01565 
01566 static int
01567 UniteJ_Rule (char p, VNODE * v, DIRECTION * cdir)
01568 {
01569   assert (*cdir == FORW);
01570   return (v->Flags.status == OUTSIDE || v->Flags.status == SHARED);
01571 }
01572 
01573 static int
01574 XorJ_Rule (char p, VNODE * v, DIRECTION * cdir)
01575 {
01576   if (v->Flags.status == INSIDE)
01577     {
01578       *cdir = BACKW;
01579       return TRUE;
01580     }
01581   if (v->Flags.status == OUTSIDE)
01582     {
01583       *cdir = FORW;
01584       return TRUE;
01585     }
01586   return FALSE;
01587 }
01588 
01589 static int
01590 SubJ_Rule (char p, VNODE * v, DIRECTION * cdir)
01591 {
01592   if (p == 'B' && v->Flags.status == INSIDE)
01593     {
01594       *cdir = BACKW;
01595       return TRUE;
01596     }
01597   if (p == 'A' && v->Flags.status == OUTSIDE)
01598     {
01599       *cdir = FORW;
01600       return TRUE;
01601     }
01602   if (v->Flags.status == SHARED2)
01603     {
01604       if (p == 'A')
01605         *cdir = FORW;
01606       else
01607         *cdir = BACKW;
01608       return TRUE;
01609     }
01610   return FALSE;
01611 }
01612 
01621 static int
01622 jump (VNODE ** cur, DIRECTION * cdir, J_Rule rule)
01623 {
01624   CVCList *d, *start;
01625   VNODE *e;
01626   DIRECTION newone;
01627 
01628   if (!(*cur)->cvc_prev)        /* not a cross-vertex */
01629     {
01630       if (*cdir == FORW ? (*cur)->Flags.mark : (*cur)->prev->Flags.mark)
01631         return FALSE;
01632       return TRUE;
01633     }
01634 #ifdef DEBUG_JUMP
01635   DEBUGP ("jump entering node at %$mD\n", (*cur)->point[0], (*cur)->point[1]);
01636 #endif
01637   if (*cdir == FORW)
01638     d = (*cur)->cvc_prev->prev;
01639   else
01640     d = (*cur)->cvc_next->prev;
01641   start = d;
01642   do
01643     {
01644       e = d->parent;
01645       if (d->side == 'P')
01646         e = e->prev;
01647       newone = *cdir;
01648       if (!e->Flags.mark && rule (d->poly, e, &newone))
01649         {
01650           if ((d->side == 'N' && newone == FORW) ||
01651               (d->side == 'P' && newone == BACKW))
01652             {
01653 #ifdef DEBUG_JUMP
01654               if (newone == FORW)
01655                 DEBUGP ("jump leaving node at %#mD\n",
01656                         e->next->point[0], e->next->point[1]);
01657               else
01658                 DEBUGP ("jump leaving node at %#mD\n",
01659                         e->point[0], e->point[1]);
01660 #endif
01661               *cur = d->parent;
01662               *cdir = newone;
01663               return TRUE;
01664             }
01665         }
01666     }
01667   while ((d = d->prev) != start);
01668   return FALSE;
01669 }
01670 
01671 static int
01672 Gather (VNODE * start, PLINE ** result, J_Rule v_rule, DIRECTION initdir)
01673 {
01674   VNODE *cur = start, *newn;
01675   DIRECTION dir = initdir;
01676 #ifdef DEBUG_GATHER
01677   DEBUGP ("gather direction = %d\n", dir);
01678 #endif
01679   assert (*result == NULL);
01680   do
01681     {
01682       /* see where to go next */
01683       if (!jump (&cur, &dir, v_rule))
01684         break;
01685       /* add edge to polygon */
01686       if (!*result)
01687         {
01688           *result = poly_NewContour (cur->point);
01689           if (*result == NULL)
01690             return err_no_memory;
01691         }
01692       else
01693         {
01694           if ((newn = poly_CreateNode (cur->point)) == NULL)
01695             return err_no_memory;
01696           poly_InclVertex ((*result)->head.prev, newn);
01697         }
01698 #ifdef DEBUG_GATHER
01699       DEBUGP ("gather vertex at %#mD\n", cur->point[0], cur->point[1]);
01700 #endif
01701       /* Now mark the edge as included.  */
01702       newn = (dir == FORW ? cur : cur->prev);
01703       newn->Flags.mark = 1;
01704       /* for SHARED edge mark both */
01705       if (newn->shared)
01706         newn->shared->Flags.mark = 1;
01707 
01708       /* Advance to the next edge.  */
01709       cur = (dir == FORW ? cur->next : cur->prev);
01710     }
01711   while (1);
01712   return err_ok;
01713 }                               /* Gather */
01714 
01715 static void
01716 Collect1 (jmp_buf * e, VNODE * cur, DIRECTION dir, POLYAREA ** contours,
01717           PLINE ** holes, J_Rule j_rule)
01718 {
01719   PLINE *p = NULL;              /* start making contour */
01720   int errc = err_ok;
01721   if ((errc =
01722        Gather (cur, &p, j_rule, dir)) != err_ok)
01723     {
01724       if (p != NULL)
01725         poly_DelContour (&p);
01726       error (errc);
01727     }
01728   if (!p)
01729     return;
01730   poly_PreContour (p, TRUE);
01731   if (p->Count > 2)
01732     {
01733 #ifdef DEBUG_GATHER
01734       DEBUGP ("adding contour with %d verticies and direction %c\n",
01735               p->Count, p->Flags.orient ? 'F' : 'B');
01736 #endif
01737       PutContour (e, p, contours, holes, NULL, NULL, NULL);
01738     }
01739   else
01740     {
01741       /* some sort of computation error ? */
01742 #ifdef DEBUG_GATHER
01743       DEBUGP ("Bad contour! Not enough points!!\n");
01744 #endif
01745       poly_DelContour (&p);
01746     }
01747 }
01748 
01749 static void
01750 Collect (jmp_buf * e, PLINE * a, POLYAREA ** contours, PLINE ** holes,
01751          S_Rule s_rule, J_Rule j_rule)
01752 {
01753   VNODE *cur, *other;
01754   DIRECTION dir;
01755 
01756   cur = &a->head;
01757   do
01758     {
01759       dir = FORW;       /* avoid uninitialized variable with XOR rule (side note: XOR not used in PCB anyway) */
01760       if (s_rule (cur, &dir) && cur->Flags.mark == 0)
01761         Collect1 (e, dir == FORW ? cur : cur->next, dir, contours, holes, j_rule);
01762                 /* Note: when the direction is not FORW, move to the vertex, Gather() should actually start from. */
01763       other = cur;
01764       if ((other->cvc_prev && jump (&other, &dir, j_rule)))
01765         Collect1 (e, other, dir, contours, holes, j_rule);
01766     }
01767   while ((cur = cur->next) != &a->head);
01768 }                               /* Collect */
01769 
01770 
01771 static int
01772 cntr_Collect (jmp_buf * e, PLINE ** A, POLYAREA ** contours, PLINE ** holes,
01773               int action, POLYAREA * owner, POLYAREA * parent,
01774               PLINE * parent_contour)
01775 {
01776   PLINE *tmprev;
01777 
01778   if ((*A)->Flags.status == ISECTED)
01779     {
01780       switch (action)
01781         {
01782         case PBO_UNITE:
01783           Collect (e, *A, contours, holes, UniteS_Rule, UniteJ_Rule);
01784           break;
01785         case PBO_ISECT:
01786           Collect (e, *A, contours, holes, IsectS_Rule, IsectJ_Rule);
01787           break;
01788         case PBO_XOR:
01789           Collect (e, *A, contours, holes, XorS_Rule, XorJ_Rule);
01790           break;
01791         case PBO_SUB:
01792           Collect (e, *A, contours, holes, SubS_Rule, SubJ_Rule);
01793           break;
01794         };
01795     }
01796   else
01797     {
01798       switch (action)
01799         {
01800         case PBO_ISECT:
01801           if ((*A)->Flags.status == INSIDE)
01802             {
01803               tmprev = *A;
01804               /* disappear this contour (rtree entry removed in PutContour) */
01805               *A = tmprev->next;
01806               tmprev->next = NULL;
01807               PutContour (e, tmprev, contours, holes, owner, NULL, NULL);
01808               return TRUE;
01809             }
01810           break;
01811         case PBO_XOR:
01812           if ((*A)->Flags.status == INSIDE)
01813             {
01814               tmprev = *A;
01815               /* disappear this contour (rtree entry removed in PutContour) */
01816               *A = tmprev->next;
01817               tmprev->next = NULL;
01818               poly_InvContour (tmprev);
01819               PutContour (e, tmprev, contours, holes, owner, NULL, NULL);
01820               return TRUE;
01821             }
01822           /* break; *//* Fall through (I think this is correct! pcjc2) */
01823         case PBO_UNITE:
01824         case PBO_SUB:
01825           if ((*A)->Flags.status == OUTSIDE)
01826             {
01827               tmprev = *A;
01828               /* disappear this contour (rtree entry removed in PutContour) */
01829               *A = tmprev->next;
01830               tmprev->next = NULL;
01831               PutContour (e, tmprev, contours, holes, owner, parent,
01832                           parent_contour);
01833               return TRUE;
01834             }
01835           break;
01836         }
01837     }
01838   return FALSE;
01839 }                               /* cntr_Collect */
01840 
01841 static void
01842 M_B_AREA_Collect (jmp_buf * e, POLYAREA * bfst, POLYAREA ** contours,
01843                   PLINE ** holes, int action)
01844 {
01845   POLYAREA *b = bfst;
01846   PLINE **cur, **next, *tmp;
01847 
01848   assert (b != NULL);
01849   do
01850     {
01851       for (cur = &b->contours; *cur != NULL; cur = next)
01852         {
01853           next = &((*cur)->next);
01854           if ((*cur)->Flags.status == ISECTED)
01855             continue;
01856 
01857           if ((*cur)->Flags.status == INSIDE)
01858             switch (action)
01859               {
01860               case PBO_XOR:
01861               case PBO_SUB:
01862                 poly_InvContour (*cur);
01863               case PBO_ISECT:
01864                 tmp = *cur;
01865                 *cur = tmp->next;
01866                 next = cur;
01867                 tmp->next = NULL;
01868                 tmp->Flags.status = UNKNWN;
01869                 PutContour (e, tmp, contours, holes, b, NULL, NULL);
01870                 break;
01871               case PBO_UNITE:
01872                 break;          /* nothing to do - already included */
01873               }
01874           else if ((*cur)->Flags.status == OUTSIDE)
01875             switch (action)
01876               {
01877               case PBO_XOR:
01878               case PBO_UNITE:
01879                 /* include */
01880                 tmp = *cur;
01881                 *cur = tmp->next;
01882                 next = cur;
01883                 tmp->next = NULL;
01884                 tmp->Flags.status = UNKNWN;
01885                 PutContour (e, tmp, contours, holes, b, NULL, NULL);
01886                 break;
01887               case PBO_ISECT:
01888               case PBO_SUB:
01889                 break;          /* do nothing, not included */
01890               }
01891         }
01892     }
01893   while ((b = b->f) != bfst);
01894 }
01895 
01896 
01897 static inline int
01898 contour_is_first (POLYAREA * a, PLINE * cur)
01899 {
01900   return (a->contours == cur);
01901 }
01902 
01903 
01904 static inline int
01905 contour_is_last (PLINE * cur)
01906 {
01907   return (cur->next == NULL);
01908 }
01909 
01910 
01911 static inline void
01912 remove_polyarea (POLYAREA ** list, POLYAREA * piece)
01913 {
01914   /* If this item was the start of the list, advance that pointer */
01915   if (*list == piece)
01916     *list = (*list)->f;
01917 
01918   /* But reset it to NULL if it wraps around and hits us again */
01919   if (*list == piece)
01920     *list = NULL;
01921 
01922   piece->b->f = piece->f;
01923   piece->f->b = piece->b;
01924   piece->f = piece->b = piece;
01925 }
01926 
01927 static void
01928 M_POLYAREA_separate_isected (jmp_buf * e, POLYAREA ** pieces,
01929                              PLINE ** holes, PLINE ** isected)
01930 {
01931   POLYAREA *a = *pieces;
01932   POLYAREA *anext;
01933   PLINE *curc, *next, *prev;
01934   int finished;
01935 
01936   if (a == NULL)
01937     return;
01938 
01939   /* TODO: STASH ENOUGH INFORMATION EARLIER ON, SO WE CAN REMOVE THE INTERSECTED
01940      CONTOURS WITHOUT HAVING TO WALK THE FULL DATA-STRUCTURE LOOKING FOR THEM. */
01941 
01942   do
01943     {
01944       int hole_contour = 0;
01945       int is_outline = 1;
01946 
01947       anext = a->f;
01948       finished = (anext == *pieces);
01949 
01950       prev = NULL;
01951       for (curc = a->contours; curc != NULL; curc = next, is_outline = 0)
01952         {
01953           int is_first = contour_is_first (a, curc);
01954           int is_last = contour_is_last (curc);
01955           int isect_contour = (curc->Flags.status == ISECTED);
01956 
01957           next = curc->next;
01958 
01959           if (isect_contour || hole_contour)
01960             {
01961 
01962               /* Reset the intersection flags, since we keep these pieces */
01963               if (curc->Flags.status != ISECTED)
01964                 curc->Flags.status = UNKNWN;
01965 
01966               remove_contour (a, prev, curc, !(is_first && is_last));
01967 
01968               if (isect_contour)
01969                 {
01970                   /* Link into the list of intersected contours */
01971                   curc->next = *isected;
01972                   *isected = curc;
01973                 }
01974               else if (hole_contour)
01975                 {
01976                   /* Link into the list of holes */
01977                   curc->next = *holes;
01978                   *holes = curc;
01979                 }
01980               else
01981                 {
01982                   assert (0);
01983                 }
01984 
01985               if (is_first && is_last)
01986                 {
01987                   remove_polyarea (pieces, a);
01988                   poly_Free (&a);       /* NB: Sets a to NULL */
01989                 }
01990 
01991             }
01992           else
01993             {
01994               /* Note the item we just didn't delete as the next
01995                  candidate for having its "next" pointer adjusted.
01996                  Saves walking the contour list when we delete one. */
01997               prev = curc;
01998             }
01999 
02000           /* If we move or delete an outer contour, we need to move any holes
02001              we wish to keep within that contour to the holes list. */
02002           if (is_outline && isect_contour)
02003             hole_contour = 1;
02004 
02005         }
02006 
02007       /* If we deleted all the pieces of the polyarea, *pieces is NULL */
02008     }
02009   while ((a = anext), *pieces != NULL && !finished);
02010 }
02011 
02012 
02013 struct find_inside_m_pa_info
02014 {
02015   jmp_buf jb;
02016   POLYAREA *want_inside;
02017   PLINE *result;
02018 };
02019 
02020 static int
02021 find_inside_m_pa (const BoxType * b, void *cl)
02022 {
02023   struct find_inside_m_pa_info *info = (struct find_inside_m_pa_info *) cl;
02024   PLINE *check = (PLINE *) b;
02025   /* Don't report for the main contour */
02026   if (check->Flags.orient == PLF_DIR)
02027     return 0;
02028   /* Don't look at contours marked as being intersected */
02029   if (check->Flags.status == ISECTED)
02030     return 0;
02031   if (cntr_in_M_POLYAREA (check, info->want_inside, FALSE))
02032     {
02033       info->result = check;
02034       longjmp (info->jb, 1);
02035     }
02036   return 0;
02037 }
02038 
02039 
02040 static void
02041 M_POLYAREA_update_primary (jmp_buf * e, POLYAREA ** pieces,
02042                            PLINE ** holes, int action, POLYAREA * bpa)
02043 {
02044   POLYAREA *a = *pieces;
02045   POLYAREA *b;
02046   POLYAREA *anext;
02047   PLINE *curc, *next, *prev;
02048   BoxType box;
02049   /* int inv_inside = 0; */
02050   int del_inside = 0;
02051   int del_outside = 0;
02052   int finished;
02053 
02054   if (a == NULL)
02055     return;
02056 
02057   switch (action)
02058     {
02059     case PBO_ISECT:
02060       del_outside = 1;
02061       break;
02062     case PBO_UNITE:
02063     case PBO_SUB:
02064       del_inside = 1;
02065       break;
02066     case PBO_XOR:               /* NOT IMPLEMENTED OR USED */
02067       /* inv_inside = 1; */
02068       assert (0);
02069       break;
02070     }
02071 
02072   box = *((BoxType *) bpa->contours);
02073   b = bpa;
02074   while ((b = b->f) != bpa)
02075     {
02076       BoxType *b_box = (BoxType *) b->contours;
02077       MAKEMIN (box.X1, b_box->X1);
02078       MAKEMIN (box.Y1, b_box->Y1);
02079       MAKEMAX (box.X2, b_box->X2);
02080       MAKEMAX (box.Y2, b_box->Y2);
02081     }
02082 
02083   if (del_inside)
02084     {
02085 
02086       do
02087         {
02088           anext = a->f;
02089           finished = (anext == *pieces);
02090 
02091           /* Test the outer contour first, as we may need to remove all children */
02092 
02093           /* We've not yet split intersected contours out, just ignore them */
02094           if (a->contours->Flags.status != ISECTED &&
02095               /* Pre-filter on bounding box */
02096               ((a->contours->xmin >= box.X1) && (a->contours->ymin >= box.Y1)
02097                && (a->contours->xmax <= box.X2)
02098                && (a->contours->ymax <= box.Y2)) &&
02099               /* Then test properly */
02100               cntr_in_M_POLYAREA (a->contours, bpa, FALSE))
02101             {
02102 
02103               /* Delete this contour, all children -> holes queue */
02104 
02105               /* Delete the outer contour */
02106               curc = a->contours;
02107               remove_contour (a, NULL, curc, FALSE);    /* Rtree deleted in poly_Free below */
02108               /* a->contours now points to the remaining holes */
02109               poly_DelContour (&curc);
02110 
02111               if (a->contours != NULL)
02112                 {
02113                   /* Find the end of the list of holes */
02114                   curc = a->contours;
02115                   while (curc->next != NULL)
02116                     curc = curc->next;
02117 
02118                   /* Take the holes and prepend to the holes queue */
02119                   curc->next = *holes;
02120                   *holes = a->contours;
02121                   a->contours = NULL;
02122                 }
02123 
02124               remove_polyarea (pieces, a);
02125               poly_Free (&a);   /* NB: Sets a to NULL */
02126 
02127               continue;
02128             }
02129 
02130           /* Loop whilst we find INSIDE contours to delete */
02131           while (1)
02132             {
02133               struct find_inside_m_pa_info info;
02134               PLINE *prev;
02135 
02136               info.want_inside = bpa;
02137 
02138               /* Set jump return */
02139               if (setjmp (info.jb))
02140                 {
02141                   /* Returned here! */
02142                 }
02143               else
02144                 {
02145                   info.result = NULL;
02146                   /* r-tree search, calling back a routine to longjmp back with
02147                    * data about any hole inside the B polygon.
02148                    * NB: Does not jump back to report the main contour!
02149                    */
02150                   r_search (a->contour_tree, &box, NULL, find_inside_m_pa,
02151                             &info);
02152 
02153                   /* Nothing found? */
02154                   break;
02155                 }
02156 
02157               /* We need to find the contour before it, so we can update its next pointer */
02158               prev = a->contours;
02159               while (prev->next != info.result)
02160                 {
02161                   prev = prev->next;
02162                 }
02163 
02164               /* Remove hole from the contour */
02165               remove_contour (a, prev, info.result, TRUE);
02166               poly_DelContour (&info.result);
02167             }
02168           /* End check for deleted holes */
02169 
02170           /* If we deleted all the pieces of the polyarea, *pieces is NULL */
02171         }
02172       while ((a = anext), *pieces != NULL && !finished);
02173 
02174       return;
02175     }
02176   else
02177     {
02178       /* This path isn't optimised for speed */
02179     }
02180 
02181   do
02182     {
02183       int hole_contour = 0;
02184       int is_outline = 1;
02185 
02186       anext = a->f;
02187       finished = (anext == *pieces);
02188 
02189       prev = NULL;
02190       for (curc = a->contours; curc != NULL; curc = next, is_outline = 0)
02191         {
02192           int is_first = contour_is_first (a, curc);
02193           int is_last = contour_is_last (curc);
02194           int del_contour = 0;
02195 
02196           next = curc->next;
02197 
02198           if (del_outside)
02199             del_contour = curc->Flags.status != ISECTED &&
02200               !cntr_in_M_POLYAREA (curc, bpa, FALSE);
02201 
02202           /* Skip intersected contours */
02203           if (curc->Flags.status == ISECTED)
02204             {
02205               prev = curc;
02206               continue;
02207             }
02208 
02209           /* Reset the intersection flags, since we keep these pieces */
02210           curc->Flags.status = UNKNWN;
02211 
02212           if (del_contour || hole_contour)
02213             {
02214 
02215               remove_contour (a, prev, curc, !(is_first && is_last));
02216 
02217               if (del_contour)
02218                 {
02219                   /* Delete the contour */
02220                   poly_DelContour (&curc);      /* NB: Sets curc to NULL */
02221                 }
02222               else if (hole_contour)
02223                 {
02224                   /* Link into the list of holes */
02225                   curc->next = *holes;
02226                   *holes = curc;
02227                 }
02228               else
02229                 {
02230                   assert (0);
02231                 }
02232 
02233               if (is_first && is_last)
02234                 {
02235                   remove_polyarea (pieces, a);
02236                   poly_Free (&a);       /* NB: Sets a to NULL */
02237                 }
02238 
02239             }
02240           else
02241             {
02242               /* Note the item we just didn't delete as the next
02243                  candidate for having its "next" pointer adjusted.
02244                  Saves walking the contour list when we delete one. */
02245               prev = curc;
02246             }
02247 
02248           /* If we move or delete an outer contour, we need to move any holes
02249              we wish to keep within that contour to the holes list. */
02250           if (is_outline && del_contour)
02251             hole_contour = 1;
02252 
02253         }
02254 
02255       /* If we deleted all the pieces of the polyarea, *pieces is NULL */
02256     }
02257   while ((a = anext), *pieces != NULL && !finished);
02258 }
02259 
02260 static void
02261 M_POLYAREA_Collect_separated (jmp_buf * e, PLINE * afst, POLYAREA ** contours,
02262                               PLINE ** holes, int action, BOOLp maybe)
02263 {
02264   PLINE **cur, **next;
02265 
02266   for (cur = &afst; *cur != NULL; cur = next)
02267     {
02268       next = &((*cur)->next);
02269       /* if we disappear a contour, don't advance twice */
02270       if (cntr_Collect (e, cur, contours, holes, action, NULL, NULL, NULL))
02271         next = cur;
02272     }
02273 }
02274 
02275 static void
02276 M_POLYAREA_Collect (jmp_buf * e, POLYAREA * afst, POLYAREA ** contours,
02277                     PLINE ** holes, int action, BOOLp maybe)
02278 {
02279   POLYAREA *a = afst;
02280   POLYAREA *parent = NULL;      /* Quiet compiler warning */
02281   PLINE **cur, **next, *parent_contour;
02282 
02283   assert (a != NULL);
02284   while ((a = a->f) != afst);
02285   /* now the non-intersect parts are collected in temp/holes */
02286   do
02287     {
02288       if (maybe && a->contours->Flags.status != ISECTED)
02289         parent_contour = a->contours;
02290       else
02291         parent_contour = NULL;
02292 
02293       /* Take care of the first contour - so we know if we
02294        * can shortcut reparenting some of its children
02295        */
02296       cur = &a->contours;
02297       if (*cur != NULL)
02298         {
02299           next = &((*cur)->next);
02300           /* if we disappear a contour, don't advance twice */
02301           if (cntr_Collect (e, cur, contours, holes, action, a, NULL, NULL))
02302             {
02303               parent = (*contours)->b;  /* InsCntr inserts behind the head */
02304               next = cur;
02305             }
02306           else
02307             parent = a;
02308           cur = next;
02309         }
02310       for (; *cur != NULL; cur = next)
02311         {
02312           next = &((*cur)->next);
02313           /* if we disappear a contour, don't advance twice */
02314           if (cntr_Collect (e, cur, contours, holes, action, a, parent,
02315                             parent_contour))
02316             next = cur;
02317         }
02318     }
02319   while ((a = a->f) != afst);
02320 }
02321 
02325 BOOLp
02326 Touching (POLYAREA * a, POLYAREA * b)
02327 {
02328   jmp_buf e;
02329   int code;
02330 
02331   if ((code = setjmp (e)) == 0)
02332     {
02333 #ifdef DEBUG
02334       if (!poly_Valid (a))
02335         return -1;
02336       if (!poly_Valid (b))
02337         return -1;
02338 #endif
02339       M_POLYAREA_intersect (&e, a, b, false);
02340 
02341       if (M_POLYAREA_label (a, b, TRUE))
02342         return TRUE;
02343       if (M_POLYAREA_label (b, a, TRUE))
02344         return TRUE;
02345     }
02346   else if (code == TOUCHES)
02347     return TRUE;
02348   return FALSE;
02349 }
02350 
02354 int
02355 poly_Boolean (const POLYAREA * a_org, const POLYAREA * b_org,
02356               POLYAREA ** res, int action)
02357 {
02358   POLYAREA *a = NULL, *b = NULL;
02359 
02360   if (!poly_M_Copy0 (&a, a_org) || !poly_M_Copy0 (&b, b_org))
02361     return err_no_memory;
02362 
02363   return poly_Boolean_free (a, b, res, action);
02364 }                               /* poly_Boolean */
02365 
02369 int
02370 poly_Boolean_free (POLYAREA * ai, POLYAREA * bi, POLYAREA ** res, int action)
02371 {
02372   POLYAREA *a = ai, *b = bi;
02373   PLINE *a_isected = NULL;
02374   PLINE *p, *holes = NULL;
02375   jmp_buf e;
02376   int code;
02377 
02378   *res = NULL;
02379 
02380   if (!a)
02381     {
02382       switch (action)
02383         {
02384         case PBO_XOR:
02385         case PBO_UNITE:
02386           *res = bi;
02387           return err_ok;
02388         case PBO_SUB:
02389         case PBO_ISECT:
02390           if (b != NULL)
02391             poly_Free (&b);
02392           return err_ok;
02393         }
02394     }
02395   if (!b)
02396     {
02397       switch (action)
02398         {
02399         case PBO_SUB:
02400         case PBO_XOR:
02401         case PBO_UNITE:
02402           *res = ai;
02403           return err_ok;
02404         case PBO_ISECT:
02405           if (a != NULL)
02406             poly_Free (&a);
02407           return err_ok;
02408         }
02409     }
02410 
02411   if ((code = setjmp (e)) == 0)
02412     {
02413 #ifdef DEBUG
02414       assert (poly_Valid (a));
02415       assert (poly_Valid (b));
02416 #endif
02417 
02418       /* intersect needs to make a list of the contours in a and b which are intersected */
02419       M_POLYAREA_intersect (&e, a, b, TRUE);
02420 
02421       /* We could speed things up a lot here if we only processed the relevant contours */
02422       /* NB: Relevant parts of a are labeled below */
02423       M_POLYAREA_label (b, a, FALSE);
02424 
02425       *res = a;
02426       M_POLYAREA_update_primary (&e, res, &holes, action, b);
02427       M_POLYAREA_separate_isected (&e, res, &holes, &a_isected);
02428       M_POLYAREA_label_separated (a_isected, b, FALSE);
02429       M_POLYAREA_Collect_separated (&e, a_isected, res, &holes, action,
02430                                     FALSE);
02431       M_B_AREA_Collect (&e, b, res, &holes, action);
02432       poly_Free (&b);
02433 
02434       /* free a_isected */
02435       while ((p = a_isected) != NULL)
02436         {
02437           a_isected = p->next;
02438           poly_DelContour (&p);
02439         }
02440 
02441       InsertHoles (&e, *res, &holes);
02442     }
02443   /* delete holes if any left */
02444   while ((p = holes) != NULL)
02445     {
02446       holes = p->next;
02447       poly_DelContour (&p);
02448     }
02449 
02450   if (code)
02451     {
02452       poly_Free (res);
02453       return code;
02454     }
02455   assert (!*res || poly_Valid (*res));
02456   return code;
02457 }                               /* poly_Boolean_free */
02458 
02459 static void
02460 clear_marks (POLYAREA * p)
02461 {
02462   POLYAREA *n = p;
02463   PLINE *c;
02464   VNODE *v;
02465 
02466   do
02467     {
02468       for (c = n->contours; c; c = c->next)
02469         {
02470           v = &c->head;
02471           do
02472             {
02473               v->Flags.mark = 0;
02474             }
02475           while ((v = v->next) != &c->head);
02476         }
02477     }
02478   while ((n = n->f) != p);
02479 }
02480 
02487 int
02488 poly_AndSubtract_free (POLYAREA * ai, POLYAREA * bi,
02489                        POLYAREA ** aandb, POLYAREA ** aminusb)
02490 {
02491   POLYAREA *a = ai, *b = bi;
02492   PLINE *p, *holes = NULL;
02493   jmp_buf e;
02494   int code;
02495 
02496   *aandb = NULL;
02497   *aminusb = NULL;
02498 
02499   if ((code = setjmp (e)) == 0)
02500     {
02501 
02502 #ifdef DEBUG
02503       if (!poly_Valid (a))
02504         return -1;
02505       if (!poly_Valid (b))
02506         return -1;
02507 #endif
02508       M_POLYAREA_intersect (&e, a, b, TRUE);
02509 
02510       M_POLYAREA_label (a, b, FALSE);
02511       M_POLYAREA_label (b, a, FALSE);
02512 
02513       M_POLYAREA_Collect (&e, a, aandb, &holes, PBO_ISECT, FALSE);
02514       InsertHoles (&e, *aandb, &holes);
02515       assert (poly_Valid (*aandb));
02516       /* delete holes if any left */
02517       while ((p = holes) != NULL)
02518         {
02519           holes = p->next;
02520           poly_DelContour (&p);
02521         }
02522       holes = NULL;
02523       clear_marks (a);
02524       clear_marks (b);
02525       M_POLYAREA_Collect (&e, a, aminusb, &holes, PBO_SUB, FALSE);
02526       InsertHoles (&e, *aminusb, &holes);
02527       poly_Free (&a);
02528       poly_Free (&b);
02529       assert (poly_Valid (*aminusb));
02530     }
02531   /* delete holes if any left */
02532   while ((p = holes) != NULL)
02533     {
02534       holes = p->next;
02535       poly_DelContour (&p);
02536     }
02537 
02538 
02539   if (code)
02540     {
02541       poly_Free (aandb);
02542       poly_Free (aminusb);
02543       return code;
02544     }
02545   assert (!*aandb || poly_Valid (*aandb));
02546   assert (!*aminusb || poly_Valid (*aminusb));
02547   return code;
02548 }                               /* poly_AndSubtract_free */
02549 
02550 static inline int
02551 cntrbox_pointin (PLINE * c, Vector p)
02552 {
02553   return (p[0] >= c->xmin && p[1] >= c->ymin &&
02554           p[0] <= c->xmax && p[1] <= c->ymax);
02555 
02556 }
02557 
02558 static inline int
02559 node_neighbours (VNODE * a, VNODE * b)
02560 {
02561   return (a == b) || (a->next == b) || (b->next == a) || (a->next == b->next);
02562 }
02563 
02564 VNODE *
02565 poly_CreateNode (Vector v)
02566 {
02567   VNODE *res;
02568   Coord *c;
02569 
02570   assert (v);
02571   res = (VNODE *) calloc (1, sizeof (VNODE));
02572   if (res == NULL)
02573     return NULL;
02574   // bzero (res, sizeof (VNODE) - sizeof(Vector));
02575   c = res->point;
02576   *c++ = *v++;
02577   *c = *v;
02578   return res;
02579 }
02580 
02581 void
02582 poly_IniContour (PLINE * c)
02583 {
02584   if (c == NULL)
02585     return;
02586   /* bzero (c, sizeof(PLINE)); */
02587   c->head.next = c->head.prev = &c->head;
02588   c->xmin = c->ymin = COORD_MAX;
02589   c->xmax = c->ymax = -COORD_MAX - 1;
02590   c->is_round = FALSE;
02591   c->cx = 0;
02592   c->cy = 0;
02593   c->radius = 0;
02594 }
02595 
02596 PLINE *
02597 poly_NewContour (Vector v)
02598 {
02599   PLINE *res;
02600 
02601   res = (PLINE *) calloc (1, sizeof (PLINE));
02602   if (res == NULL)
02603     return NULL;
02604 
02605   poly_IniContour (res);
02606 
02607   if (v != NULL)
02608     {
02609       Vcopy (res->head.point, v);
02610       cntrbox_adjust (res, v);
02611     }
02612 
02613   return res;
02614 }
02615 
02616 void
02617 poly_ClrContour (PLINE * c)
02618 {
02619   VNODE *cur;
02620 
02621   assert (c != NULL);
02622   while ((cur = c->head.next) != &c->head)
02623     {
02624       poly_ExclVertex (cur);
02625       free (cur);
02626     }
02627   poly_IniContour (c);
02628 }
02629 
02630 void
02631 poly_DelContour (PLINE ** c)
02632 {
02633   VNODE *cur, *prev;
02634 
02635   if (*c == NULL)
02636     return;
02637   for (cur = (*c)->head.prev; cur != &(*c)->head; cur = prev)
02638     {
02639       prev = cur->prev;
02640       if (cur->cvc_next != NULL)
02641         {
02642           free (cur->cvc_next);
02643           free (cur->cvc_prev);
02644         }
02645       free (cur);
02646     }
02647   if ((*c)->head.cvc_next != NULL)
02648     {
02649       free ((*c)->head.cvc_next);
02650       free ((*c)->head.cvc_prev);
02651     }
02653   if ((*c)->tree)
02654     {
02655       rtree_t *r = (*c)->tree;
02656       r_destroy_tree (&r);
02657     }
02658   free (*c), *c = NULL;
02659 }
02660 
02661 void
02662 poly_PreContour (PLINE * C, BOOLp optimize)
02663 {
02664   double area = 0;
02665   VNODE *p, *c;
02666   Vector p1, p2;
02667 
02668   assert (C != NULL);
02669 
02670   if (optimize)
02671     {
02672       for (c = (p = &C->head)->next; c != &C->head; c = (p = c)->next)
02673         {
02674           /* if the previous node is on the same line with this one, we should remove it */
02675           Vsub2 (p1, c->point, p->point);
02676           Vsub2 (p2, c->next->point, c->point);
02677           /* If the product below is zero then
02678            * the points on either side of c 
02679            * are on the same line!
02680            * So, remove the point c
02681            */
02682 
02683           if (vect_det2 (p1, p2) == 0)
02684             {
02685               poly_ExclVertex (c);
02686               free (c);
02687               c = p;
02688             }
02689         }
02690     }
02691   C->Count = 0;
02692   C->xmin = C->xmax = C->head.point[0];
02693   C->ymin = C->ymax = C->head.point[1];
02694 
02695   p = (c = &C->head)->prev;
02696   if (c != p)
02697     {
02698       do
02699         {
02700           /* calculate area for orientation */
02701           area +=
02702             (double) (p->point[0] - c->point[0]) * (p->point[1] +
02703                                                     c->point[1]);
02704           cntrbox_adjust (C, c->point);
02705           C->Count++;
02706         }
02707       while ((c = (p = c)->next) != &C->head);
02708     }
02709   C->area = ABS (area);
02710   if (C->Count > 2)
02711     C->Flags.orient = ((area < 0) ? PLF_INV : PLF_DIR);
02712   C->tree = (rtree_t *)make_edge_tree (C);
02713 }                               /* poly_PreContour */
02714 
02715 static int
02716 flip_cb (const BoxType * b, void *cl)
02717 {
02718   struct seg *s = (struct seg *) b;
02719   s->v = s->v->prev;
02720   return 1;
02721 }
02722 
02723 void
02724 poly_InvContour (PLINE * c)
02725 {
02726   VNODE *cur, *next;
02727 #ifndef NDEBUG
02728   int r;
02729 #endif
02730 
02731   assert (c != NULL);
02732   cur = &c->head;
02733   do
02734     {
02735       next = cur->next;
02736       cur->next = cur->prev;
02737       cur->prev = next;
02738       /* fix the segment tree */
02739     }
02740   while ((cur = next) != &c->head);
02741   c->Flags.orient ^= 1;
02742   if (c->tree)
02743     {
02744 #ifndef NDEBUG
02745       r =
02746 #endif
02747         r_search (c->tree, NULL, NULL, flip_cb, NULL);
02748 #ifndef NDEBUG
02749       assert (r == c->Count);
02750 #endif
02751     }
02752 }
02753 
02754 void
02755 poly_ExclVertex (VNODE * node)
02756 {
02757   assert (node != NULL);
02758   if (node->cvc_next)
02759     {
02760       free (node->cvc_next);
02761       free (node->cvc_prev);
02762     }
02763   node->prev->next = node->next;
02764   node->next->prev = node->prev;
02765 }
02766 
02767 void
02768 poly_InclVertex (VNODE * after, VNODE * node)
02769 {
02770   double a, b;
02771   assert (after != NULL);
02772   assert (node != NULL);
02773 
02774   node->prev = after;
02775   node->next = after->next;
02776   after->next = after->next->prev = node;
02777   /* remove points on same line */
02778   if (node->prev->prev == node)
02779     return;                     /* we don't have 3 points in the poly yet */
02780   a = (node->point[1] - node->prev->prev->point[1]);
02781   a *= (node->prev->point[0] - node->prev->prev->point[0]);
02782   b = (node->point[0] - node->prev->prev->point[0]);
02783   b *= (node->prev->point[1] - node->prev->prev->point[1]);
02784   if (fabs (a - b) < EPSILON)
02785     {
02786       VNODE *t = node->prev;
02787       t->prev->next = node;
02788       node->prev = t->prev;
02789       free (t);
02790     }
02791 }
02792 
02793 BOOLp
02794 poly_CopyContour (PLINE ** dst, PLINE * src)
02795 {
02796   VNODE *cur, *newnode;
02797 
02798   assert (src != NULL);
02799   *dst = NULL;
02800   *dst = poly_NewContour (src->head.point);
02801   if (*dst == NULL)
02802     return FALSE;
02803 
02804   (*dst)->Count = src->Count;
02805   (*dst)->Flags.orient = src->Flags.orient;
02806   (*dst)->xmin = src->xmin, (*dst)->xmax = src->xmax;
02807   (*dst)->ymin = src->ymin, (*dst)->ymax = src->ymax;
02808   (*dst)->area = src->area;
02809 
02810   for (cur = src->head.next; cur != &src->head; cur = cur->next)
02811     {
02812       if ((newnode = poly_CreateNode (cur->point)) == NULL)
02813         return FALSE;
02814       // newnode->Flags = cur->Flags;
02815       poly_InclVertex ((*dst)->head.prev, newnode);
02816     }
02817   (*dst)->tree = (rtree_t *)make_edge_tree (*dst);
02818   return TRUE;
02819 }
02820 
02821 /* polygon routines */
02822 
02823 BOOLp
02824 poly_Copy0 (POLYAREA ** dst, const POLYAREA * src)
02825 {
02826   *dst = NULL;
02827   if (src != NULL)
02828     *dst = (POLYAREA *)calloc (1, sizeof (POLYAREA));
02829   if (*dst == NULL)
02830     return FALSE;
02831   (*dst)->contour_tree = r_create_tree (NULL, 0, 0);
02832 
02833   return poly_Copy1 (*dst, src);
02834 }
02835 
02836 BOOLp
02837 poly_Copy1 (POLYAREA * dst, const POLYAREA * src)
02838 {
02839   PLINE *cur, **last = &dst->contours;
02840 
02841   *last = NULL;
02842   dst->f = dst->b = dst;
02843 
02844   for (cur = src->contours; cur != NULL; cur = cur->next)
02845     {
02846       if (!poly_CopyContour (last, cur))
02847         return FALSE;
02848       r_insert_entry (dst->contour_tree, (BoxType *) * last, 0);
02849       last = &(*last)->next;
02850     }
02851   return TRUE;
02852 }
02853 
02854 void
02855 poly_M_Incl (POLYAREA ** list, POLYAREA * a)
02856 {
02857   if (*list == NULL)
02858     a->f = a->b = a, *list = a;
02859   else
02860     {
02861       a->f = *list;
02862       a->b = (*list)->b;
02863       (*list)->b = (*list)->b->f = a;
02864     }
02865 }
02866 
02867 BOOLp
02868 poly_M_Copy0 (POLYAREA ** dst, const POLYAREA * srcfst)
02869 {
02870   const POLYAREA *src = srcfst;
02871   POLYAREA *di;
02872 
02873   *dst = NULL;
02874   if (src == NULL)
02875     return FALSE;
02876   do
02877     {
02878       if ((di = poly_Create ()) == NULL || !poly_Copy1 (di, src))
02879         return FALSE;
02880       poly_M_Incl (dst, di);
02881     }
02882   while ((src = src->f) != srcfst);
02883   return TRUE;
02884 }
02885 
02886 BOOLp
02887 poly_InclContour (POLYAREA * p, PLINE * c)
02888 {
02889   PLINE *tmp;
02890 
02891   if ((c == NULL) || (p == NULL))
02892     return FALSE;
02893   if (c->Flags.orient == PLF_DIR)
02894     {
02895       if (p->contours != NULL)
02896         return FALSE;
02897       p->contours = c;
02898     }
02899   else
02900     {
02901       if (p->contours == NULL)
02902         return FALSE;
02903       /* link at front of hole list */
02904       tmp = p->contours->next;
02905       p->contours->next = c;
02906       c->next = tmp;
02907     }
02908   r_insert_entry (p->contour_tree, (BoxType *) c, 0);
02909   return TRUE;
02910 }
02911 
02912 typedef struct pip
02913 {
02914   int f;
02915   Vector p;
02916   jmp_buf env;
02917 } pip;
02918 
02919 
02920 static int
02921 crossing (const BoxType * b, void *cl)
02922 {
02923   struct seg *s = (struct seg *) b;
02924   struct pip *p = (struct pip *) cl;
02925 
02926   if (s->v->point[1] <= p->p[1])
02927     {
02928       if (s->v->next->point[1] > p->p[1])
02929         {
02930           Vector v1, v2;
02931           long long cross;
02932           Vsub2 (v1, s->v->next->point, s->v->point);
02933           Vsub2 (v2, p->p, s->v->point);
02934           cross = (long long) v1[0] * v2[1] - (long long) v2[0] * v1[1];
02935           if (cross == 0)
02936             {
02937               p->f = 1;
02938               longjmp (p->env, 1);
02939             }
02940           if (cross > 0)
02941             p->f += 1;
02942         }
02943     }
02944   else
02945     {
02946       if (s->v->next->point[1] <= p->p[1])
02947         {
02948           Vector v1, v2;
02949           long long cross;
02950           Vsub2 (v1, s->v->next->point, s->v->point);
02951           Vsub2 (v2, p->p, s->v->point);
02952           cross = (long long) v1[0] * v2[1] - (long long) v2[0] * v1[1];
02953           if (cross == 0)
02954             {
02955               p->f = 1;
02956               longjmp (p->env, 1);
02957             }
02958           if (cross < 0)
02959             p->f -= 1;
02960         }
02961     }
02962   return 1;
02963 }
02964 
02965 int
02966 poly_InsideContour (PLINE * c, Vector p)
02967 {
02968   struct pip info;
02969   BoxType ray;
02970 
02971   if (!cntrbox_pointin (c, p))
02972     return FALSE;
02973   info.f = 0;
02974   info.p[0] = ray.X1 = p[0];
02975   info.p[1] = ray.Y1 = p[1];
02976   ray.X2 = COORD_MAX;
02977   ray.Y2 = p[1] + 1;
02978   if (setjmp (info.env) == 0)
02979     r_search (c->tree, &ray, NULL, crossing, &info);
02980   return info.f;
02981 }
02982 
02983 BOOLp
02984 poly_CheckInside (POLYAREA * p, Vector v0)
02985 {
02986   PLINE *cur;
02987 
02988   if ((p == NULL) || (v0 == NULL) || (p->contours == NULL))
02989     return FALSE;
02990   cur = p->contours;
02991   if (poly_InsideContour (cur, v0))
02992     {
02993       for (cur = cur->next; cur != NULL; cur = cur->next)
02994         if (poly_InsideContour (cur, v0))
02995           return FALSE;
02996       return TRUE;
02997     }
02998   return FALSE;
02999 }
03000 
03001 BOOLp
03002 poly_M_CheckInside (POLYAREA * p, Vector v0)
03003 {
03004   POLYAREA *cur;
03005 
03006   if ((p == NULL) || (v0 == NULL))
03007     return FALSE;
03008   cur = p;
03009   do
03010     {
03011       if (poly_CheckInside (cur, v0))
03012         return TRUE;
03013     }
03014   while ((cur = cur->f) != p);
03015   return FALSE;
03016 }
03017 
03018 static double
03019 dot (Vector A, Vector B)
03020 {
03021   return (double)A[0] * (double)B[0] + (double)A[1] * (double)B[1];
03022 }
03023 
03030 static int
03031 point_in_triangle (Vector A, Vector B, Vector C, Vector P)
03032 {
03033   Vector v0, v1, v2;
03034   double dot00, dot01, dot02, dot11, dot12;
03035   double invDenom;
03036   double u, v;
03037 
03038   /* Compute vectors */
03039   v0[0] = C[0] - A[0];  v0[1] = C[1] - A[1];
03040   v1[0] = B[0] - A[0];  v1[1] = B[1] - A[1];
03041   v2[0] = P[0] - A[0];  v2[1] = P[1] - A[1];
03042 
03043   /* Compute dot products */
03044   dot00 = dot (v0, v0);
03045   dot01 = dot (v0, v1);
03046   dot02 = dot (v0, v2);
03047   dot11 = dot (v1, v1);
03048   dot12 = dot (v1, v2);
03049 
03050   /* Compute barycentric coordinates */
03051   invDenom = 1. / (dot00 * dot11 - dot01 * dot01);
03052   u = (dot11 * dot02 - dot01 * dot12) * invDenom;
03053   v = (dot00 * dot12 - dot01 * dot02) * invDenom;
03054 
03055   /* Check if point is in triangle */
03056   return (u > 0.0) && (v > 0.0) && (u + v < 1.0);
03057 }
03058 
03059 
03067 static double
03068 dot_orthogonal_to_direction (Vector A, Vector B, Vector C, Vector D)
03069 {
03070   Vector l1, l2, l3;
03071   l1[0] = B[0] - A[0];  l1[1] = B[1] - A[1];
03072   l2[0] = D[0] - C[0];  l2[1] = D[1] - C[1];
03073 
03074   l3[0] = -l2[1];
03075   l3[1] = l2[0];
03076 
03077   return dot (l1, l3);
03078 }
03079 
03107 static void
03108 poly_ComputeInteriorPoint (PLINE *poly, Vector v)
03109 {
03110   VNODE *pt1, *pt2, *pt3, *q;
03111   VNODE *min_q = NULL;
03112   double dist;
03113   double min_dist = 0.0;
03114   double dir = (poly->Flags.orient == PLF_DIR) ? 1. : -1;
03115 
03116   /* Find a convex node on the polygon */
03117   pt1 = &poly->head;
03118   do
03119     {
03120       double dot_product;
03121 
03122       pt2 = pt1->next;
03123       pt3 = pt2->next;
03124 
03125       dot_product = dot_orthogonal_to_direction (pt1->point, pt2->point,
03126                                                  pt3->point, pt2->point);
03127 
03128       if (dot_product * dir > 0.)
03129         break;
03130     }
03131   while ((pt1 = pt1->next) != &poly->head);
03132 
03133   /* Loop over remaining vertices */
03134   q = pt3;
03135   do
03136     {
03137       /* Is current vertex "q" outside pt1 pt2 pt3 triangle? */
03138       if (!point_in_triangle (pt1->point, pt2->point, pt3->point, q->point))
03139         continue;
03140 
03141       /* NO: compute distance to pt2 (v) orthogonal to pt1 - pt3) */
03142       /*     Record minimum */
03143       dist = dot_orthogonal_to_direction (q->point, pt2->point, pt1->point, pt3->point);
03144       if (min_q == NULL || dist < min_dist) {
03145         min_dist = dist;
03146         min_q = q;
03147       }
03148     }
03149   while ((q = q->next) != pt2);
03150 
03151   /* Were any "q" found inside pt1 pt2 pt3? */
03152   if (min_q == NULL) {
03153     /* NOT FOUND: Return midpoint of pt1 pt3 */
03154     v[0] = (pt1->point[0] + pt3->point[0]) / 2;
03155     v[1] = (pt1->point[1] + pt3->point[1]) / 2;
03156   } else {
03157     /* FOUND: Return mid point of min_q, pt2 */
03158     v[0] = (pt2->point[0] + min_q->point[0]) / 2;
03159     v[1] = (pt2->point[1] + min_q->point[1]) / 2;
03160   }
03161 }
03162 
03163 
03173 int
03174 poly_ContourInContour (PLINE * poly, PLINE * inner)
03175 {
03176   Vector point;
03177   assert (poly != NULL);
03178   assert (inner != NULL);
03179   if (cntrbox_inside (inner, poly))
03180     {
03181       /* We need to prove the "inner" contour is not outside
03182        * "poly" contour. If it is outside, we can return.
03183        */
03184       if (!poly_InsideContour (poly, inner->head.point))
03185         return 0;
03186 
03187       poly_ComputeInteriorPoint (inner, point);
03188       return poly_InsideContour (poly, point);
03189     }
03190   return 0;
03191 }
03192 
03193 void
03194 poly_Init (POLYAREA * p)
03195 {
03196   p->f = p->b = p;
03197   p->contours = NULL;
03198   p->contour_tree = r_create_tree (NULL, 0, 0);
03199 }
03200 
03201 POLYAREA *
03202 poly_Create (void)
03203 {
03204   POLYAREA *res;
03205 
03206   if ((res = (POLYAREA *)malloc (sizeof (POLYAREA))) != NULL)
03207     poly_Init (res);
03208   return res;
03209 }
03210 
03211 void
03212 poly_FreeContours (PLINE ** pline)
03213 {
03214   PLINE *pl;
03215 
03216   while ((pl = *pline) != NULL)
03217     {
03218       *pline = pl->next;
03219       poly_DelContour (&pl);
03220     }
03221 }
03222 
03223 void
03224 poly_Free (POLYAREA ** p)
03225 {
03226   POLYAREA *cur;
03227 
03228   if (*p == NULL)
03229     return;
03230   for (cur = (*p)->f; cur != *p; cur = (*p)->f)
03231     {
03232       poly_FreeContours (&cur->contours);
03233       r_destroy_tree (&cur->contour_tree);
03234       cur->f->b = cur->b;
03235       cur->b->f = cur->f;
03236       free (cur);
03237     }
03238   poly_FreeContours (&cur->contours);
03239   r_destroy_tree (&cur->contour_tree);
03240   free (*p), *p = NULL;
03241 }
03242 
03243 static BOOLp
03244 inside_sector (VNODE * pn, Vector p2)
03245 {
03246   Vector cdir, ndir, pdir;
03247   int p_c, n_c, p_n;
03248 
03249   assert (pn != NULL);
03250   vect_sub (cdir, p2, pn->point);
03251   vect_sub (pdir, pn->point, pn->prev->point);
03252   vect_sub (ndir, pn->next->point, pn->point);
03253 
03254   p_c = vect_det2 (pdir, cdir) >= 0;
03255   n_c = vect_det2 (ndir, cdir) >= 0;
03256   p_n = vect_det2 (pdir, ndir) >= 0;
03257 
03258   if ((p_n && p_c && n_c) || ((!p_n) && (p_c || n_c)))
03259     return TRUE;
03260   else
03261     return FALSE;
03262 }                               /* inside_sector */
03263 
03269 BOOLp
03270 poly_ChkContour (PLINE * a)
03271 {
03272   VNODE *a1, *a2, *hit1, *hit2;
03273   Vector i1, i2;
03274   int icnt;
03275 
03276   assert (a != NULL);
03277   a1 = &a->head;
03278   do
03279     {
03280       a2 = a1;
03281       do
03282         {
03283           if (!node_neighbours (a1, a2) &&
03284               (icnt = vect_inters2 (a1->point, a1->next->point,
03285                                     a2->point, a2->next->point, i1, i2)) > 0)
03286             {
03287               if (icnt > 1)
03288                 return TRUE;
03289 
03290               if (vect_dist2 (i1, a1->point) < EPSILON)
03291                 hit1 = a1;
03292               else if (vect_dist2 (i1, a1->next->point) < EPSILON)
03293                 hit1 = a1->next;
03294               else
03295                 hit1 = NULL;
03296 
03297               if (vect_dist2 (i1, a2->point) < EPSILON)
03298                 hit2 = a2;
03299               else if (vect_dist2 (i1, a2->next->point) < EPSILON)
03300                 hit2 = a2->next;
03301               else
03302                 hit2 = NULL;
03303 
03304               if ((hit1 == NULL) && (hit2 == NULL))
03305                 {
03306                   /* If the intersection didn't land on an end-point of either
03307                    * line, we know the lines cross and we return TRUE.
03308                    */
03309                   return TRUE;
03310                 }
03311               else if (hit1 == NULL)
03312                 {
03313                 /* An end-point of the second line touched somewhere along the
03314                    length of the first line. Check where the second line leads. */
03315                   if (inside_sector (hit2, a1->point) !=
03316                       inside_sector (hit2, a1->next->point))
03317                     return TRUE;
03318                 }
03319               else if (hit2 == NULL)
03320                 {
03321                 /* An end-point of the first line touched somewhere along the
03322                    length of the second line. Check where the first line leads. */
03323                   if (inside_sector (hit1, a2->point) !=
03324                       inside_sector (hit1, a2->next->point))
03325                     return TRUE;
03326                 }
03327               else
03328                 {
03329                 /* Both lines intersect at an end-point. Check where they lead. */
03330                   if (inside_sector (hit1, hit2->prev->point) !=
03331                       inside_sector (hit1, hit2->next->point))
03332                     return TRUE;
03333                 }
03334             }
03335         }
03336       while ((a2 = a2->next) != &a->head);
03337     }
03338   while ((a1 = a1->next) != &a->head);
03339   return FALSE;
03340 }
03341 
03342 
03343 BOOLp
03344 poly_Valid (POLYAREA * p)
03345 {
03346   PLINE *c;
03347 
03348   if ((p == NULL) || (p->contours == NULL))
03349     return FALSE;
03350 
03351   if (p->contours->Flags.orient == PLF_INV || poly_ChkContour (p->contours))
03352     {
03353 #ifndef NDEBUG
03354       VNODE *v, *n;
03355       DEBUGP ("Invalid Outer PLINE\n");
03356       if (p->contours->Flags.orient == PLF_INV)
03357         DEBUGP ("failed orient\n");
03358       if (poly_ChkContour (p->contours))
03359         DEBUGP ("failed self-intersection\n");
03360       v = &p->contours->head;
03361       do
03362         {
03363           n = v->next;
03364           pcb_fprintf (stderr, "Line [%#mS %#mS %#mS %#mS 100 100 \"\"]\n",
03365                    v->point[0], v->point[1], n->point[0], n->point[1]);
03366         }
03367       while ((v = v->next) != &p->contours->head);
03368 #endif
03369       return FALSE;
03370     }
03371   for (c = p->contours->next; c != NULL; c = c->next)
03372     {
03373       if (c->Flags.orient == PLF_DIR ||
03374           poly_ChkContour (c) || !poly_ContourInContour (p->contours, c))
03375         {
03376 #ifndef NDEBUG
03377           VNODE *v, *n;
03378           DEBUGP ("Invalid Inner PLINE orient = %d\n", c->Flags.orient);
03379           if (c->Flags.orient == PLF_DIR)
03380             DEBUGP ("failed orient\n");
03381           if (poly_ChkContour (c))
03382             DEBUGP ("failed self-intersection\n");
03383           if (!poly_ContourInContour (p->contours, c))
03384             DEBUGP ("failed containment\n");
03385           v = &c->head;
03386           do
03387             {
03388               n = v->next;
03389               pcb_fprintf (stderr, "Line [%#mS %#mS %#mS %#mS 100 100 \"\"]\n",
03390                        v->point[0], v->point[1], n->point[0], n->point[1]);
03391             }
03392           while ((v = v->next) != &c->head);
03393 #endif
03394           return FALSE;
03395         }
03396     }
03397   return TRUE;
03398 }
03399 
03400 
03401 Vector vect_zero = { (long) 0, (long) 0 };
03402 
03403 /*             L o n g   V e c t o r   S t u f f                     */
03404 
03405 void
03406 vect_init (Vector v, double x, double y)
03407 {
03408   v[0] = (long) x;
03409   v[1] = (long) y;
03410 }                               /* vect_init */
03411 
03412 #define Vzero(a)   ((a)[0] == 0. && (a)[1] == 0.)
03413 
03414 #define Vsub(a,b,c) {(a)[0]=(b)[0]-(c)[0];(a)[1]=(b)[1]-(c)[1];}
03415 
03416 int
03417 vect_equal (Vector v1, Vector v2)
03418 {
03419   return (v1[0] == v2[0] && v1[1] == v2[1]);
03420 }                               /* vect_equal */
03421 
03422 
03423 void
03424 vect_sub (Vector res, Vector v1, Vector v2)
03425 {
03426 Vsub (res, v1, v2)}             /* vect_sub */
03427 
03428 void
03429 vect_min (Vector v1, Vector v2, Vector v3)
03430 {
03431   v1[0] = (v2[0] < v3[0]) ? v2[0] : v3[0];
03432   v1[1] = (v2[1] < v3[1]) ? v2[1] : v3[1];
03433 }                               /* vect_min */
03434 
03435 void
03436 vect_max (Vector v1, Vector v2, Vector v3)
03437 {
03438   v1[0] = (v2[0] > v3[0]) ? v2[0] : v3[0];
03439   v1[1] = (v2[1] > v3[1]) ? v2[1] : v3[1];
03440 }                               /* vect_max */
03441 
03442 double
03443 vect_len2 (Vector v)
03444 {
03445   return ((double) v[0] * v[0] + (double) v[1] * v[1]); /* why sqrt? only used for compares */
03446 }
03447 
03448 double
03449 vect_dist2 (Vector v1, Vector v2)
03450 {
03451   double dx = v1[0] - v2[0];
03452   double dy = v1[1] - v2[1];
03453 
03454   return (dx * dx + dy * dy);   /* why sqrt */
03455 }
03456 
03460 double
03461 vect_det2 (Vector v1, Vector v2)
03462 {
03463   return (((double) v1[0] * v2[1]) - ((double) v2[0] * v1[1]));
03464 }
03465 
03466 static double
03467 vect_m_dist (Vector v1, Vector v2)
03468 {
03469   double dx = v1[0] - v2[0];
03470   double dy = v1[1] - v2[1];
03471   double dd = (dx * dx + dy * dy);      /* sqrt */
03472 
03473   if (dx > 0)
03474     return +dd;
03475   if (dx < 0)
03476     return -dd;
03477   if (dy > 0)
03478     return +dd;
03479   return -dd;
03480 }                               /* vect_m_dist */
03481 
03489 int
03490 vect_inters2 (Vector p1, Vector p2, Vector q1, Vector q2,
03491               Vector S1, Vector S2)
03492 {
03493   double s, t, deel;
03494   double rpx, rpy, rqx, rqy;
03495 
03496   if (max (p1[0], p2[0]) < min (q1[0], q2[0]) ||
03497       max (q1[0], q2[0]) < min (p1[0], p2[0]) ||
03498       max (p1[1], p2[1]) < min (q1[1], q2[1]) ||
03499       max (q1[1], q2[1]) < min (p1[1], p2[1]))
03500     return 0;
03501 
03502   rpx = p2[0] - p1[0];
03503   rpy = p2[1] - p1[1];
03504   rqx = q2[0] - q1[0];
03505   rqy = q2[1] - q1[1];
03506 
03507   deel = rpy * rqx - rpx * rqy; /* -vect_det(rp,rq); */
03508 
03509   /* coordinates are 30-bit integers so deel will be exactly zero
03510    * if the lines are parallel
03511    */
03512 
03513   if (deel == 0)                /* parallel */
03514     {
03515       double dc1, dc2, d1, d2, h;       /* Check to see whether p1-p2 and q1-q2 are on the same line */
03516       Vector hp1, hq1, hp2, hq2, q1p1, q1q2;
03517 
03518       Vsub2 (q1p1, q1, p1);
03519       Vsub2 (q1q2, q1, q2);
03520 
03521 
03522       /* If this product is not zero then p1-p2 and q1-q2 are not on same line! */
03523       if (vect_det2 (q1p1, q1q2) != 0)
03524         return 0;
03525       dc1 = 0;                  /* m_len(p1 - p1) */
03526 
03527       dc2 = vect_m_dist (p1, p2);
03528       d1 = vect_m_dist (p1, q1);
03529       d2 = vect_m_dist (p1, q2);
03530 
03531 /* Sorting the independent points from small to large */
03532       Vcpy2 (hp1, p1);
03533       Vcpy2 (hp2, p2);
03534       Vcpy2 (hq1, q1);
03535       Vcpy2 (hq2, q2);
03536       if (dc1 > dc2)
03537         {                       /* hv and h are used as help-variable. */
03538           Vswp2 (hp1, hp2);
03539           h = dc1, dc1 = dc2, dc2 = h;
03540         }
03541       if (d1 > d2)
03542         {
03543           Vswp2 (hq1, hq2);
03544           h = d1, d1 = d2, d2 = h;
03545         }
03546 
03547 /* Now the line-pieces are compared */
03548 
03549       if (dc1 < d1)
03550         {
03551           if (dc2 < d1)
03552             return 0;
03553           if (dc2 < d2)
03554             {
03555               Vcpy2 (S1, hp2);
03556               Vcpy2 (S2, hq1);
03557             }
03558           else
03559             {
03560               Vcpy2 (S1, hq1);
03561               Vcpy2 (S2, hq2);
03562             };
03563         }
03564       else
03565         {
03566           if (dc1 > d2)
03567             return 0;
03568           if (dc2 < d2)
03569             {
03570               Vcpy2 (S1, hp1);
03571               Vcpy2 (S2, hp2);
03572             }
03573           else
03574             {
03575               Vcpy2 (S1, hp1);
03576               Vcpy2 (S2, hq2);
03577             };
03578         }
03579       return (Vequ2 (S1, S2) ? 1 : 2);
03580     }
03581   else
03582     {                           /* not parallel */
03583       /*
03584        * We have the lines:
03585        * l1: p1 + s(p2 - p1)
03586        * l2: q1 + t(q2 - q1)
03587        * And we want to know the intersection point.
03588        * Calculate t:
03589        * p1 + s(p2-p1) = q1 + t(q2-q1)
03590        * which is similar to the two equations:
03591        * p1x + s * rpx = q1x + t * rqx
03592        * p1y + s * rpy = q1y + t * rqy
03593        * Multiplying these by rpy resp. rpx gives:
03594        * rpy * p1x + s * rpx * rpy = rpy * q1x + t * rpy * rqx
03595        * rpx * p1y + s * rpx * rpy = rpx * q1y + t * rpx * rqy
03596        * Subtracting these gives:
03597        * rpy * p1x - rpx * p1y = rpy * q1x - rpx * q1y + t * ( rpy * rqx - rpx * rqy )
03598        * So t can be isolated:
03599        * t = (rpy * ( p1x - q1x ) + rpx * ( - p1y + q1y )) / ( rpy * rqx - rpx * rqy )
03600        * and s can be found similarly
03601        * s = (rqy * (q1x - p1x) + rqx * (p1y - q1y))/( rqy * rpx - rqx * rpy)
03602        */
03603 
03604       if (Vequ2 (q1, p1) || Vequ2 (q1, p2))
03605         {
03606           S1[0] = q1[0];
03607           S1[1] = q1[1];
03608         }
03609       else if (Vequ2 (q2, p1) || Vequ2 (q2, p2))
03610         {
03611           S1[0] = q2[0];
03612           S1[1] = q2[1];
03613         }
03614       else
03615         {
03616           s = (rqy * (p1[0] - q1[0]) + rqx * (q1[1] - p1[1])) / deel;
03617           if (s < 0 || s > 1.)
03618             return 0;
03619           t = (rpy * (p1[0] - q1[0]) + rpx * (q1[1] - p1[1])) / deel;
03620           if (t < 0 || t > 1.)
03621             return 0;
03622 
03623           S1[0] = q1[0] + ROUND (t * rqx);
03624           S1[1] = q1[1] + ROUND (t * rqy);
03625         }
03626       return 1;
03627     }
03628 }                               /* vect_inters2 */