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


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Thu Aug 27 2015 14:13:26