TASPolyUtils.c

Go to the documentation of this file.
00001 // @(#)root/asimage:$Id: TASPolyUtils.c 20882 2007-11-19 11:31:26Z rdm $
00002 // Author: Valeriy Onuchin  20/04/2005
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /************************************************************************
00013 
00014 Copyright 1987, 1998  The Open Group
00015 
00016 All Rights Reserved.
00017 
00018 The above copyright notice and this permission notice shall be included in
00019 all copies or substantial portions of the Software.
00020 
00021 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00022 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00024 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00025 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00026 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00027 
00028 Except as contained in this notice, the name of The Open Group shall not be
00029 used in advertising or otherwise to promote the sale, use or other dealings
00030 in this Software without prior written authorization from The Open Group.
00031 
00032 
00033 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
00034 
00035                         All Rights Reserved
00036 
00037 Permission to use, copy, modify, and distribute this software and its 
00038 documentation for any purpose and without fee is hereby granted, 
00039 provided that the above copyright notice appear in all copies and that
00040 both that copyright notice and this permission notice appear in 
00041 supporting documentation, and that the name of Digital not be
00042 used in advertising or publicity pertaining to distribution of the
00043 software without specific, written prior permission.  
00044 
00045 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00046 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00047 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00048 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00049 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00050 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00051 SOFTWARE.
00052 
00053 ************************************************************************/
00054 
00055 #include "TPoint.h"
00056 
00057 /*
00058  *     This file contains a few macros to help track
00059  *     the edge of a filled object.  The object is assumed
00060  *     to be filled in scanline order, and thus the
00061  *     algorithm used is an extension of Bresenham's line
00062  *     drawing algorithm which assumes that y is always the
00063  *     major axis.
00064  *     Since these pieces of code are the same for any filled shape,
00065  *     it is more convenient to gather the library in one
00066  *     place, but since these pieces of code are also in
00067  *     the inner loops of output primitives, procedure call
00068  *     overhead is out of the question.
00069  *     See the author for a derivation if needed.
00070  */
00071 
00072 
00073 /*
00074  *  In scan converting polygons, we want to choose those pixels
00075  *  which are inside the polygon.  Thus, we add .5 to the starting
00076  *  x coordinate for both left and right edges.  Now we choose the
00077  *  first pixel which is inside the pgon for the left edge and the
00078  *  first pixel which is outside the pgon for the right edge.
00079  *  Draw the left pixel, but not the right.
00080  *
00081  *  How to add .5 to the starting x coordinate:
00082  *      If the edge is moving to the right, then subtract dy from the
00083  *  error term from the general form of the algorithm.
00084  *      If the edge is moving to the left, then add dy to the error term.
00085  *
00086  *  The reason for the difference between edges moving to the left
00087  *  and edges moving to the right is simple:  If an edge is moving
00088  *  to the right, then we want the algorithm to flip immediately.
00089  *  If it is moving to the left, then we don't want it to flip until
00090  *  we traverse an entire pixel.
00091  */
00092 
00093 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
00094     int dx;\
00095 \
00096     if ((dy) != 0) { \
00097         xStart = (x1); \
00098         dx = (x2) - xStart; \
00099         if (dx < 0) { \
00100             m = dx / (dy); \
00101             m1 = m - 1; \
00102             incr1 = -2 * dx + 2 * (dy) * m1; \
00103             incr2 = -2 * dx + 2 * (dy) * m; \
00104             d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
00105         } else { \
00106             m = dx / (dy); \
00107             m1 = m + 1; \
00108             incr1 = 2 * dx - 2 * (dy) * m1; \
00109             incr2 = 2 * dx - 2 * (dy) * m; \
00110             d = -2 * m * (dy) + 2 * dx; \
00111         } \
00112     } \
00113 }
00114 
00115 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
00116     if (m1 > 0) { \
00117         if (d > 0) { \
00118             minval += m1; \
00119             d += incr1; \
00120         } \
00121         else { \
00122             minval += m; \
00123             d += incr2; \
00124         } \
00125     } else {\
00126         if (d >= 0) { \
00127             minval += m1; \
00128             d += incr1; \
00129         } \
00130         else { \
00131             minval += m; \
00132             d += incr2; \
00133         } \
00134     } \
00135 }
00136 
00137 
00138 /*
00139  *     This structure contains all of the information needed
00140  *     to run the bresenham algorithm.
00141  *     The variables may be hardcoded into the declarations
00142  *     instead of using this structure to make use of
00143  *     register declarations.
00144  */
00145 typedef struct {
00146     int minor_axis;     /* minor axis        */
00147     int d;              /* decision variable */
00148     int m, m1;          /* slope and slope+1 */
00149     int incr1, incr2;   /* error increments */
00150 } BRESINFO;
00151 
00152 
00153 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
00154         BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
00155                      bres.m, bres.m1, bres.incr1, bres.incr2)
00156 
00157 #define BRESINCRPGONSTRUCT(bres) \
00158         BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
00159 
00160 
00161 /*
00162  *     These are the data structures needed to scan
00163  *     convert regions.  Two different scan conversion
00164  *     methods are available -- the even-odd method, and
00165  *     the winding number method.
00166  *     The even-odd rule states that a point is inside
00167  *     the polygon if a ray drawn from that point in any
00168  *     direction will pass through an odd number of
00169  *     path segments.
00170  *     By the winding number rule, a point is decided
00171  *     to be inside the polygon if a ray drawn from that
00172  *     point in any direction passes through a different
00173  *     number of clockwise and counter-clockwise path
00174  *     segments.
00175  *
00176  *     These data structures are adapted somewhat from
00177  *     the algorithm in (Foley/Van Dam) for scan converting
00178  *     polygons.
00179  *     The basic algorithm is to start at the top (smallest y)
00180  *     of the polygon, stepping down to the bottom of
00181  *     the polygon by incrementing the y coordinate.  We
00182  *     keep a list of edges which the current scanline crosses,
00183  *     sorted by x.  This list is called the Active Edge Table (AET)
00184  *     As we change the y-coordinate, we update each entry in 
00185  *     in the active edge table to reflect the edges new xcoord.
00186  *     This list must be sorted at each scanline in case
00187  *     two edges intersect.
00188  *     We also keep a data structure known as the Edge Table (ET),
00189  *     which keeps track of all the edges which the current
00190  *     scanline has not yet reached.  The ET is basically a
00191  *     list of ScanLineList structures containing a list of
00192  *     edges which are entered at a given scanline.  There is one
00193  *     ScanLineList per scanline at which an edge is entered.
00194  *     When we enter a new edge, we move it from the ET to the AET.
00195  *
00196  *     From the AET, we can implement the even-odd rule as in
00197  *     (Foley/Van Dam).
00198  *     The winding number rule is a little trickier.  We also
00199  *     keep the EdgeTableEntries in the AET linked by the
00200  *     nextWETE (winding EdgeTableEntry) link.  This allows
00201  *     the edges to be linked just as before for updating
00202  *     purposes, but only uses the edges linked by the nextWETE
00203  *     link as edges representing spans of the polygon to
00204  *     drawn (as with the even-odd rule).
00205  */
00206 
00207 /*
00208  * for the winding number rule
00209  */
00210 #define CLOCKWISE          1
00211 #define COUNTERCLOCKWISE  -1 
00212 
00213 typedef struct _EdgeTableEntry {
00214      int ymax;             /* ycoord at which we exit this edge. */
00215      BRESINFO bres;        /* Bresenham info to run the edge     */
00216      struct _EdgeTableEntry *next;       /* next in the list     */
00217      struct _EdgeTableEntry *back;       /* for insertion sort   */
00218      struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
00219      int ClockWise;        /* flag for winding number rule       */
00220 } EdgeTableEntry;
00221 
00222 
00223 typedef struct _ScanLineList{
00224      int scanline;              /* the scanline represented */
00225      EdgeTableEntry *edgelist;  /* header node              */
00226      struct _ScanLineList *next;  /* next in the list       */
00227 } ScanLineList;
00228 
00229 
00230 typedef struct {
00231      int ymax;                 /* ymax for the polygon     */
00232      int ymin;                 /* ymin for the polygon     */
00233      ScanLineList scanlines;   /* header node              */
00234 } EdgeTable;
00235 
00236 
00237 /*
00238  * Here is a struct to help with storage allocation
00239  * so we can allocate a big chunk at a time, and then take
00240  * pieces from this heap when we need to.
00241  */
00242 #define SLLSPERBLOCK 25
00243 
00244 typedef struct _ScanLineListBlock {
00245      ScanLineList SLLs[SLLSPERBLOCK];
00246      struct _ScanLineListBlock *next;
00247 } ScanLineListBlock;
00248 
00249 
00250 
00251 /*
00252  *
00253  *     a few macros for the inner loops of the fill code where
00254  *     performance considerations don't allow a procedure call.
00255  *
00256  *     Evaluate the given edge at the given scanline.
00257  *     If the edge has expired, then we leave it and fix up
00258  *     the active edge table; otherwise, we increment the
00259  *     x value to be ready for the next scanline.
00260  *     The winding number rule is in effect, so we must notify
00261  *     the caller when the edge has been removed so he
00262  *     can reorder the Winding Active Edge Table.
00263  */
00264 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
00265    if (pAET->ymax == y) {          /* leaving this edge */ \
00266       pPrevAET->next = pAET->next; \
00267       pAET = pPrevAET->next; \
00268       fixWAET = 1; \
00269       if (pAET) \
00270          pAET->back = pPrevAET; \
00271    } \
00272    else { \
00273       BRESINCRPGONSTRUCT(pAET->bres); \
00274       pPrevAET = pAET; \
00275       pAET = pAET->next; \
00276    } \
00277 }
00278 
00279 
00280 /*
00281  *     Evaluate the given edge at the given scanline.
00282  *     If the edge has expired, then we leave it and fix up
00283  *     the active edge table; otherwise, we increment the
00284  *     x value to be ready for the next scanline.
00285  *     The even-odd rule is in effect.
00286  */
00287 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
00288    if (pAET->ymax == y) {          /* leaving this edge */ \
00289       pPrevAET->next = pAET->next; \
00290       pAET = pPrevAET->next; \
00291       if (pAET) \
00292          pAET->back = pPrevAET; \
00293    } \
00294    else { \
00295       BRESINCRPGONSTRUCT(pAET->bres); \
00296       pPrevAET = pAET; \
00297       pAET = pAET->next; \
00298    } \
00299 }
00300 
00301 #define LARGE_COORDINATE 1000000
00302 #define SMALL_COORDINATE -LARGE_COORDINATE
00303 
00304 //______________________________________________________________________________
00305 static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
00306                            ScanLineListBlock **SLLBlock, int *iSLLBlock)
00307 {
00308    //     Insert the given edge into the edge table.
00309    //    First we must find the correct bucket in the
00310    //    Edge table, then find the right slot in the
00311    //    bucket.  Finally, we can insert it.
00312 
00313    EdgeTableEntry *start, *prev;
00314    ScanLineList *pSLL, *pPrevSLL;
00315    ScanLineListBlock *tmpSLLBlock;
00316 
00317    /*
00318     * find the right bucket to put the edge into
00319     */
00320    pPrevSLL = &ET->scanlines;
00321    pSLL = pPrevSLL->next;
00322    while (pSLL && (pSLL->scanline < scanline)) {
00323       pPrevSLL = pSLL;
00324       pSLL = pSLL->next;
00325    }
00326 
00327     /*
00328      * reassign pSLL (pointer to ScanLineList) if necessary
00329      */
00330    if ((!pSLL) || (pSLL->scanline > scanline)) {
00331       if (*iSLLBlock > SLLSPERBLOCK-1) {
00332          tmpSLLBlock = new ScanLineListBlock;
00333          (*SLLBlock)->next = tmpSLLBlock;
00334          tmpSLLBlock->next = (ScanLineListBlock *)0;
00335          *SLLBlock = tmpSLLBlock;
00336          *iSLLBlock = 0;
00337       }
00338       pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
00339 
00340       pSLL->next = pPrevSLL->next;
00341       pSLL->edgelist = (EdgeTableEntry *)0;
00342       pPrevSLL->next = pSLL;
00343    }
00344    pSLL->scanline = scanline;
00345 
00346     /*
00347      * now insert the edge in the right bucket
00348      */
00349    prev = (EdgeTableEntry *)0;
00350    start = pSLL->edgelist;
00351    while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
00352       prev = start;
00353       start = start->next;
00354    }
00355    ETE->next = start;
00356 
00357    if (prev) {
00358       prev->next = ETE;
00359    } else {
00360       pSLL->edgelist = ETE;
00361    }
00362 }
00363 
00364 //______________________________________________________________________________
00365 static void CreateETandAET(int count, TPoint *pts, EdgeTable *ET, EdgeTableEntry *AET,
00366                            EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
00367 {
00368    //     This routine creates the edge table for
00369    //     scan converting polygons. 
00370    //     The Edge Table (ET) looks like:
00371    //
00372    //    EdgeTable
00373    //     --------
00374    //    |  ymax  |        ScanLineLists
00375    //    |scanline|-->------------>-------------->...
00376    //     --------   |scanline|   |scanline|
00377    //                |edgelist|   |edgelist|
00378    //                ---------    ---------
00379    //                    |             |
00380    //                    |             |
00381    //                    V             V
00382    //              list of ETEs   list of ETEs
00383    //
00384    //     where ETE is an EdgeTableEntry data structure,
00385    //     and there is one ScanLineList per scanline at
00386    //     which an edge is initially entered.
00387 
00388    TPoint *top, *bottom;
00389    TPoint *PrevPt, *CurrPt;
00390    int iSLLBlock = 0;
00391    int dy;
00392 
00393    if (count < 2)  return;
00394 
00395     /*
00396      *  initialize the Active Edge Table
00397      */
00398    AET->next = (EdgeTableEntry *)0;
00399    AET->back = (EdgeTableEntry *)0;
00400    AET->nextWETE = (EdgeTableEntry *)0;
00401    AET->bres.minor_axis = SMALL_COORDINATE;
00402 
00403     /*
00404      *  initialize the Edge Table.
00405      */
00406    ET->scanlines.next = (ScanLineList *)0;
00407    ET->ymax = SMALL_COORDINATE;
00408    ET->ymin = LARGE_COORDINATE;
00409    pSLLBlock->next = (ScanLineListBlock *)0;
00410 
00411    PrevPt = &pts[count-1];
00412 
00413     /*
00414      *  for each vertex in the array of points.
00415      *  In this loop we are dealing with two vertices at
00416      *  a time -- these make up one edge of the polygon.
00417      */
00418    while (count--) {
00419       CurrPt = pts++;
00420 
00421         /*
00422          *  find out which point is above and which is below.
00423          */
00424       if (PrevPt->fY > CurrPt->fY) {
00425          bottom = PrevPt, top = CurrPt;
00426          pETEs->ClockWise = 0;
00427       } else {
00428          bottom = CurrPt, top = PrevPt;
00429          pETEs->ClockWise = 1;
00430       }
00431 
00432         /*
00433          * don't add horizontal edges to the Edge table.
00434          */
00435       if (bottom->fY != top->fY) {
00436          pETEs->ymax = bottom->fY-1;  /* -1 so we don't get last scanline */
00437 
00438             /*
00439              *  initialize integer edge algorithm
00440              */
00441          dy = bottom->fY - top->fY;
00442          BRESINITPGONSTRUCT(dy, top->fX, bottom->fX, pETEs->bres);
00443 
00444          InsertEdgeInET(ET, pETEs, top->fY, &pSLLBlock, &iSLLBlock);
00445 
00446               if (PrevPt->fY > ET->ymax) ET->ymax = PrevPt->fY;
00447               if (PrevPt->fY < ET->ymin) ET->ymin = PrevPt->fY;
00448          pETEs++;
00449       }
00450       PrevPt = CurrPt;
00451    }
00452 }
00453 
00454 //______________________________________________________________________________
00455 static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
00456 {
00457    //    This routine moves EdgeTableEntries from the
00458    //     EdgeTable into the Active Edge Table,
00459    //     leaving them sorted by smaller x coordinate.
00460 
00461    EdgeTableEntry *pPrevAET;
00462    EdgeTableEntry *tmp;
00463 
00464    pPrevAET = AET;
00465    AET = AET->next;
00466    while (ETEs) {
00467       while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))  {
00468          pPrevAET = AET;
00469          AET = AET->next;
00470       }
00471       tmp = ETEs->next;
00472       ETEs->next = AET;
00473       if (AET) {
00474          AET->back = ETEs;
00475       }
00476       ETEs->back = pPrevAET;
00477       pPrevAET->next = ETEs;
00478       pPrevAET = ETEs;
00479 
00480       ETEs = tmp;
00481    }
00482 }
00483 
00484 //______________________________________________________________________________
00485 static int InsertionSort(EdgeTableEntry * AET)
00486 {
00487    // InsertionSort
00488    //
00489    //    Just a simple insertion sort using
00490    //     pointers and back pointers to sort the Active
00491    //     Edge Table.
00492 
00493    EdgeTableEntry *pETEchase;
00494    EdgeTableEntry *pETEinsert;
00495    EdgeTableEntry *pETEchaseBackTMP;
00496    int changed = 0;
00497 
00498    AET = AET->next;
00499    while (AET) {
00500       pETEinsert = AET;
00501       pETEchase = AET;
00502       while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis) {
00503          pETEchase = pETEchase->back;
00504       }
00505 
00506       AET = AET->next;
00507       if (pETEchase != pETEinsert) {
00508          pETEchaseBackTMP = pETEchase->back;
00509          pETEinsert->back->next = AET;
00510          if (AET) {
00511             AET->back = pETEinsert->back;
00512          }
00513          pETEinsert->next = pETEchase;
00514          pETEchase->back->next = pETEinsert;
00515          pETEchase->back = pETEinsert;
00516          pETEinsert->back = pETEchaseBackTMP;
00517          changed = 1;
00518       }
00519    }
00520    return (changed);
00521 }
00522 
00523 //______________________________________________________________________________
00524 static void FreeStorage(ScanLineListBlock *pSLLBlock)
00525 {
00526    // Clean up our act.
00527 
00528    ScanLineListBlock *tmpSLLBlock;
00529 
00530    while (pSLLBlock) {
00531       tmpSLLBlock = pSLLBlock->next;
00532       delete pSLLBlock;
00533       pSLLBlock = tmpSLLBlock;
00534    }
00535 }
00536 

Generated on Tue Jul 5 14:13:34 2011 for ROOT_528-00b_version by  doxygen 1.5.1