$search
00001 /* 00002 =========================================================================== 00003 00004 Project: Generic Polygon Clipper 00005 00006 A new algorithm for calculating the difference, intersection, 00007 exclusive-or or union of arbitrary polygon sets. 00008 00009 File: gpc.c 00010 Author: Alan Murta (email: gpc@cs.man.ac.uk) 00011 Version: 2.32 00012 Date: 17th December 2004 00013 00014 Copyright: (C) Advanced Interfaces Group, 00015 University of Manchester. 00016 00017 This software is free for non-commercial use. It may be copied, 00018 modified, and redistributed provided that this copyright notice 00019 is preserved on all copies. The intellectual property rights of 00020 the algorithms used reside with the University of Manchester 00021 Advanced Interfaces Group. 00022 00023 You may not use this software, in whole or in part, in support 00024 of any commercial product without the express consent of the 00025 author. 00026 00027 There is no warranty or other guarantee of fitness of this 00028 software for any purpose. It is provided solely "as is". 00029 00030 =========================================================================== 00031 */ 00032 00033 00034 /* 00035 =========================================================================== 00036 Includes 00037 =========================================================================== 00038 */ 00039 00040 #include "cob_3d_mapping_common/gpc.h" 00041 #include <stdlib.h> 00042 #include <float.h> 00043 #include <math.h> 00044 00045 00046 /* 00047 =========================================================================== 00048 Constants 00049 =========================================================================== 00050 */ 00051 00052 #ifndef TRUE 00053 #define FALSE 0 00054 #define TRUE 1 00055 #endif 00056 00057 #define LEFT 0 00058 #define RIGHT 1 00059 00060 #define ABOVE 0 00061 #define BELOW 1 00062 00063 #define CLIP 0 00064 #define SUBJ 1 00065 00066 #define INVERT_TRISTRIPS FALSE 00067 00068 00069 /* 00070 =========================================================================== 00071 Macros 00072 =========================================================================== 00073 */ 00074 00075 #define EQ(a, b) (fabs((a) - (b)) <= GPC_EPSILON) 00076 00077 #define PREV_INDEX(i, n) ((i - 1 + n) % n) 00078 #define NEXT_INDEX(i, n) ((i + 1 ) % n) 00079 00080 #define OPTIMAL(v, i, n) ((v[PREV_INDEX(i, n)].y != v[i].y) || \ 00081 (v[NEXT_INDEX(i, n)].y != v[i].y)) 00082 00083 #define FWD_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y >= v[i].vertex.y) \ 00084 && (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y)) 00085 00086 #define NOT_FMAX(v, i, n) (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y) 00087 00088 #define REV_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) \ 00089 && (v[NEXT_INDEX(i, n)].vertex.y >= v[i].vertex.y)) 00090 00091 #define NOT_RMAX(v, i, n) (v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) 00092 00093 #define VERTEX(e,p,s,x,y) {add_vertex(&((e)->outp[(p)]->v[(s)]), x, y); \ 00094 (e)->outp[(p)]->active++;} 00095 00096 #define P_EDGE(d,e,p,i,j) {(d)= (e); \ 00097 do {(d)= (d)->prev;} while (!(d)->outp[(p)]); \ 00098 (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} 00099 00100 #define N_EDGE(d,e,p,i,j) {(d)= (e); \ 00101 do {(d)= (d)->next;} while (!(d)->outp[(p)]); \ 00102 (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} 00103 00104 #define MALLOC(p, b, s, t) {if ((b) > 0) { \ 00105 p= (t*)malloc(b); if (!(p)) { \ 00106 fprintf(stderr, "gpc malloc failure: %s\n", s); \ 00107 exit(0);}} else p= NULL;} 00108 00109 #define FREE(p) {if (p) {free(p); (p)= NULL;}} 00110 00111 00112 /* 00113 =========================================================================== 00114 Private Data Types 00115 =========================================================================== 00116 */ 00117 00118 typedef enum /* Edge intersection classes */ 00119 { 00120 NUL, /* Empty non-intersection */ 00121 EMX, /* External maximum */ 00122 ELI, /* External left intermediate */ 00123 TED, /* Top edge */ 00124 ERI, /* External right intermediate */ 00125 RED, /* Right edge */ 00126 IMM, /* Internal maximum and minimum */ 00127 IMN, /* Internal minimum */ 00128 EMN, /* External minimum */ 00129 EMM, /* External maximum and minimum */ 00130 LED, /* Left edge */ 00131 ILI, /* Internal left intermediate */ 00132 BED, /* Bottom edge */ 00133 IRI, /* Internal right intermediate */ 00134 IMX, /* Internal maximum */ 00135 FUL /* Full non-intersection */ 00136 } vertex_type; 00137 00138 typedef enum /* Horizontal edge states */ 00139 { 00140 NH, /* No horizontal edge */ 00141 BH, /* Bottom horizontal edge */ 00142 TH /* Top horizontal edge */ 00143 } h_state; 00144 00145 typedef enum /* Edge bundle state */ 00146 { 00147 UNBUNDLED, /* Isolated edge not within a bundle */ 00148 BUNDLE_HEAD, /* Bundle head node */ 00149 BUNDLE_TAIL /* Passive bundle tail node */ 00150 } bundle_state; 00151 00152 typedef struct v_shape /* Internal vertex list datatype */ 00153 { 00154 double x; /* X coordinate component */ 00155 double y; /* Y coordinate component */ 00156 struct v_shape *next; /* Pointer to next vertex in list */ 00157 } vertex_node; 00158 00159 typedef struct p_shape /* Internal contour / tristrip type */ 00160 { 00161 int active; /* Active flag / vertex count */ 00162 int hole; /* Hole / external contour flag */ 00163 vertex_node *v[2]; /* Left and right vertex list ptrs */ 00164 struct p_shape *next; /* Pointer to next polygon contour */ 00165 struct p_shape *proxy; /* Pointer to actual structure used */ 00166 } polygon_node; 00167 00168 typedef struct edge_shape 00169 { 00170 gpc_vertex vertex; /* Piggy-backed contour vertex data */ 00171 gpc_vertex bot; /* Edge lower (x, y) coordinate */ 00172 gpc_vertex top; /* Edge upper (x, y) coordinate */ 00173 double xb; /* Scanbeam bottom x coordinate */ 00174 double xt; /* Scanbeam top x coordinate */ 00175 double dx; /* Change in x for a unit y increase */ 00176 int type; /* Clip / subject edge flag */ 00177 int bundle[2][2]; /* Bundle edge flags */ 00178 int bside[2]; /* Bundle left / right indicators */ 00179 bundle_state bstate[2]; /* Edge bundle state */ 00180 polygon_node *outp[2]; /* Output polygon / tristrip pointer */ 00181 struct edge_shape *prev; /* Previous edge in the AET */ 00182 struct edge_shape *next; /* Next edge in the AET */ 00183 struct edge_shape *pred; /* Edge connected at the lower end */ 00184 struct edge_shape *succ; /* Edge connected at the upper end */ 00185 struct edge_shape *next_bound; /* Pointer to next bound in LMT */ 00186 } edge_node; 00187 00188 typedef struct lmt_shape /* Local minima table */ 00189 { 00190 double y; /* Y coordinate at local minimum */ 00191 edge_node *first_bound; /* Pointer to bound list */ 00192 struct lmt_shape *next; /* Pointer to next local minimum */ 00193 } lmt_node; 00194 00195 typedef struct sbt_t_shape /* Scanbeam tree */ 00196 { 00197 double y; /* Scanbeam node y value */ 00198 struct sbt_t_shape *less; /* Pointer to nodes with lower y */ 00199 struct sbt_t_shape *more; /* Pointer to nodes with higher y */ 00200 } sb_tree; 00201 00202 typedef struct it_shape /* Intersection table */ 00203 { 00204 edge_node *ie[2]; /* Intersecting edge (bundle) pair */ 00205 gpc_vertex point; /* Point of intersection */ 00206 struct it_shape *next; /* The next intersection table node */ 00207 } it_node; 00208 00209 typedef struct st_shape /* Sorted edge table */ 00210 { 00211 edge_node *edge; /* Pointer to AET edge */ 00212 double xb; /* Scanbeam bottom x coordinate */ 00213 double xt; /* Scanbeam top x coordinate */ 00214 double dx; /* Change in x for a unit y increase */ 00215 struct st_shape *prev; /* Previous edge in sorted list */ 00216 } st_node; 00217 00218 typedef struct bbox_shape /* Contour axis-aligned bounding box */ 00219 { 00220 double xmin; /* Minimum x coordinate */ 00221 double ymin; /* Minimum y coordinate */ 00222 double xmax; /* Maximum x coordinate */ 00223 double ymax; /* Maximum y coordinate */ 00224 } bbox; 00225 00226 00227 /* 00228 =========================================================================== 00229 Global Data 00230 =========================================================================== 00231 */ 00232 00233 /* Horizontal edge state transitions within scanbeam boundary */ 00234 const h_state next_h_state[3][6]= 00235 { 00236 /* ABOVE BELOW CROSS */ 00237 /* L R L R L R */ 00238 /* NH */ {BH, TH, TH, BH, NH, NH}, 00239 /* BH */ {NH, NH, NH, NH, TH, TH}, 00240 /* TH */ {NH, NH, NH, NH, BH, BH} 00241 }; 00242 00243 00244 /* 00245 =========================================================================== 00246 Private Functions 00247 =========================================================================== 00248 */ 00249 00250 static void reset_it(it_node **it) 00251 { 00252 it_node *itn; 00253 00254 while (*it) 00255 { 00256 itn= (*it)->next; 00257 FREE(*it); 00258 *it= itn; 00259 } 00260 } 00261 00262 00263 static void reset_lmt(lmt_node **lmt) 00264 { 00265 lmt_node *lmtn; 00266 00267 while (*lmt) 00268 { 00269 lmtn= (*lmt)->next; 00270 FREE(*lmt); 00271 *lmt= lmtn; 00272 } 00273 } 00274 00275 00276 static void insert_bound(edge_node **b, edge_node *e) 00277 { 00278 edge_node *existing_bound; 00279 00280 if (!*b) 00281 { 00282 /* Link node e to the tail of the list */ 00283 *b= e; 00284 } 00285 else 00286 { 00287 /* Do primary sort on the x field */ 00288 if (e[0].bot.x < (*b)[0].bot.x) 00289 { 00290 /* Insert a new node mid-list */ 00291 existing_bound= *b; 00292 *b= e; 00293 (*b)->next_bound= existing_bound; 00294 } 00295 else 00296 { 00297 if (e[0].bot.x == (*b)[0].bot.x) 00298 { 00299 /* Do secondary sort on the dx field */ 00300 if (e[0].dx < (*b)[0].dx) 00301 { 00302 /* Insert a new node mid-list */ 00303 existing_bound= *b; 00304 *b= e; 00305 (*b)->next_bound= existing_bound; 00306 } 00307 else 00308 { 00309 /* Head further down the list */ 00310 insert_bound(&((*b)->next_bound), e); 00311 } 00312 } 00313 else 00314 { 00315 /* Head further down the list */ 00316 insert_bound(&((*b)->next_bound), e); 00317 } 00318 } 00319 } 00320 } 00321 00322 00323 static edge_node **bound_list(lmt_node **lmt, double y) 00324 { 00325 lmt_node *existing_node; 00326 00327 if (!*lmt) 00328 { 00329 /* Add node onto the tail end of the LMT */ 00330 MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); 00331 (*lmt)->y= y; 00332 (*lmt)->first_bound= NULL; 00333 (*lmt)->next= NULL; 00334 return &((*lmt)->first_bound); 00335 } 00336 else 00337 if (y < (*lmt)->y) 00338 { 00339 /* Insert a new LMT node before the current node */ 00340 existing_node= *lmt; 00341 MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); 00342 (*lmt)->y= y; 00343 (*lmt)->first_bound= NULL; 00344 (*lmt)->next= existing_node; 00345 return &((*lmt)->first_bound); 00346 } 00347 else 00348 if (y > (*lmt)->y) 00349 /* Head further up the LMT */ 00350 return bound_list(&((*lmt)->next), y); 00351 else 00352 /* Use this existing LMT node */ 00353 return &((*lmt)->first_bound); 00354 } 00355 00356 00357 static void add_to_sbtree(int *entries, sb_tree **sbtree, double y) 00358 { 00359 if (!*sbtree) 00360 { 00361 /* Add a new tree node here */ 00362 MALLOC(*sbtree, sizeof(sb_tree), "scanbeam tree insertion", sb_tree); 00363 (*sbtree)->y= y; 00364 (*sbtree)->less= NULL; 00365 (*sbtree)->more= NULL; 00366 (*entries)++; 00367 } 00368 else 00369 { 00370 if ((*sbtree)->y > y) 00371 { 00372 /* Head into the 'less' sub-tree */ 00373 add_to_sbtree(entries, &((*sbtree)->less), y); 00374 } 00375 else 00376 { 00377 if ((*sbtree)->y < y) 00378 { 00379 /* Head into the 'more' sub-tree */ 00380 add_to_sbtree(entries, &((*sbtree)->more), y); 00381 } 00382 } 00383 } 00384 } 00385 00386 00387 static void build_sbt(int *entries, double *sbt, sb_tree *sbtree) 00388 { 00389 if (sbtree->less) 00390 build_sbt(entries, sbt, sbtree->less); 00391 sbt[*entries]= sbtree->y; 00392 (*entries)++; 00393 if (sbtree->more) 00394 build_sbt(entries, sbt, sbtree->more); 00395 } 00396 00397 00398 static void free_sbtree(sb_tree **sbtree) 00399 { 00400 if (*sbtree) 00401 { 00402 free_sbtree(&((*sbtree)->less)); 00403 free_sbtree(&((*sbtree)->more)); 00404 FREE(*sbtree); 00405 } 00406 } 00407 00408 00409 static int count_optimal_vertices(gpc_vertex_list c) 00410 { 00411 int result= 0, i; 00412 00413 /* Ignore non-contributing contours */ 00414 if (c.num_vertices > 0) 00415 { 00416 for (i= 0; i < c.num_vertices; i++) 00417 /* Ignore superfluous vertices embedded in horizontal edges */ 00418 if (OPTIMAL(c.vertex, i, c.num_vertices)) 00419 result++; 00420 } 00421 return result; 00422 } 00423 00424 00425 static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, 00426 int *sbt_entries, gpc_polygon *p, int type, 00427 gpc_op op) 00428 { 00429 int c, i, min, max, num_edges, v, num_vertices; 00430 int total_vertices= 0, e_index=0; 00431 edge_node *e, *edge_table; 00432 00433 for (c= 0; c < p->num_contours; c++) 00434 total_vertices+= count_optimal_vertices(p->contour[c]); 00435 00436 /* Create the entire input polygon edge table in one go */ 00437 MALLOC(edge_table, total_vertices * sizeof(edge_node), 00438 "edge table creation", edge_node); 00439 00440 for (c= 0; c < p->num_contours; c++) 00441 { 00442 if (p->contour[c].num_vertices < 0) 00443 { 00444 /* Ignore the non-contributing contour and repair the vertex count */ 00445 p->contour[c].num_vertices= -p->contour[c].num_vertices; 00446 } 00447 else 00448 { 00449 /* Perform contour optimisation */ 00450 num_vertices= 0; 00451 for (i= 0; i < p->contour[c].num_vertices; i++) 00452 if (OPTIMAL(p->contour[c].vertex, i, p->contour[c].num_vertices)) 00453 { 00454 edge_table[num_vertices].vertex.x= p->contour[c].vertex[i].x; 00455 edge_table[num_vertices].vertex.y= p->contour[c].vertex[i].y; 00456 00457 /* Record vertex in the scanbeam table */ 00458 add_to_sbtree(sbt_entries, sbtree, 00459 edge_table[num_vertices].vertex.y); 00460 00461 num_vertices++; 00462 } 00463 00464 /* Do the contour forward pass */ 00465 for (min= 0; min < num_vertices; min++) 00466 { 00467 /* If a forward local minimum... */ 00468 if (FWD_MIN(edge_table, min, num_vertices)) 00469 { 00470 /* Search for the next local maximum... */ 00471 num_edges= 1; 00472 max= NEXT_INDEX(min, num_vertices); 00473 while (NOT_FMAX(edge_table, max, num_vertices)) 00474 { 00475 num_edges++; 00476 max= NEXT_INDEX(max, num_vertices); 00477 } 00478 00479 /* Build the next edge list */ 00480 e= &edge_table[e_index]; 00481 e_index+= num_edges; 00482 v= min; 00483 e[0].bstate[BELOW]= UNBUNDLED; 00484 e[0].bundle[BELOW][CLIP]= FALSE; 00485 e[0].bundle[BELOW][SUBJ]= FALSE; 00486 for (i= 0; i < num_edges; i++) 00487 { 00488 e[i].xb= edge_table[v].vertex.x; 00489 e[i].bot.x= edge_table[v].vertex.x; 00490 e[i].bot.y= edge_table[v].vertex.y; 00491 00492 v= NEXT_INDEX(v, num_vertices); 00493 00494 e[i].top.x= edge_table[v].vertex.x; 00495 e[i].top.y= edge_table[v].vertex.y; 00496 e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / 00497 (e[i].top.y - e[i].bot.y); 00498 e[i].type= type; 00499 e[i].outp[ABOVE]= NULL; 00500 e[i].outp[BELOW]= NULL; 00501 e[i].next= NULL; 00502 e[i].prev= NULL; 00503 e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? 00504 &(e[i + 1]) : NULL; 00505 e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; 00506 e[i].next_bound= NULL; 00507 e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; 00508 e[i].bside[SUBJ]= LEFT; 00509 } 00510 insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); 00511 } 00512 } 00513 00514 /* Do the contour reverse pass */ 00515 for (min= 0; min < num_vertices; min++) 00516 { 00517 /* If a reverse local minimum... */ 00518 if (REV_MIN(edge_table, min, num_vertices)) 00519 { 00520 /* Search for the previous local maximum... */ 00521 num_edges= 1; 00522 max= PREV_INDEX(min, num_vertices); 00523 while (NOT_RMAX(edge_table, max, num_vertices)) 00524 { 00525 num_edges++; 00526 max= PREV_INDEX(max, num_vertices); 00527 } 00528 00529 /* Build the previous edge list */ 00530 e= &edge_table[e_index]; 00531 e_index+= num_edges; 00532 v= min; 00533 e[0].bstate[BELOW]= UNBUNDLED; 00534 e[0].bundle[BELOW][CLIP]= FALSE; 00535 e[0].bundle[BELOW][SUBJ]= FALSE; 00536 for (i= 0; i < num_edges; i++) 00537 { 00538 e[i].xb= edge_table[v].vertex.x; 00539 e[i].bot.x= edge_table[v].vertex.x; 00540 e[i].bot.y= edge_table[v].vertex.y; 00541 00542 v= PREV_INDEX(v, num_vertices); 00543 00544 e[i].top.x= edge_table[v].vertex.x; 00545 e[i].top.y= edge_table[v].vertex.y; 00546 e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / 00547 (e[i].top.y - e[i].bot.y); 00548 e[i].type= type; 00549 e[i].outp[ABOVE]= NULL; 00550 e[i].outp[BELOW]= NULL; 00551 e[i].next= NULL; 00552 e[i].prev= NULL; 00553 e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? 00554 &(e[i + 1]) : NULL; 00555 e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; 00556 e[i].next_bound= NULL; 00557 e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; 00558 e[i].bside[SUBJ]= LEFT; 00559 } 00560 insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); 00561 } 00562 } 00563 } 00564 } 00565 return edge_table; 00566 } 00567 00568 00569 static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev) 00570 { 00571 if (!*aet) 00572 { 00573 /* Append edge onto the tail end of the AET */ 00574 *aet= edge; 00575 edge->prev= prev; 00576 edge->next= NULL; 00577 } 00578 else 00579 { 00580 /* Do primary sort on the xb field */ 00581 if (edge->xb < (*aet)->xb) 00582 { 00583 /* Insert edge here (before the AET edge) */ 00584 edge->prev= prev; 00585 edge->next= *aet; 00586 (*aet)->prev= edge; 00587 *aet= edge; 00588 } 00589 else 00590 { 00591 if (edge->xb == (*aet)->xb) 00592 { 00593 /* Do secondary sort on the dx field */ 00594 if (edge->dx < (*aet)->dx) 00595 { 00596 /* Insert edge here (before the AET edge) */ 00597 edge->prev= prev; 00598 edge->next= *aet; 00599 (*aet)->prev= edge; 00600 *aet= edge; 00601 } 00602 else 00603 { 00604 /* Head further into the AET */ 00605 add_edge_to_aet(&((*aet)->next), edge, *aet); 00606 } 00607 } 00608 else 00609 { 00610 /* Head further into the AET */ 00611 add_edge_to_aet(&((*aet)->next), edge, *aet); 00612 } 00613 } 00614 } 00615 } 00616 00617 00618 static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1, 00619 double x, double y) 00620 { 00621 it_node *existing_node; 00622 00623 if (!*it) 00624 { 00625 /* Append a new node to the tail of the list */ 00626 MALLOC(*it, sizeof(it_node), "IT insertion", it_node); 00627 (*it)->ie[0]= edge0; 00628 (*it)->ie[1]= edge1; 00629 (*it)->point.x= x; 00630 (*it)->point.y= y; 00631 (*it)->next= NULL; 00632 } 00633 else 00634 { 00635 if ((*it)->point.y > y) 00636 { 00637 /* Insert a new node mid-list */ 00638 existing_node= *it; 00639 MALLOC(*it, sizeof(it_node), "IT insertion", it_node); 00640 (*it)->ie[0]= edge0; 00641 (*it)->ie[1]= edge1; 00642 (*it)->point.x= x; 00643 (*it)->point.y= y; 00644 (*it)->next= existing_node; 00645 } 00646 else 00647 /* Head further down the list */ 00648 add_intersection(&((*it)->next), edge0, edge1, x, y); 00649 } 00650 } 00651 00652 00653 static void add_st_edge(st_node **st, it_node **it, edge_node *edge, 00654 double dy) 00655 { 00656 st_node *existing_node; 00657 double den, r, x, y; 00658 00659 if (!*st) 00660 { 00661 /* Append edge onto the tail end of the ST */ 00662 MALLOC(*st, sizeof(st_node), "ST insertion", st_node); 00663 (*st)->edge= edge; 00664 (*st)->xb= edge->xb; 00665 (*st)->xt= edge->xt; 00666 (*st)->dx= edge->dx; 00667 (*st)->prev= NULL; 00668 } 00669 else 00670 { 00671 den= ((*st)->xt - (*st)->xb) - (edge->xt - edge->xb); 00672 00673 /* If new edge and ST edge don't cross */ 00674 if ((edge->xt >= (*st)->xt) || (edge->dx == (*st)->dx) || 00675 (fabs(den) <= DBL_EPSILON)) 00676 { 00677 /* No intersection - insert edge here (before the ST edge) */ 00678 existing_node= *st; 00679 MALLOC(*st, sizeof(st_node), "ST insertion", st_node); 00680 (*st)->edge= edge; 00681 (*st)->xb= edge->xb; 00682 (*st)->xt= edge->xt; 00683 (*st)->dx= edge->dx; 00684 (*st)->prev= existing_node; 00685 } 00686 else 00687 { 00688 /* Compute intersection between new edge and ST edge */ 00689 r= (edge->xb - (*st)->xb) / den; 00690 x= (*st)->xb + r * ((*st)->xt - (*st)->xb); 00691 y= r * dy; 00692 00693 /* Insert the edge pointers and the intersection point in the IT */ 00694 add_intersection(it, (*st)->edge, edge, x, y); 00695 00696 /* Head further into the ST */ 00697 add_st_edge(&((*st)->prev), it, edge, dy); 00698 } 00699 } 00700 } 00701 00702 00703 static void build_intersection_table(it_node **it, edge_node *aet, double dy) 00704 { 00705 st_node *st, *stp; 00706 edge_node *edge; 00707 00708 /* Build intersection table for the current scanbeam */ 00709 reset_it(it); 00710 st= NULL; 00711 00712 /* Process each AET edge */ 00713 for (edge= aet; edge; edge= edge->next) 00714 { 00715 if ((edge->bstate[ABOVE] == BUNDLE_HEAD) || 00716 edge->bundle[ABOVE][CLIP] || edge->bundle[ABOVE][SUBJ]) 00717 add_st_edge(&st, it, edge, dy); 00718 } 00719 00720 /* Free the sorted edge table */ 00721 while (st) 00722 { 00723 stp= st->prev; 00724 FREE(st); 00725 st= stp; 00726 } 00727 } 00728 00729 static int count_contours(polygon_node *polygon) 00730 { 00731 int nc, nv; 00732 vertex_node *v, *nextv; 00733 00734 for (nc= 0; polygon; polygon= polygon->next) 00735 if (polygon->active) 00736 { 00737 /* Count the vertices in the current contour */ 00738 nv= 0; 00739 for (v= polygon->proxy->v[LEFT]; v; v= v->next) 00740 nv++; 00741 00742 /* Record valid vertex counts in the active field */ 00743 if (nv > 2) 00744 { 00745 polygon->active= nv; 00746 nc++; 00747 } 00748 else 00749 { 00750 /* Invalid contour: just free the heap */ 00751 for (v= polygon->proxy->v[LEFT]; v; v= nextv) 00752 { 00753 nextv= v->next; 00754 FREE(v); 00755 } 00756 polygon->active= 0; 00757 } 00758 } 00759 return nc; 00760 } 00761 00762 00763 static void add_left(polygon_node *p, double x, double y) 00764 { 00765 vertex_node *nv; 00766 00767 /* Create a new vertex node and set its fields */ 00768 MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); 00769 nv->x= x; 00770 nv->y= y; 00771 00772 /* Add vertex nv to the left end of the polygon's vertex list */ 00773 nv->next= p->proxy->v[LEFT]; 00774 00775 /* Update proxy->[LEFT] to point to nv */ 00776 p->proxy->v[LEFT]= nv; 00777 } 00778 00779 00780 static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list) 00781 { 00782 polygon_node *target; 00783 00784 /* Label contour as a hole */ 00785 q->proxy->hole= TRUE; 00786 00787 if (p->proxy != q->proxy) 00788 { 00789 /* Assign p's vertex list to the left end of q's list */ 00790 p->proxy->v[RIGHT]->next= q->proxy->v[LEFT]; 00791 q->proxy->v[LEFT]= p->proxy->v[LEFT]; 00792 00793 /* Redirect any p->proxy references to q->proxy */ 00794 00795 for (target= p->proxy; list; list= list->next) 00796 { 00797 if (list->proxy == target) 00798 { 00799 list->active= FALSE; 00800 list->proxy= q->proxy; 00801 } 00802 } 00803 } 00804 } 00805 00806 00807 static void add_right(polygon_node *p, double x, double y) 00808 { 00809 vertex_node *nv; 00810 00811 /* Create a new vertex node and set its fields */ 00812 MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); 00813 nv->x= x; 00814 nv->y= y; 00815 nv->next= NULL; 00816 00817 /* Add vertex nv to the right end of the polygon's vertex list */ 00818 p->proxy->v[RIGHT]->next= nv; 00819 00820 /* Update proxy->v[RIGHT] to point to nv */ 00821 p->proxy->v[RIGHT]= nv; 00822 } 00823 00824 00825 static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list) 00826 { 00827 polygon_node *target; 00828 00829 /* Label contour as external */ 00830 q->proxy->hole= FALSE; 00831 00832 if (p->proxy != q->proxy) 00833 { 00834 /* Assign p's vertex list to the right end of q's list */ 00835 q->proxy->v[RIGHT]->next= p->proxy->v[LEFT]; 00836 q->proxy->v[RIGHT]= p->proxy->v[RIGHT]; 00837 00838 /* Redirect any p->proxy references to q->proxy */ 00839 for (target= p->proxy; list; list= list->next) 00840 { 00841 if (list->proxy == target) 00842 { 00843 list->active= FALSE; 00844 list->proxy= q->proxy; 00845 } 00846 } 00847 } 00848 } 00849 00850 00851 static void add_local_min(polygon_node **p, edge_node *edge, 00852 double x, double y) 00853 { 00854 polygon_node *existing_min; 00855 vertex_node *nv; 00856 00857 existing_min= *p; 00858 00859 MALLOC(*p, sizeof(polygon_node), "polygon node creation", polygon_node); 00860 00861 /* Create a new vertex node and set its fields */ 00862 MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); 00863 nv->x= x; 00864 nv->y= y; 00865 nv->next= NULL; 00866 00867 /* Initialise proxy to point to p itself */ 00868 (*p)->proxy= (*p); 00869 (*p)->active= TRUE; 00870 (*p)->next= existing_min; 00871 00872 /* Make v[LEFT] and v[RIGHT] point to new vertex nv */ 00873 (*p)->v[LEFT]= nv; 00874 (*p)->v[RIGHT]= nv; 00875 00876 /* Assign polygon p to the edge */ 00877 edge->outp[ABOVE]= *p; 00878 } 00879 00880 00881 static int count_tristrips(polygon_node *tn) 00882 { 00883 int total; 00884 00885 for (total= 0; tn; tn= tn->next) 00886 if (tn->active > 2) 00887 total++; 00888 return total; 00889 } 00890 00891 00892 static void add_vertex(vertex_node **t, double x, double y) 00893 { 00894 if (!(*t)) 00895 { 00896 MALLOC(*t, sizeof(vertex_node), "tristrip vertex creation", vertex_node); 00897 (*t)->x= x; 00898 (*t)->y= y; 00899 (*t)->next= NULL; 00900 } 00901 else 00902 /* Head further down the list */ 00903 add_vertex(&((*t)->next), x, y); 00904 } 00905 00906 00907 static void new_tristrip(polygon_node **tn, edge_node *edge, 00908 double x, double y) 00909 { 00910 if (!(*tn)) 00911 { 00912 MALLOC(*tn, sizeof(polygon_node), "tristrip node creation", polygon_node); 00913 (*tn)->next= NULL; 00914 (*tn)->v[LEFT]= NULL; 00915 (*tn)->v[RIGHT]= NULL; 00916 (*tn)->active= 1; 00917 add_vertex(&((*tn)->v[LEFT]), x, y); 00918 edge->outp[ABOVE]= *tn; 00919 } 00920 else 00921 /* Head further down the list */ 00922 new_tristrip(&((*tn)->next), edge, x, y); 00923 } 00924 00925 00926 static bbox *create_contour_bboxes(gpc_polygon *p) 00927 { 00928 bbox *box; 00929 int c, v; 00930 00931 MALLOC(box, p->num_contours * sizeof(bbox), "Bounding box creation", bbox); 00932 00933 /* Construct contour bounding boxes */ 00934 for (c= 0; c < p->num_contours; c++) 00935 { 00936 /* Initialise bounding box extent */ 00937 box[c].xmin= DBL_MAX; 00938 box[c].ymin= DBL_MAX; 00939 box[c].xmax= -DBL_MAX; 00940 box[c].ymax= -DBL_MAX; 00941 00942 for (v= 0; v < p->contour[c].num_vertices; v++) 00943 { 00944 /* Adjust bounding box */ 00945 if (p->contour[c].vertex[v].x < box[c].xmin) 00946 box[c].xmin= p->contour[c].vertex[v].x; 00947 if (p->contour[c].vertex[v].y < box[c].ymin) 00948 box[c].ymin= p->contour[c].vertex[v].y; 00949 if (p->contour[c].vertex[v].x > box[c].xmax) 00950 box[c].xmax= p->contour[c].vertex[v].x; 00951 if (p->contour[c].vertex[v].y > box[c].ymax) 00952 box[c].ymax= p->contour[c].vertex[v].y; 00953 } 00954 } 00955 return box; 00956 } 00957 00958 00959 static void minimax_test(gpc_polygon *subj, gpc_polygon *clip, gpc_op op) 00960 { 00961 bbox *s_bbox, *c_bbox; 00962 int s, c, *o_table, overlap; 00963 00964 s_bbox= create_contour_bboxes(subj); 00965 c_bbox= create_contour_bboxes(clip); 00966 00967 MALLOC(o_table, subj->num_contours * clip->num_contours * sizeof(int), 00968 "overlap table creation", int); 00969 00970 /* Check all subject contour bounding boxes against clip boxes */ 00971 for (s= 0; s < subj->num_contours; s++) 00972 for (c= 0; c < clip->num_contours; c++) 00973 o_table[c * subj->num_contours + s]= 00974 (!((s_bbox[s].xmax < c_bbox[c].xmin) || 00975 (s_bbox[s].xmin > c_bbox[c].xmax))) && 00976 (!((s_bbox[s].ymax < c_bbox[c].ymin) || 00977 (s_bbox[s].ymin > c_bbox[c].ymax))); 00978 00979 /* For each clip contour, search for any subject contour overlaps */ 00980 for (c= 0; c < clip->num_contours; c++) 00981 { 00982 overlap= 0; 00983 for (s= 0; (!overlap) && (s < subj->num_contours); s++) 00984 overlap= o_table[c * subj->num_contours + s]; 00985 00986 if (!overlap) 00987 /* Flag non contributing status by negating vertex count */ 00988 clip->contour[c].num_vertices = -clip->contour[c].num_vertices; 00989 } 00990 00991 if (op == GPC_INT) 00992 { 00993 /* For each subject contour, search for any clip contour overlaps */ 00994 for (s= 0; s < subj->num_contours; s++) 00995 { 00996 overlap= 0; 00997 for (c= 0; (!overlap) && (c < clip->num_contours); c++) 00998 overlap= o_table[c * subj->num_contours + s]; 00999 01000 if (!overlap) 01001 /* Flag non contributing status by negating vertex count */ 01002 subj->contour[s].num_vertices = -subj->contour[s].num_vertices; 01003 } 01004 } 01005 01006 FREE(s_bbox); 01007 FREE(c_bbox); 01008 FREE(o_table); 01009 } 01010 01011 01012 /* 01013 =========================================================================== 01014 Public Functions 01015 =========================================================================== 01016 */ 01017 01018 void gpc_free_polygon(gpc_polygon *p) 01019 { 01020 int c; 01021 01022 for (c= 0; c < p->num_contours; c++) 01023 FREE(p->contour[c].vertex); 01024 FREE(p->hole); 01025 FREE(p->contour); 01026 p->num_contours= 0; 01027 } 01028 01029 01030 void gpc_read_polygon(FILE *fp, int read_hole_flags, gpc_polygon *p) 01031 { 01032 int c, v; 01033 01034 fscanf(fp, "%d", &(p->num_contours)); 01035 MALLOC(p->hole, p->num_contours * sizeof(int), 01036 "hole flag array creation", int); 01037 MALLOC(p->contour, p->num_contours 01038 * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); 01039 for (c= 0; c < p->num_contours; c++) 01040 { 01041 fscanf(fp, "%d", &(p->contour[c].num_vertices)); 01042 01043 if (read_hole_flags) 01044 fscanf(fp, "%d", &(p->hole[c])); 01045 else 01046 p->hole[c]= FALSE; /* Assume all contours to be external */ 01047 01048 MALLOC(p->contour[c].vertex, p->contour[c].num_vertices 01049 * sizeof(gpc_vertex), "vertex creation", gpc_vertex); 01050 for (v= 0; v < p->contour[c].num_vertices; v++) 01051 fscanf(fp, "%lf %lf", &(p->contour[c].vertex[v].x), 01052 &(p->contour[c].vertex[v].y)); 01053 } 01054 } 01055 01056 01057 void gpc_write_polygon(FILE *fp, int write_hole_flags, gpc_polygon *p) 01058 { 01059 int c, v; 01060 01061 fprintf(fp, "%d\n", p->num_contours); 01062 for (c= 0; c < p->num_contours; c++) 01063 { 01064 fprintf(fp, "%d\n", p->contour[c].num_vertices); 01065 01066 if (write_hole_flags) 01067 fprintf(fp, "%d\n", p->hole[c]); 01068 01069 for (v= 0; v < p->contour[c].num_vertices; v++) 01070 fprintf(fp, "% .*lf % .*lf\n", 01071 DBL_DIG, p->contour[c].vertex[v].x, 01072 DBL_DIG, p->contour[c].vertex[v].y); 01073 } 01074 } 01075 01076 01077 void gpc_add_contour(gpc_polygon *p, gpc_vertex_list *new_contour, int hole) 01078 { 01079 int *extended_hole, c, v; 01080 gpc_vertex_list *extended_contour; 01081 01082 /* Create an extended hole array */ 01083 MALLOC(extended_hole, (p->num_contours + 1) 01084 * sizeof(int), "contour hole addition", int); 01085 01086 /* Create an extended contour array */ 01087 MALLOC(extended_contour, (p->num_contours + 1) 01088 * sizeof(gpc_vertex_list), "contour addition", gpc_vertex_list); 01089 01090 /* Copy the old contour and hole data into the extended arrays */ 01091 for (c= 0; c < p->num_contours; c++) 01092 { 01093 extended_hole[c]= p->hole[c]; 01094 extended_contour[c]= p->contour[c]; 01095 } 01096 01097 /* Copy the new contour and hole onto the end of the extended arrays */ 01098 c= p->num_contours; 01099 extended_hole[c]= hole; 01100 extended_contour[c].num_vertices= new_contour->num_vertices; 01101 MALLOC(extended_contour[c].vertex, new_contour->num_vertices 01102 * sizeof(gpc_vertex), "contour addition", gpc_vertex); 01103 for (v= 0; v < new_contour->num_vertices; v++) 01104 extended_contour[c].vertex[v]= new_contour->vertex[v]; 01105 01106 /* Dispose of the old contour */ 01107 FREE(p->contour); 01108 FREE(p->hole); 01109 01110 /* Update the polygon information */ 01111 p->num_contours++; 01112 p->hole= extended_hole; 01113 p->contour= extended_contour; 01114 } 01115 01116 01117 void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, 01118 gpc_polygon *result) 01119 { 01120 sb_tree *sbtree= NULL; 01121 it_node *it= NULL, *intersect; 01122 edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; 01123 edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL; 01124 lmt_node *lmt= NULL, *local_min; 01125 polygon_node *out_poly= NULL, *p, *q, *poly, *npoly, *cf= NULL; 01126 vertex_node *vtx, *nv; 01127 h_state horiz[2]; 01128 int in[2], exists[2], parity[2]= {LEFT, LEFT}; 01129 int c, v, contributing, search, scanbeam= 0, sbt_entries= 0; 01130 int vclass, bl, br, tl, tr; 01131 double *sbt= NULL, xb, px, yb, yt, dy, ix, iy; 01132 01133 /* Test for trivial NULL result cases */ 01134 if (((subj->num_contours == 0) && (clip->num_contours == 0)) 01135 || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) 01136 || ((clip->num_contours == 0) && (op == GPC_INT))) 01137 { 01138 result->num_contours= 0; 01139 result->hole= NULL; 01140 result->contour= NULL; 01141 return; 01142 } 01143 01144 /* Identify potentialy contributing contours */ 01145 if (((op == GPC_INT) || (op == GPC_DIFF)) 01146 && (subj->num_contours > 0) && (clip->num_contours > 0)) 01147 minimax_test(subj, clip, op); 01148 01149 /* Build LMT */ 01150 if (subj->num_contours > 0) 01151 s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); 01152 if (clip->num_contours > 0) 01153 c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); 01154 01155 /* Return a NULL result if no contours contribute */ 01156 if (lmt == NULL) 01157 { 01158 result->num_contours= 0; 01159 result->hole= NULL; 01160 result->contour= NULL; 01161 reset_lmt(&lmt); 01162 FREE(s_heap); 01163 FREE(c_heap); 01164 return; 01165 } 01166 01167 /* Build scanbeam table from scanbeam tree */ 01168 MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); 01169 build_sbt(&scanbeam, sbt, sbtree); 01170 scanbeam= 0; 01171 free_sbtree(&sbtree); 01172 01173 /* Allow pointer re-use without causing memory leak */ 01174 if (subj == result) 01175 gpc_free_polygon(subj); 01176 if (clip == result) 01177 gpc_free_polygon(clip); 01178 01179 /* Invert clip polygon for difference operation */ 01180 if (op == GPC_DIFF) 01181 parity[CLIP]= RIGHT; 01182 01183 local_min= lmt; 01184 01185 /* Process each scanbeam */ 01186 while (scanbeam < sbt_entries) 01187 { 01188 /* Set yb and yt to the bottom and top of the scanbeam */ 01189 yb= sbt[scanbeam++]; 01190 if (scanbeam < sbt_entries) 01191 { 01192 yt= sbt[scanbeam]; 01193 dy= yt - yb; 01194 } 01195 01196 /* === SCANBEAM BOUNDARY PROCESSING ================================ */ 01197 01198 /* If LMT node corresponding to yb exists */ 01199 if (local_min) 01200 { 01201 if (local_min->y == yb) 01202 { 01203 /* Add edges starting at this local minimum to the AET */ 01204 for (edge= local_min->first_bound; edge; edge= edge->next_bound) 01205 add_edge_to_aet(&aet, edge, NULL); 01206 01207 local_min= local_min->next; 01208 } 01209 } 01210 01211 /* Set dummy previous x value */ 01212 px= -DBL_MAX; 01213 01214 /* Create bundles within AET */ 01215 e0= aet; 01216 e1= aet; 01217 01218 /* Set up bundle fields of first edge */ 01219 aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); 01220 aet->bundle[ABOVE][!aet->type]= FALSE; 01221 aet->bstate[ABOVE]= UNBUNDLED; 01222 01223 for (next_edge= aet->next; next_edge; next_edge= next_edge->next) 01224 { 01225 /* Set up bundle fields of next edge */ 01226 next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); 01227 next_edge->bundle[ABOVE][!next_edge->type]= FALSE; 01228 next_edge->bstate[ABOVE]= UNBUNDLED; 01229 01230 /* Bundle edges above the scanbeam boundary if they coincide */ 01231 if (next_edge->bundle[ABOVE][next_edge->type]) 01232 { 01233 if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) 01234 && (e0->top.y != yb)) 01235 { 01236 next_edge->bundle[ABOVE][ next_edge->type]^= 01237 e0->bundle[ABOVE][ next_edge->type]; 01238 next_edge->bundle[ABOVE][!next_edge->type]= 01239 e0->bundle[ABOVE][!next_edge->type]; 01240 next_edge->bstate[ABOVE]= BUNDLE_HEAD; 01241 e0->bundle[ABOVE][CLIP]= FALSE; 01242 e0->bundle[ABOVE][SUBJ]= FALSE; 01243 e0->bstate[ABOVE]= BUNDLE_TAIL; 01244 } 01245 e0= next_edge; 01246 } 01247 } 01248 01249 horiz[CLIP]= NH; 01250 horiz[SUBJ]= NH; 01251 01252 /* Process each edge at this scanbeam boundary */ 01253 for (edge= aet; edge; edge= edge->next) 01254 { 01255 exists[CLIP]= edge->bundle[ABOVE][CLIP] + 01256 (edge->bundle[BELOW][CLIP] << 1); 01257 exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + 01258 (edge->bundle[BELOW][SUBJ] << 1); 01259 01260 if (exists[CLIP] || exists[SUBJ]) 01261 { 01262 /* Set bundle side */ 01263 edge->bside[CLIP]= parity[CLIP]; 01264 edge->bside[SUBJ]= parity[SUBJ]; 01265 01266 /* Determine contributing status and quadrant occupancies */ 01267 switch (op) 01268 { 01269 case GPC_DIFF: 01270 case GPC_INT: 01271 contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) 01272 || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) 01273 || (exists[CLIP] && exists[SUBJ] 01274 && (parity[CLIP] == parity[SUBJ])); 01275 br= (parity[CLIP]) 01276 && (parity[SUBJ]); 01277 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01278 && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01279 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01280 && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01281 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01282 && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01283 break; 01284 case GPC_XOR: 01285 contributing= exists[CLIP] || exists[SUBJ]; 01286 br= (parity[CLIP]) 01287 ^ (parity[SUBJ]); 01288 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01289 ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01290 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01291 ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01292 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01293 ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01294 break; 01295 case GPC_UNION: 01296 contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) 01297 || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) 01298 || (exists[CLIP] && exists[SUBJ] 01299 && (parity[CLIP] == parity[SUBJ])); 01300 br= (parity[CLIP]) 01301 || (parity[SUBJ]); 01302 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01303 || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01304 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01305 || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01306 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01307 || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01308 break; 01309 } 01310 01311 /* Update parity */ 01312 parity[CLIP]^= edge->bundle[ABOVE][CLIP]; 01313 parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; 01314 01315 /* Update horizontal state */ 01316 if (exists[CLIP]) 01317 horiz[CLIP]= 01318 next_h_state[horiz[CLIP]] 01319 [((exists[CLIP] - 1) << 1) + parity[CLIP]]; 01320 if (exists[SUBJ]) 01321 horiz[SUBJ]= 01322 next_h_state[horiz[SUBJ]] 01323 [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; 01324 01325 vclass= tr + (tl << 1) + (br << 2) + (bl << 3); 01326 01327 if (contributing) 01328 { 01329 xb= edge->xb; 01330 01331 switch (vclass) 01332 { 01333 case EMN: 01334 case IMN: 01335 add_local_min(&out_poly, edge, xb, yb); 01336 px= xb; 01337 cf= edge->outp[ABOVE]; 01338 break; 01339 case ERI: 01340 if (xb != px) 01341 { 01342 add_right(cf, xb, yb); 01343 px= xb; 01344 } 01345 edge->outp[ABOVE]= cf; 01346 cf= NULL; 01347 break; 01348 case ELI: 01349 add_left(edge->outp[BELOW], xb, yb); 01350 px= xb; 01351 cf= edge->outp[BELOW]; 01352 break; 01353 case EMX: 01354 if (xb != px) 01355 { 01356 add_left(cf, xb, yb); 01357 px= xb; 01358 } 01359 merge_right(cf, edge->outp[BELOW], out_poly); 01360 cf= NULL; 01361 break; 01362 case ILI: 01363 if (xb != px) 01364 { 01365 add_left(cf, xb, yb); 01366 px= xb; 01367 } 01368 edge->outp[ABOVE]= cf; 01369 cf= NULL; 01370 break; 01371 case IRI: 01372 add_right(edge->outp[BELOW], xb, yb); 01373 px= xb; 01374 cf= edge->outp[BELOW]; 01375 edge->outp[BELOW]= NULL; 01376 break; 01377 case IMX: 01378 if (xb != px) 01379 { 01380 add_right(cf, xb, yb); 01381 px= xb; 01382 } 01383 merge_left(cf, edge->outp[BELOW], out_poly); 01384 cf= NULL; 01385 edge->outp[BELOW]= NULL; 01386 break; 01387 case IMM: 01388 if (xb != px) 01389 { 01390 add_right(cf, xb, yb); 01391 px= xb; 01392 } 01393 merge_left(cf, edge->outp[BELOW], out_poly); 01394 edge->outp[BELOW]= NULL; 01395 add_local_min(&out_poly, edge, xb, yb); 01396 cf= edge->outp[ABOVE]; 01397 break; 01398 case EMM: 01399 if (xb != px) 01400 { 01401 add_left(cf, xb, yb); 01402 px= xb; 01403 } 01404 merge_right(cf, edge->outp[BELOW], out_poly); 01405 edge->outp[BELOW]= NULL; 01406 add_local_min(&out_poly, edge, xb, yb); 01407 cf= edge->outp[ABOVE]; 01408 break; 01409 case LED: 01410 if (edge->bot.y == yb) 01411 add_left(edge->outp[BELOW], xb, yb); 01412 edge->outp[ABOVE]= edge->outp[BELOW]; 01413 px= xb; 01414 break; 01415 case RED: 01416 if (edge->bot.y == yb) 01417 add_right(edge->outp[BELOW], xb, yb); 01418 edge->outp[ABOVE]= edge->outp[BELOW]; 01419 px= xb; 01420 break; 01421 default: 01422 break; 01423 } /* End of switch */ 01424 } /* End of contributing conditional */ 01425 } /* End of edge exists conditional */ 01426 } /* End of AET loop */ 01427 01428 /* Delete terminating edges from the AET, otherwise compute xt */ 01429 for (edge= aet; edge; edge= edge->next) 01430 { 01431 if (edge->top.y == yb) 01432 { 01433 prev_edge= edge->prev; 01434 next_edge= edge->next; 01435 if (prev_edge) 01436 prev_edge->next= next_edge; 01437 else 01438 aet= next_edge; 01439 if (next_edge) 01440 next_edge->prev= prev_edge; 01441 01442 /* Copy bundle head state to the adjacent tail edge if required */ 01443 if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) 01444 { 01445 if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) 01446 { 01447 prev_edge->outp[BELOW]= edge->outp[BELOW]; 01448 prev_edge->bstate[BELOW]= UNBUNDLED; 01449 if (prev_edge->prev) 01450 if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) 01451 prev_edge->bstate[BELOW]= BUNDLE_HEAD; 01452 } 01453 } 01454 } 01455 else 01456 { 01457 if (edge->top.y == yt) 01458 edge->xt= edge->top.x; 01459 else 01460 edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); 01461 } 01462 } 01463 01464 if (scanbeam < sbt_entries) 01465 { 01466 /* === SCANBEAM INTERIOR PROCESSING ============================== */ 01467 01468 build_intersection_table(&it, aet, dy); 01469 01470 /* Process each node in the intersection table */ 01471 for (intersect= it; intersect; intersect= intersect->next) 01472 { 01473 e0= intersect->ie[0]; 01474 e1= intersect->ie[1]; 01475 01476 /* Only generate output for contributing intersections */ 01477 if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) 01478 && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) 01479 { 01480 p= e0->outp[ABOVE]; 01481 q= e1->outp[ABOVE]; 01482 ix= intersect->point.x; 01483 iy= intersect->point.y + yb; 01484 01485 in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) 01486 || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) 01487 || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] 01488 && e0->bside[CLIP] && e1->bside[CLIP]); 01489 in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) 01490 || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) 01491 || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] 01492 && e0->bside[SUBJ] && e1->bside[SUBJ]); 01493 01494 /* Determine quadrant occupancies */ 01495 switch (op) 01496 { 01497 case GPC_DIFF: 01498 case GPC_INT: 01499 tr= (in[CLIP]) 01500 && (in[SUBJ]); 01501 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 01502 && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 01503 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 01504 && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01505 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 01506 && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01507 break; 01508 case GPC_XOR: 01509 tr= (in[CLIP]) 01510 ^ (in[SUBJ]); 01511 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 01512 ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 01513 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 01514 ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01515 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 01516 ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01517 break; 01518 case GPC_UNION: 01519 tr= (in[CLIP]) 01520 || (in[SUBJ]); 01521 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 01522 || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 01523 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 01524 || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01525 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 01526 || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 01527 break; 01528 } 01529 01530 vclass= tr + (tl << 1) + (br << 2) + (bl << 3); 01531 01532 switch (vclass) 01533 { 01534 case EMN: 01535 add_local_min(&out_poly, e0, ix, iy); 01536 e1->outp[ABOVE]= e0->outp[ABOVE]; 01537 break; 01538 case ERI: 01539 if (p) 01540 { 01541 add_right(p, ix, iy); 01542 e1->outp[ABOVE]= p; 01543 e0->outp[ABOVE]= NULL; 01544 } 01545 break; 01546 case ELI: 01547 if (q) 01548 { 01549 add_left(q, ix, iy); 01550 e0->outp[ABOVE]= q; 01551 e1->outp[ABOVE]= NULL; 01552 } 01553 break; 01554 case EMX: 01555 if (p && q) 01556 { 01557 add_left(p, ix, iy); 01558 merge_right(p, q, out_poly); 01559 e0->outp[ABOVE]= NULL; 01560 e1->outp[ABOVE]= NULL; 01561 } 01562 break; 01563 case IMN: 01564 add_local_min(&out_poly, e0, ix, iy); 01565 e1->outp[ABOVE]= e0->outp[ABOVE]; 01566 break; 01567 case ILI: 01568 if (p) 01569 { 01570 add_left(p, ix, iy); 01571 e1->outp[ABOVE]= p; 01572 e0->outp[ABOVE]= NULL; 01573 } 01574 break; 01575 case IRI: 01576 if (q) 01577 { 01578 add_right(q, ix, iy); 01579 e0->outp[ABOVE]= q; 01580 e1->outp[ABOVE]= NULL; 01581 } 01582 break; 01583 case IMX: 01584 if (p && q) 01585 { 01586 add_right(p, ix, iy); 01587 merge_left(p, q, out_poly); 01588 e0->outp[ABOVE]= NULL; 01589 e1->outp[ABOVE]= NULL; 01590 } 01591 break; 01592 case IMM: 01593 if (p && q) 01594 { 01595 add_right(p, ix, iy); 01596 merge_left(p, q, out_poly); 01597 add_local_min(&out_poly, e0, ix, iy); 01598 e1->outp[ABOVE]= e0->outp[ABOVE]; 01599 } 01600 break; 01601 case EMM: 01602 if (p && q) 01603 { 01604 add_left(p, ix, iy); 01605 merge_right(p, q, out_poly); 01606 add_local_min(&out_poly, e0, ix, iy); 01607 e1->outp[ABOVE]= e0->outp[ABOVE]; 01608 } 01609 break; 01610 default: 01611 break; 01612 } /* End of switch */ 01613 } /* End of contributing intersection conditional */ 01614 01615 /* Swap bundle sides in response to edge crossing */ 01616 if (e0->bundle[ABOVE][CLIP]) 01617 e1->bside[CLIP]= !e1->bside[CLIP]; 01618 if (e1->bundle[ABOVE][CLIP]) 01619 e0->bside[CLIP]= !e0->bside[CLIP]; 01620 if (e0->bundle[ABOVE][SUBJ]) 01621 e1->bside[SUBJ]= !e1->bside[SUBJ]; 01622 if (e1->bundle[ABOVE][SUBJ]) 01623 e0->bside[SUBJ]= !e0->bside[SUBJ]; 01624 01625 /* Swap e0 and e1 bundles in the AET */ 01626 prev_edge= e0->prev; 01627 next_edge= e1->next; 01628 if (next_edge) 01629 next_edge->prev= e0; 01630 01631 if (e0->bstate[ABOVE] == BUNDLE_HEAD) 01632 { 01633 search= TRUE; 01634 while (search) 01635 { 01636 prev_edge= prev_edge->prev; 01637 if (prev_edge) 01638 { 01639 if (prev_edge->bstate[ABOVE] != BUNDLE_TAIL) 01640 search= FALSE; 01641 } 01642 else 01643 search= FALSE; 01644 } 01645 } 01646 if (!prev_edge) 01647 { 01648 aet->prev= e1; 01649 e1->next= aet; 01650 aet= e0->next; 01651 } 01652 else 01653 { 01654 prev_edge->next->prev= e1; 01655 e1->next= prev_edge->next; 01656 prev_edge->next= e0->next; 01657 } 01658 e0->next->prev= prev_edge; 01659 e1->next->prev= e1; 01660 e0->next= next_edge; 01661 } /* End of IT loop*/ 01662 01663 /* Prepare for next scanbeam */ 01664 for (edge= aet; edge; edge= next_edge) 01665 { 01666 next_edge= edge->next; 01667 succ_edge= edge->succ; 01668 01669 if ((edge->top.y == yt) && succ_edge) 01670 { 01671 /* Replace AET edge by its successor */ 01672 succ_edge->outp[BELOW]= edge->outp[ABOVE]; 01673 succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; 01674 succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; 01675 succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; 01676 prev_edge= edge->prev; 01677 if (prev_edge) 01678 prev_edge->next= succ_edge; 01679 else 01680 aet= succ_edge; 01681 if (next_edge) 01682 next_edge->prev= succ_edge; 01683 succ_edge->prev= prev_edge; 01684 succ_edge->next= next_edge; 01685 } 01686 else 01687 { 01688 /* Update this edge */ 01689 edge->outp[BELOW]= edge->outp[ABOVE]; 01690 edge->bstate[BELOW]= edge->bstate[ABOVE]; 01691 edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; 01692 edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; 01693 edge->xb= edge->xt; 01694 } 01695 edge->outp[ABOVE]= NULL; 01696 } 01697 } 01698 } /* === END OF SCANBEAM PROCESSING ================================== */ 01699 01700 /* Generate result polygon from out_poly */ 01701 result->contour= NULL; 01702 result->hole= NULL; 01703 result->num_contours= count_contours(out_poly); 01704 if (result->num_contours > 0) 01705 { 01706 MALLOC(result->hole, result->num_contours 01707 * sizeof(int), "hole flag table creation", int); 01708 MALLOC(result->contour, result->num_contours 01709 * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); 01710 01711 c= 0; 01712 for (poly= out_poly; poly; poly= npoly) 01713 { 01714 npoly= poly->next; 01715 if (poly->active) 01716 { 01717 result->hole[c]= poly->proxy->hole; 01718 result->contour[c].num_vertices= poly->active; 01719 MALLOC(result->contour[c].vertex, 01720 result->contour[c].num_vertices * sizeof(gpc_vertex), 01721 "vertex creation", gpc_vertex); 01722 01723 v= result->contour[c].num_vertices - 1; 01724 for (vtx= poly->proxy->v[LEFT]; vtx; vtx= nv) 01725 { 01726 nv= vtx->next; 01727 result->contour[c].vertex[v].x= vtx->x; 01728 result->contour[c].vertex[v].y= vtx->y; 01729 FREE(vtx); 01730 v--; 01731 } 01732 c++; 01733 } 01734 FREE(poly); 01735 } 01736 } 01737 else 01738 { 01739 for (poly= out_poly; poly; poly= npoly) 01740 { 01741 npoly= poly->next; 01742 FREE(poly); 01743 } 01744 } 01745 01746 /* Tidy up */ 01747 reset_it(&it); 01748 reset_lmt(&lmt); 01749 FREE(c_heap); 01750 FREE(s_heap); 01751 FREE(sbt); 01752 } 01753 01754 01755 void gpc_free_tristrip(gpc_tristrip *t) 01756 { 01757 int s; 01758 01759 for (s= 0; s < t->num_strips; s++) 01760 FREE(t->strip[s].vertex); 01761 FREE(t->strip); 01762 t->num_strips= 0; 01763 } 01764 01765 01766 void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) 01767 { 01768 gpc_polygon c; 01769 01770 c.num_contours= 0; 01771 c.hole= NULL; 01772 c.contour= NULL; 01773 gpc_tristrip_clip(GPC_DIFF, s, &c, t); 01774 } 01775 01776 01777 void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, 01778 gpc_tristrip *result) 01779 { 01780 sb_tree *sbtree= NULL; 01781 it_node *it= NULL, *intersect; 01782 edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; 01783 edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL, *cf; 01784 lmt_node *lmt= NULL, *local_min; 01785 polygon_node *tlist= NULL, *tn, *tnn, *p, *q; 01786 vertex_node *lt, *ltn, *rt, *rtn; 01787 h_state horiz[2]; 01788 vertex_type cft; 01789 int in[2], exists[2], parity[2]= {LEFT, LEFT}; 01790 int s, v, contributing, search, scanbeam= 0, sbt_entries= 0; 01791 int vclass, bl, br, tl, tr; 01792 double *sbt= NULL, xb, px, nx, yb, yt, dy, ix, iy; 01793 01794 /* Test for trivial NULL result cases */ 01795 if (((subj->num_contours == 0) && (clip->num_contours == 0)) 01796 || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) 01797 || ((clip->num_contours == 0) && (op == GPC_INT))) 01798 { 01799 result->num_strips= 0; 01800 result->strip= NULL; 01801 return; 01802 } 01803 01804 /* Identify potentialy contributing contours */ 01805 if (((op == GPC_INT) || (op == GPC_DIFF)) 01806 && (subj->num_contours > 0) && (clip->num_contours > 0)) 01807 minimax_test(subj, clip, op); 01808 01809 /* Build LMT */ 01810 if (subj->num_contours > 0) 01811 s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); 01812 if (clip->num_contours > 0) 01813 c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); 01814 01815 /* Return a NULL result if no contours contribute */ 01816 if (lmt == NULL) 01817 { 01818 result->num_strips= 0; 01819 result->strip= NULL; 01820 reset_lmt(&lmt); 01821 FREE(s_heap); 01822 FREE(c_heap); 01823 return; 01824 } 01825 01826 /* Build scanbeam table from scanbeam tree */ 01827 MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); 01828 build_sbt(&scanbeam, sbt, sbtree); 01829 scanbeam= 0; 01830 free_sbtree(&sbtree); 01831 01832 /* Invert clip polygon for difference operation */ 01833 if (op == GPC_DIFF) 01834 parity[CLIP]= RIGHT; 01835 01836 local_min= lmt; 01837 01838 /* Process each scanbeam */ 01839 while (scanbeam < sbt_entries) 01840 { 01841 /* Set yb and yt to the bottom and top of the scanbeam */ 01842 yb= sbt[scanbeam++]; 01843 if (scanbeam < sbt_entries) 01844 { 01845 yt= sbt[scanbeam]; 01846 dy= yt - yb; 01847 } 01848 01849 /* === SCANBEAM BOUNDARY PROCESSING ================================ */ 01850 01851 /* If LMT node corresponding to yb exists */ 01852 if (local_min) 01853 { 01854 if (local_min->y == yb) 01855 { 01856 /* Add edges starting at this local minimum to the AET */ 01857 for (edge= local_min->first_bound; edge; edge= edge->next_bound) 01858 add_edge_to_aet(&aet, edge, NULL); 01859 01860 local_min= local_min->next; 01861 } 01862 } 01863 01864 /* Set dummy previous x value */ 01865 px= -DBL_MAX; 01866 01867 /* Create bundles within AET */ 01868 e0= aet; 01869 e1= aet; 01870 01871 /* Set up bundle fields of first edge */ 01872 aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); 01873 aet->bundle[ABOVE][!aet->type]= FALSE; 01874 aet->bstate[ABOVE]= UNBUNDLED; 01875 01876 for (next_edge= aet->next; next_edge; next_edge= next_edge->next) 01877 { 01878 /* Set up bundle fields of next edge */ 01879 next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); 01880 next_edge->bundle[ABOVE][!next_edge->type]= FALSE; 01881 next_edge->bstate[ABOVE]= UNBUNDLED; 01882 01883 /* Bundle edges above the scanbeam boundary if they coincide */ 01884 if (next_edge->bundle[ABOVE][next_edge->type]) 01885 { 01886 if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) 01887 && (e0->top.y != yb)) 01888 { 01889 next_edge->bundle[ABOVE][ next_edge->type]^= 01890 e0->bundle[ABOVE][ next_edge->type]; 01891 next_edge->bundle[ABOVE][!next_edge->type]= 01892 e0->bundle[ABOVE][!next_edge->type]; 01893 next_edge->bstate[ABOVE]= BUNDLE_HEAD; 01894 e0->bundle[ABOVE][CLIP]= FALSE; 01895 e0->bundle[ABOVE][SUBJ]= FALSE; 01896 e0->bstate[ABOVE]= BUNDLE_TAIL; 01897 } 01898 e0= next_edge; 01899 } 01900 } 01901 01902 horiz[CLIP]= NH; 01903 horiz[SUBJ]= NH; 01904 01905 /* Process each edge at this scanbeam boundary */ 01906 for (edge= aet; edge; edge= edge->next) 01907 { 01908 exists[CLIP]= edge->bundle[ABOVE][CLIP] + 01909 (edge->bundle[BELOW][CLIP] << 1); 01910 exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + 01911 (edge->bundle[BELOW][SUBJ] << 1); 01912 01913 if (exists[CLIP] || exists[SUBJ]) 01914 { 01915 /* Set bundle side */ 01916 edge->bside[CLIP]= parity[CLIP]; 01917 edge->bside[SUBJ]= parity[SUBJ]; 01918 01919 /* Determine contributing status and quadrant occupancies */ 01920 switch (op) 01921 { 01922 case GPC_DIFF: 01923 case GPC_INT: 01924 contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) 01925 || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) 01926 || (exists[CLIP] && exists[SUBJ] 01927 && (parity[CLIP] == parity[SUBJ])); 01928 br= (parity[CLIP]) 01929 && (parity[SUBJ]); 01930 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01931 && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01932 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01933 && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01934 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01935 && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01936 break; 01937 case GPC_XOR: 01938 contributing= exists[CLIP] || exists[SUBJ]; 01939 br= (parity[CLIP]) 01940 ^ (parity[SUBJ]); 01941 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01942 ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01943 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01944 ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01945 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01946 ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01947 break; 01948 case GPC_UNION: 01949 contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) 01950 || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) 01951 || (exists[CLIP] && exists[SUBJ] 01952 && (parity[CLIP] == parity[SUBJ])); 01953 br= (parity[CLIP]) 01954 || (parity[SUBJ]); 01955 bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) 01956 || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); 01957 tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) 01958 || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); 01959 tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) 01960 || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); 01961 break; 01962 } 01963 01964 /* Update parity */ 01965 parity[CLIP]^= edge->bundle[ABOVE][CLIP]; 01966 parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; 01967 01968 /* Update horizontal state */ 01969 if (exists[CLIP]) 01970 horiz[CLIP]= 01971 next_h_state[horiz[CLIP]] 01972 [((exists[CLIP] - 1) << 1) + parity[CLIP]]; 01973 if (exists[SUBJ]) 01974 horiz[SUBJ]= 01975 next_h_state[horiz[SUBJ]] 01976 [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; 01977 01978 vclass= tr + (tl << 1) + (br << 2) + (bl << 3); 01979 01980 if (contributing) 01981 { 01982 xb= edge->xb; 01983 01984 switch (vclass) 01985 { 01986 case EMN: 01987 new_tristrip(&tlist, edge, xb, yb); 01988 cf= edge; 01989 break; 01990 case ERI: 01991 edge->outp[ABOVE]= cf->outp[ABOVE]; 01992 if (xb != cf->xb) 01993 VERTEX(edge, ABOVE, RIGHT, xb, yb); 01994 cf= NULL; 01995 break; 01996 case ELI: 01997 VERTEX(edge, BELOW, LEFT, xb, yb); 01998 edge->outp[ABOVE]= NULL; 01999 cf= edge; 02000 break; 02001 case EMX: 02002 if (xb != cf->xb) 02003 VERTEX(edge, BELOW, RIGHT, xb, yb); 02004 edge->outp[ABOVE]= NULL; 02005 cf= NULL; 02006 break; 02007 case IMN: 02008 if (cft == LED) 02009 { 02010 if (cf->bot.y != yb) 02011 VERTEX(cf, BELOW, LEFT, cf->xb, yb); 02012 new_tristrip(&tlist, cf, cf->xb, yb); 02013 } 02014 edge->outp[ABOVE]= cf->outp[ABOVE]; 02015 VERTEX(edge, ABOVE, RIGHT, xb, yb); 02016 break; 02017 case ILI: 02018 new_tristrip(&tlist, edge, xb, yb); 02019 cf= edge; 02020 cft= ILI; 02021 break; 02022 case IRI: 02023 if (cft == LED) 02024 { 02025 if (cf->bot.y != yb) 02026 VERTEX(cf, BELOW, LEFT, cf->xb, yb); 02027 new_tristrip(&tlist, cf, cf->xb, yb); 02028 } 02029 VERTEX(edge, BELOW, RIGHT, xb, yb); 02030 edge->outp[ABOVE]= NULL; 02031 break; 02032 case IMX: 02033 VERTEX(edge, BELOW, LEFT, xb, yb); 02034 edge->outp[ABOVE]= NULL; 02035 cft= IMX; 02036 break; 02037 case IMM: 02038 VERTEX(edge, BELOW, LEFT, xb, yb); 02039 edge->outp[ABOVE]= cf->outp[ABOVE]; 02040 if (xb != cf->xb) 02041 VERTEX(cf, ABOVE, RIGHT, xb, yb); 02042 cf= edge; 02043 break; 02044 case EMM: 02045 VERTEX(edge, BELOW, RIGHT, xb, yb); 02046 edge->outp[ABOVE]= NULL; 02047 new_tristrip(&tlist, edge, xb, yb); 02048 cf= edge; 02049 break; 02050 case LED: 02051 if (edge->bot.y == yb) 02052 VERTEX(edge, BELOW, LEFT, xb, yb); 02053 edge->outp[ABOVE]= edge->outp[BELOW]; 02054 cf= edge; 02055 cft= LED; 02056 break; 02057 case RED: 02058 edge->outp[ABOVE]= cf->outp[ABOVE]; 02059 if (cft == LED) 02060 { 02061 if (cf->bot.y == yb) 02062 { 02063 VERTEX(edge, BELOW, RIGHT, xb, yb); 02064 } 02065 else 02066 { 02067 if (edge->bot.y == yb) 02068 { 02069 VERTEX(cf, BELOW, LEFT, cf->xb, yb); 02070 VERTEX(edge, BELOW, RIGHT, xb, yb); 02071 } 02072 } 02073 } 02074 else 02075 { 02076 VERTEX(edge, BELOW, RIGHT, xb, yb); 02077 VERTEX(edge, ABOVE, RIGHT, xb, yb); 02078 } 02079 cf= NULL; 02080 break; 02081 default: 02082 break; 02083 } /* End of switch */ 02084 } /* End of contributing conditional */ 02085 } /* End of edge exists conditional */ 02086 } /* End of AET loop */ 02087 02088 /* Delete terminating edges from the AET, otherwise compute xt */ 02089 for (edge= aet; edge; edge= edge->next) 02090 { 02091 if (edge->top.y == yb) 02092 { 02093 prev_edge= edge->prev; 02094 next_edge= edge->next; 02095 if (prev_edge) 02096 prev_edge->next= next_edge; 02097 else 02098 aet= next_edge; 02099 if (next_edge) 02100 next_edge->prev= prev_edge; 02101 02102 /* Copy bundle head state to the adjacent tail edge if required */ 02103 if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) 02104 { 02105 if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) 02106 { 02107 prev_edge->outp[BELOW]= edge->outp[BELOW]; 02108 prev_edge->bstate[BELOW]= UNBUNDLED; 02109 if (prev_edge->prev) 02110 if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) 02111 prev_edge->bstate[BELOW]= BUNDLE_HEAD; 02112 } 02113 } 02114 } 02115 else 02116 { 02117 if (edge->top.y == yt) 02118 edge->xt= edge->top.x; 02119 else 02120 edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); 02121 } 02122 } 02123 02124 if (scanbeam < sbt_entries) 02125 { 02126 /* === SCANBEAM INTERIOR PROCESSING ============================== */ 02127 02128 build_intersection_table(&it, aet, dy); 02129 02130 /* Process each node in the intersection table */ 02131 for (intersect= it; intersect; intersect= intersect->next) 02132 { 02133 e0= intersect->ie[0]; 02134 e1= intersect->ie[1]; 02135 02136 /* Only generate output for contributing intersections */ 02137 if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) 02138 && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) 02139 { 02140 p= e0->outp[ABOVE]; 02141 q= e1->outp[ABOVE]; 02142 ix= intersect->point.x; 02143 iy= intersect->point.y + yb; 02144 02145 in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) 02146 || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) 02147 || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] 02148 && e0->bside[CLIP] && e1->bside[CLIP]); 02149 in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) 02150 || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) 02151 || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] 02152 && e0->bside[SUBJ] && e1->bside[SUBJ]); 02153 02154 /* Determine quadrant occupancies */ 02155 switch (op) 02156 { 02157 case GPC_DIFF: 02158 case GPC_INT: 02159 tr= (in[CLIP]) 02160 && (in[SUBJ]); 02161 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 02162 && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 02163 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 02164 && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02165 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 02166 && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02167 break; 02168 case GPC_XOR: 02169 tr= (in[CLIP]) 02170 ^ (in[SUBJ]); 02171 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 02172 ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 02173 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 02174 ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02175 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 02176 ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02177 break; 02178 case GPC_UNION: 02179 tr= (in[CLIP]) 02180 || (in[SUBJ]); 02181 tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) 02182 || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); 02183 br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) 02184 || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02185 bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) 02186 || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); 02187 break; 02188 } 02189 02190 vclass= tr + (tl << 1) + (br << 2) + (bl << 3); 02191 02192 switch (vclass) 02193 { 02194 case EMN: 02195 new_tristrip(&tlist, e1, ix, iy); 02196 e0->outp[ABOVE]= e1->outp[ABOVE]; 02197 break; 02198 case ERI: 02199 if (p) 02200 { 02201 P_EDGE(prev_edge, e0, ABOVE, px, iy); 02202 VERTEX(prev_edge, ABOVE, LEFT, px, iy); 02203 VERTEX(e0, ABOVE, RIGHT, ix, iy); 02204 e1->outp[ABOVE]= e0->outp[ABOVE]; 02205 e0->outp[ABOVE]= NULL; 02206 } 02207 break; 02208 case ELI: 02209 if (q) 02210 { 02211 N_EDGE(next_edge, e1, ABOVE, nx, iy); 02212 VERTEX(e1, ABOVE, LEFT, ix, iy); 02213 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02214 e0->outp[ABOVE]= e1->outp[ABOVE]; 02215 e1->outp[ABOVE]= NULL; 02216 } 02217 break; 02218 case EMX: 02219 if (p && q) 02220 { 02221 VERTEX(e0, ABOVE, LEFT, ix, iy); 02222 e0->outp[ABOVE]= NULL; 02223 e1->outp[ABOVE]= NULL; 02224 } 02225 break; 02226 case IMN: 02227 P_EDGE(prev_edge, e0, ABOVE, px, iy); 02228 VERTEX(prev_edge, ABOVE, LEFT, px, iy); 02229 N_EDGE(next_edge, e1, ABOVE, nx, iy); 02230 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02231 new_tristrip(&tlist, prev_edge, px, iy); 02232 e1->outp[ABOVE]= prev_edge->outp[ABOVE]; 02233 VERTEX(e1, ABOVE, RIGHT, ix, iy); 02234 new_tristrip(&tlist, e0, ix, iy); 02235 next_edge->outp[ABOVE]= e0->outp[ABOVE]; 02236 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02237 break; 02238 case ILI: 02239 if (p) 02240 { 02241 VERTEX(e0, ABOVE, LEFT, ix, iy); 02242 N_EDGE(next_edge, e1, ABOVE, nx, iy); 02243 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02244 e1->outp[ABOVE]= e0->outp[ABOVE]; 02245 e0->outp[ABOVE]= NULL; 02246 } 02247 break; 02248 case IRI: 02249 if (q) 02250 { 02251 VERTEX(e1, ABOVE, RIGHT, ix, iy); 02252 P_EDGE(prev_edge, e0, ABOVE, px, iy); 02253 VERTEX(prev_edge, ABOVE, LEFT, px, iy); 02254 e0->outp[ABOVE]= e1->outp[ABOVE]; 02255 e1->outp[ABOVE]= NULL; 02256 } 02257 break; 02258 case IMX: 02259 if (p && q) 02260 { 02261 VERTEX(e0, ABOVE, RIGHT, ix, iy); 02262 VERTEX(e1, ABOVE, LEFT, ix, iy); 02263 e0->outp[ABOVE]= NULL; 02264 e1->outp[ABOVE]= NULL; 02265 P_EDGE(prev_edge, e0, ABOVE, px, iy); 02266 VERTEX(prev_edge, ABOVE, LEFT, px, iy); 02267 new_tristrip(&tlist, prev_edge, px, iy); 02268 N_EDGE(next_edge, e1, ABOVE, nx, iy); 02269 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02270 next_edge->outp[ABOVE]= prev_edge->outp[ABOVE]; 02271 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02272 } 02273 break; 02274 case IMM: 02275 if (p && q) 02276 { 02277 VERTEX(e0, ABOVE, RIGHT, ix, iy); 02278 VERTEX(e1, ABOVE, LEFT, ix, iy); 02279 P_EDGE(prev_edge, e0, ABOVE, px, iy); 02280 VERTEX(prev_edge, ABOVE, LEFT, px, iy); 02281 new_tristrip(&tlist, prev_edge, px, iy); 02282 N_EDGE(next_edge, e1, ABOVE, nx, iy); 02283 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02284 e1->outp[ABOVE]= prev_edge->outp[ABOVE]; 02285 VERTEX(e1, ABOVE, RIGHT, ix, iy); 02286 new_tristrip(&tlist, e0, ix, iy); 02287 next_edge->outp[ABOVE]= e0->outp[ABOVE]; 02288 VERTEX(next_edge, ABOVE, RIGHT, nx, iy); 02289 } 02290 break; 02291 case EMM: 02292 if (p && q) 02293 { 02294 VERTEX(e0, ABOVE, LEFT, ix, iy); 02295 new_tristrip(&tlist, e1, ix, iy); 02296 e0->outp[ABOVE]= e1->outp[ABOVE]; 02297 } 02298 break; 02299 default: 02300 break; 02301 } /* End of switch */ 02302 } /* End of contributing intersection conditional */ 02303 02304 /* Swap bundle sides in response to edge crossing */ 02305 if (e0->bundle[ABOVE][CLIP]) 02306 e1->bside[CLIP]= !e1->bside[CLIP]; 02307 if (e1->bundle[ABOVE][CLIP]) 02308 e0->bside[CLIP]= !e0->bside[CLIP]; 02309 if (e0->bundle[ABOVE][SUBJ]) 02310 e1->bside[SUBJ]= !e1->bside[SUBJ]; 02311 if (e1->bundle[ABOVE][SUBJ]) 02312 e0->bside[SUBJ]= !e0->bside[SUBJ]; 02313 02314 /* Swap e0 and e1 bundles in the AET */ 02315 prev_edge= e0->prev; 02316 next_edge= e1->next; 02317 if (e1->next) 02318 e1->next->prev= e0; 02319 02320 if (e0->bstate[ABOVE] == BUNDLE_HEAD) 02321 { 02322 search= TRUE; 02323 while (search) 02324 { 02325 prev_edge= prev_edge->prev; 02326 if (prev_edge) 02327 { 02328 if (prev_edge->bundle[ABOVE][CLIP] 02329 || prev_edge->bundle[ABOVE][SUBJ] 02330 || (prev_edge->bstate[ABOVE] == BUNDLE_HEAD)) 02331 search= FALSE; 02332 } 02333 else 02334 search= FALSE; 02335 } 02336 } 02337 if (!prev_edge) 02338 { 02339 e1->next= aet; 02340 aet= e0->next; 02341 } 02342 else 02343 { 02344 e1->next= prev_edge->next; 02345 prev_edge->next= e0->next; 02346 } 02347 e0->next->prev= prev_edge; 02348 e1->next->prev= e1; 02349 e0->next= next_edge; 02350 } /* End of IT loop*/ 02351 02352 /* Prepare for next scanbeam */ 02353 for (edge= aet; edge; edge= next_edge) 02354 { 02355 next_edge= edge->next; 02356 succ_edge= edge->succ; 02357 02358 if ((edge->top.y == yt) && succ_edge) 02359 { 02360 /* Replace AET edge by its successor */ 02361 succ_edge->outp[BELOW]= edge->outp[ABOVE]; 02362 succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; 02363 succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; 02364 succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; 02365 prev_edge= edge->prev; 02366 if (prev_edge) 02367 prev_edge->next= succ_edge; 02368 else 02369 aet= succ_edge; 02370 if (next_edge) 02371 next_edge->prev= succ_edge; 02372 succ_edge->prev= prev_edge; 02373 succ_edge->next= next_edge; 02374 } 02375 else 02376 { 02377 /* Update this edge */ 02378 edge->outp[BELOW]= edge->outp[ABOVE]; 02379 edge->bstate[BELOW]= edge->bstate[ABOVE]; 02380 edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; 02381 edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; 02382 edge->xb= edge->xt; 02383 } 02384 edge->outp[ABOVE]= NULL; 02385 } 02386 } 02387 } /* === END OF SCANBEAM PROCESSING ================================== */ 02388 02389 /* Generate result tristrip from tlist */ 02390 result->strip= NULL; 02391 result->num_strips= count_tristrips(tlist); 02392 if (result->num_strips > 0) 02393 { 02394 MALLOC(result->strip, result->num_strips * sizeof(gpc_vertex_list), 02395 "tristrip list creation", gpc_vertex_list); 02396 02397 s= 0; 02398 for (tn= tlist; tn; tn= tnn) 02399 { 02400 tnn= tn->next; 02401 02402 if (tn->active > 2) 02403 { 02404 /* Valid tristrip: copy the vertices and free the heap */ 02405 result->strip[s].num_vertices= tn->active; 02406 MALLOC(result->strip[s].vertex, tn->active * sizeof(gpc_vertex), 02407 "tristrip creation", gpc_vertex); 02408 v= 0; 02409 if (INVERT_TRISTRIPS) 02410 { 02411 lt= tn->v[RIGHT]; 02412 rt= tn->v[LEFT]; 02413 } 02414 else 02415 { 02416 lt= tn->v[LEFT]; 02417 rt= tn->v[RIGHT]; 02418 } 02419 while (lt || rt) 02420 { 02421 if (lt) 02422 { 02423 ltn= lt->next; 02424 result->strip[s].vertex[v].x= lt->x; 02425 result->strip[s].vertex[v].y= lt->y; 02426 v++; 02427 FREE(lt); 02428 lt= ltn; 02429 } 02430 if (rt) 02431 { 02432 rtn= rt->next; 02433 result->strip[s].vertex[v].x= rt->x; 02434 result->strip[s].vertex[v].y= rt->y; 02435 v++; 02436 FREE(rt); 02437 rt= rtn; 02438 } 02439 } 02440 s++; 02441 } 02442 else 02443 { 02444 /* Invalid tristrip: just free the heap */ 02445 for (lt= tn->v[LEFT]; lt; lt= ltn) 02446 { 02447 ltn= lt->next; 02448 FREE(lt); 02449 } 02450 for (rt= tn->v[RIGHT]; rt; rt=rtn) 02451 { 02452 rtn= rt->next; 02453 FREE(rt); 02454 } 02455 } 02456 FREE(tn); 02457 } 02458 } 02459 02460 /* Tidy up */ 02461 reset_it(&it); 02462 reset_lmt(&lmt); 02463 FREE(c_heap); 02464 FREE(s_heap); 02465 FREE(sbt); 02466 } 02467 02468 /* 02469 =========================================================================== 02470 End of file: gpc.c 02471 =========================================================================== 02472 */