|
|
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 = ®->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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.