gpc232/0002755000175000017500000000000010211043737012564 5ustar rafaelrafael00000000000000gpc232/gpc.c0000644000175000017500000022271110160524516013506 0ustar rafaelrafael00000000000000/* =========================================================================== Project: Generic Polygon Clipper A new algorithm for calculating the difference, intersection, exclusive-or or union of arbitrary polygon sets. File: gpc.c Author: Alan Murta (email: gpc@cs.man.ac.uk) Version: 2.32 Date: 17th December 2004 Copyright: (C) 1997-2004, Advanced Interfaces Group, University of Manchester. This software is free for non-commercial use. It may be copied, modified, and redistributed provided that this copyright notice is preserved on all copies. The intellectual property rights of the algorithms used reside with the University of Manchester Advanced Interfaces Group. You may not use this software, in whole or in part, in support of any commercial product without the express consent of the author. There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is". =========================================================================== */ /* =========================================================================== Includes =========================================================================== */ #include "gpc.h" #include #include #include /* =========================================================================== Constants =========================================================================== */ #ifndef TRUE #define FALSE 0 #define TRUE 1 #endif #define LEFT 0 #define RIGHT 1 #define ABOVE 0 #define BELOW 1 #define CLIP 0 #define SUBJ 1 #define INVERT_TRISTRIPS FALSE /* =========================================================================== Macros =========================================================================== */ #define EQ(a, b) (fabs((a) - (b)) <= GPC_EPSILON) #define PREV_INDEX(i, n) ((i - 1 + n) % n) #define NEXT_INDEX(i, n) ((i + 1 ) % n) #define OPTIMAL(v, i, n) ((v[PREV_INDEX(i, n)].y != v[i].y) || \ (v[NEXT_INDEX(i, n)].y != v[i].y)) #define FWD_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y >= v[i].vertex.y) \ && (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y)) #define NOT_FMAX(v, i, n) (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y) #define REV_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) \ && (v[NEXT_INDEX(i, n)].vertex.y >= v[i].vertex.y)) #define NOT_RMAX(v, i, n) (v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) #define VERTEX(e,p,s,x,y) {add_vertex(&((e)->outp[(p)]->v[(s)]), x, y); \ (e)->outp[(p)]->active++;} #define P_EDGE(d,e,p,i,j) {(d)= (e); \ do {(d)= (d)->prev;} while (!(d)->outp[(p)]); \ (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} #define N_EDGE(d,e,p,i,j) {(d)= (e); \ do {(d)= (d)->next;} while (!(d)->outp[(p)]); \ (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} #define MALLOC(p, b, s, t) {if ((b) > 0) { \ p= (t*)malloc(b); if (!(p)) { \ fprintf(stderr, "gpc malloc failure: %s\n", s); \ exit(0);}} else p= NULL;} #define FREE(p) {if (p) {free(p); (p)= NULL;}} /* =========================================================================== Private Data Types =========================================================================== */ typedef enum /* Edge intersection classes */ { NUL, /* Empty non-intersection */ EMX, /* External maximum */ ELI, /* External left intermediate */ TED, /* Top edge */ ERI, /* External right intermediate */ RED, /* Right edge */ IMM, /* Internal maximum and minimum */ IMN, /* Internal minimum */ EMN, /* External minimum */ EMM, /* External maximum and minimum */ LED, /* Left edge */ ILI, /* Internal left intermediate */ BED, /* Bottom edge */ IRI, /* Internal right intermediate */ IMX, /* Internal maximum */ FUL /* Full non-intersection */ } vertex_type; typedef enum /* Horizontal edge states */ { NH, /* No horizontal edge */ BH, /* Bottom horizontal edge */ TH /* Top horizontal edge */ } h_state; typedef enum /* Edge bundle state */ { UNBUNDLED, /* Isolated edge not within a bundle */ BUNDLE_HEAD, /* Bundle head node */ BUNDLE_TAIL /* Passive bundle tail node */ } bundle_state; typedef struct v_shape /* Internal vertex list datatype */ { double x; /* X coordinate component */ double y; /* Y coordinate component */ struct v_shape *next; /* Pointer to next vertex in list */ } vertex_node; typedef struct p_shape /* Internal contour / tristrip type */ { int active; /* Active flag / vertex count */ int hole; /* Hole / external contour flag */ vertex_node *v[2]; /* Left and right vertex list ptrs */ struct p_shape *next; /* Pointer to next polygon contour */ struct p_shape *proxy; /* Pointer to actual structure used */ } polygon_node; typedef struct edge_shape { gpc_vertex vertex; /* Piggy-backed contour vertex data */ gpc_vertex bot; /* Edge lower (x, y) coordinate */ gpc_vertex top; /* Edge upper (x, y) coordinate */ double xb; /* Scanbeam bottom x coordinate */ double xt; /* Scanbeam top x coordinate */ double dx; /* Change in x for a unit y increase */ int type; /* Clip / subject edge flag */ int bundle[2][2]; /* Bundle edge flags */ int bside[2]; /* Bundle left / right indicators */ bundle_state bstate[2]; /* Edge bundle state */ polygon_node *outp[2]; /* Output polygon / tristrip pointer */ struct edge_shape *prev; /* Previous edge in the AET */ struct edge_shape *next; /* Next edge in the AET */ struct edge_shape *pred; /* Edge connected at the lower end */ struct edge_shape *succ; /* Edge connected at the upper end */ struct edge_shape *next_bound; /* Pointer to next bound in LMT */ } edge_node; typedef struct lmt_shape /* Local minima table */ { double y; /* Y coordinate at local minimum */ edge_node *first_bound; /* Pointer to bound list */ struct lmt_shape *next; /* Pointer to next local minimum */ } lmt_node; typedef struct sbt_t_shape /* Scanbeam tree */ { double y; /* Scanbeam node y value */ struct sbt_t_shape *less; /* Pointer to nodes with lower y */ struct sbt_t_shape *more; /* Pointer to nodes with higher y */ } sb_tree; typedef struct it_shape /* Intersection table */ { edge_node *ie[2]; /* Intersecting edge (bundle) pair */ gpc_vertex point; /* Point of intersection */ struct it_shape *next; /* The next intersection table node */ } it_node; typedef struct st_shape /* Sorted edge table */ { edge_node *edge; /* Pointer to AET edge */ double xb; /* Scanbeam bottom x coordinate */ double xt; /* Scanbeam top x coordinate */ double dx; /* Change in x for a unit y increase */ struct st_shape *prev; /* Previous edge in sorted list */ } st_node; typedef struct bbox_shape /* Contour axis-aligned bounding box */ { double xmin; /* Minimum x coordinate */ double ymin; /* Minimum y coordinate */ double xmax; /* Maximum x coordinate */ double ymax; /* Maximum y coordinate */ } bbox; /* =========================================================================== Global Data =========================================================================== */ /* Horizontal edge state transitions within scanbeam boundary */ const h_state next_h_state[3][6]= { /* ABOVE BELOW CROSS */ /* L R L R L R */ /* NH */ {BH, TH, TH, BH, NH, NH}, /* BH */ {NH, NH, NH, NH, TH, TH}, /* TH */ {NH, NH, NH, NH, BH, BH} }; /* =========================================================================== Private Functions =========================================================================== */ static void reset_it(it_node **it) { it_node *itn; while (*it) { itn= (*it)->next; FREE(*it); *it= itn; } } static void reset_lmt(lmt_node **lmt) { lmt_node *lmtn; while (*lmt) { lmtn= (*lmt)->next; FREE(*lmt); *lmt= lmtn; } } static void insert_bound(edge_node **b, edge_node *e) { edge_node *existing_bound; if (!*b) { /* Link node e to the tail of the list */ *b= e; } else { /* Do primary sort on the x field */ if (e[0].bot.x < (*b)[0].bot.x) { /* Insert a new node mid-list */ existing_bound= *b; *b= e; (*b)->next_bound= existing_bound; } else { if (e[0].bot.x == (*b)[0].bot.x) { /* Do secondary sort on the dx field */ if (e[0].dx < (*b)[0].dx) { /* Insert a new node mid-list */ existing_bound= *b; *b= e; (*b)->next_bound= existing_bound; } else { /* Head further down the list */ insert_bound(&((*b)->next_bound), e); } } else { /* Head further down the list */ insert_bound(&((*b)->next_bound), e); } } } } static edge_node **bound_list(lmt_node **lmt, double y) { lmt_node *existing_node; if (!*lmt) { /* Add node onto the tail end of the LMT */ MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); (*lmt)->y= y; (*lmt)->first_bound= NULL; (*lmt)->next= NULL; return &((*lmt)->first_bound); } else if (y < (*lmt)->y) { /* Insert a new LMT node before the current node */ existing_node= *lmt; MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); (*lmt)->y= y; (*lmt)->first_bound= NULL; (*lmt)->next= existing_node; return &((*lmt)->first_bound); } else if (y > (*lmt)->y) /* Head further up the LMT */ return bound_list(&((*lmt)->next), y); else /* Use this existing LMT node */ return &((*lmt)->first_bound); } static void add_to_sbtree(int *entries, sb_tree **sbtree, double y) { if (!*sbtree) { /* Add a new tree node here */ MALLOC(*sbtree, sizeof(sb_tree), "scanbeam tree insertion", sb_tree); (*sbtree)->y= y; (*sbtree)->less= NULL; (*sbtree)->more= NULL; (*entries)++; } else { if ((*sbtree)->y > y) { /* Head into the 'less' sub-tree */ add_to_sbtree(entries, &((*sbtree)->less), y); } else { if ((*sbtree)->y < y) { /* Head into the 'more' sub-tree */ add_to_sbtree(entries, &((*sbtree)->more), y); } } } } static void build_sbt(int *entries, double *sbt, sb_tree *sbtree) { if (sbtree->less) build_sbt(entries, sbt, sbtree->less); sbt[*entries]= sbtree->y; (*entries)++; if (sbtree->more) build_sbt(entries, sbt, sbtree->more); } static void free_sbtree(sb_tree **sbtree) { if (*sbtree) { free_sbtree(&((*sbtree)->less)); free_sbtree(&((*sbtree)->more)); FREE(*sbtree); } } static int count_optimal_vertices(gpc_vertex_list c) { int result= 0, i; /* Ignore non-contributing contours */ if (c.num_vertices > 0) { for (i= 0; i < c.num_vertices; i++) /* Ignore superfluous vertices embedded in horizontal edges */ if (OPTIMAL(c.vertex, i, c.num_vertices)) result++; } return result; } static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, int *sbt_entries, gpc_polygon *p, int type, gpc_op op) { int c, i, min, max, num_edges, v, num_vertices; int total_vertices= 0, e_index=0; edge_node *e, *edge_table; for (c= 0; c < p->num_contours; c++) total_vertices+= count_optimal_vertices(p->contour[c]); /* Create the entire input polygon edge table in one go */ MALLOC(edge_table, total_vertices * sizeof(edge_node), "edge table creation", edge_node); for (c= 0; c < p->num_contours; c++) { if (p->contour[c].num_vertices < 0) { /* Ignore the non-contributing contour and repair the vertex count */ p->contour[c].num_vertices= -p->contour[c].num_vertices; } else { /* Perform contour optimisation */ num_vertices= 0; for (i= 0; i < p->contour[c].num_vertices; i++) if (OPTIMAL(p->contour[c].vertex, i, p->contour[c].num_vertices)) { edge_table[num_vertices].vertex.x= p->contour[c].vertex[i].x; edge_table[num_vertices].vertex.y= p->contour[c].vertex[i].y; /* Record vertex in the scanbeam table */ add_to_sbtree(sbt_entries, sbtree, edge_table[num_vertices].vertex.y); num_vertices++; } /* Do the contour forward pass */ for (min= 0; min < num_vertices; min++) { /* If a forward local minimum... */ if (FWD_MIN(edge_table, min, num_vertices)) { /* Search for the next local maximum... */ num_edges= 1; max= NEXT_INDEX(min, num_vertices); while (NOT_FMAX(edge_table, max, num_vertices)) { num_edges++; max= NEXT_INDEX(max, num_vertices); } /* Build the next edge list */ e= &edge_table[e_index]; e_index+= num_edges; v= min; e[0].bstate[BELOW]= UNBUNDLED; e[0].bundle[BELOW][CLIP]= FALSE; e[0].bundle[BELOW][SUBJ]= FALSE; for (i= 0; i < num_edges; i++) { e[i].xb= edge_table[v].vertex.x; e[i].bot.x= edge_table[v].vertex.x; e[i].bot.y= edge_table[v].vertex.y; v= NEXT_INDEX(v, num_vertices); e[i].top.x= edge_table[v].vertex.x; e[i].top.y= edge_table[v].vertex.y; e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; e[i].outp[ABOVE]= NULL; e[i].outp[BELOW]= NULL; e[i].next= NULL; e[i].prev= NULL; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? &(e[i + 1]) : NULL; e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; e[i].next_bound= NULL; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); } } /* Do the contour reverse pass */ for (min= 0; min < num_vertices; min++) { /* If a reverse local minimum... */ if (REV_MIN(edge_table, min, num_vertices)) { /* Search for the previous local maximum... */ num_edges= 1; max= PREV_INDEX(min, num_vertices); while (NOT_RMAX(edge_table, max, num_vertices)) { num_edges++; max= PREV_INDEX(max, num_vertices); } /* Build the previous edge list */ e= &edge_table[e_index]; e_index+= num_edges; v= min; e[0].bstate[BELOW]= UNBUNDLED; e[0].bundle[BELOW][CLIP]= FALSE; e[0].bundle[BELOW][SUBJ]= FALSE; for (i= 0; i < num_edges; i++) { e[i].xb= edge_table[v].vertex.x; e[i].bot.x= edge_table[v].vertex.x; e[i].bot.y= edge_table[v].vertex.y; v= PREV_INDEX(v, num_vertices); e[i].top.x= edge_table[v].vertex.x; e[i].top.y= edge_table[v].vertex.y; e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / (e[i].top.y - e[i].bot.y); e[i].type= type; e[i].outp[ABOVE]= NULL; e[i].outp[BELOW]= NULL; e[i].next= NULL; e[i].prev= NULL; e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? &(e[i + 1]) : NULL; e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; e[i].next_bound= NULL; e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; e[i].bside[SUBJ]= LEFT; } insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); } } } } return edge_table; } static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev) { if (!*aet) { /* Append edge onto the tail end of the AET */ *aet= edge; edge->prev= prev; edge->next= NULL; } else { /* Do primary sort on the xb field */ if (edge->xb < (*aet)->xb) { /* Insert edge here (before the AET edge) */ edge->prev= prev; edge->next= *aet; (*aet)->prev= edge; *aet= edge; } else { if (edge->xb == (*aet)->xb) { /* Do secondary sort on the dx field */ if (edge->dx < (*aet)->dx) { /* Insert edge here (before the AET edge) */ edge->prev= prev; edge->next= *aet; (*aet)->prev= edge; *aet= edge; } else { /* Head further into the AET */ add_edge_to_aet(&((*aet)->next), edge, *aet); } } else { /* Head further into the AET */ add_edge_to_aet(&((*aet)->next), edge, *aet); } } } } static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1, double x, double y) { it_node *existing_node; if (!*it) { /* Append a new node to the tail of the list */ MALLOC(*it, sizeof(it_node), "IT insertion", it_node); (*it)->ie[0]= edge0; (*it)->ie[1]= edge1; (*it)->point.x= x; (*it)->point.y= y; (*it)->next= NULL; } else { if ((*it)->point.y > y) { /* Insert a new node mid-list */ existing_node= *it; MALLOC(*it, sizeof(it_node), "IT insertion", it_node); (*it)->ie[0]= edge0; (*it)->ie[1]= edge1; (*it)->point.x= x; (*it)->point.y= y; (*it)->next= existing_node; } else /* Head further down the list */ add_intersection(&((*it)->next), edge0, edge1, x, y); } } static void add_st_edge(st_node **st, it_node **it, edge_node *edge, double dy) { st_node *existing_node; double den, r, x, y; if (!*st) { /* Append edge onto the tail end of the ST */ MALLOC(*st, sizeof(st_node), "ST insertion", st_node); (*st)->edge= edge; (*st)->xb= edge->xb; (*st)->xt= edge->xt; (*st)->dx= edge->dx; (*st)->prev= NULL; } else { den= ((*st)->xt - (*st)->xb) - (edge->xt - edge->xb); /* If new edge and ST edge don't cross */ if ((edge->xt >= (*st)->xt) || (edge->dx == (*st)->dx) || (fabs(den) <= DBL_EPSILON)) { /* No intersection - insert edge here (before the ST edge) */ existing_node= *st; MALLOC(*st, sizeof(st_node), "ST insertion", st_node); (*st)->edge= edge; (*st)->xb= edge->xb; (*st)->xt= edge->xt; (*st)->dx= edge->dx; (*st)->prev= existing_node; } else { /* Compute intersection between new edge and ST edge */ r= (edge->xb - (*st)->xb) / den; x= (*st)->xb + r * ((*st)->xt - (*st)->xb); y= r * dy; /* Insert the edge pointers and the intersection point in the IT */ add_intersection(it, (*st)->edge, edge, x, y); /* Head further into the ST */ add_st_edge(&((*st)->prev), it, edge, dy); } } } static void build_intersection_table(it_node **it, edge_node *aet, double dy) { st_node *st, *stp; edge_node *edge; /* Build intersection table for the current scanbeam */ reset_it(it); st= NULL; /* Process each AET edge */ for (edge= aet; edge; edge= edge->next) { if ((edge->bstate[ABOVE] == BUNDLE_HEAD) || edge->bundle[ABOVE][CLIP] || edge->bundle[ABOVE][SUBJ]) add_st_edge(&st, it, edge, dy); } /* Free the sorted edge table */ while (st) { stp= st->prev; FREE(st); st= stp; } } static int count_contours(polygon_node *polygon) { int nc, nv; vertex_node *v, *nextv; for (nc= 0; polygon; polygon= polygon->next) if (polygon->active) { /* Count the vertices in the current contour */ nv= 0; for (v= polygon->proxy->v[LEFT]; v; v= v->next) nv++; /* Record valid vertex counts in the active field */ if (nv > 2) { polygon->active= nv; nc++; } else { /* Invalid contour: just free the heap */ for (v= polygon->proxy->v[LEFT]; v; v= nextv) { nextv= v->next; FREE(v); } polygon->active= 0; } } return nc; } static void add_left(polygon_node *p, double x, double y) { vertex_node *nv; /* Create a new vertex node and set its fields */ MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); nv->x= x; nv->y= y; /* Add vertex nv to the left end of the polygon's vertex list */ nv->next= p->proxy->v[LEFT]; /* Update proxy->[LEFT] to point to nv */ p->proxy->v[LEFT]= nv; } static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target; /* Label contour as a hole */ q->proxy->hole= TRUE; if (p->proxy != q->proxy) { /* Assign p's vertex list to the left end of q's list */ p->proxy->v[RIGHT]->next= q->proxy->v[LEFT]; q->proxy->v[LEFT]= p->proxy->v[LEFT]; /* Redirect any p->proxy references to q->proxy */ for (target= p->proxy; list; list= list->next) { if (list->proxy == target) { list->active= FALSE; list->proxy= q->proxy; } } } } static void add_right(polygon_node *p, double x, double y) { vertex_node *nv; /* Create a new vertex node and set its fields */ MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); nv->x= x; nv->y= y; nv->next= NULL; /* Add vertex nv to the right end of the polygon's vertex list */ p->proxy->v[RIGHT]->next= nv; /* Update proxy->v[RIGHT] to point to nv */ p->proxy->v[RIGHT]= nv; } static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list) { polygon_node *target; /* Label contour as external */ q->proxy->hole= FALSE; if (p->proxy != q->proxy) { /* Assign p's vertex list to the right end of q's list */ q->proxy->v[RIGHT]->next= p->proxy->v[LEFT]; q->proxy->v[RIGHT]= p->proxy->v[RIGHT]; /* Redirect any p->proxy references to q->proxy */ for (target= p->proxy; list; list= list->next) { if (list->proxy == target) { list->active= FALSE; list->proxy= q->proxy; } } } } static void add_local_min(polygon_node **p, edge_node *edge, double x, double y) { polygon_node *existing_min; vertex_node *nv; existing_min= *p; MALLOC(*p, sizeof(polygon_node), "polygon node creation", polygon_node); /* Create a new vertex node and set its fields */ MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); nv->x= x; nv->y= y; nv->next= NULL; /* Initialise proxy to point to p itself */ (*p)->proxy= (*p); (*p)->active= TRUE; (*p)->next= existing_min; /* Make v[LEFT] and v[RIGHT] point to new vertex nv */ (*p)->v[LEFT]= nv; (*p)->v[RIGHT]= nv; /* Assign polygon p to the edge */ edge->outp[ABOVE]= *p; } static int count_tristrips(polygon_node *tn) { int total; for (total= 0; tn; tn= tn->next) if (tn->active > 2) total++; return total; } static void add_vertex(vertex_node **t, double x, double y) { if (!(*t)) { MALLOC(*t, sizeof(vertex_node), "tristrip vertex creation", vertex_node); (*t)->x= x; (*t)->y= y; (*t)->next= NULL; } else /* Head further down the list */ add_vertex(&((*t)->next), x, y); } static void new_tristrip(polygon_node **tn, edge_node *edge, double x, double y) { if (!(*tn)) { MALLOC(*tn, sizeof(polygon_node), "tristrip node creation", polygon_node); (*tn)->next= NULL; (*tn)->v[LEFT]= NULL; (*tn)->v[RIGHT]= NULL; (*tn)->active= 1; add_vertex(&((*tn)->v[LEFT]), x, y); edge->outp[ABOVE]= *tn; } else /* Head further down the list */ new_tristrip(&((*tn)->next), edge, x, y); } static bbox *create_contour_bboxes(gpc_polygon *p) { bbox *box; int c, v; MALLOC(box, p->num_contours * sizeof(bbox), "Bounding box creation", bbox); /* Construct contour bounding boxes */ for (c= 0; c < p->num_contours; c++) { /* Initialise bounding box extent */ box[c].xmin= DBL_MAX; box[c].ymin= DBL_MAX; box[c].xmax= -DBL_MAX; box[c].ymax= -DBL_MAX; for (v= 0; v < p->contour[c].num_vertices; v++) { /* Adjust bounding box */ if (p->contour[c].vertex[v].x < box[c].xmin) box[c].xmin= p->contour[c].vertex[v].x; if (p->contour[c].vertex[v].y < box[c].ymin) box[c].ymin= p->contour[c].vertex[v].y; if (p->contour[c].vertex[v].x > box[c].xmax) box[c].xmax= p->contour[c].vertex[v].x; if (p->contour[c].vertex[v].y > box[c].ymax) box[c].ymax= p->contour[c].vertex[v].y; } } return box; } static void minimax_test(gpc_polygon *subj, gpc_polygon *clip, gpc_op op) { bbox *s_bbox, *c_bbox; int s, c, *o_table, overlap; s_bbox= create_contour_bboxes(subj); c_bbox= create_contour_bboxes(clip); MALLOC(o_table, subj->num_contours * clip->num_contours * sizeof(int), "overlap table creation", int); /* Check all subject contour bounding boxes against clip boxes */ for (s= 0; s < subj->num_contours; s++) for (c= 0; c < clip->num_contours; c++) o_table[c * subj->num_contours + s]= (!((s_bbox[s].xmax < c_bbox[c].xmin) || (s_bbox[s].xmin > c_bbox[c].xmax))) && (!((s_bbox[s].ymax < c_bbox[c].ymin) || (s_bbox[s].ymin > c_bbox[c].ymax))); /* For each clip contour, search for any subject contour overlaps */ for (c= 0; c < clip->num_contours; c++) { overlap= 0; for (s= 0; (!overlap) && (s < subj->num_contours); s++) overlap= o_table[c * subj->num_contours + s]; if (!overlap) /* Flag non contributing status by negating vertex count */ clip->contour[c].num_vertices = -clip->contour[c].num_vertices; } if (op == GPC_INT) { /* For each subject contour, search for any clip contour overlaps */ for (s= 0; s < subj->num_contours; s++) { overlap= 0; for (c= 0; (!overlap) && (c < clip->num_contours); c++) overlap= o_table[c * subj->num_contours + s]; if (!overlap) /* Flag non contributing status by negating vertex count */ subj->contour[s].num_vertices = -subj->contour[s].num_vertices; } } FREE(s_bbox); FREE(c_bbox); FREE(o_table); } /* =========================================================================== Public Functions =========================================================================== */ void gpc_free_polygon(gpc_polygon *p) { int c; for (c= 0; c < p->num_contours; c++) FREE(p->contour[c].vertex); FREE(p->hole); FREE(p->contour); p->num_contours= 0; } void gpc_read_polygon(FILE *fp, int read_hole_flags, gpc_polygon *p) { int c, v; fscanf(fp, "%d", &(p->num_contours)); MALLOC(p->hole, p->num_contours * sizeof(int), "hole flag array creation", int); MALLOC(p->contour, p->num_contours * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); for (c= 0; c < p->num_contours; c++) { fscanf(fp, "%d", &(p->contour[c].num_vertices)); if (read_hole_flags) fscanf(fp, "%d", &(p->hole[c])); else p->hole[c]= FALSE; /* Assume all contours to be external */ MALLOC(p->contour[c].vertex, p->contour[c].num_vertices * sizeof(gpc_vertex), "vertex creation", gpc_vertex); for (v= 0; v < p->contour[c].num_vertices; v++) fscanf(fp, "%lf %lf", &(p->contour[c].vertex[v].x), &(p->contour[c].vertex[v].y)); } } void gpc_write_polygon(FILE *fp, int write_hole_flags, gpc_polygon *p) { int c, v; fprintf(fp, "%d\n", p->num_contours); for (c= 0; c < p->num_contours; c++) { fprintf(fp, "%d\n", p->contour[c].num_vertices); if (write_hole_flags) fprintf(fp, "%d\n", p->hole[c]); for (v= 0; v < p->contour[c].num_vertices; v++) fprintf(fp, "% .*lf % .*lf\n", DBL_DIG, p->contour[c].vertex[v].x, DBL_DIG, p->contour[c].vertex[v].y); } } void gpc_add_contour(gpc_polygon *p, gpc_vertex_list *new_contour, int hole) { int *extended_hole, c, v; gpc_vertex_list *extended_contour; /* Create an extended hole array */ MALLOC(extended_hole, (p->num_contours + 1) * sizeof(int), "contour hole addition", int); /* Create an extended contour array */ MALLOC(extended_contour, (p->num_contours + 1) * sizeof(gpc_vertex_list), "contour addition", gpc_vertex_list); /* Copy the old contour and hole data into the extended arrays */ for (c= 0; c < p->num_contours; c++) { extended_hole[c]= p->hole[c]; extended_contour[c]= p->contour[c]; } /* Copy the new contour and hole onto the end of the extended arrays */ c= p->num_contours; extended_hole[c]= hole; extended_contour[c].num_vertices= new_contour->num_vertices; MALLOC(extended_contour[c].vertex, new_contour->num_vertices * sizeof(gpc_vertex), "contour addition", gpc_vertex); for (v= 0; v < new_contour->num_vertices; v++) extended_contour[c].vertex[v]= new_contour->vertex[v]; /* Dispose of the old contour */ FREE(p->contour); FREE(p->hole); /* Update the polygon information */ p->num_contours++; p->hole= extended_hole; p->contour= extended_contour; } void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_polygon *result) { sb_tree *sbtree= NULL; it_node *it= NULL, *intersect; edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL; lmt_node *lmt= NULL, *local_min; polygon_node *out_poly= NULL, *p, *q, *poly, *npoly, *cf= NULL; vertex_node *vtx, *nv; h_state horiz[2]; int in[2], exists[2], parity[2]= {LEFT, LEFT}; int c, v, contributing, search, scanbeam= 0, sbt_entries= 0; int vclass, bl, br, tl, tr; double *sbt= NULL, xb, px, yb, yt, dy, ix, iy; /* Test for trivial NULL result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_contours= 0; result->hole= NULL; result->contour= NULL; return; } /* Identify potentialy contributing contours */ if (((op == GPC_INT) || (op == GPC_DIFF)) && (subj->num_contours > 0) && (clip->num_contours > 0)) minimax_test(subj, clip, op); /* Build LMT */ if (subj->num_contours > 0) s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); /* Return a NULL result if no contours contribute */ if (lmt == NULL) { result->num_contours= 0; result->hole= NULL; result->contour= NULL; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); return; } /* Build scanbeam table from scanbeam tree */ MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); build_sbt(&scanbeam, sbt, sbtree); scanbeam= 0; free_sbtree(&sbtree); /* Allow pointer re-use without causing memory leak */ if (subj == result) gpc_free_polygon(subj); if (clip == result) gpc_free_polygon(clip); /* Invert clip polygon for difference operation */ if (op == GPC_DIFF) parity[CLIP]= RIGHT; local_min= lmt; /* Process each scanbeam */ while (scanbeam < sbt_entries) { /* Set yb and yt to the bottom and top of the scanbeam */ yb= sbt[scanbeam++]; if (scanbeam < sbt_entries) { yt= sbt[scanbeam]; dy= yt - yb; } /* === SCANBEAM BOUNDARY PROCESSING ================================ */ /* If LMT node corresponding to yb exists */ if (local_min) { if (local_min->y == yb) { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) add_edge_to_aet(&aet, edge, NULL); local_min= local_min->next; } } /* Set dummy previous x value */ px= -DBL_MAX; /* Create bundles within AET */ e0= aet; e1= aet; /* Set up bundle fields of first edge */ aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); aet->bundle[ABOVE][!aet->type]= FALSE; aet->bstate[ABOVE]= UNBUNDLED; for (next_edge= aet->next; next_edge; next_edge= next_edge->next) { /* Set up bundle fields of next edge */ next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); next_edge->bundle[ABOVE][!next_edge->type]= FALSE; next_edge->bstate[ABOVE]= UNBUNDLED; /* Bundle edges above the scanbeam boundary if they coincide */ if (next_edge->bundle[ABOVE][next_edge->type]) { if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) && (e0->top.y != yb)) { next_edge->bundle[ABOVE][ next_edge->type]^= e0->bundle[ABOVE][ next_edge->type]; next_edge->bundle[ABOVE][!next_edge->type]= e0->bundle[ABOVE][!next_edge->type]; next_edge->bstate[ABOVE]= BUNDLE_HEAD; e0->bundle[ABOVE][CLIP]= FALSE; e0->bundle[ABOVE][SUBJ]= FALSE; e0->bstate[ABOVE]= BUNDLE_TAIL; } e0= next_edge; } } horiz[CLIP]= NH; horiz[SUBJ]= NH; /* Process each edge at this scanbeam boundary */ for (edge= aet; edge; edge= edge->next) { exists[CLIP]= edge->bundle[ABOVE][CLIP] + (edge->bundle[BELOW][CLIP] << 1); exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + (edge->bundle[BELOW][SUBJ] << 1); if (exists[CLIP] || exists[SUBJ]) { /* Set bundle side */ edge->bside[CLIP]= parity[CLIP]; edge->bside[SUBJ]= parity[SUBJ]; /* Determine contributing status and quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) && (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_XOR: contributing= exists[CLIP] || exists[SUBJ]; br= (parity[CLIP]) ^ (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_UNION: contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) || (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; } /* Update parity */ parity[CLIP]^= edge->bundle[ABOVE][CLIP]; parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; /* Update horizontal state */ if (exists[CLIP]) horiz[CLIP]= next_h_state[horiz[CLIP]] [((exists[CLIP] - 1) << 1) + parity[CLIP]]; if (exists[SUBJ]) horiz[SUBJ]= next_h_state[horiz[SUBJ]] [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; vclass= tr + (tl << 1) + (br << 2) + (bl << 3); if (contributing) { xb= edge->xb; switch (vclass) { case EMN: case IMN: add_local_min(&out_poly, edge, xb, yb); px= xb; cf= edge->outp[ABOVE]; break; case ERI: if (xb != px) { add_right(cf, xb, yb); px= xb; } edge->outp[ABOVE]= cf; cf= NULL; break; case ELI: add_left(edge->outp[BELOW], xb, yb); px= xb; cf= edge->outp[BELOW]; break; case EMX: if (xb != px) { add_left(cf, xb, yb); px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); cf= NULL; break; case ILI: if (xb != px) { add_left(cf, xb, yb); px= xb; } edge->outp[ABOVE]= cf; cf= NULL; break; case IRI: add_right(edge->outp[BELOW], xb, yb); px= xb; cf= edge->outp[BELOW]; edge->outp[BELOW]= NULL; break; case IMX: if (xb != px) { add_right(cf, xb, yb); px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); cf= NULL; edge->outp[BELOW]= NULL; break; case IMM: if (xb != px) { add_right(cf, xb, yb); px= xb; } merge_left(cf, edge->outp[BELOW], out_poly); edge->outp[BELOW]= NULL; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; case EMM: if (xb != px) { add_left(cf, xb, yb); px= xb; } merge_right(cf, edge->outp[BELOW], out_poly); edge->outp[BELOW]= NULL; add_local_min(&out_poly, edge, xb, yb); cf= edge->outp[ABOVE]; break; case LED: if (edge->bot.y == yb) add_left(edge->outp[BELOW], xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; px= xb; break; case RED: if (edge->bot.y == yb) add_right(edge->outp[BELOW], xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; px= xb; break; default: break; } /* End of switch */ } /* End of contributing conditional */ } /* End of edge exists conditional */ } /* End of AET loop */ /* Delete terminating edges from the AET, otherwise compute xt */ for (edge= aet; edge; edge= edge->next) { if (edge->top.y == yb) { prev_edge= edge->prev; next_edge= edge->next; if (prev_edge) prev_edge->next= next_edge; else aet= next_edge; if (next_edge) next_edge->prev= prev_edge; /* Copy bundle head state to the adjacent tail edge if required */ if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) { if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) { prev_edge->outp[BELOW]= edge->outp[BELOW]; prev_edge->bstate[BELOW]= UNBUNDLED; if (prev_edge->prev) if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) prev_edge->bstate[BELOW]= BUNDLE_HEAD; } } } else { if (edge->top.y == yt) edge->xt= edge->top.x; else edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); } } if (scanbeam < sbt_entries) { /* === SCANBEAM INTERIOR PROCESSING ============================== */ build_intersection_table(&it, aet, dy); /* Process each node in the intersection table */ for (intersect= it; intersect; intersect= intersect->next) { e0= intersect->ie[0]; e1= intersect->ie[1]; /* Only generate output for contributing intersections */ if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) { p= e0->outp[ABOVE]; q= e1->outp[ABOVE]; ix= intersect->point.x; iy= intersect->point.y + yb; in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] && e0->bside[CLIP] && e1->bside[CLIP]); in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] && e0->bside[SUBJ] && e1->bside[SUBJ]); /* Determine quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: tr= (in[CLIP]) && (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_XOR: tr= (in[CLIP]) ^ (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_UNION: tr= (in[CLIP]) || (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; } vclass= tr + (tl << 1) + (br << 2) + (bl << 3); switch (vclass) { case EMN: add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; break; case ERI: if (p) { add_right(p, ix, iy); e1->outp[ABOVE]= p; e0->outp[ABOVE]= NULL; } break; case ELI: if (q) { add_left(q, ix, iy); e0->outp[ABOVE]= q; e1->outp[ABOVE]= NULL; } break; case EMX: if (p && q) { add_left(p, ix, iy); merge_right(p, q, out_poly); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMN: add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; break; case ILI: if (p) { add_left(p, ix, iy); e1->outp[ABOVE]= p; e0->outp[ABOVE]= NULL; } break; case IRI: if (q) { add_right(q, ix, iy); e0->outp[ABOVE]= q; e1->outp[ABOVE]= NULL; } break; case IMX: if (p && q) { add_right(p, ix, iy); merge_left(p, q, out_poly); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMM: if (p && q) { add_right(p, ix, iy); merge_left(p, q, out_poly); add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; } break; case EMM: if (p && q) { add_left(p, ix, iy); merge_right(p, q, out_poly); add_local_min(&out_poly, e0, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; } break; default: break; } /* End of switch */ } /* End of contributing intersection conditional */ /* Swap bundle sides in response to edge crossing */ if (e0->bundle[ABOVE][CLIP]) e1->bside[CLIP]= !e1->bside[CLIP]; if (e1->bundle[ABOVE][CLIP]) e0->bside[CLIP]= !e0->bside[CLIP]; if (e0->bundle[ABOVE][SUBJ]) e1->bside[SUBJ]= !e1->bside[SUBJ]; if (e1->bundle[ABOVE][SUBJ]) e0->bside[SUBJ]= !e0->bside[SUBJ]; /* Swap e0 and e1 bundles in the AET */ prev_edge= e0->prev; next_edge= e1->next; if (next_edge) next_edge->prev= e0; if (e0->bstate[ABOVE] == BUNDLE_HEAD) { search= TRUE; while (search) { prev_edge= prev_edge->prev; if (prev_edge) { if (prev_edge->bstate[ABOVE] != BUNDLE_TAIL) search= FALSE; } else search= FALSE; } } if (!prev_edge) { aet->prev= e1; e1->next= aet; aet= e0->next; } else { prev_edge->next->prev= e1; e1->next= prev_edge->next; prev_edge->next= e0->next; } e0->next->prev= prev_edge; e1->next->prev= e1; e0->next= next_edge; } /* End of IT loop*/ /* Prepare for next scanbeam */ for (edge= aet; edge; edge= next_edge) { next_edge= edge->next; succ_edge= edge->succ; if ((edge->top.y == yt) && succ_edge) { /* Replace AET edge by its successor */ succ_edge->outp[BELOW]= edge->outp[ABOVE]; succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; prev_edge= edge->prev; if (prev_edge) prev_edge->next= succ_edge; else aet= succ_edge; if (next_edge) next_edge->prev= succ_edge; succ_edge->prev= prev_edge; succ_edge->next= next_edge; } else { /* Update this edge */ edge->outp[BELOW]= edge->outp[ABOVE]; edge->bstate[BELOW]= edge->bstate[ABOVE]; edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } edge->outp[ABOVE]= NULL; } } } /* === END OF SCANBEAM PROCESSING ================================== */ /* Generate result polygon from out_poly */ result->contour= NULL; result->hole= NULL; result->num_contours= count_contours(out_poly); if (result->num_contours > 0) { MALLOC(result->hole, result->num_contours * sizeof(int), "hole flag table creation", int); MALLOC(result->contour, result->num_contours * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); c= 0; for (poly= out_poly; poly; poly= npoly) { npoly= poly->next; if (poly->active) { result->hole[c]= poly->proxy->hole; result->contour[c].num_vertices= poly->active; MALLOC(result->contour[c].vertex, result->contour[c].num_vertices * sizeof(gpc_vertex), "vertex creation", gpc_vertex); v= result->contour[c].num_vertices - 1; for (vtx= poly->proxy->v[LEFT]; vtx; vtx= nv) { nv= vtx->next; result->contour[c].vertex[v].x= vtx->x; result->contour[c].vertex[v].y= vtx->y; FREE(vtx); v--; } c++; } FREE(poly); } } else { for (poly= out_poly; poly; poly= npoly) { npoly= poly->next; FREE(poly); } } /* Tidy up */ reset_it(&it); reset_lmt(&lmt); FREE(c_heap); FREE(s_heap); FREE(sbt); } void gpc_free_tristrip(gpc_tristrip *t) { int s; for (s= 0; s < t->num_strips; s++) FREE(t->strip[s].vertex); FREE(t->strip); t->num_strips= 0; } void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) { gpc_polygon c; c.num_contours= 0; c.hole= NULL; c.contour= NULL; gpc_tristrip_clip(GPC_DIFF, s, &c, t); } void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, gpc_tristrip *result) { sb_tree *sbtree= NULL; it_node *it= NULL, *intersect; edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL, *cf; lmt_node *lmt= NULL, *local_min; polygon_node *tlist= NULL, *tn, *tnn, *p, *q; vertex_node *lt, *ltn, *rt, *rtn; h_state horiz[2]; vertex_type cft; int in[2], exists[2], parity[2]= {LEFT, LEFT}; int s, v, contributing, search, scanbeam= 0, sbt_entries= 0; int vclass, bl, br, tl, tr; double *sbt= NULL, xb, px, nx, yb, yt, dy, ix, iy; /* Test for trivial NULL result cases */ if (((subj->num_contours == 0) && (clip->num_contours == 0)) || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) || ((clip->num_contours == 0) && (op == GPC_INT))) { result->num_strips= 0; result->strip= NULL; return; } /* Identify potentialy contributing contours */ if (((op == GPC_INT) || (op == GPC_DIFF)) && (subj->num_contours > 0) && (clip->num_contours > 0)) minimax_test(subj, clip, op); /* Build LMT */ if (subj->num_contours > 0) s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); if (clip->num_contours > 0) c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); /* Return a NULL result if no contours contribute */ if (lmt == NULL) { result->num_strips= 0; result->strip= NULL; reset_lmt(&lmt); FREE(s_heap); FREE(c_heap); return; } /* Build scanbeam table from scanbeam tree */ MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); build_sbt(&scanbeam, sbt, sbtree); scanbeam= 0; free_sbtree(&sbtree); /* Invert clip polygon for difference operation */ if (op == GPC_DIFF) parity[CLIP]= RIGHT; local_min= lmt; /* Process each scanbeam */ while (scanbeam < sbt_entries) { /* Set yb and yt to the bottom and top of the scanbeam */ yb= sbt[scanbeam++]; if (scanbeam < sbt_entries) { yt= sbt[scanbeam]; dy= yt - yb; } /* === SCANBEAM BOUNDARY PROCESSING ================================ */ /* If LMT node corresponding to yb exists */ if (local_min) { if (local_min->y == yb) { /* Add edges starting at this local minimum to the AET */ for (edge= local_min->first_bound; edge; edge= edge->next_bound) add_edge_to_aet(&aet, edge, NULL); local_min= local_min->next; } } /* Set dummy previous x value */ px= -DBL_MAX; /* Create bundles within AET */ e0= aet; e1= aet; /* Set up bundle fields of first edge */ aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); aet->bundle[ABOVE][!aet->type]= FALSE; aet->bstate[ABOVE]= UNBUNDLED; for (next_edge= aet->next; next_edge; next_edge= next_edge->next) { /* Set up bundle fields of next edge */ next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); next_edge->bundle[ABOVE][!next_edge->type]= FALSE; next_edge->bstate[ABOVE]= UNBUNDLED; /* Bundle edges above the scanbeam boundary if they coincide */ if (next_edge->bundle[ABOVE][next_edge->type]) { if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) && (e0->top.y != yb)) { next_edge->bundle[ABOVE][ next_edge->type]^= e0->bundle[ABOVE][ next_edge->type]; next_edge->bundle[ABOVE][!next_edge->type]= e0->bundle[ABOVE][!next_edge->type]; next_edge->bstate[ABOVE]= BUNDLE_HEAD; e0->bundle[ABOVE][CLIP]= FALSE; e0->bundle[ABOVE][SUBJ]= FALSE; e0->bstate[ABOVE]= BUNDLE_TAIL; } e0= next_edge; } } horiz[CLIP]= NH; horiz[SUBJ]= NH; /* Process each edge at this scanbeam boundary */ for (edge= aet; edge; edge= edge->next) { exists[CLIP]= edge->bundle[ABOVE][CLIP] + (edge->bundle[BELOW][CLIP] << 1); exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + (edge->bundle[BELOW][SUBJ] << 1); if (exists[CLIP] || exists[SUBJ]) { /* Set bundle side */ edge->bside[CLIP]= parity[CLIP]; edge->bside[SUBJ]= parity[SUBJ]; /* Determine contributing status and quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) && (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_XOR: contributing= exists[CLIP] || exists[SUBJ]; br= (parity[CLIP]) ^ (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; case GPC_UNION: contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) || (exists[CLIP] && exists[SUBJ] && (parity[CLIP] == parity[SUBJ])); br= (parity[CLIP]) || (parity[SUBJ]); bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); break; } /* Update parity */ parity[CLIP]^= edge->bundle[ABOVE][CLIP]; parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; /* Update horizontal state */ if (exists[CLIP]) horiz[CLIP]= next_h_state[horiz[CLIP]] [((exists[CLIP] - 1) << 1) + parity[CLIP]]; if (exists[SUBJ]) horiz[SUBJ]= next_h_state[horiz[SUBJ]] [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; vclass= tr + (tl << 1) + (br << 2) + (bl << 3); if (contributing) { xb= edge->xb; switch (vclass) { case EMN: new_tristrip(&tlist, edge, xb, yb); cf= edge; break; case ERI: edge->outp[ABOVE]= cf->outp[ABOVE]; if (xb != cf->xb) VERTEX(edge, ABOVE, RIGHT, xb, yb); cf= NULL; break; case ELI: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= NULL; cf= edge; break; case EMX: if (xb != cf->xb) VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; cf= NULL; break; case IMN: if (cft == LED) { if (cf->bot.y != yb) VERTEX(cf, BELOW, LEFT, cf->xb, yb); new_tristrip(&tlist, cf, cf->xb, yb); } edge->outp[ABOVE]= cf->outp[ABOVE]; VERTEX(edge, ABOVE, RIGHT, xb, yb); break; case ILI: new_tristrip(&tlist, edge, xb, yb); cf= edge; cft= ILI; break; case IRI: if (cft == LED) { if (cf->bot.y != yb) VERTEX(cf, BELOW, LEFT, cf->xb, yb); new_tristrip(&tlist, cf, cf->xb, yb); } VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; break; case IMX: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= NULL; cft= IMX; break; case IMM: VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= cf->outp[ABOVE]; if (xb != cf->xb) VERTEX(cf, ABOVE, RIGHT, xb, yb); cf= edge; break; case EMM: VERTEX(edge, BELOW, RIGHT, xb, yb); edge->outp[ABOVE]= NULL; new_tristrip(&tlist, edge, xb, yb); cf= edge; break; case LED: if (edge->bot.y == yb) VERTEX(edge, BELOW, LEFT, xb, yb); edge->outp[ABOVE]= edge->outp[BELOW]; cf= edge; cft= LED; break; case RED: edge->outp[ABOVE]= cf->outp[ABOVE]; if (cft == LED) { if (cf->bot.y == yb) { VERTEX(edge, BELOW, RIGHT, xb, yb); } else { if (edge->bot.y == yb) { VERTEX(cf, BELOW, LEFT, cf->xb, yb); VERTEX(edge, BELOW, RIGHT, xb, yb); } } } else { VERTEX(edge, BELOW, RIGHT, xb, yb); VERTEX(edge, ABOVE, RIGHT, xb, yb); } cf= NULL; break; default: break; } /* End of switch */ } /* End of contributing conditional */ } /* End of edge exists conditional */ } /* End of AET loop */ /* Delete terminating edges from the AET, otherwise compute xt */ for (edge= aet; edge; edge= edge->next) { if (edge->top.y == yb) { prev_edge= edge->prev; next_edge= edge->next; if (prev_edge) prev_edge->next= next_edge; else aet= next_edge; if (next_edge) next_edge->prev= prev_edge; /* Copy bundle head state to the adjacent tail edge if required */ if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) { if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) { prev_edge->outp[BELOW]= edge->outp[BELOW]; prev_edge->bstate[BELOW]= UNBUNDLED; if (prev_edge->prev) if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) prev_edge->bstate[BELOW]= BUNDLE_HEAD; } } } else { if (edge->top.y == yt) edge->xt= edge->top.x; else edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); } } if (scanbeam < sbt_entries) { /* === SCANBEAM INTERIOR PROCESSING ============================== */ build_intersection_table(&it, aet, dy); /* Process each node in the intersection table */ for (intersect= it; intersect; intersect= intersect->next) { e0= intersect->ie[0]; e1= intersect->ie[1]; /* Only generate output for contributing intersections */ if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) { p= e0->outp[ABOVE]; q= e1->outp[ABOVE]; ix= intersect->point.x; iy= intersect->point.y + yb; in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] && e0->bside[CLIP] && e1->bside[CLIP]); in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] && e0->bside[SUBJ] && e1->bside[SUBJ]); /* Determine quadrant occupancies */ switch (op) { case GPC_DIFF: case GPC_INT: tr= (in[CLIP]) && (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_XOR: tr= (in[CLIP]) ^ (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; case GPC_UNION: tr= (in[CLIP]) || (in[SUBJ]); tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); break; } vclass= tr + (tl << 1) + (br << 2) + (bl << 3); switch (vclass) { case EMN: new_tristrip(&tlist, e1, ix, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; break; case ERI: if (p) { P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); VERTEX(e0, ABOVE, RIGHT, ix, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; e0->outp[ABOVE]= NULL; } break; case ELI: if (q) { N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; e1->outp[ABOVE]= NULL; } break; case EMX: if (p && q) { VERTEX(e0, ABOVE, LEFT, ix, iy); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; } break; case IMN: P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); new_tristrip(&tlist, prev_edge, px, iy); e1->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(e1, ABOVE, RIGHT, ix, iy); new_tristrip(&tlist, e0, ix, iy); next_edge->outp[ABOVE]= e0->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); break; case ILI: if (p) { VERTEX(e0, ABOVE, LEFT, ix, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e1->outp[ABOVE]= e0->outp[ABOVE]; e0->outp[ABOVE]= NULL; } break; case IRI: if (q) { VERTEX(e1, ABOVE, RIGHT, ix, iy); P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; e1->outp[ABOVE]= NULL; } break; case IMX: if (p && q) { VERTEX(e0, ABOVE, RIGHT, ix, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); e0->outp[ABOVE]= NULL; e1->outp[ABOVE]= NULL; P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); new_tristrip(&tlist, prev_edge, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); next_edge->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); } break; case IMM: if (p && q) { VERTEX(e0, ABOVE, RIGHT, ix, iy); VERTEX(e1, ABOVE, LEFT, ix, iy); P_EDGE(prev_edge, e0, ABOVE, px, iy); VERTEX(prev_edge, ABOVE, LEFT, px, iy); new_tristrip(&tlist, prev_edge, px, iy); N_EDGE(next_edge, e1, ABOVE, nx, iy); VERTEX(next_edge, ABOVE, RIGHT, nx, iy); e1->outp[ABOVE]= prev_edge->outp[ABOVE]; VERTEX(e1, ABOVE, RIGHT, ix, iy); new_tristrip(&tlist, e0, ix, iy); next_edge->outp[ABOVE]= e0->outp[ABOVE]; VERTEX(next_edge, ABOVE, RIGHT, nx, iy); } break; case EMM: if (p && q) { VERTEX(e0, ABOVE, LEFT, ix, iy); new_tristrip(&tlist, e1, ix, iy); e0->outp[ABOVE]= e1->outp[ABOVE]; } break; default: break; } /* End of switch */ } /* End of contributing intersection conditional */ /* Swap bundle sides in response to edge crossing */ if (e0->bundle[ABOVE][CLIP]) e1->bside[CLIP]= !e1->bside[CLIP]; if (e1->bundle[ABOVE][CLIP]) e0->bside[CLIP]= !e0->bside[CLIP]; if (e0->bundle[ABOVE][SUBJ]) e1->bside[SUBJ]= !e1->bside[SUBJ]; if (e1->bundle[ABOVE][SUBJ]) e0->bside[SUBJ]= !e0->bside[SUBJ]; /* Swap e0 and e1 bundles in the AET */ prev_edge= e0->prev; next_edge= e1->next; if (e1->next) e1->next->prev= e0; if (e0->bstate[ABOVE] == BUNDLE_HEAD) { search= TRUE; while (search) { prev_edge= prev_edge->prev; if (prev_edge) { if (prev_edge->bundle[ABOVE][CLIP] || prev_edge->bundle[ABOVE][SUBJ] || (prev_edge->bstate[ABOVE] == BUNDLE_HEAD)) search= FALSE; } else search= FALSE; } } if (!prev_edge) { e1->next= aet; aet= e0->next; } else { e1->next= prev_edge->next; prev_edge->next= e0->next; } e0->next->prev= prev_edge; e1->next->prev= e1; e0->next= next_edge; } /* End of IT loop*/ /* Prepare for next scanbeam */ for (edge= aet; edge; edge= next_edge) { next_edge= edge->next; succ_edge= edge->succ; if ((edge->top.y == yt) && succ_edge) { /* Replace AET edge by its successor */ succ_edge->outp[BELOW]= edge->outp[ABOVE]; succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; prev_edge= edge->prev; if (prev_edge) prev_edge->next= succ_edge; else aet= succ_edge; if (next_edge) next_edge->prev= succ_edge; succ_edge->prev= prev_edge; succ_edge->next= next_edge; } else { /* Update this edge */ edge->outp[BELOW]= edge->outp[ABOVE]; edge->bstate[BELOW]= edge->bstate[ABOVE]; edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; edge->xb= edge->xt; } edge->outp[ABOVE]= NULL; } } } /* === END OF SCANBEAM PROCESSING ================================== */ /* Generate result tristrip from tlist */ result->strip= NULL; result->num_strips= count_tristrips(tlist); if (result->num_strips > 0) { MALLOC(result->strip, result->num_strips * sizeof(gpc_vertex_list), "tristrip list creation", gpc_vertex_list); s= 0; for (tn= tlist; tn; tn= tnn) { tnn= tn->next; if (tn->active > 2) { /* Valid tristrip: copy the vertices and free the heap */ result->strip[s].num_vertices= tn->active; MALLOC(result->strip[s].vertex, tn->active * sizeof(gpc_vertex), "tristrip creation", gpc_vertex); v= 0; if (INVERT_TRISTRIPS) { lt= tn->v[RIGHT]; rt= tn->v[LEFT]; } else { lt= tn->v[LEFT]; rt= tn->v[RIGHT]; } while (lt || rt) { if (lt) { ltn= lt->next; result->strip[s].vertex[v].x= lt->x; result->strip[s].vertex[v].y= lt->y; v++; FREE(lt); lt= ltn; } if (rt) { rtn= rt->next; result->strip[s].vertex[v].x= rt->x; result->strip[s].vertex[v].y= rt->y; v++; FREE(rt); rt= rtn; } } s++; } else { /* Invalid tristrip: just free the heap */ for (lt= tn->v[LEFT]; lt; lt= ltn) { ltn= lt->next; FREE(lt); } for (rt= tn->v[RIGHT]; rt; rt=rtn) { rtn= rt->next; FREE(rt); } } FREE(tn); } } /* Tidy up */ reset_it(&it); reset_lmt(&lmt); FREE(c_heap); FREE(s_heap); FREE(sbt); } /* =========================================================================== End of file: gpc.c =========================================================================== */ gpc232/gpc.h0000644000175000017500000001147110160522134013504 0ustar rafaelrafael00000000000000/* =========================================================================== Project: Generic Polygon Clipper A new algorithm for calculating the difference, intersection, exclusive-or or union of arbitrary polygon sets. File: gpc.h Author: Alan Murta (email: gpc@cs.man.ac.uk) Version: 2.32 Date: 17th December 2004 Copyright: (C) 1997-2004, Advanced Interfaces Group, University of Manchester. This software is free for non-commercial use. It may be copied, modified, and redistributed provided that this copyright notice is preserved on all copies. The intellectual property rights of the algorithms used reside with the University of Manchester Advanced Interfaces Group. You may not use this software, in whole or in part, in support of any commercial product without the express consent of the author. There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is". =========================================================================== */ #ifndef __gpc_h #define __gpc_h #include /* =========================================================================== Constants =========================================================================== */ /* Increase GPC_EPSILON to encourage merging of near coincident edges */ #define GPC_EPSILON (DBL_EPSILON) #define GPC_VERSION "2.32" /* =========================================================================== Public Data Types =========================================================================== */ typedef enum /* Set operation type */ { GPC_DIFF, /* Difference */ GPC_INT, /* Intersection */ GPC_XOR, /* Exclusive or */ GPC_UNION /* Union */ } gpc_op; typedef struct /* Polygon vertex structure */ { double x; /* Vertex x component */ double y; /* vertex y component */ } gpc_vertex; typedef struct /* Vertex list structure */ { int num_vertices; /* Number of vertices in list */ gpc_vertex *vertex; /* Vertex array pointer */ } gpc_vertex_list; typedef struct /* Polygon set structure */ { int num_contours; /* Number of contours in polygon */ int *hole; /* Hole / external contour flags */ gpc_vertex_list *contour; /* Contour array pointer */ } gpc_polygon; typedef struct /* Tristrip set structure */ { int num_strips; /* Number of tristrips */ gpc_vertex_list *strip; /* Tristrip array pointer */ } gpc_tristrip; /* =========================================================================== Public Function Prototypes =========================================================================== */ void gpc_read_polygon (FILE *infile_ptr, int read_hole_flags, gpc_polygon *polygon); void gpc_write_polygon (FILE *outfile_ptr, int write_hole_flags, gpc_polygon *polygon); void gpc_add_contour (gpc_polygon *polygon, gpc_vertex_list *contour, int hole); void gpc_polygon_clip (gpc_op set_operation, gpc_polygon *subject_polygon, gpc_polygon *clip_polygon, gpc_polygon *result_polygon); void gpc_tristrip_clip (gpc_op set_operation, gpc_polygon *subject_polygon, gpc_polygon *clip_polygon, gpc_tristrip *result_tristrip); void gpc_polygon_to_tristrip (gpc_polygon *polygon, gpc_tristrip *tristrip); void gpc_free_polygon (gpc_polygon *polygon); void gpc_free_tristrip (gpc_tristrip *tristrip); #endif /* =========================================================================== End of file: gpc.h =========================================================================== */ gpc232/VERSIONS.TXT0000644000175000017500000001121510160524730014433 0ustar rafaelrafael00000000000000 Generic Polygon Clipper (gpc) Revision History ============================================== v2.32 17th Dec 2004 --------------------- Fixed occasional memory leak occurring when processing some degenerate polygon arrangements. Added explicit type casting to memory allocator in support of increased code portability. v2.31 4th Jun 1999 --------------------- Separated edge merging measure based on a user-defined GPC_EPSILON value from general numeric equality testing and ordering, which now uses direct arithmetic comparison rather an EPSILON based proximity test. Fixed problem with numerical equality test during construction of local minima and scanbeam tables, leading to occasional crash. Fixed hole array memory leak in gpc_add_contour. Fixed uninitialised hole field bug in gpc_polygon_clip result. v2.30 11th Apr 1999 --------------------- Major re-write. Minor API change: additional 'hole' array field added to gpc_polygon datatype to indicate which constituent contours are internal holes, and which form external boundaries. Minor API change: additional 'hole' argument to gpc_add_contour to indicate whether the new contour is a hole or external contour. Minor API change: additional parameter to gpc_read_polygon and gpc_write_polygon to indicate whether or not to read or write contour hole flags. Fixed NULL pointer bug in add/merge left/right operations. Fixed numerical problem in intersection table generation. Fixed zero byte malloc problem. Fixed problem producing occasional 2 vertex contours. Added bounding box test optimisations. Simplified edge bundle creation, detection of scanbeam internal edge intersections and tristrip scanbeam boundary code. Renamed 'class' variable to be C++ friendly. v2.22 17th Oct 1998 --------------------- Re-implemented edge interpolation and intersection calculations to improve numerical robustness. Simplified setting of GPC_EPSILON. v2.21 19th Aug 1998 --------------------- Fixed problem causing occasional incorrect output when processing self-intersecting polygons (bow-ties etc). Removed bug which may lead to non-generation of uppermost triangle in tristrip output. v2.20 26th May 1998 --------------------- Major re-write. Added exclusive-or polygon set operation. Replaced table-based processing of edge intersections with rule-based system. Replaced two-pass approach to scanbeam interior processing with single pass method. v2.10a 14th May 1998 --------------------- Minor bug-fixes to counter some v2.10 reliability problems. v2.10 11th May 1998 --------------------- Major re-write. Incorporated edge bundle processing of AET to overcome coincident edge problems present in previous releases. Replaced Vatti's method for processing scanbeam interior regions with an adapted version of the scanbeam boundary processing algorithm. v2.02 16th Apr 1998 (unreleased) ---------------------------------- Fixed internal minimum vertex duplication in gpc_polygon_clip result. Improved line intersection code discourage superfluous intersections near line ends. Removed limited precision number formatting in gpc_write_polygon. Modification to allow subject or clip polygon to be reused as the result in gpc_polygon_clip without memory leakage. v2.01 23rd Feb 1998 --------------------- Removed bug causing duplicated vertices in output polygon. Fixed scanbeam table index overrun problem. v2.00 25th Nov 1997 --------------------- Major re-write. Replaced temporary horizontal edge work-around (using tilting) with true horizontal edge handling. Trapezoidal output replaced by tristrips. gpc_op constants now feature a `GPC_' prefix. Data structures now passed by reference to gpc functions. Replaced AET search by proxy addressing in polygon table. Eliminated most (all?) coincident vertex / edge crashes. v1.02 18th Oct 1997 (unreleased) ---------------------------------- Significantly reduced number of mallocs in build_lmt. Scanbeam table now built using heapsort rather than insertion sort. v1.01 12th Oct 1997 --------------------- Fixed memory leak during output polygon build in gpc_clip_polygon. Removed superfluous logfile debug code. Commented out malloc counts. Added missing horizontal edge tilt-correction code in gpc_clip_polygon. v1.00 8th Oct 1997 -------------------- First release. gpc232/doc/0002755000175000017500000000000007321360007013331 5ustar rafaelrafael00000000000000gpc232/doc/xor.gif0000644000175000017500000000536507321172760014646 0ustar rafaelrafael00000000000000GIF87a,ڋ޼H扦ʶ L @4L ϦRID NrS;;j/cv'hg7x舸(YX)Xe J9JFjb':@+ ;'||UܶL-<)[@$ -mMu-ή%}\.{hVKG074} 84WpSK7Xhȼ%gy+*1K::P&JDp̩3!4TȣL %bkiSΈ9hU5f-U_%J,geTMW[?Eڙ]8x}ۻoI 9(NXǃE6jɹsflCW1%ͺה-^f该oȵ޾ MZnK^.05C|wVGP62ؘEܱ26/uu=gxPCRU`J7Dr>%_YaVY֠Mjrن!ה&|,a}ElğGn 8Rh̏fUd$>$^ z;GQEI.XBПU89{un-$ė]UOt(SϞ aYti }le&i .%XzB*`ꡜ|I>c<*7!ꠢm8aҧI!~V@kx?+j^c VjJbz̭-?m,'RQֆ ﴢ+Z#{ŖZg;0/dg`s,ldgo|nŸzFn(NfU av|2sLۡb/l+HLvMBSy܀UWCEJ5f;Sj K57UL՞FR見ݵ{aVvBmw-fBQv[w//jgKuK+M~㖿}kL X/jEyx,p~PʞfiEmq踃|!+/˾O@p^y7|^km|Ҧ)p^~\rE|ֹhʰXm(lXHhe'[d(:ַҡxUUW_@Zɴ5u;_&..% ߜW&k22 ۵¥I3N&񑓂⢬[qH}Lb;GSZ&7:wL".=(K7r'\I3M헅 {b-в(p_%;Jv:Zt[X9 `;ޘ{+\ÓnmB̪A>L>8}@q4UyqӨ#ܙҐn3:gv+li;X#)RyזrxA-Ӗ*wizloSS\Siv .[*̿eWeуj`%fs^j $GxځSf\5f99{=憼iin6^ `VغJڵ#wɷw{~lo%]v3 [qfrɓ:mnRS=yYHs0{G$njjF {/6ݟzҶymȎDal Fo "| H 2z_#rG%r?gxˇz/B܏(GfU72t {oB*G *=ף2awRFBi'v=AW8tCA~Esg}qk$<,fL26Z|b7({;M&>(Yg'-00 dC%XxxTBABS c%.;gD[JXVua-c#d(Irh(Erl;px`(uhwy{ȇ}4Q;gpc232/doc/VERSIONS.TXT0000644000175000017500000001043607321172760015213 0ustar rafaelrafael00000000000000 Generic Polygon Clipper (gpc) Revision History ============================================== v2.31 4th Jun 1999 --------------------- Separated edge merging measure based on a user-defined GPC_EPSILON value from general numeric equality testing and ordering, which now uses direct arithmetic comparison rather an EPSILON based proximity test. Fixed problem with numerical equality test during construction of local minima and scanbeam tables, leading to occasional crash. Fixed hole array memory leak in gpc_add_contour. Fixed uninitialised hole field bug in gpc_polygon_clip result. v2.30 11th Apr 1999 --------------------- Major re-write. Minor API change: additional 'hole' array field added to gpc_polygon datatype to indicate which constituent contours are internal holes, and which form external boundaries. Minor API change: additional 'hole' argument to gpc_add_contour to indicate whether the new contour is a hole or external contour. Minor API change: additional parameter to gpc_read_polygon and gpc_write_polygon to indicate whether or not to read or write contour hole flags. Fixed NULL pointer bug in add/merge left/right operations. Fixed numerical problem in intersection table generation. Fixed zero byte malloc problem. Fixed problem producing occasional 2 vertex contours. Added bounding box test optimisations. Simplified edge bundle creation, detection of scanbeam internal edge intersections and tristrip scanbeam boundary code. Renamed 'class' variable to be C++ friendly. v2.22 17th Oct 1998 --------------------- Re-implemented edge interpolation and intersection calculations to improve numerical robustness. Simplified setting of GPC_EPSILON. v2.21 19th Aug 1998 --------------------- Fixed problem causing occasional incorrect output when processing self-intersecting polygons (bow-ties etc). Removed bug which may lead to non-generation of uppermost triangle in tristrip output. v2.20 26th May 1998 --------------------- Major re-write. Added exclusive-or polygon set operation. Replaced table-based processing of edge intersections with rule-based system. Replaced two-pass approach to scanbeam interior processing with single pass method. v2.10a 14th May 1998 --------------------- Minor bug-fixes to counter some v2.10 reliability problems. v2.10 11th May 1998 --------------------- Major re-write. Incorporated edge bundle processing of AET to overcome coincident edge problems present in previous releases. Replaced Vatti's method for processing scanbeam interior regions with an adapted version of the scanbeam boundary processing algorithm. v2.02 16th Apr 1998 (unreleased) ---------------------------------- Fixed internal minimum vertex duplication in gpc_polygon_clip result. Improved line intersection code discourage superfluous intersections near line ends. Removed limited precision number formatting in gpc_write_polygon. Modification to allow subject or clip polygon to be reused as the result in gpc_polygon_clip without memory leakage. v2.01 23rd Feb 1998 --------------------- Removed bug causing duplicated vertices in output polygon. Fixed scanbeam table index overrun problem. v2.00 25th Nov 1997 --------------------- Major re-write. Replaced temporary horizontal edge work-around (using tilting) with true horizontal edge handling. Trapezoidal output replaced by tristrips. gpc_op constants now feature a `GPC_' prefix. Data structures now passed by reference to gpc functions. Replaced AET search by proxy addressing in polygon table. Eliminated most (all?) coincident vertex / edge crashes. v1.02 18th Oct 1997 (unreleased) ---------------------------------- Significantly reduced number of mallocs in build_lmt. Scanbeam table now built using heapsort rather than insertion sort. v1.01 12th Oct 1997 --------------------- Fixed memory leak during output polygon build in gpc_clip_polygon. Removed superfluous logfile debug code. Commented out malloc counts. Added missing horizontal edge tilt-correction code in gpc_clip_polygon. v1.00 8th Oct 1997 -------------------- First release. gpc232/doc/union.gif0000644000175000017500000000516707321172760015166 0ustar rafaelrafael00000000000000GIF87a,ڋ޼H扦ʶ L @4L ϦRID NrS;;j/cv'hg7x舸(YX)Xe J9JFjb':@+ ;'||UܶL-<)[@$ -mMu-ή%}\.{hVKG074} 84WpSK7Xhȼ%gy+*1K::P&JDp̩3!4TȣL %bkiSΈ9hU5f-U_%J,geTMW[?Eڙ]8x}ۻoI 9(NXǃE6jɹsflCW1%ͺה-^f该oȵ޾ MZnK^.05C|wVGP62ؘS@X{{Bԗ:1ro||z|!Z]%vjU ^W\Iz_/P:ڍ(3X߉g^Y`{1GN- |:by#N'VJWxHpU:畔g[Q\xOHPԣt5f-ZTDj&h!b%f$ٴZv(JyThhUJv͓R aDx(:.Zjנr }膌QK )mb5*$6LjrmB- b+x"z %%P.-[g:Bݨ<)Q+ݮ"Xhpu"1 J6˫RLҖFDay i\^-"a7$]:?DװN&Y6yV̂0念KQS55M]ܲ"sOUTu_ No^o? ;M4ڀcEoT.X~kV7<)!/q!ƞ%рu9FqnCֳqMyE k%^O.t^xh.}JYiu7ErCbDѭ{S_^h*EHi!ohxl,QQkbťI>\>-lSG5BBsx#bZt*RFBp$ ?9h.<ыkXX+\o,^KlND#MyJ$:SICXsThʮDC4bK 1; ʞ D'<ȅSNܔ[oӛE&fEg\Amˊ2M kOm<4=zVPˢJi1pbđ3 .spAP;bldV1=cUUu$V8Jn*Y.NAM5E]ucVXXyբ'iu+^CV|OY_۽Ѯh5#W櫋U#KTj+5)KuOLpe!.rĆä;U"Ȣj* FC*6I ЅMmqΒ-JkGNWmi;gKmm_\:խyq~S-]Mt|D nyBrэNA&-qn)h5k ^1P>0W l pd^g$ƔMء!f8ƤDqXfܘOt ] ?#ۘq!#2d|M$< >y-ogeuϰž?%d'pz oh,sL]|O\*0y|#{ӆ#8uGn I5UQҬe?ό^x=bj[[V<5x^v׾41Z܊={g4{CJk =di&~-k/Ia!ӍLvL}߂`ٍ53@dzL:RH EgC -M0|ц3ik87"wÖVhs<#zU_:0T tߜRkK|I_ _"Y]ܷ`iA3.=k; Q(9\O=gWRldcD%zxY p.Ie#9bXI"o*gdIFq|͵ >n_<:Gg jueO Hn0!(#H%h')+ȂP;gpc232/doc/polygon.gif0000644000175000017500000000414007321172760015513 0ustar rafaelrafael00000000000000GIF87ahš,hڋ޼H扦ʶ L ĢL*̦ JԪjܮ N x'xGP訦X))hh酙) :*Uj:ʴʪIZ;+;k *|7D@V4aB y1DeId1ƍ})R5::2eJ,,sMHsg<{<4E{ TS4L2**6gZ5JM>^ &V׮fۮZ6ٶte+wn]4巖޺}5X`F|\Iy /̬ysbR?-z&w<廱<^i:ꫵ}}p(Z /jt͟O39Ͻ~Zz7'vrY#`KvLXp`"[9"f7b+tw*cF*c:@T#F“BDR3RYZ~•!)^0 +儦&ai+&_nfHm9F(hkLUH&:Ӣcԥ b(fFftwqةB*8XbɋժzjW"\׫h#W6!ΞjҊ_^]F'Vhҹ^T ,pqP鞛޽H{ /K /uBY ﱦ=<10Y5Tl:dÞ"@rtPԱn+\0T/ Å;в)| &G4Ke.zKд~2ַvѵׅPFEfO`2JZ.`wj[covgZUF[ x44I3qʩ*ӪXUa/KXm'Y yo<(s-Z_7b\0)~`v|U;6WH=nPcJ6.}۩AH2ƿ|>tO;_Ѕ7!}3`KE..p?$-fjI߇E- f ȧPzs-F"$L=&qpW!܀h" n<> :r;DұHhx o@6ƵPRϸ4cLȎg"Mr~$xRtErM b-YZ)KVR ӗSah5-Әd&L"MӖd1U.mӔ$/ٗMSN77$Nպ@Tzg8B/;cBx>3GR2@^"QԠO[beR(jd0wz3h+\s74v{)L`ΙsVSH(*XO_Ҥ?i#'EQH(.UV-B3P6,4[Wh]1PQ$a1sj_ QLga[X,v_ue!RJN%#Ȋ6d4`Z \BeҔ5B6(`O;lОХ&ǴCSrSϸEen C0L$4r=XHirz@*ANf u&*u"%s3N2|c {5Ȓ2{΃amͅa wLB,[7޲Sl9 {.f"J?f>%uV9*Gb%0yd.ό4ze8ytn]TofE=m?^ࡇ SIWԵx/^80G!c) H+QxKE}f3d|2O6>!QQ<.qFҧ NI5IUXIaqtZX@icY;IZ;u . _C{J9LWd\]c=lI9%2e8k`ͬka^rr$k۝`6{O=Eխ8!XG~tU3ƎWZO|t\tk$'w)}&6ȱp7~E>4~"U R!o#FqHYEͷEZ8려^1 K7ҁ-G9$z q=xA#izIޏב5eg Ge%<-)4!&K %;n7$wI]72}bBЛ\旅iE $~ܔIiu&iP)>zj~N֞|(E)YZ믠 Mz ,*];q4WPd)aJ=E0t[rٟRiKxpnk{zk봕X{le('̮`WuQ);/-pU1Jͳ9aҙSE!-oC34kxL Dإb86R$q9 R Hs d VVo3DwRAW%|ģA*lH,h. :,w*C[RY5i}5R#l:>=G M} n 9!JĬps#OZT(eS*¸O؋{)JTURIJ*%p{Ayڡџ gSUpq-$$Nר: mHXkn6]jxqAa#фLB+LAY[1d@_1X*pM('V$9U7ڐU%[Dz2%Mlʢy%W+Ҭ\GĴ>Wѽt#n.٠^dp)j۠hu2Ӫ}[ޤrSUh70IWr0#@|JRqIpEax=bLh9ETA7+Jƍ 'ܾxeȳX"Kl8AQvn2ÍmK$=x4-q+Jx߃n.f.'^~U0߳uq)jd K-E`β$Q,Josa̴ԉՊ䈺n7Ί7iOskL)BQ<ʹ Wr+=WFN>QL?SiLݡMkOxWG+@|*+Ec轗L/]'? h䴸'Th*w/m8wkRO`XC2xsL1ljRmXiwy:ڐgI#ekV3\4Is̰0Αb $AGlPhPѫN{Y{J$snX)u&7J` +$"e L APdgv#^>~!A~vIgt9ZФS̰o,]Gw$ׇObP"^[!?_Աto}e/uP;gpc232/doc/hole2.gif0000644000175000017500000001335207321172760015042 0ustar rafaelrafael00000000000000GIF87avV///888999>>>???@@@DDDIIIJJJMMMNNNOOOPPPTTTXXXYYYZZZ\\\^^^___```dddeeehhhiiijjjmmmoooppprrrtttvvvxxxyyyzzz{{{}}}~~~,vVn˲n(nTn?\iYӃb҃bN?b88h]<.0W "JD ; kPē(QD8qBRÐn(2Ց@,ࡍA'ԫNH)Tc̣/XChjڷnX#4!@pWh.jZ[W!EໄQN R†vN͑ 8@hLnA&\MFO :9 ޾ E導#OsEUg%}:ɮ/p|޿'&Q(KO>P -} ~h" Ѓ( QX PXx! a$A$T"$"H⊯( (H.h*2NE;&c:YJ\ IdLd%\PN> 啛Li~[ry&dj٠p0foo)8Ww♡IvFb('9袌6ȣ'औVji"z}v駅jꩨ*(꫰Z:k(Vw+깫()*+r9(4v,2,)?,8m)J"v-ٮ)U-j8)`u.".*jJ.7*tt/*~/W70+Nt0 p+F06+s1 +1!5rts2)Kr,214,.s39T t\K}4(mK84H}KX}5hKx5/f1bR//m0qo.u}70yR-}w/Ұqlnw$Lų8rsu KFQ ta,8 #nxmHAB5ByP 0LX-D rÇv,v C+1H._=!? >PR~!~+(]e4AF@P<WADX1AU*.h6NBⓏx>H9"SB RnXWFn "?h[Fox_JB9E-SD2LC8GӔD'BL\s,6A|$DQRœ\'tJ I9Y \:%ɠВAJ^ⓡ$!z;N<(&(˷̑GͳFf@DQ t=Kt&|(фMBnb >4*'7P-T !Xj'0/T9HVk1P\'0؆;A`@7!  k-XTD@<"%mQ{`ɀbc U-pp+| !Xk<`0/hˆvA`hPZZ0q C<-II[Eq J( Z$e&5qd  ӹn+;) @wQ.!QJXbh|UA_JQ8 $Qf?eX\BHpz|Fpdq, Veg{Y~L{ ATl]!b j 3̍d)g&}Յ{w zσs ZNF9ўwb(V G/.Scq{y l?-@})T9׏濟Z0!nx-x r@o>О5A0z탌=I#~C?P"BвR*x( ҀXX0H&H ؁9o)1P& (*8,h .1Pp8:<> @CEHG I؁K8M O Q(SU W Yh~[]X _ a{cXe( g8ih8km oHq6su wXyx5{X} h}з"h 2h8 1 / .h ,x (Ȁ'H 8H)  xx'H! Ljɨ%˨!͸ ϘxX' x!Ȉh߈ H#H ט.h# #$8FRpp $ Y)Q2Py%ɑ%)%i&+ɋh .yzR5YiR;Y蓍RA IHRGY7RM%RS hX\~\ZU}cY\Eh8`i 3Ȗ2` !HyǗ9Iyp٘_阒9Yyٙ9Yyٚ9YyWѰ|u XśfBjYP^eaYy%>#p^Sv![ 'Rgyccb ]`g%# ^^ [s:Zz !=:Zzj;&ѝVv p(*,ڢ.0"z8:*<AaVaA dA<2p3YA6cN IѤQ@ip|)e Vqfe`bʌd: hp1 Jo6a% vzĸP(Ѩ  zꨙ* :zJ: * ʊ* J ʉ J ź  ͪjѺӊ jځJ ZJʇ J纀J :*ʆ J ˅  k~ K }˄{  |Kk { {!#[ %k '{9)++K -[ /813; 5K 7k89 ;+ =; ?7A{C E+ Gk7IK M O6Q[S U W{6Y[ ] _5a;c e g{5i~k m o4qz u w{4y{k } WAE`@'\P{ Q@@H ;[{[ۻ5ʻۼ%@ p4b 5[ɗ{蛾껾싾Jr;[{q:w 4)pܢ;u J5{%Ep(*,*^A̩ % J K JRPF|HJl8,PFFJ. " .$&  UWY 9֥è#ã0ƟWp٦apzcW6ѺY .[]-_a x Df1f gtزȧ ^LǢ`Ǩ0d̡H*Bʦ`ʎʡʧʞ p\ʍ -l| ̨,>uģ̱˳2P̫|̠`^!% Ĭ@͜ uJθbΣ@lˠ˦Λί /l ,Lޜ <+=˽ s ͩ,͢ϚϾ ϯϡ@lϟϥљ-ҦBҠ`ҞB<\ӝ"ӟ@mӝӬӪpԩ `b,Mը`ՐՒ-է%Я+m֘=\,L, t>M)@nlm*n p|֦3=؝RpG NPՔ}( BD ) ,=׊] ԎM) r} }]՟(o( ڵ]M -xz͝=vMm -ϖ}י=֛]םѧѷ|ڠڶ]ܣpܢہ=ܕp_wۛ0ڄ]ڛ`Դuy={- m^ي|k\1.02.{8`=(B>D^Fn@ߟ`ͨP.L! V~,|>B^`b>d L>n 5~ߎy@d;lxz|~D^kH``#0Pu#ŀ闊ʱ*AomBD确ܮ. ~nصC^>~n蹮ٽ >͞+Ӯ8n..QKzn r.H/_  _%rt8p__`/o!@b- &i jN;o $XW (RA`BEb?d_fhj@#o 0t_vxdz|ޕ \ ^?0o =N?_'!?_/c`l ?_;gpc232/doc/hole1.gif0000644000175000017500000000763507321172760015050 0ustar rafaelrafael00000000000000GIF87a $$$)))///000444999???@@@DDDIIIOOOPPPZZZ[[[___jjjkkkoooyyyzzz,@pH,Ȥrl:ШtJZجvzxL.zn|N~W%T$$D %"%ЈG%#ܖ#~BF"#٩ nH!H&b?$dqo:n* b`*G"UX|6BhŽ,z}m i iM*gB5i/Ip4g8* 70:U ䷬'`d:+˰POjd=tI!IRR ôSzy!|!$=NXH@$I]d֦V$,'V$߀s,Hk̸Gv|w~HeM$!SQcM&0Ϊ,$5K*OFHI.GW@ >PPR*U]dʥ`ILQr -K夙xҚ2Y#bQ:1LtclA%\ o߬5GmOM:DNlFsY"w.%{O`st8YLiT BJNS5ԢND&ʀ.1E?Q 4XZ cIQ|V:2ƖC'tړ &dAfIvԩʟmJ*O3?uU ;?S+Z_˱PD)Z:huzCWCKZx]*RZbm=iůr4}*GYU#JK5bٲʱ Tmdz҃jkXChIG 퍔+\ Vin %]7c| ]@襀TWauPkx8vq-#9&*z}{Wb~)<>";M7q/(¥It웭&].[7bPR\'ޔbKV.TL'WǪbuX+-Fywlaaa?H8yS*E;C&WGfNYٜw "aԼe[jhֲEuuOy;\t:v.Cq;~7ߪU?NO;'N[ϸ7{ GN(OW0gN8_ aL0B0I2LH`(AA8egEgFs4\c0hR\3!8.HRgIȁVKBR~hZbjX[|]joX*lxcHOx|X^X`x┆NȁPH[nX?(DdhhyȈhPnv5fs+ e7chmttIg34SXo'z_-~=u'vO{D}xlywwvnw d $ +!jhMk547Ǩ {7 Q\6%9ƃ769cvZ5}|yxÐ~aup G;`;^}r_Sh8{S(?QF+('v=3>P>SH}54}x ?@ @)5 (A ~(AAX~>yk@᱒גԇT fI_ }^1GKRYfv9k(Ds)u 闆Y}P^`99d) ry8}ك9 gtuyH%Y9ɗyIfy TȘf%`E͉yۥěչ{9#ӖxiiɖY*=)ѱ^ȝkaXy9 y~f#vc,.yj 2 ɇ{I-jp/)kɚ Mģ 0I%zGɡ;X*+jU$Zhy yy ǥKʦM:_=8tZy5Z'uꐀɊ2iWxi|ڧvJD:WZƨ hÈU|*fU*|~e$oЪi*iJBȊ ifzhZ&:Z:Z*?8$Ч꭬jڀzazfpȭ*kj]DjigʙʈJ`*Q +kJZ㺭 oڬJJgY+ o ,yty,Hx2;4[6{8: A;gpc232/doc/gpc.html0000644000175000017500000005120207321172760014775 0ustar rafaelrafael00000000000000 A General Polygon Clipping Library

A General Polygon Clipping Library

Version 2.31

  Alan Murta
Advanced Interfaces Group
Department of Computer Science
University of Manchester
Manchester M13 9PL, UK

Abstract:

This document describes a C library implementation of a new polygon clipping algorithm. The techniques used are descended from Vatti's polygon clipping method [1]. Subject and clip polygons may be convex or concave, self-intersecting, contain holes, or be comprised of several disjoint contours. It extends the Vatti algorithm to allow horizontal edges in the source polygons, and to handle coincident edges in a robust manner. Four types of clipping operation are supported: intersection, exclusive-or, union or difference of subject and clip polygons. The output may take the form of polygon outlines or tristrips.

Introduction

A generic polygon (or `polygon set') consists of zero or more disjoint boundaries of arbitrary configuration. Each boundary is termed a `contour', and may be convex, concave or self-intersecting. Internal holes may be formed by contour nesting.
A polygon set
Figure 1: A polygon set with four contours.

Figure 1 shows a polygon set comprised of four contours. Over to the left is a seven sided concave contour. Lying completely within it is a four-sided contour, which forms a hole in the surrounding shape. A third, triangular contour intersects the boundary of the first. Finally, over to the right is a disjoint self-intersecting four-sided contour. The interior of the polygon has been shaded for clarity.

The library supports four kinds of clipping (Boolean set) operation: difference, intersection exclusive-or or union of subject and clip polygon pairs. These are illustrated in Figure 2. In each case, the (single) resulting polygon is shown shaded.

Difference  Intersection
Exclusive-or  Union
Figure 2: Difference, intersection, exclusive-or and union operations.

Recent API changes

The release of Version 2.30 featured some minor changes to the application programmer's interface. These included:
  • An additional hole field in the gpc_polygon datatype to differentiate hole contours from external contours.
  • A similar additional hole parameter to gpc_add_contour().
  • An extra parameter in the gpc_read_polygon() and gpc_write_polygon() functions to specify the polygon datafile format (with or without hole contour flags).

Data types

The generic polygon clipper (gpc) library defines the following structure types for the representation of polygons:
          typedef struct   /* Polygon vertex */
          {
            double            x;
            double            y;
          } gpc_vertex;

          typedef struct   /* Polygon contour */
          {
            int               num_vertices;
            gpc_vertex       *vertex;      
          } gpc_vertex_list;

          typedef struct   /* Polygon set */
          {
            int               num_contours;
            int              *hole;
            gpc_vertex_list  *contour;     
          } gpc_polygon;
The clipper takes a pair of subject and clip polygons and combines them to form a result polygon. For each contour polygon in the result polygon, the hole value flags whether or not the given contour forms a hole or an external boundary.

Alternatively a collection of tristrips may be generated as the result, this form being more suitable for rendering filled shapes. (The polygon result form is better for drawing outlines, or as intermediate values in multi-clip operations.) Tristrip collections are represented using the following data type:

          typedef struct   /* Set of tristrips */
          {
            int               num_strips;
            gpc_vertex_list  *strip;     
          } gpc_tristrip;

Library functions

Eight functions are provided by the library. Two support the reading and writing of data between polygon files and gpc_polygon structures.
          void gpc_read_polygon(FILE        *fp,
                                int          read_hole_flags,
                                gpc_polygon *polygon);
  
          void gpc_write_polygon(FILE        *fp,
                                 int          write_hole_flags,
                                 gpc_polygon *polygon);
A polygon is stored in an ASCII file using the format:

    <num-contours>
    <num-vertices-in-first-contour>
    [<first-contour-hole-flag>]
    <vertex-list>
    <num-vertices-in-second-contour>
    [<second-contour-hole-flag>]
    <vertex-list>

etc. The hole-flag values are optional, their reading and writing being controlled by setting the second argument of gpc_read_polygon() and gpc_write_polygon() to 1 (TRUE) or 0 (FALSE). Clip operations will correctly set the contour hole flags of the result polygon. This information may be ignored by the user application if it is not required.

For example, a single polygon consisting of a triangular hole within a quadrilateral (with hole flags included) may take the form:

          2
          3
          1
            4.0   4.0
            6.0   5.0
            5.0   6.0
          4
          0
            2.0   1.0
            8.0   2.0
            7.0   9.0
            1.0   7.0
An interactive drawing program may require the ability to construct a polygon contour-by-contour in an incremental fashion. The function gpc_add_contour() facilitates the merging of a new contour with an existing polygon. The final parameter has the value 1 (TRUE) or 0 (FALSE), and indicates whether or not the contour should be considered to be a hole. It is suggested that all contours are initially treated as non-hole (external) contours. Any subsequent clipping operation will set the result polygon hole flags correctly.
          void gpc_add_contour(gpc_polygon     *p,
                               gpc_vertex_list *c,
                               int              hole);
The clipping operation itself is performed by the function
          void gpc_polygon_clip(gpc_op       operation,
                                gpc_polygon *subject_p,
                                gpc_polygon *clip_p,
                                gpc_polygon *result_p);
or, if a tristrip based result is required
          void gpc_tristrip_clip(gpc_op        operation,
                                 gpc_polygon  *subject_p,
                                 gpc_polygon  *clip_p,
                                 gpc_tristrip *result_t);
In both cases the first parameter specifies the clip operation to be performed (namely GPC_DIFF, GPC_INT, GPC_XOR or GPC_UNION). This is followed by subject and clip polygon parameters. The final parameter delivers the result, either as a polygon structure or as a collection of tristrips.

 A polygon may be converted to the equivalent tristrip form using the function

          void gpc_polygon_to_tristrip(gpc_polygon   *source_p,
                                        gpc_tristrip *result_t);
Finally, the functions
          void gpc_free_polygon(gpc_polygon *p);

          void gpc_free_tristrip(gpc_tristrip *t);
may be used to release the memory taken up by a polygon or trapezoid on the heap.

Hole and external contours

A contour is classified as an external contour if its uppermost (or rightmost, when the contour top is horizontal) vertex  forms an external local maximum (EMX). If this vertex forms an internal local maximum (IMX) the contour is classified as a hole contour.

When contour edges cross (in self intersecting shapes for example) the clipper will always generate a local maximum vertex below the intersection (or when one of the edges is horizontal,  to the left of the intersection) which connects the two edge parts which  meet at the intersection point from below or from the left. The edge parts which emerge from the opposite side of the intersection point originate from a new local minimum vertex. The closed contours generated by the clipper will never self-intersect.

Holes

Figure 3: Self-intersecting contours which decompose into an external contour containing a nested hole contour.

These rules have implications with regard to how self intersecting shapes decompose into a set of closed, non-intersecting contours. The intersecting square examples of Figure 3, will each create two nested contours. In each case, the upper / rightmost maximum vertex of the internal contour forms an internal maximum, therefore the contour is classed as a hole (shown dotted). The corresponding outer contour is considered external as it terminates with an external maximum vertex.

No holes

Figure 4: Self-intersecting contours which decompose into two touching external contours.

The examples of Figure 4, however, show how similar self intersecting shapes may each create two external contours which touch at the points of intersection. In summary, the contour paths generated by the clipper are affected not only by the shape of the input polygons, but also by their orientation.

Associating holes with external contours

The current version of the clipper merely flags which contours are considered to be holes, and which form external boundaries. Discovering which holes lie within which external contours takes a little more work on the part of the user. One way to associate holes H1, H2 ... Hn with external contours E1, E2 ... Em is to use the clipper to compute the difference of the ith hole Hi and each external contour Ej, for all j from 1 to m. Any difference which gives an empty result indicates that hole i lies within external contour j.

Coincident and near-coincident edges

The clipper will merge edges which are coincident. Adjacent subject and clip contours which share share a common edge will fuse to form a single contour under the union operation, and will produce a null result along their shared boundary under the intersection operation.  Numerical precision limits are likely to cause the slight misregistration of coincident edges, resulting in a failure to merge. Increasing the value of the GPC_EPSILON constant in gpc.h will encourage the merging of near-coincident edges. However, incorrect output polygon shapes may result if GPC_EPSILON is given too large a value.

A code example

In the following example program a clip / subject polygon pair is read from an input file. The intersection of these polygons is then calculated, and the result polygon is written to file. Hole classification information is neither read nor written in this example.

          #include <stdio.h>
          #include "gpc.h"

          int main(void)
          {
            gpc_polygon subject, clip, result;
            FILE *sfp, *cfp, *ofp;
    
            sfp= fopen("subjfile", "r");
            cfp= fopen("clipfile", "r");
            gpc_read_polygon(sfp, 0, &subject);
            gpc_read_polygon(cfp, 0, &clip);
    
            gpc_polygon_clip(GPC_INT, &subject, &clip, &result);

            ofp= fopen("outfile", "w");
            gpc_write_polygon(ofp, 0, &result);
    
            gpc_free_polygon(&subject);
            gpc_free_polygon(&clip);
            gpc_free_polygon(&result);
          
            fclose(sfp);
            fclose(cfp);
            fclose(ofp);
            return 0;
          }

Known bugs

The following problems will hopefully be rectified within subsequent releases. Please see the release notes which follow for bug report procedures.
Non-serious
Tristrip and polygonal output forms will not always be optimal in minimising triangle or vertex counts.

Release notes

This software is Copyright © 1997-1999, Advanced Interfaces Group, Department of Computer Science, University of Manchester. This software is free for non-commercial use. It may be copied, modified, and redistributed provided that the copyright notices which appear within the library source files are preserved on all copies. The intellectual property rights of the algorithms used reside with the University of Manchester Advanced Interfaces Group.

You may not use this software, in whole or in part, in support of any commercial product without the express consent of the author.

There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is". Although no direct support for the use of this software will be given, bug reports may be sent to gpc@cs.man.ac.uk.

See the VERSIONS.TXT file for a revision history.

References

[1]
Vatti, B.R., "A Generic Solution to Polygon Clipping", Communications of the ACM, 35(7), July 1992, pp.56-63.

Back to the gpc home page.

gpc232/doc/diff.gif0000644000175000017500000000520007321172760014732 0ustar rafaelrafael00000000000000GIF87a,ڋ޼H扦ʶ L @4L ϦRID NrS;;j/cv'hg7x舸(YX)Xe J9JFjb':@+ ;'||UܶL-<)[@$ -mMu-ή%}\.{hVKG074} 84WpSK7Xhȼ%gy+*1K::P&JDp̩3!4TȣL %bkiSΈ9hU5f-U_%J,geTMW[?Eڙ]8x}ۻoI 9(NXǃE6jɹsflCW1%ͺה-^f该oȵ޾ MZnK^.05C|wVGP62(| wpKdz9Ưvu]vCtDe6 cK8GG]90:+}D X&#T.&b-،Y H#=D;.ʇ \A$F?"EQ.˔E@W) UZ"څ&"\)f~o'$َ|Y4`ReHE~YDP{j J)=Y9yi{F0(r)g٠%dڇE jH댭az Y:ꯧj쁷 챝1$+.lB),j|V9 E`g2㦳VBݸɼq#-ZкJDob -g@Ѝh#VUBu$H]gia2#Ǘ~K'ui"kl]_g ACoN=M;d(Kuy1Km1R7vaNI=-@ݚy],`&ȭ^n,83,+Kl-*Ҏt{y Z:;nKRF-TV %0Mav\xҖܮk4rMܗmvbMȸ8²dw$X=nx'a"65B(sG&qѳ\d\" #ρP+(/Z "#xErMq]8:2A|Afm'XI߶k8587gjX)b^_PnbE'/%њi3zl*ԁH̎}); WrcқwVcuO&Dis|?o@Fmc܇ bp-ſeEٯgc?N?7sykCD=@zmlޅX,6A@%j9}81'')+Ȃ-/1(P;gpc232/examples/0000755000175000017500000000000007321360006014377 5ustar rafaelrafael00000000000000gpc232/examples/test.c0000644000175000017500000000211207321172760015526 0ustar rafaelrafael00000000000000#include #include int main(int argc, char** argv) { gpc_polygon subject, clip, result; FILE *sfp, *cfp, *ofp; if ( argc < 3 || argc > 4 ) { fprintf (stderr, "Usage: %s subject-file clip-file [result-file]\n", argv[0]); return 1; } sfp = fopen(argv[1], "r"); if ( sfp == NULL ) { fprintf (stderr, "%s: cannot open file %s\n", argv[0], argv[1]); return 1; } cfp = fopen(argv[2], "r"); if ( cfp == NULL ) { fprintf (stderr, "%s: cannot open file %s\n", argv[0], argv[2]); return 1; } ofp = ( argc == 4 ) ? fopen(argv[3], "w") : stdout; if ( ofp == NULL ) { fprintf (stderr, "%s: cannot open file %s\n", argv[0], argv[2]); return 1; } gpc_read_polygon(sfp, 0, &subject); gpc_read_polygon(cfp, 0, &clip); gpc_polygon_clip(GPC_INT, &subject, &clip, &result); gpc_write_polygon(ofp, 0, &result); gpc_free_polygon(&subject); gpc_free_polygon(&clip); gpc_free_polygon(&result); fclose(sfp); fclose(cfp); fclose(ofp); return 0; } gpc232/examples/subj2.gpf0000644000175000017500000000223707321172760016136 0ustar rafaelrafael0000000000000027 4 100 2000 100 1900 150 1900 150 2000 4 100 1800 100 1700 150 1700 150 1800 4 150 1800 150 1700 200 1700 200 1800 4 300 1950 300 1900 400 1900 400 1950 4 300 1800 300 1750 400 1750 400 1800 4 300 1750 300 1700 400 1700 400 1750 4 500 2000 500 1950 600 1950 600 2000 4 500 1800 500 1750 600 1750 600 1800 4 500 1800 500 1700 550 1700 550 1800 4 700 1950 700 1900 800 1900 800 1950 4 700 1750 700 1700 800 1700 800 1750 4 700 1800 700 1700 750 1700 750 1800 4 900 2000 900 1900 1000 1900 1000 2000 4 900 1800 900 1700 1000 1700 1000 1800 4 900 1800 900 1700 1000 1700 1000 1800 4 1100 1950 1100 1900 1200 1900 1200 1950 4 1100 1750 1100 1700 1200 1700 1200 1750 4 1150 1800 1150 1700 1200 1700 1200 1800 4 1300 2000 1300 1950 1400 1950 1400 2000 4 1300 1800 1300 1750 1400 1750 1400 1800 4 1350 1800 1350 1700 1400 1700 1400 1800 4 150 1400 150 1300 200 1300 200 1400 4 300 1400 300 1350 400 1350 400 1400 4 500 1400 500 1300 550 1300 550 1400 4 700 1400 700 1300 750 1300 750 1400 4 1150 1400 1150 1300 1200 1300 1200 1400 4 1350 1400 1350 1300 1400 1300 1400 1400 gpc232/examples/subj1.gpf0000644000175000017500000005772107321172760016145 0ustar rafaelrafael000000000000002 702 1250.8 1312.4 1252.8 1311.6 1254 1312 1254.8 1313.6 1254.8 1314.8 1256 1314 1257.6 1313.6 1258.4 1314.4 1260.4 1315.6 1261.6 1315.6 1262.4 1315.6 1263.2 1315.6 1264.8 1314.8 1266 1315.2 1266.8 1315.2 1267.2 1312.8 1266.8 1311.2 1267.6 1310.8 1268 1310.4 1268 1308.8 1268.8 1308.4 1270 1307.2 1270 1306.8 1270 1305.6 1270.8 1305.6 1271.2 1304 1271.2 1304 1270.4 1305.6 1270.8 1306.4 1271.2 1306 1271.6 1305.6 1272 1304.8 1271.6 1303.2 1271.2 1302.8 1269.2 1302 1268.4 1300.4 1268.4 1300 1269.2 1300.4 1270.8 1302.4 1272.4 1302 1273.2 1302 1273.6 1300.4 1274.8 1299.2 1274.4 1298 1275.2 1297.2 1274.4 1295.6 1274.4 1294.8 1274.4 1294.4 1274.4 1293.6 1273.6 1293.6 1273.6 1293.6 1273.2 1295.2 1273.6 1296.4 1273.6 1297.6 1273.2 1298 1272 1299.2 1271.6 1299.2 1271.2 1298 1272 1298 1271.6 1297.6 1272 1297.2 1272.4 1295.6 1270.8 1294 1272.8 1294.8 1273.2 1293.6 1273.6 1293.2 1272.8 1292.4 1271.6 1291.2 1271.2 1291.6 1270.4 1292 1268.8 1290.8 1268.8 1289.2 1268.4 1287.6 1266 1286.4 1265.2 1286.4 1265.6 1287.2 1264.4 1287.6 1264 1287.6 1263.2 1288 1264 1287.6 1264.4 1286.4 1264.8 1286.4 1265.2 1286 1264 1285.2 1262 1286.4 1261.6 1286.4 1261.6 1286.4 1261.6 1285.6 1261.2 1284 1261.6 1283.2 1262.8 1283.2 1262.8 1281.6 1263.2 1280.8 1263.2 1280 1263.2 1278.4 1263.2 1277.6 1265.2 1275.6 1264.8 1274.4 1264 1272.4 1264.4 1271.2 1265.2 1271.2 1265.6 1270.4 1264 1271.2 1263.6 1270.4 1263.2 1270.4 1263.6 1269.2 1264.4 1268.4 1264.4 1266.8 1265.2 1264.4 1264.8 1261.6 1266 1261.2 1264.8 1258.4 1264 1257.6 1263.2 1256 1262 1254 1262.4 1251.6 1260 1247.6 1259.6 1246.8 1258.8 1247.2 1258.8 1246.8 1258.8 1246 1259.2 1245.6 1259.2 1246 1259.2 1244.4 1260 1243.6 1259.2 1242.4 1258.8 1242.4 1259.2 1242.8 1258 1242.4 1258 1242.8 1257.6 1242.8 1256 1242.4 1254.4 1244 1253.2 1243.2 1253.6 1244 1253.2 1244 1252.8 1244 1252.4 1243.6 1252.8 1242.8 1252.4 1242.8 1251.6 1242 1250.8 1241.2 1250.8 1241.6 1251.6 1242 1251.6 1242.8 1251.2 1243.6 1250.8 1244 1250.4 1245.2 1250.8 1243.6 1250.4 1242.8 1250.8 1242.8 1250 1241.6 1248.4 1242 1249.2 1243.2 1248.4 1243.2 1248.4 1243.2 1248.4 1242.4 1247.6 1242.4 1247.2 1242 1243.6 1242 1242 1241.6 1242 1241.2 1241.2 1241.6 1240.8 1241.2 1241.2 1240.4 1242 1240 1241.6 1240 1241.6 1239.2 1239.6 1239.2 1239.2 1238 1238.4 1238 1237.6 1238 1237.2 1238.8 1236.8 1238 1236.4 1238 1236.8 1236.8 1235.2 1236.4 1234.4 1235.6 1234.8 1235.2 1232.4 1234.8 1231.2 1235.2 1231.2 1235.6 1232.4 1236 1232.8 1236.8 1230.8 1236.4 1229.6 1237.2 1229.2 1236.4 1230 1236.4 1230.8 1235.6 1230.4 1234.8 1230.4 1234.4 1229.6 1233.2 1228.4 1233.2 1228 1232.8 1226.8 1233.2 1227.2 1232.8 1226.4 1232 1226.4 1230.8 1226 1231.2 1224.4 1231.2 1224 1229.6 1223.2 1229.6 1223.2 1230.4 1221.6 1230.8 1221.2 1229.2 1220.4 1229.2 1220.4 1229.2 1219.6 1230.4 1218.4 1229.6 1217.6 1230.8 1218 1229.6 1216.8 1229.6 1216.8 1230 1216.8 1228.8 1216.4 1228.8 1216 1228.8 1216.4 1228.8 1215.6 1229.2 1215.6 1228.8 1214.8 1228.8 1214.4 1228.8 1214 1229.2 1214.4 1230.4 1213.6 1231.6 1213.6 1230.8 1212.8 1230.4 1212 1230.8 1212 1229.6 1211.6 1229.6 1211.2 1229.2 1210.8 1229.6 1210.8 1230.8 1209.6 1229.6 1210 1229.6 1208.8 1229.2 1208.8 1230 1208 1229.2 1208 1230 1208 1230 1209.6 1231.2 1210.8 1231.2 1212.4 1232.8 1212 1232.8 1208.4 1231.2 1208 1231.2 1208.8 1232 1209.6 1232.8 1214 1234 1214 1234 1214 1234.4 1213.6 1234.8 1213.2 1235.6 1212.8 1236 1212.8 1235.6 1212 1234 1207.2 1233.6 1206.8 1233.2 1205.2 1233.2 1204.8 1233.2 1204 1233.2 1203.6 1233.2 1203.6 1233.2 1203.6 1233.6 1204.8 1233.2 1204.8 1234 1204.4 1234.4 1204.8 1234.4 1206.4 1234.8 1206.8 1235.6 1206 1235.6 1206.4 1236.4 1207.6 1236.8 1208 1236.4 1208 1236.8 1209.6 1236.8 1208.8 1237.2 1210 1238.4 1211.2 1238.8 1212.4 1238.4 1210.4 1238.8 1209.2 1238 1208.4 1238 1208 1237.6 1207.6 1238 1204 1236.4 1204 1236.8 1202.8 1237.2 1203.2 1237.6 1203.6 1238.4 1203.2 1239.2 1202.4 1238.8 1201.2 1238 1201.6 1239.6 1200.8 1239.6 1200.4 1240.4 1202.4 1240.8 1202.8 1240.4 1202.4 1241.2 1202 1241.6 1202.8 1242 1202.8 1242.4 1206.8 1243.6 1207.6 1244.8 1207.6 1244 1208 1243.6 1208.8 1245.6 1209.2 1245.2 1210.4 1245.2 1208.8 1246 1207.6 1246 1207.6 1245.2 1207.2 1246 1204.4 1245.2 1203.6 1246 1202.8 1246 1202.4 1246 1203.2 1245.6 1202.8 1245.2 1201.2 1246 1202 1245.6 1200.8 1245.6 1200 1246 1200 1246.4 1200 1246.8 1200.4 1247.2 1200 1247.6 1200.8 1247.6 1200.8 1247.2 1201.6 1247.2 1201.6 1248.8 1202.4 1248.4 1203.2 1249.2 1204.8 1249.6 1204.8 1248.4 1206 1248 1206.8 1249.6 1206.4 1250 1207.2 1250.4 1206.8 1249.2 1208 1248 1209.2 1248 1209.6 1248 1209.6 1248 1210.8 1248 1210.8 1248.4 1208.8 1248.8 1208.8 1250 1209.6 1249.6 1209.6 1250 1210 1251.2 1208.4 1252 1208.4 1252.4 1211.2 1252.8 1212.4 1254 1213.2 1253.2 1212.8 1254 1212.4 1254 1212.4 1254 1212.8 1255.2 1213.6 1255.6 1215.6 1254.8 1215.6 1255.2 1217.6 1254.8 1221.2 1256 1221.2 1255.2 1222 1255.2 1222.8 1256.4 1224.4 1256 1224.8 1256.4 1226 1256.4 1224 1257.2 1222.8 1257.2 1222.8 1257.6 1222.4 1258.8 1221.2 1258.4 1221.2 1257.6 1219.6 1255.6 1218.4 1256 1217.6 1254.8 1217.2 1255.6 1218 1256.4 1216 1256 1214.8 1256.4 1214.4 1257.2 1214 1257.6 1214.4 1256.4 1212.4 1256.4 1212.4 1255.6 1209.6 1256 1208.8 1256 1210.4 1256.4 1212.8 1258.4 1214 1259.6 1215.2 1259.6 1215.2 1260.8 1216 1261.2 1216 1262.8 1217.6 1263.6 1217.2 1263.6 1215.6 1264 1215.6 1264 1216.4 1264.4 1218.8 1268 1220.4 1267.6 1221.6 1268 1221.2 1268 1222.8 1268 1221.6 1268 1223.2 1268 1223.2 1268 1223.6 1267.6 1223.6 1267.6 1223.6 1268.4 1224.4 1269.6 1223.6 1269.2 1222.8 1269.6 1223.2 1270 1223.6 1270.4 1224 1270.4 1224 1271.2 1222.4 1271.2 1220.4 1270.4 1216 1270.4 1215.2 1270.8 1215.2 1272.4 1215.2 1272 1214.8 1270.8 1214.8 1270.8 1214.8 1271.6 1214.8 1272.4 1214.8 1273.2 1214.8 1273.2 1215.2 1273.2 1214.8 1273.6 1214.8 1273.2 1214.8 1273.6 1214.4 1273.6 1214.8 1274 1214.4 1274 1213.6 1273.2 1213.2 1272.8 1212 1273.6 1211.2 1273.6 1211.6 1274.4 1211.2 1274.4 1213.2 1275.2 1213.2 1275.2 1212.8 1275.2 1212.8 1275.6 1211.6 1275.6 1211.6 1275.6 1211.6 1275.6 1211.2 1275.6 1210.8 1275.6 1210.4 1274.8 1209.2 1275.6 1208.8 1276 1208 1275.6 1207.6 1276.4 1207.2 1276 1208 1277.6 1209.2 1277.2 1208.4 1278 1208.4 1278.8 1208 1279.2 1207.2 1279.6 1208.8 1279.2 1208.8 1280 1210.4 1279.6 1209.6 1281.2 1212 1281.2 1212 1282.4 1212.4 1283.6 1214 1284.4 1215.6 1284 1216.4 1284.8 1215.6 1284.8 1216 1285.2 1215.6 1285.2 1216 1286.4 1216 1286.4 1216.4 1286.8 1214 1286.8 1213.2 1286.8 1212 1286.8 1212 1286.8 1212.4 1288.8 1213.6 1288 1214 1287.6 1214 1287.6 1214 1289.2 1213.6 1289.2 1213.6 1288.4 1213.6 1289.2 1213.6 1289.6 1212.8 1290.4 1212.8 1291.2 1213.6 1291.6 1213.2 1291.6 1214 1292.4 1213.2 1292.4 1213.2 1291.6 1212.4 1292 1212 1292 1212 1292 1212.8 1292.8 1212.4 1293.2 1212.8 1293.6 1212.4 1294 1212.8 1294.4 1212.8 1294.4 1211.6 1295.2 1211.6 1294.4 1211.2 1294.4 1211.6 1294 1210.8 1294 1210.8 1293.6 1210.4 1293.2 1210.8 1292 1210 1292.4 1210.4 1295.2 1210.8 1295.2 1210 1296 1210.8 1296 1210.8 1296.4 1212 1297.6 1212.4 1296.4 1213.2 1295.6 1212.8 1294.8 1212 1295.6 1212 1295.2 1213.6 1294.8 1213.6 1296 1214 1295.6 1214 1296.4 1214 1296.4 1213.6 1297.2 1214 1297.6 1215.6 1297.2 1218.4 1296.8 1219.6 1295.2 1220.4 1296.4 1221.2 1296 1221.6 1295.2 1222.4 1294.8 1222 1294.4 1222.4 1294 1222 1293.6 1222.8 1293.2 1223.2 1292.8 1224.4 1295.2 1226 1295.2 1227.6 1294 1228.4 1294.4 1228.8 1294.4 1229.6 1294 1230.8 1292.8 1231.6 1292.8 1230.8 1294 1230.4 1294 1231.2 1294.4 1232.4 1294.4 1231.2 1295.6 1231.2 1295.6 1232.4 1295.2 1232.4 1295.6 1231.6 1296 1230.4 1295.6 1230 1296 1231.2 1296.8 1231.2 1297.6 1231.6 1297.6 1232.8 1298 1232.4 1298.8 1232.8 1299.2 1233.2 1298.8 1235.2 1298.8 1236 1300 1236.4 1300.4 1237.6 1302.4 1238 1302.4 1238.4 1302 1238 1302.4 1236 1302.4 1235.6 1302.4 1235.6 1302.4 1235.6 1302.4 1234.8 1302.4 1233.2 1300.8 1233.2 1302 1234.4 1302.4 1234.4 1302.4 1233.2 1302.4 1232.8 1302.4 1231.6 1302.4 1230.4 1302.4 1228.8 1304 1229.2 1304.4 1228.8 1304.4 1229.6 1304.4 1229.2 1305.6 1230.4 1306.4 1234 1305.6 1233.2 1306.4 1232.4 1306.4 1233.2 1306.4 1234.4 1305.6 1232.4 1307.6 1233.2 1307.6 1235.6 1307.6 1234.8 1308.4 1234.8 1308.8 1235.6 1308.4 1236 1308.4 1235.6 1308.8 1234.8 1309.2 1234.8 1308.8 1234 1309.2 1234 1310.4 1235.2 1310.4 1234.8 1310.4 1234 1312 1234.8 1312 1234.8 1312.8 1235.6 1312.4 1235.6 1313.2 1236 1313.2 1236 1313.2 1236.4 1313.2 1236.4 1313.6 1236.8 1314.8 1238.4 1314.4 1238.8 1314.4 1238.8 1314.4 1238.4 1314 1239.6 1314.4 1240.4 1314.8 1240.4 1316.4 1240.8 1316.8 1241.6 1316.4 1241.6 1315.6 1242 1315.6 1242.4 1314.8 1242 1314.4 1242.8 1314.4 1242 1314.4 1242.8 1314.4 1242.8 1314.4 1243.2 1315.6 1242.4 1315.6 1242 1316.8 1242.8 1316.8 1243.2 1316.8 1243.2 1314.8 1244 1314.4 1244.8 1314 1244.8 1313.2 1245.2 1314 1244.8 1316.4 1244.4 1314.4 1244.4 1315.2 1244.4 1316 1243.6 1316.4 1244 1316.8 1244.4 1316.8 1245.2 1317.6 1246 1316.8 1246 1315.2 1246.8 1314 1246.8 1314 1246.8 1312.8 1245.2 1311.6 1246 1311.6 1246.4 1311.6 1245.2 1311.2 1244.8 1310 1246.4 1311.6 1247.6 1312 1247.6 1312.4 1247.6 1314 1246.8 1316 1247.6 1316.4 1246.8 1317.2 1247.6 1317.2 1247.6 1317.2 1248 1317.2 1249.2 1317.6 1249.6 1317.6 1249.6 1317.2 1250.8 1317.2 1249.6 1317.6 1249.2 1318.4 1249.6 1318.4 1249.2 1319.2 1248.8 1319.6 1248.8 1319.6 1250.8 1319.2 1251.6 1318.4 1252.4 1317.6 1255.2 1316 1255.2 1315.6 1252 1314 1155 1284 1396.4 1284.4 1395.6 1285.2 1395.6 1286 1395.2 1286 1394.8 1286.8 1395.2 1286.4 1395.2 1286.4 1395.2 1286.8 1394.8 1288 1394 1288 1393.6 1286.8 1391.6 1288 1392.8 1288 1393.6 1288.8 1393.6 1288.8 1394.8 1290 1394.4 1290.8 1393.6 1291.2 1393.2 1290.4 1391.2 1291.6 1393.6 1292.8 1393.6 1293.6 1392.8 1293.6 1393.2 1293.6 1394 1294.4 1393.6 1294.8 1394.4 1295.6 1394 1296 1394.8 1296 1394.4 1297.6 1394.4 1298.8 1394.4 1300.4 1394.8 1302 1394.8 1302 1394.4 1302.4 1394.4 1303.2 1395.2 1304.4 1394.8 1304.4 1395.2 1303.6 1396.4 1304.4 1396.8 1304.4 1396.4 1306.8 1396 1306.8 1395.6 1308.4 1396 1308.8 1395.6 1307.6 1392.8 1307.6 1392 1308.8 1392 1307.6 1389.6 1307.2 1389.2 1306.4 1387.6 1304.4 1387.2 1302.8 1384 1299.6 1382 1298.8 1381.6 1298 1380.8 1296.4 1379.2 1296 1377.6 1295.2 1377.6 1294.4 1377.2 1293.6 1376.8 1293.6 1376.4 1295.2 1376.4 1296.4 1376.8 1296.8 1376.8 1296.8 1376.4 1298 1376.4 1298.8 1377.6 1299.2 1377.2 1298 1375.2 1296.4 1373.6 1296 1373.6 1296 1374 1295.2 1374 1294 1373.2 1292.4 1373.6 1292.4 1372.4 1290.8 1371.2 1290.4 1370.4 1293.2 1372.8 1295.2 1372.8 1295.6 1373.6 1296.4 1372.8 1294.8 1371.2 1294.8 1371.2 1294.8 1370.4 1294 1370 1293.6 1369.6 1292.8 1370 1293.2 1369.6 1292.8 1368.8 1293.6 1368.4 1294 1368.4 1294 1368.4 1295.6 1370 1295.6 1370.4 1295.2 1371.2 1298 1371.2 1300.4 1372 1302 1372.4 1302.8 1373.6 1304.8 1374.4 1308.8 1372.4 1310.8 1373.6 1311.2 1373.2 1312.4 1373.2 1316.8 1372.4 1317.6 1372.4 1318.4 1373.2 1319.6 1372.4 1320.4 1373.2 1322 1373.2 1322 1372.4 1322.8 1372.8 1323.6 1372.4 1324 1371.6 1324 1370.4 1324.8 1368.8 1324.4 1368.8 1324.8 1368 1325.2 1368 1321.6 1363.2 1320.8 1360.4 1321.2 1359.6 1319.6 1356 1319.6 1354.4 1318.4 1352.4 1317.2 1351.2 1316.8 1351.2 1316.8 1349.2 1316.8 1349.2 1315.6 1348.4 1316 1347.6 1315.2 1346 1312.8 1344.4 1312.4 1344 1311.6 1344 1310.8 1343.6 1310 1344 1309.2 1343.6 1308.4 1343.6 1305.6 1342 1304.8 1341.6 1305.2 1341.2 1306.4 1342 1310.4 1343.6 1311.6 1343.2 1311.2 1342 1311.2 1341.6 1311.2 1341.6 1312 1340.4 1313.6 1340.4 1314.8 1338.8 1313.2 1338 1311.6 1337.6 1310 1337.6 1309.6 1337.6 1307.2 1335.2 1306.8 1334.4 1305.2 1334 1303.6 1332.8 1301.2 1334 1299.6 1334 1299.6 1332.8 1300 1332.8 1302 1332.8 1304 1332.4 1304.4 1332.8 1305.2 1332.4 1307.2 1332.4 1307.6 1331.6 1308.8 1331.6 1309.6 1332.4 1310 1332.4 1310.8 1332.8 1310.8 1333.6 1311.6 1334.4 1313.6 1334.4 1314.8 1332.8 1314.8 1332.8 1316 1332.8 1318.4 1330.8 1320.8 1330.4 1320.8 1330.4 1321.6 1329.6 1322.8 1326.8 1324.8 1324.4 1325.2 1324.4 1325.6 1324 1325.6 1323.6 1325.6 1323.2 1326.8 1323.2 1327.2 1323.2 1327.6 1321.6 1328.4 1320.4 1328.4 1319.2 1328 1318 1328.8 1316.8 1328.4 1315.6 1329.6 1313.2 1329.6 1312.4 1330.8 1309.2 1331.6 1308 1331.6 1307.2 1332.8 1303.6 1333.2 1302 1334.4 1301.6 1334 1301.6 1334.4 1300.8 1334.4 1299.6 1334.4 1299.6 1334.8 1299.6 1334.8 1300 1337.2 1299.2 1339.6 1298.4 1341.6 1297.2 1342.8 1296.8 1343.6 1296.4 1343.6 1295.6 1344.8 1294 1346 1292 1347.2 1291.2 1347.6 1289.6 1350 1288.8 1348.8 1287.6 1348 1286.4 1349.6 1282.8 1351.2 1280 1352.8 1277.2 1353.2 1275.6 1353.2 1275.6 1353.2 1276.4 1352.8 1276.8 1351.6 1277.2 1351.2 1276.8 1350.4 1276.8 1349.6 1277.2 1348 1279.2 1347.2 1279.6 1345.6 1278.4 1343.6 1278 1342.4 1278.8 1341.2 1278 1341.6 1277.6 1342.8 1278 1344 1277.6 1344.8 1277.6 1347.2 1278.4 1348 1278 1348.4 1277.2 1350.4 1275.6 1351.2 1275.6 1351.6 1274.4 1352.4 1273.2 1353.6 1273.2 1354 1272.4 1354.8 1271.2 1356 1267.6 1356.8 1266 1356.4 1264.4 1354 1262 1352.8 1259.6 1352.4 1259.6 1352 1259.2 1352.8 1259.2 1353.6 1259.2 1354 1258.8 1355.6 1257.2 1357.2 1257.6 1357.6 1256.4 1357.6 1256.8 1358 1258 1358.8 1260.8 1359.6 1261.6 1360.4 1261.2 1361.2 1261.6 1364 1261.2 1364.4 1261.6 1364.8 1261.6 1365.6 1261.6 1366.4 1261.6 1365.6 1262 1366 1262 1366.8 1262 1367.6 1261.6 1370.4 1261.2 1372.4 1259.6 1376 1257.2 1376.4 1257.2 1377.6 1254.4 1377.6 1252.8 1378 1251.6 1377.6 1250 1378 1248.8 1376.4 1245.6 1376.4 1243.6 1376 1241.2 1374 1240 1372.8 1237.2 1371.6 1238.8 1371.6 1237.6 1370 1238 1369.6 1237.6 1372 1237.6 1370.8 1235.2 1371.6 1235.2 1371.6 1236 1372 1235.2 1372 1235.2 1370.8 1234 1369.6 1233.2 1368.4 1233.6 1367.6 1234 1366.8 1234 1366 1233.2 1365.6 1232.4 1363.6 1232 1364.4 1231.6 1364.8 1231.6 1366.4 1232.8 1367.2 1232.4 1367.2 1231.2 1366.8 1229.6 1366.4 1229.6 1365.2 1229.2 1366 1229.6 1366.4 1229.2 1366.4 1229.6 1367.2 1229.6 1367.6 1229.2 1365.2 1227.2 1363.2 1227.2 1362 1226 1360.4 1226 1360 1226 1359.2 1225.2 1360 1225.2 1360.4 1226 1361.6 1226 1364 1226 1364.4 1225.2 1364 1224.8 1363.2 1224.8 1362.4 1224.4 1361.6 1224.4 1362.4 1223.6 1363.2 1223.6 1363.6 1223.6 1364 1223.6 1364 1224.4 1364.4 1224 1364.4 1224.4 1364.4 1225.2 1366.8 1224.8 1367.6 1223.2 1366.8 1223.2 1365.2 1222.8 1367.2 1222.8 1371.6 1224 1375.2 1224.4 1374.8 1223.2 1374 1222 1374.8 1220.4 1374.4 1218.4 1374 1218 1372 1217.2 1371.6 1217.2 1370.4 1216.4 1369.2 1215.6 1368.4 1214.4 1368.8 1212.8 1366 1212.8 1364.8 1212.4 1364 1211.6 1359.2 1210 1358.4 1208.4 1357.6 1207.6 1354.4 1208.8 1351.2 1210 1344 1208.4 1343.6 1207.6 1343.2 1208.4 1343.2 1207.2 1342.4 1207.2 1340.8 1208.4 1341.2 1208.4 1340.8 1209.6 1340.4 1209.2 1340 1209.6 1339.6 1209.6 1340 1209.2 1340.4 1208.4 1338.8 1208.4 1339.2 1208.4 1339.2 1209.6 1338.4 1209.2 1338.4 1208 1338 1208 1337.6 1208 1338 1209.2 1338 1210 1336.4 1209.2 1337.2 1208.8 1336.8 1208 1334.4 1209.2 1333.6 1210.4 1332 1211.2 1332 1210.8 1333.2 1210.4 1334.4 1208.8 1333.6 1208 1332.4 1208 1331.2 1206.8 1329.2 1206.8 1328 1206.8 1328.4 1206.8 1328.4 1206.8 1327.2 1206.8 1326.4 1206.8 1325.2 1205.6 1325.2 1206.8 1323.6 1206.8 1323.2 1205.6 1323.6 1206 1323.6 1205.2 1325.2 1205.2 1325.2 1204.4 1325.6 1204.4 1325.2 1204 1324.8 1203.2 1323.6 1203.2 1323.2 1203.2 1321.2 1204 1318 1204 1317.6 1203.6 1317.2 1202.8 1318 1202 1317.2 1201.2 1317.2 1202.4 1314.8 1204.4 1312.4 1206 1310.8 1206.4 1309.6 1205.6 1307.6 1205.6 1306 1205.6 1303.6 1203.2 1302.8 1203.6 1302 1205.2 1302.4 1203.2 1301.2 1201.2 1301.6 1200 1300.4 1199.2 1300.8 1198.8 1301.6 1198 1301.2 1198 1300.8 1197.6 1300 1197.2 1300 1196.8 1299.2 1196.4 1299.2 1195.6 1299.2 1194.4 1298 1194 1297.2 1194.4 1297.2 1194.4 1296.4 1194.4 1295.6 1196 1294.4 1196.8 1292.8 1196.8 1291.6 1196.8 1291.6 1197.6 1290.4 1198 1290.4 1198 1291.2 1197.6 1290.8 1196.8 1290 1196.8 1289.6 1198 1288.8 1198 1287.2 1198 1286.4 1197.2 1283.6 1197.2 1283.2 1197.2 1283.2 1197.6 1282 1197.2 1281.2 1194.8 1280 1195.2 1279.6 1194.4 1278.8 1194.4 1278.8 1192.8 1278 1192.8 1278.4 1192.8 1278 1192.8 1278 1195.2 1277.6 1195.2 1277.2 1194.4 1277.6 1193.6 1277.2 1192.8 1277.6 1192.8 1277.2 1192.8 1277.2 1192 1276.4 1192 1277.2 1191.6 1277.2 1190.8 1276.8 1190 1275.6 1190 1275.2 1188.8 1274.4 1190 1274 1191.2 1273.2 1191.6 1270.8 1193.2 1270 1192.8 1270 1192 1269.6 1191.2 1268 1190.8 1267.2 1191.6 1267.6 1192 1267.2 1193.6 1268 1193.2 1270 1195.2 1271.6 1194.4 1272.4 1195.2 1273.2 1195.2 1274 1196.4 1274.8 1197.6 1276 1198.4 1276 1199.2 1277.6 1199.6 1278.4 1200.8 1278 1201.6 1278.4 1202.4 1278.8 1202.4 1279.6 1203.2 1279.6 1202.8 1280 1203.6 1282 1203.6 1282 1205.2 1283.2 1206.4 1283.6 1207.2 1285.6 1208 1285.6 1210.8 1286.4 1213.2 1286.8 1213.2 1288.8 1212.8 1289.2 1212.8 1290.4 1213.6 1291.2 1214.4 1290 1216.4 1290.4 1216.4 1290.4 1216.8 1290.8 1216.8 1297.2 1218.8 1300 1218.4 1300.4 1218.4 1302.4 1217.6 1302.8 1217.2 1304.4 1217.2 1306 1217.6 1308 1217.6 1308.8 1218.4 1308.8 1218.8 1308.8 1220 1309.2 1220 1309.6 1222 1310.4 1222.8 1312.4 1224.4 1313.2 1224.8 1316.8 1230 1318 1230.8 1318 1231.6 1318 1230.8 1316.8 1230.8 1313.2 1227.2 1310.8 1226 1309.6 1225.6 1309.6 1225.6 1309.6 1225.6 1308.8 1225.6 1307.2 1224.4 1307.2 1223.6 1306.4 1223.6 1306.4 1222.8 1305.2 1222.4 1302.8 1222.4 1300.8 1222.8 1299.2 1224.4 1298.4 1224.4 1297.2 1225.6 1296.4 1228 1294 1228 1294 1227.6 1294 1226 1291.6 1226 1291.6 1226 1290.8 1225.6 1289.6 1226 1289.6 1227.2 1290 1227.6 1290.4 1227.6 1290.8 1227.6 1292.4 1228 1292.8 1228.8 1293.2 1229.2 1292 1228.8 1291.2 1229.6 1289.6 1229.2 1289.6 1229.2 1288.4 1230 1288.4 1230.8 1289.6 1230 1288.8 1231.2 1288.8 1232 1288.4 1231.2 1287.6 1231.6 1287.6 1230.8 1284.4 1230.4 1283.6 1229.2 1282.8 1229.2 1282.4 1228.4 1281.2 1228 1280 1227.6 1278.4 1228.4 1278.4 1229.2 1277.6 1229.2 1277.6 1229.6 1278.4 1229.2 1278.8 1229.6 1278.8 1229.6 1279.6 1229.6 1281.2 1230 1279.6 1230.4 1276.8 1230.4 1276.8 1229.6 1276 1230.4 1275.6 1231.2 1276.4 1231.2 1276.8 1232 1278 1232 1277.6 1234 1276.4 1234 1274.4 1234.4 1274.8 1236 1276 1235.6 1276.4 1236 1278 1236.8 1278 1237.6 1279.6 1237.2 1280 1237.2 1280.8 1237.2 1280.8 1238 1281.2 1237.2 1282 1237.6 1282 1238.4 1282.8 1238.8 1283.6 1240 1284 1240 1284 1240.8 1286.8 1240.4 1288.8 1242.4 1289.6 1242.4 1290.8 1242.8 1292 1244.8 1292.8 1246.4 1293.6 1249.6 1294.4 1250 1295.2 1250.4 1293.6 1250.4 1292.4 1251.6 1293.6 1254 1294.4 1255.2 1293.6 1254.4 1293.2 1255.2 1292.4 1255.6 1292 1256.4 1292.8 1257.6 1292 1258.4 1288.8 1258.4 1288 1257.6 1287.6 1256.8 1287.6 1256.4 1286.8 1255.2 1285.6 1256.8 1285.2 1256.4 1284 1256.8 1283.6 1256 1283.6 1256.8 1284 1257.6 1285.6 1258.8 1286.8 1259.6 1289.2 1261.6 1289.2 1263.6 1290 1263.6 1290 1263.6 1292 1266.4 1292.8 1266.8 1293.6 1266.8 1296.4 1267.6 1296.8 1267.6 1296.4 1268.8 1297.6 1268.4 1298.4 1267.6 1300 1268 1303.6 1269.2 1304.8 1269.2 1304.8 1268.8 1307.6 1266.4 1308 1267.6 1306 1270 1306.4 1270 1308.4 1271.2 1308.8 1270.4 1310 1268.4 1311.2 1268 1312.4 1268 1312.8 1268.8 1312 1268.8 1310.4 1268.8 1309.6 1270.4 1307.6 1273.2 1309.2 1277.2 1311.2 1278.8 1308.4 1278.8 1308 1280.4 1308.4 1282.8 1310.4 1283.6 1310.8 1283.2 1311.2 1284.4 1310.8 1284.4 1310.8 1284.8 1310.4 1284.8 1310 1285.6 1310.8 1286.8 1311.6 1286.8 1311.6 1287.6 1311.2 1289.2 1311.6 1290 1310.8 1290 1310 1288.4 1309.6 1288.4 1308.4 1290 1307.6 1287.6 1306.8 1286.4 1307.2 1286.4 1305.6 1287.6 1305.6 1288.4 1305.6 1288.8 1306 1288.8 1306.4 1291.2 1305.6 1289.6 1304.4 1289.6 1303.2 1291.6 1303.2 1292.8 1300 1297.2 1300.8 1299.2 1301.2 1300.4 1302 1302 1302.8 1303.2 1302.8 1304 1303.6 1305.6 1304.4 1306 1304.4 1305.6 1305.2 1305.6 1305.6 1306 1305.2 1306 1305.2 1306.8 1306 1307.6 1307.6 1306.8 1308.4 1307.2 1308.4 1307.6 1308 1307.6 1308 1308 1308.8 1308 1308.8 1308.4 1307.2 1308.4 1305.6 1308 1303.2 1308 1302.8 1308 1302 1308 1301.6 1308 1301.2 1308 1301.2 1308 1301.2 1305.6 1300.8 1305.6 1299.2 1306 1298.4 1305.6 1298 1306 1297.6 1305.6 1297.6 1306 1298 1306 1297.2 1305.2 1297.6 1304.8 1295.6 1303.2 1294.4 1303.2 1294.4 1304.8 1294 1303.6 1293.2 1303.6 1292 1304.8 1292.4 1306 1291.6 1304.8 1290.4 1306 1290 1306.4 1289.6 1307.2 1289.6 1306 1289.2 1306.4 1289.2 1304.8 1290.4 1304.4 1290 1303.6 1290.4 1301.6 1290 1301.6 1288 1301.6 1286.8 1303.6 1284.4 1304.8 1284 1306 1283.6 1306.4 1282.4 1305.2 1281.6 1304.4 1282.4 1301.6 1282.8 1301.6 1283.2 1301.2 1283.6 1300.4 1283.2 1300.4 1282 1301.2 1282 1302.4 1279.6 1306 1278.8 1308 1279.2 1309.6 1280 1309.6 1280.4 1309.6 1280.8 1307.6 1281.6 1306.4 1281.6 1307.2 1280.8 1309.6 1280.8 1310 1281.2 1312.4 1283.6 1314.8 1284 1317.2 1284.8 1317.6 1285.2 1319.2 1286.8 1319.6 1286.8 1320.4 1286.4 1321.6 1286 1321.6 1286.4 1322 1286 1323.2 1284.4 1324 1284.4 1324.4 1283.2 1326 1284 1326.8 1283.6 1328.4 1283.2 1330.8 1283.6 1331.2 1284.8 1332.4 1285.6 1330.8 1288.8 1330.8 1286.8 1332 1285.2 1333.2 1284.4 1334.4 1284.8 1333.2 1285.2 1332.8 1284.8 1332.8 1284 1332.8 1283.6 1334.4 1284.8 1335.6 1284 1335.2 1284 1336 1283.6 1336.4 1283.2 1335.6 1284 1334.8 1283.6 1333.2 1282.8 1333.2 1283.2 1332.8 1282 1330 1281.2 1330 1281.2 1331.2 1280.8 1332.8 1280.8 1330.8 1279.6 1331.2 1279.6 1332.8 1279.6 1332.8 1279.2 1330.8 1278.8 1330.8 1279.2 1329.2 1277.6 1330 1277.2 1330.8 1277.6 1333.2 1278.4 1334.8 1279.6 1335.6 1279.6 1336 1281.2 1336.8 1281.6 1338 1283.2 1339.6 1282 1338.8 1281.2 1338.8 1280.8 1337.2 1278.8 1336 1277.2 1333.2 1276.4 1333.2 1276 1333.2 1276 1332 1276.4 1331.2 1276.4 1330 1278 1328.4 1277.6 1327.6 1276.8 1327.2 1276 1326 1275.6 1324.8 1275.2 1323.6 1275.6 1323.2 1275.2 1322.8 1275.2 1322 1274 1319.6 1273.6 1319.6 1274 1319.6 1274.8 1318.4 1274 1317.2 1272 1316.4 1270.8 1316.8 1270.8 1319.2 1272 1319.6 1272.4 1322 1272 1323.2 1272.8 1324.4 1272.8 1325.2 1275.6 1329.2 1274 1328 1272.8 1328.4 1272.8 1329.6 1274.4 1331.6 1272.8 1330.8 1272.8 1331.6 1274.8 1334.4 1274 1333.6 1272.8 1331.6 1272.4 1331.6 1272.8 1333.2 1273.6 1333.6 1273.6 1334.8 1274.4 1335.2 1275.2 1335.2 1274.8 1336 1275.2 1338 1274.4 1336 1274 1336.4 1274.8 1338 1274.4 1339.2 1274.4 1341.2 1275.2 1341.2 1276.4 1344 1279.2 1343.6 1278 1344.8 1277.2 1344.4 1276.8 1344.8 1276.8 1344.4 1276.4 1344.8 1276.8 1345.6 1277.6 1345.2 1278.4 1346 1279.2 1346.4 1277.6 1346 1277.2 1346.4 1278 1348.4 1278.4 1348.8 1278.4 1348.8 1279.6 1349.2 1280.8 1349.2 1281.6 1349.6 1280.8 1349.2 1279.2 1349.6 1281.2 1352.8 1280 1351.6 1279.6 1351.6 1278.8 1350 1278 1349.6 1277.6 1349.6 1276 1348 1275.2 1346 1273.2 1345.2 1273.2 1345.2 1272.4 1346 1272.4 1346 1270.4 1346.8 1269.6 1347.6 1269.2 1348.8 1270 1349.2 1270.8 1349.2 1272.8 1350 1274 1349.6 1275.2 1349.2 1273.6 1349.6 1272.4 1350 1271.6 1349.6 1270.8 1350 1266.8 1350 1266.4 1350.4 1267.6 1351.6 1269.2 1351.6 1270 1352 1270.8 1351.6 1271.2 1351.2 1271.2 1352 1271.2 1351.6 1272.4 1352 1272.4 1352 1271.6 1353.2 1271.6 1353.6 1272.8 1353.6 1273.2 1353.6 1274 1354 1273.6 1354 1273.2 1353.6 1272.8 1354 1273.2 1354.8 1270.8 1355.2 1271.2 1354.8 1272 1354.8 1271.6 1355.2 1272 1357.2 1273.2 1357.6 1273.2 1357.2 1274 1356.4 1276 1356.8 1274.8 1356.8 1274 1357.2 1274 1357.6 1274 1358.4 1272.8 1358.8 1272.8 1359.2 1273.6 1360 1274.4 1360 1276 1358.8 1277.2 1359.6 1275.6 1359.2 1275.6 1360 1274.4 1361.2 1274 1361.6 1274.8 1361.6 1274.8 1362.4 1274.8 1362.8 1274.8 1363.6 1276 1363.6 1276.4 1363.6 1277.6 1362.4 1278 1362.8 1277.2 1362.8 1276.4 1364 1274 1364 1273.6 1364 1274.4 1365.2 1276.4 1366.4 1277.2 1367.6 1276 1366.4 1275.2 1365.2 1274.8 1366.4 1275.2 1366.4 1275.2 1366.8 1273.2 1365.6 1272.4 1365.6 1272.4 1366.8 1272.8 1367.2 1272.4 1367.2 1272.8 1367.6 1272 1368 1272 1369.2 1272.8 1370.8 1273.2 1370.8 1273.6 1370 1274 1370.4 1274.8 1369.2 1274.8 1369.6 1275.2 1369.2 1276.4 1370 1275.6 1370 1274.8 1370.4 1274.4 1370.8 1274.4 1370.8 1274 1371.6 1274 1372.4 1272.8 1372.4 1273.2 1374.4 1274.4 1374.4 1274.4 1374.4 1273.6 1374.4 1272.8 1375.2 1273.2 1376 1272.8 1377.6 1274.4 1378 1274.8 1377.6 1274.8 1376 1275.2 1375.2 1275.6 1376 1276 1376 1276 1377.6 1275.2 1378 1275.6 1379.6 1276 1379.2 1276.4 1379.6 1276.4 1378 1277.6 1378 1278 1379.2 1280.8 1377.6 1280.4 1378 1278.8 1379.6 1278.4 1380 1278.8 1380 1279.6 1378.8 1280.4 1379.2 1281.6 1378 1282.4 1377.2 1282.4 1377.6 1280.8 1379.2 1281.2 1379.6 1281.2 1379.6 1280 1380.4 1279.2 1381.2 1278.4 1382.4 1278.4 1382.4 1278 1382.8 1278 1383.6 1279.2 1382.8 1279.2 1382.8 1280.4 1382.8 1280.8 1382.8 1280 1384 1280.4 1384 1280 1384.4 1280.4 1384.4 1280 1384.8 1280 1384.8 1279.2 1385.6 1279.6 1385.6 1278.8 1386.8 1278.8 1387.6 1280 1386 1281.2 1387.2 1281.6 1386.4 1282.4 1387.2 1284.4 1386.4 1284 1386.8 1284.4 1387.2 1283.2 1387.2 1282 1388 1282.4 1388.4 1282 1388.4 1281.6 1388.8 1282.4 1390.4 1283.6 1390 1283.2 1390.4 1282.8 1390.8 1283.2 1390.8 1282.8 1391.2 1283.6 1391.6 1284.4 1391.2 1284 1392 1282.4 1392.8 1282.4 1393.2 1283.6 1393.6 gpc232/examples/clip2.gpf0000644000175000017500000000224207321172760016116 0ustar rafaelrafael0000000000000027 4 150 2000 150 1900 200 1900 200 2000 4 100 1600 100 1500 150 1500 150 1600 4 150 1600 150 1500 200 1500 200 1600 4 300 2000 300 1950 400 1950 400 2000 4 300 1600 300 1550 400 1550 400 1600 4 300 1550 300 1500 400 1500 400 1550 4 500 2000 500 1900 550 1900 550 2000 4 500 1600 500 1550 600 1550 600 1600 4 500 1600 500 1500 550 1500 550 1600 4 700 2000 700 1900 750 1900 750 2000 4 700 1600 700 1500 750 1500 750 1600 4 700 1550 700 1500 800 1500 800 1550 4 900 2000 900 1900 1000 1900 1000 2000 4 900 1600 900 1500 1000 1500 1000 1600 4 900 1600 900 1500 1000 1500 1000 1600 4 1150 2000 1150 1900 1200 1900 1200 2000 4 1150 1600 1150 1500 1200 1500 1200 1600 4 1100 1550 1100 1500 1200 1500 1200 1550 4 1350 2000 1350 1900 1400 1900 1400 2000 4 1350 1600 1350 1500 1400 1500 1400 1600 4 1300 1600 1300 1550 1400 1550 1400 1600 4 100 1400 100 1300 150 1300 150 1400 4 300 1350 300 1300 400 1300 400 1350 4 500 1400 500 1350 600 1350 600 1400 4 700 1350 700 1300 800 1300 800 1350 4 1100 1350 1100 1300 1200 1300 1200 1350 4 1300 1400 1300 1350 1400 1350 1400 1400gpc232/examples/clip1.gpf0000644000175000017500000000233207321172760016115 0ustar rafaelrafael000000000000004 7 1330.599999999999909 1282.399999999999864 1377.400000000000091 1282.399999999999864 1361.799999999999955 1298.000000000000000 1393.000000000000000 1313.599999999999909 1361.799999999999955 1344.799999999999955 1346.200000000000045 1313.599999999999909 1330.599999999999909 1329.200000000000045 7 1330.599999999999909 1266.799999999999955 1377.400000000000091 1266.799999999999955 1361.799999999999955 1251.200000000000045 1393.000000000000000 1235.599999999999909 1361.799999999999955 1204.399999999999864 1346.200000000000045 1235.599999999999909 1330.599999999999909 1220.000000000000000 7 1315.000000000000000 1282.399999999999864 1315.000000000000000 1329.200000000000045 1299.400000000000091 1313.599999999999909 1283.799999999999955 1344.799999999999955 1252.599999999999909 1313.599999999999909 1283.799999999999955 1298.000000000000000 1268.200000000000045 1282.399999999999864 7 1268.200000000000045 1266.799999999999955 1315.000000000000000 1266.799999999999955 1315.000000000000000 1220.000000000000000 1299.400000000000091 1235.599999999999909 1283.799999999999955 1204.399999999999864 1252.599999999999909 1235.599999999999909 1283.799999999999955 1251.200000000000045 gpc232/examples/Makefile0000644000175000017500000000007607321172760016052 0ustar rafaelrafael00000000000000test: test.c $(CC) -o test -lgpcl test.c .PHONY: examples