pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 */