ocssw  1.0
/disk01/web/ocssw/build/src/l2gen/mipolyutil.c (r8102/r3)
Go to the documentation of this file.
00001 /***********************************************************
00002 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
00003 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
00004 
00005                         All Rights Reserved
00006 
00007 Permission to use, copy, modify, and distribute this software and its 
00008 documentation for any purpose and without fee is hereby granted, 
00009 provided that the above copyright notice appear in all copies and that
00010 both that copyright notice and this permission notice appear in 
00011 supporting documentation, and that the names of Digital or MIT not be
00012 used in advertising or publicity pertaining to distribution of the
00013 software without specific, written prior permission.  
00014 
00015 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00016 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00017 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00018 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00019 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00020 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00021 SOFTWARE.
00022 
00023 ******************************************************************/
00024 /* $XConsortium: mipolyutil.c,v 1.14 89/03/22 10:50:55 rws Exp $ */
00025 #include <stdlib.h>
00026 #include "miscstruct.h"
00027 #include "gc.h"
00028 #include "miscanfill.h"
00029 #include "mipoly.h"
00030 
00031 extern void  miFreeStorage();
00032 
00033 #define MAXINT 0x7fffffff
00034 #define MININT -MAXINT
00035 
00036 /*
00037  *     fillUtils.c
00038  *
00039  *     Written by Brian Kelleher;  Oct. 1985
00040  *
00041  *     This module contains all of the utility functions
00042  *     needed to scan convert a polygon.
00043  *
00044  */
00045 
00046 /*
00047  *     InsertEdgeInET
00048  *
00049  *     Insert the given edge into the edge table.
00050  *     First we must find the correct bucket in the
00051  *     Edge table, then find the right slot in the
00052  *     bucket.  Finally, we can insert it.
00053  *
00054  */
00055 Bool
00056 miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
00057     EdgeTable *ET;
00058     EdgeTableEntry *ETE;
00059     int scanline;
00060     ScanLineListBlock **SLLBlock;
00061     int *iSLLBlock;
00062 {
00063     register EdgeTableEntry *start, *prev;
00064     register ScanLineList *pSLL, *pPrevSLL;
00065     ScanLineListBlock *tmpSLLBlock;
00066 
00067     /*
00068      * find the right bucket to put the edge into
00069      */
00070     pPrevSLL = &ET->scanlines;
00071     pSLL = pPrevSLL->next;
00072     while (pSLL && (pSLL->scanline < scanline)) 
00073     {
00074         pPrevSLL = pSLL;
00075         pSLL = pSLL->next;
00076     }
00077 
00078     /*
00079      * reassign pSLL (pointer to ScanLineList) if necessary
00080      */
00081     if ((!pSLL) || (pSLL->scanline > scanline)) 
00082     {
00083         if (*iSLLBlock > SLLSPERBLOCK-1) 
00084         {
00085             tmpSLLBlock = 
00086           (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
00087         if (!tmpSLLBlock)
00088         return FALSE;
00089             (*SLLBlock)->next = tmpSLLBlock;
00090             tmpSLLBlock->next = (ScanLineListBlock *)NULL;
00091             *SLLBlock = tmpSLLBlock;
00092             *iSLLBlock = 0;
00093         }
00094         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
00095 
00096         pSLL->next = pPrevSLL->next;
00097         pSLL->edgelist = (EdgeTableEntry *)NULL;
00098         pPrevSLL->next = pSLL;
00099     }
00100     pSLL->scanline = scanline;
00101 
00102     /*
00103      * now insert the edge in the right bucket
00104      */
00105     prev = (EdgeTableEntry *)NULL;
00106     start = pSLL->edgelist;
00107     while (start && (start->bres.minor < ETE->bres.minor)) 
00108     {
00109         prev = start;
00110         start = start->next;
00111     }
00112     ETE->next = start;
00113 
00114     if (prev)
00115         prev->next = ETE;
00116     else
00117         pSLL->edgelist = ETE;
00118     return TRUE;
00119 }
00120 
00121 /*
00122  *     CreateEdgeTable
00123  *
00124  *     This routine creates the edge table for
00125  *     scan converting polygons. 
00126  *     The Edge Table (ET) looks like:
00127  *
00128  *    EdgeTable
00129  *     --------
00130  *    |  ymax  |        ScanLineLists
00131  *    |scanline|-->------------>-------------->...
00132  *     --------   |scanline|   |scanline|
00133  *                |edgelist|   |edgelist|
00134  *                ---------    ---------
00135  *                    |             |
00136  *                    |             |
00137  *                    V             V
00138  *              list of ETEs   list of ETEs
00139  *
00140  *     where ETE is an EdgeTableEntry data structure,
00141  *     and there is one ScanLineList per scanline at
00142  *     which an edge is initially entered.
00143  *
00144  */
00145 
00146 Bool
00147 miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
00148     register int count;
00149     register DDXPointPtr pts;
00150     EdgeTable *ET;
00151     EdgeTableEntry *AET;
00152     register EdgeTableEntry *pETEs;
00153     ScanLineListBlock   *pSLLBlock;
00154 {
00155     register DDXPointPtr top, bottom;
00156     register DDXPointPtr PrevPt, CurrPt;
00157     int iSLLBlock = 0;
00158 
00159     int dy;
00160 
00161     if (count < 2)  return TRUE;
00162 
00163     /*
00164      *  initialize the Active Edge Table
00165      */
00166     AET->next = (EdgeTableEntry *)NULL;
00167     AET->back = (EdgeTableEntry *)NULL;
00168     AET->nextWETE = (EdgeTableEntry *)NULL;
00169     AET->bres.minor = MININT;
00170 
00171     /*
00172      *  initialize the Edge Table.
00173      */
00174     ET->scanlines.next = (ScanLineList *)NULL;
00175     ET->ymax = MININT;
00176     ET->ymin = MAXINT;
00177     pSLLBlock->next = (ScanLineListBlock *)NULL;
00178 
00179     PrevPt = &pts[count-1];
00180 
00181     /*
00182      *  for each vertex in the array of points.
00183      *  In this loop we are dealing with two vertices at
00184      *  a time -- these make up one edge of the polygon.
00185      */
00186     while (count--) 
00187     {
00188         CurrPt = pts++;
00189 
00190         /*
00191          *  find out which point is above and which is below.
00192          */
00193         if (PrevPt->y > CurrPt->y) 
00194         {
00195             bottom = PrevPt, top = CurrPt;
00196             pETEs->ClockWise = 0;
00197         }
00198         else 
00199         {
00200             bottom = CurrPt, top = PrevPt;
00201             pETEs->ClockWise = 1;
00202         }
00203 
00204         /*
00205          * don't add horizontal edges to the Edge table.
00206          */
00207         if (bottom->y != top->y) 
00208         {
00209             pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
00210 
00211             /*
00212              *  initialize integer edge algorithm
00213              */
00214             dy = bottom->y - top->y;
00215             BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
00216 
00217             if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
00218         {
00219         miFreeStorage(pSLLBlock->next);
00220         return FALSE;
00221         }
00222 
00223             ET->ymax = max(ET->ymax, PrevPt->y);
00224             ET->ymin = min(ET->ymin, PrevPt->y);
00225             pETEs++;
00226         }
00227 
00228         PrevPt = CurrPt;
00229     }
00230     return TRUE;
00231 }
00232 
00233 /*
00234  *     loadAET
00235  *
00236  *     This routine moves EdgeTableEntries from the
00237  *     EdgeTable into the Active Edge Table,
00238  *     leaving them sorted by smaller x coordinate.
00239  *
00240  */
00241 
00242 void
00243 miloadAET(AET, ETEs)
00244     register EdgeTableEntry *AET, *ETEs;
00245 {
00246     register EdgeTableEntry *pPrevAET;
00247     register EdgeTableEntry *tmp;
00248 
00249     pPrevAET = AET;
00250     AET = AET->next;
00251     while (ETEs) 
00252     {
00253         while (AET && (AET->bres.minor < ETEs->bres.minor)) 
00254         {
00255             pPrevAET = AET;
00256             AET = AET->next;
00257         }
00258         tmp = ETEs->next;
00259         ETEs->next = AET;
00260         if (AET)
00261             AET->back = ETEs;
00262         ETEs->back = pPrevAET;
00263         pPrevAET->next = ETEs;
00264         pPrevAET = ETEs;
00265 
00266         ETEs = tmp;
00267     }
00268 }
00269 
00270 /*
00271  *     computeWAET
00272  *
00273  *     This routine links the AET by the
00274  *     nextWETE (winding EdgeTableEntry) link for
00275  *     use by the winding number rule.  The final 
00276  *     Active Edge Table (AET) might look something
00277  *     like:
00278  *
00279  *     AET
00280  *     ----------  ---------   ---------
00281  *     |ymax    |  |ymax    |  |ymax    | 
00282  *     | ...    |  |...     |  |...     |
00283  *     |next    |->|next    |->|next    |->...
00284  *     |nextWETE|  |nextWETE|  |nextWETE|
00285  *     ---------   ---------   ^--------
00286  *         |                   |       |
00287  *         V------------------->       V---> ...
00288  *
00289  */
00290 void
00291 micomputeWAET(AET)
00292     register EdgeTableEntry *AET;
00293 {
00294     register EdgeTableEntry *pWETE;
00295     register int inside = 1;
00296     register int isInside = 0;
00297 
00298     AET->nextWETE = (EdgeTableEntry *)NULL;
00299     pWETE = AET;
00300     AET = AET->next;
00301     while (AET) 
00302     {
00303         if (AET->ClockWise)
00304             isInside++;
00305         else
00306             isInside--;
00307 
00308         if ((!inside && !isInside) ||
00309             ( inside &&  isInside)) 
00310         {
00311             pWETE->nextWETE = AET;
00312             pWETE = AET;
00313             inside = !inside;
00314         }
00315         AET = AET->next;
00316     }
00317     pWETE->nextWETE = (EdgeTableEntry *)NULL;
00318 }
00319 
00320 /*
00321  *     InsertionSort
00322  *
00323  *     Just a simple insertion sort using
00324  *     pointers and back pointers to sort the Active
00325  *     Edge Table.
00326  *
00327  */
00328 
00329 int
00330 miInsertionSort(AET)
00331     register EdgeTableEntry *AET;
00332 {
00333     register EdgeTableEntry *pETEchase;
00334     register EdgeTableEntry *pETEinsert;
00335     register EdgeTableEntry *pETEchaseBackTMP;
00336     register int changed = 0;
00337 
00338     AET = AET->next;
00339     while (AET) 
00340     {
00341         pETEinsert = AET;
00342         pETEchase = AET;
00343         while (pETEchase->back->bres.minor > AET->bres.minor)
00344             pETEchase = pETEchase->back;
00345 
00346         AET = AET->next;
00347         if (pETEchase != pETEinsert) 
00348         {
00349             pETEchaseBackTMP = pETEchase->back;
00350             pETEinsert->back->next = AET;
00351             if (AET)
00352                 AET->back = pETEinsert->back;
00353             pETEinsert->next = pETEchase;
00354             pETEchase->back->next = pETEinsert;
00355             pETEchase->back = pETEinsert;
00356             pETEinsert->back = pETEchaseBackTMP;
00357             changed = 1;
00358         }
00359     }
00360     return(changed);
00361 }
00362 
00363 /*
00364  *     Clean up our act.
00365  */
00366 void
00367 miFreeStorage(pSLLBlock)
00368     register ScanLineListBlock   *pSLLBlock;
00369 {
00370     register ScanLineListBlock   *tmpSLLBlock;
00371 
00372     while (pSLLBlock) 
00373     {
00374         tmpSLLBlock = pSLLBlock->next;
00375         free(pSLLBlock);
00376         pSLLBlock = tmpSLLBlock;
00377     }
00378 }