Annotation of researchv9/X11/src/X.V11R1/lib/X/XPolyReg.c, revision 1.1

1.1     ! root        1: /* $Header: XPolyReg.c,v 11.11 87/09/13 22:01:50 toddb Exp $ */
        !             2: /************************************************************************
        !             3: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
        !             4: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
        !             5: 
        !             6:                         All Rights Reserved
        !             7: 
        !             8: Permission to use, copy, modify, and distribute this software and its 
        !             9: documentation for any purpose and without fee is hereby granted, 
        !            10: provided that the above copyright notice appear in all copies and that
        !            11: both that copyright notice and this permission notice appear in 
        !            12: supporting documentation, and that the names of Digital or MIT not be
        !            13: used in advertising or publicity pertaining to distribution of the
        !            14: software without specific, written prior permission.  
        !            15: 
        !            16: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
        !            17: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
        !            18: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
        !            19: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
        !            20: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
        !            21: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
        !            22: SOFTWARE.
        !            23: 
        !            24: ************************************************************************/
        !            25: 
        !            26: #define MAXINT 1000000
        !            27: #define MININT -MAXINT
        !            28: 
        !            29: #include "region.h"
        !            30: #include "poly.h"
        !            31: #include "Xlib.h"
        !            32: #include "Xutil.h"
        !            33: 
        !            34: /*
        !            35:  *     InsertEdgeInET
        !            36:  *
        !            37:  *     Insert the given edge into the edge table.
        !            38:  *     First we must find the correct bucket in the
        !            39:  *     Edge table, then find the right slot in the
        !            40:  *     bucket.  Finally, we can insert it.
        !            41:  *
        !            42:  */
        !            43: static void
        !            44: InsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
        !            45:     EdgeTable *ET;
        !            46:     EdgeTableEntry *ETE;
        !            47:     int scanline;
        !            48:     ScanLineListBlock **SLLBlock;
        !            49:     int *iSLLBlock;
        !            50: {
        !            51:     register EdgeTableEntry *start, *prev;
        !            52:     register ScanLineList *pSLL, *pPrevSLL;
        !            53:     ScanLineListBlock *tmpSLLBlock;
        !            54: 
        !            55:     /*
        !            56:      * find the right bucket to put the edge into
        !            57:      */
        !            58:     pPrevSLL = &ET->scanlines;
        !            59:     pSLL = pPrevSLL->next;
        !            60:     while (pSLL && (pSLL->scanline < scanline)) 
        !            61:     {
        !            62:         pPrevSLL = pSLL;
        !            63:         pSLL = pSLL->next;
        !            64:     }
        !            65: 
        !            66:     /*
        !            67:      * reassign pSLL (pointer to ScanLineList) if necessary
        !            68:      */
        !            69:     if ((!pSLL) || (pSLL->scanline > scanline)) 
        !            70:     {
        !            71:         if (*iSLLBlock > SLLSPERBLOCK-1) 
        !            72:         {
        !            73:             tmpSLLBlock = 
        !            74:                  (ScanLineListBlock *)Xmalloc(sizeof(ScanLineListBlock));
        !            75:             (*SLLBlock)->next = tmpSLLBlock;
        !            76:             tmpSLLBlock->next = (ScanLineListBlock *)NULL;
        !            77:             *SLLBlock = tmpSLLBlock;
        !            78:             *iSLLBlock = 0;
        !            79:         }
        !            80:         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
        !            81: 
        !            82:         pSLL->next = pPrevSLL->next;
        !            83:         pSLL->edgelist = (EdgeTableEntry *)NULL;
        !            84:         pPrevSLL->next = pSLL;
        !            85:     }
        !            86:     pSLL->scanline = scanline;
        !            87: 
        !            88:     /*
        !            89:      * now insert the edge in the right bucket
        !            90:      */
        !            91:     prev = (EdgeTableEntry *)NULL;
        !            92:     start = pSLL->edgelist;
        !            93:     while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
        !            94:     {
        !            95:         prev = start;
        !            96:         start = start->next;
        !            97:     }
        !            98:     ETE->next = start;
        !            99: 
        !           100:     if (prev)
        !           101:         prev->next = ETE;
        !           102:     else
        !           103:         pSLL->edgelist = ETE;
        !           104: }
        !           105: 
        !           106: /*
        !           107:  *     CreateEdgeTable
        !           108:  *
        !           109:  *     This routine creates the edge table for
        !           110:  *     scan converting polygons. 
        !           111:  *     The Edge Table (ET) looks like:
        !           112:  *
        !           113:  *    EdgeTable
        !           114:  *     --------
        !           115:  *    |  ymax  |        ScanLineLists
        !           116:  *    |scanline|-->------------>-------------->...
        !           117:  *     --------   |scanline|   |scanline|
        !           118:  *                |edgelist|   |edgelist|
        !           119:  *                ---------    ---------
        !           120:  *                    |             |
        !           121:  *                    |             |
        !           122:  *                    V             V
        !           123:  *              list of ETEs   list of ETEs
        !           124:  *
        !           125:  *     where ETE is an EdgeTableEntry data structure,
        !           126:  *     and there is one ScanLineList per scanline at
        !           127:  *     which an edge is initially entered.
        !           128:  *
        !           129:  */
        !           130: 
        !           131: static void
        !           132: CreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
        !           133:     register int count;
        !           134:     register XPoint *pts;
        !           135:     EdgeTable *ET;
        !           136:     EdgeTableEntry *AET;
        !           137:     register EdgeTableEntry *pETEs;
        !           138:     ScanLineListBlock   *pSLLBlock;
        !           139: {
        !           140:     register XPoint *top, *bottom;
        !           141:     register XPoint *PrevPt, *CurrPt;
        !           142:     int iSLLBlock = 0;
        !           143:     int dy;
        !           144: 
        !           145:     if (count < 2)  return;
        !           146: 
        !           147:     /*
        !           148:      *  initialize the Active Edge Table
        !           149:      */
        !           150:     AET->next = (EdgeTableEntry *)NULL;
        !           151:     AET->back = (EdgeTableEntry *)NULL;
        !           152:     AET->nextWETE = (EdgeTableEntry *)NULL;
        !           153:     AET->bres.minor_axis = MININT;
        !           154: 
        !           155:     /*
        !           156:      *  initialize the Edge Table.
        !           157:      */
        !           158:     ET->scanlines.next = (ScanLineList *)NULL;
        !           159:     ET->ymax = MININT;
        !           160:     ET->ymin = MAXINT;
        !           161:     pSLLBlock->next = (ScanLineListBlock *)NULL;
        !           162: 
        !           163:     PrevPt = &pts[count-1];
        !           164: 
        !           165:     /*
        !           166:      *  for each vertex in the array of points.
        !           167:      *  In this loop we are dealing with two vertices at
        !           168:      *  a time -- these make up one edge of the polygon.
        !           169:      */
        !           170:     while (count--) 
        !           171:     {
        !           172:         CurrPt = pts++;
        !           173: 
        !           174:         /*
        !           175:          *  find out which point is above and which is below.
        !           176:          */
        !           177:         if (PrevPt->y > CurrPt->y) 
        !           178:         {
        !           179:             bottom = PrevPt, top = CurrPt;
        !           180:             pETEs->ClockWise = 0;
        !           181:         }
        !           182:         else 
        !           183:         {
        !           184:             bottom = CurrPt, top = PrevPt;
        !           185:             pETEs->ClockWise = 1;
        !           186:         }
        !           187: 
        !           188:         /*
        !           189:          * don't add horizontal edges to the Edge table.
        !           190:          */
        !           191:         if (bottom->y != top->y) 
        !           192:         {
        !           193:             pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
        !           194: 
        !           195:             /*
        !           196:              *  initialize integer edge algorithm
        !           197:              */
        !           198:             dy = bottom->y - top->y;
        !           199:             BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
        !           200: 
        !           201:             InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
        !           202: 
        !           203:             ET->ymax = MAX(ET->ymax, PrevPt->y);
        !           204:             ET->ymin = MIN(ET->ymin, PrevPt->y);
        !           205:             pETEs++;
        !           206:         }
        !           207: 
        !           208:         PrevPt = CurrPt;
        !           209:     }
        !           210: }
        !           211: 
        !           212: /*
        !           213:  *     loadAET
        !           214:  *
        !           215:  *     This routine moves EdgeTableEntries from the
        !           216:  *     EdgeTable into the Active Edge Table,
        !           217:  *     leaving them sorted by smaller x coordinate.
        !           218:  *
        !           219:  */
        !           220: 
        !           221: static void
        !           222: loadAET(AET, ETEs)
        !           223:     register EdgeTableEntry *AET, *ETEs;
        !           224: {
        !           225:     register EdgeTableEntry *pPrevAET;
        !           226:     register EdgeTableEntry *tmp;
        !           227: 
        !           228:     pPrevAET = AET;
        !           229:     AET = AET->next;
        !           230:     while (ETEs) 
        !           231:     {
        !           232:         while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
        !           233:         {
        !           234:             pPrevAET = AET;
        !           235:             AET = AET->next;
        !           236:         }
        !           237:         tmp = ETEs->next;
        !           238:         ETEs->next = AET;
        !           239:         if (AET)
        !           240:             AET->back = ETEs;
        !           241:         ETEs->back = pPrevAET;
        !           242:         pPrevAET->next = ETEs;
        !           243:         pPrevAET = ETEs;
        !           244: 
        !           245:         ETEs = tmp;
        !           246:     }
        !           247: }
        !           248: 
        !           249: /*
        !           250:  *     computeWAET
        !           251:  *
        !           252:  *     This routine links the AET by the
        !           253:  *     nextWETE (winding EdgeTableEntry) link for
        !           254:  *     use by the winding number rule.  The final 
        !           255:  *     Active Edge Table (AET) might look something
        !           256:  *     like:
        !           257:  *
        !           258:  *     AET
        !           259:  *     ----------  ---------   ---------
        !           260:  *     |ymax    |  |ymax    |  |ymax    | 
        !           261:  *     | ...    |  |...     |  |...     |
        !           262:  *     |next    |->|next    |->|next    |->...
        !           263:  *     |nextWETE|  |nextWETE|  |nextWETE|
        !           264:  *     ---------   ---------   ^--------
        !           265:  *         |                   |       |
        !           266:  *         V------------------->       V---> ...
        !           267:  *
        !           268:  */
        !           269: static void
        !           270: computeWAET(AET)
        !           271:     register EdgeTableEntry *AET;
        !           272: {
        !           273:     register EdgeTableEntry *pWETE;
        !           274:     register int inside = 1;
        !           275:     register int isInside = 0;
        !           276: 
        !           277:     AET->nextWETE = (EdgeTableEntry *)NULL;
        !           278:     pWETE = AET;
        !           279:     AET = AET->next;
        !           280:     while (AET) 
        !           281:     {
        !           282:         if (AET->ClockWise)
        !           283:             isInside++;
        !           284:         else
        !           285:             isInside--;
        !           286: 
        !           287:         if ((!inside && !isInside) ||
        !           288:             ( inside &&  isInside)) 
        !           289:         {
        !           290:             pWETE->nextWETE = AET;
        !           291:             pWETE = AET;
        !           292:             inside = !inside;
        !           293:         }
        !           294:         AET = AET->next;
        !           295:     }
        !           296:     pWETE->nextWETE = (EdgeTableEntry *)NULL;
        !           297: }
        !           298: 
        !           299: /*
        !           300:  *     InsertionSort
        !           301:  *
        !           302:  *     Just a simple insertion sort using
        !           303:  *     pointers and back pointers to sort the Active
        !           304:  *     Edge Table.
        !           305:  *
        !           306:  */
        !           307: 
        !           308: static int
        !           309: InsertionSort(AET)
        !           310:     register EdgeTableEntry *AET;
        !           311: {
        !           312:     register EdgeTableEntry *pETEchase;
        !           313:     register EdgeTableEntry *pETEinsert;
        !           314:     register EdgeTableEntry *pETEchaseBackTMP;
        !           315:     register int changed = 0;
        !           316: 
        !           317:     AET = AET->next;
        !           318:     while (AET) 
        !           319:     {
        !           320:         pETEinsert = AET;
        !           321:         pETEchase = AET;
        !           322:         while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
        !           323:             pETEchase = pETEchase->back;
        !           324: 
        !           325:         AET = AET->next;
        !           326:         if (pETEchase != pETEinsert) 
        !           327:         {
        !           328:             pETEchaseBackTMP = pETEchase->back;
        !           329:             pETEinsert->back->next = AET;
        !           330:             if (AET)
        !           331:                 AET->back = pETEinsert->back;
        !           332:             pETEinsert->next = pETEchase;
        !           333:             pETEchase->back->next = pETEinsert;
        !           334:             pETEchase->back = pETEinsert;
        !           335:             pETEinsert->back = pETEchaseBackTMP;
        !           336:             changed = 1;
        !           337:         }
        !           338:     }
        !           339:     return(changed);
        !           340: }
        !           341: 
        !           342: /*
        !           343:  *     Clean up our act.
        !           344:  */
        !           345: static void
        !           346: FreeStorage(pSLLBlock)
        !           347:     register ScanLineListBlock   *pSLLBlock;
        !           348: {
        !           349:     register ScanLineListBlock   *tmpSLLBlock;
        !           350: 
        !           351:     while (pSLLBlock) 
        !           352:     {
        !           353:         tmpSLLBlock = pSLLBlock->next;
        !           354:         Xfree((char *)pSLLBlock);
        !           355:         pSLLBlock = tmpSLLBlock;
        !           356:     }
        !           357: }
        !           358: 
        !           359: /*
        !           360:  *     Create an array of rectangles from a list of points.
        !           361:  *     If indeed these things (POINTS, RECTS) are the same,
        !           362:  *     then this proc is still needed, because it allocates
        !           363:  *     storage for the array, which was allocated on the
        !           364:  *     stack by the calling procedure.
        !           365:  *
        !           366:  */
        !           367: static int PtsToRegion(numFullPtBlocks, iCurPtBlock, FirstPtBlock, reg)
        !           368:     register int  numFullPtBlocks, iCurPtBlock;
        !           369:     POINTBLOCK *FirstPtBlock;
        !           370:     REGION *reg;
        !           371: {
        !           372:     register BOX  *rects;
        !           373:     register XPoint *pts;
        !           374:     register POINTBLOCK *CurPtBlock;
        !           375:     register int i;
        !           376:     register BOX *extents;
        !           377:     int numRects;
        !           378:  
        !           379:     extents = &reg->extents;
        !           380:  
        !           381:     numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
        !           382:  
        !           383:     if (!(reg->rects = (BOX *)Xrealloc((char *)reg->rects, 
        !           384:            (unsigned) (sizeof(BOX) * numRects))))       return(0);
        !           385:  
        !           386:     CurPtBlock = FirstPtBlock;
        !           387:     rects = reg->rects;
        !           388:  
        !           389:     extents->y1 = FirstPtBlock->pts[0].y;
        !           390:     extents->x1 = MAXSHORT,  extents->x2 = MINSHORT;
        !           391:  
        !           392:     while (numFullPtBlocks--) {
        !           393:         i = NUMPTSTOBUFFER >> 1;  /* the loop uses 2 points per iteration */
        !           394:         pts = CurPtBlock->pts;
        !           395:         while (i--) {
        !           396:             rects->x1 = pts->x,  rects->y1 = pts->y;
        !           397:             extents->x1 = MIN(extents->x1, pts->x);
        !           398:             pts++;
        !           399:             rects->x2 = pts->x,  rects->y2 = pts->y + 1;
        !           400:             extents->x2 = MAX(extents->x2, pts->x);
        !           401:             rects++,  pts++;
        !           402:         }
        !           403:         CurPtBlock = CurPtBlock->next;
        !           404:     }
        !           405: 
        !           406:     extents->y2 = CurPtBlock->pts[iCurPtBlock-1].y+1;
        !           407:     pts = CurPtBlock->pts;
        !           408:     iCurPtBlock >>= 1;
        !           409:     while (iCurPtBlock--) {
        !           410:         rects->x1 = pts->x,  rects->y1 = pts->y;
        !           411:         extents->x1 = MIN(extents->x1, pts->x);
        !           412:         pts++;
        !           413:         rects->x2 = pts->x,  rects->y2 = pts->y + 1;
        !           414:         extents->x2 = MAX(extents->x2, pts->x);
        !           415:         rects++,  pts++;
        !           416:     }
        !           417:  
        !           418:     reg->size = reg->numRects = numRects;
        !           419:  
        !           420:     return(TRUE);
        !           421: }
        !           422: 
        !           423: Region XCreateRegion();
        !           424: /*
        !           425:  *     polytoregion
        !           426:  *
        !           427:  *     Scan converts a polygon by returning a run-length
        !           428:  *     encoding of the resultant bitmap -- the run-length
        !           429:  *     encoding is in the form of an array of rectangles.
        !           430:  */
        !           431: Region 
        !           432: XPolygonRegion(Pts, Count, rule)
        !           433:     int       Count;                 /* number of pts           */
        !           434:     XPoint     *Pts;                /* the pts                 */
        !           435:     int        rule;                        /* winding rule */
        !           436: {
        !           437:     Region region;
        !           438:     register EdgeTableEntry *pAET;   /* Active Edge Table       */
        !           439:     register int y;                  /* current scanline        */
        !           440:     register int iPts = 0;           /* number of pts in buffer */
        !           441:     register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
        !           442:     register ScanLineList *pSLL;     /* current scanLineList    */
        !           443:     register XPoint *pts;             /* output buffer           */
        !           444:     EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
        !           445:     EdgeTable ET;                    /* header node for ET      */
        !           446:     EdgeTableEntry AET;              /* header node for AET     */
        !           447:     EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
        !           448:     ScanLineListBlock SLLBlock;      /* header for scanlinelist */
        !           449:     int fixWAET = FALSE;
        !           450:     POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
        !           451:     POINTBLOCK *tmpPtBlock;
        !           452:     int numFullPtBlocks = 0;
        !           453:  
        !           454:     pETEs = (EdgeTableEntry *)Xalloca(sizeof(EdgeTableEntry) * Count);
        !           455:     pts = FirstPtBlock.pts;
        !           456:     CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
        !           457:     pSLL = ET.scanlines.next;
        !           458:     curPtBlock = &FirstPtBlock;
        !           459:  
        !           460:     if (rule == EvenOddRule) {
        !           461:         /*
        !           462:          *  for each scanline
        !           463:          */
        !           464:         for (y = ET.ymin; y < ET.ymax; y++) {
        !           465:             /*
        !           466:              *  Add a new edge to the active edge table when we
        !           467:              *  get to the next edge.
        !           468:              */
        !           469:             if (pSLL != NULL && y == pSLL->scanline) {
        !           470:                 loadAET(&AET, pSLL->edgelist);
        !           471:                 pSLL = pSLL->next;
        !           472:             }
        !           473:             pPrevAET = &AET;
        !           474:             pAET = AET.next;
        !           475:  
        !           476:             /*
        !           477:              *  for each active edge
        !           478:              */
        !           479:             while (pAET) {
        !           480:                 pts->x = pAET->bres.minor_axis,  pts->y = y;
        !           481:                 pts++, iPts++;
        !           482:  
        !           483:                 /*
        !           484:                  *  send out the buffer
        !           485:                  */
        !           486:                 if (iPts == NUMPTSTOBUFFER) {
        !           487:                     tmpPtBlock = (POINTBLOCK *)Xalloca(sizeof(POINTBLOCK));
        !           488:                     curPtBlock->next = tmpPtBlock;
        !           489:                     curPtBlock = tmpPtBlock;
        !           490:                     pts = curPtBlock->pts;
        !           491:                     numFullPtBlocks++;
        !           492:                     iPts = 0;
        !           493:                 }
        !           494:                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
        !           495:             }
        !           496:             (void) InsertionSort(&AET);
        !           497:         }
        !           498:     }
        !           499:     else {
        !           500:         /*
        !           501:          *  for each scanline
        !           502:          */
        !           503:         for (y = ET.ymin; y < ET.ymax; y++) {
        !           504:             /*
        !           505:              *  Add a new edge to the active edge table when we
        !           506:              *  get to the next edge.
        !           507:              */
        !           508:             if (pSLL != NULL && y == pSLL->scanline) {
        !           509:                 loadAET(&AET, pSLL->edgelist);
        !           510:                 computeWAET(&AET);
        !           511:                 pSLL = pSLL->next;
        !           512:             }
        !           513:             pPrevAET = &AET;
        !           514:             pAET = AET.next;
        !           515:             pWETE = pAET;
        !           516:  
        !           517:             /*
        !           518:              *  for each active edge
        !           519:              */
        !           520:             while (pAET) {
        !           521:                 /*
        !           522:                  *  add to the buffer only those edges that
        !           523:                  *  are in the Winding active edge table.
        !           524:                  */
        !           525:                 if (pWETE == pAET) {
        !           526:                     pts->x = pAET->bres.minor_axis,  pts->y = y;
        !           527:                     pts++, iPts++;
        !           528:  
        !           529:                     /*
        !           530:                      *  send out the buffer
        !           531:                      */
        !           532:                     if (iPts == NUMPTSTOBUFFER) {
        !           533:                         tmpPtBlock = (POINTBLOCK *)Xalloca(sizeof(POINTBLOCK));
        !           534:                         curPtBlock->next = tmpPtBlock;
        !           535:                         curPtBlock = tmpPtBlock;
        !           536:                         pts = curPtBlock->pts;
        !           537:                         numFullPtBlocks++;    iPts = 0;
        !           538:                     }
        !           539:                     pWETE = pWETE->nextWETE;
        !           540:                 }
        !           541:                 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
        !           542:             }
        !           543:  
        !           544:             /*
        !           545:              *  recompute the winding active edge table if
        !           546:              *  we just resorted or have exited an edge.
        !           547:              */
        !           548:             if (InsertionSort(&AET) || fixWAET) {
        !           549:                 computeWAET(&AET);
        !           550:                 fixWAET = FALSE;
        !           551:             }
        !           552:         }
        !           553:     }
        !           554:     FreeStorage(SLLBlock.next);        
        !           555:     region = XCreateRegion();
        !           556:     (void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
        !           557:     return(region);
        !           558: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.