📄 qpolygonscanner.cpp
字号:
/* * CreateEdgeTable * * This routine creates the edge table for * scan converting polygons. * The Edge Table (ET) looks like: * * EdgeTable * -------- * | ymax | ScanLineLists * |scanline|-->------------>-------------->... * -------- |scanline| |scanline| * |edgelist| |edgelist| * --------- --------- * | | * | | * V V * list of ETEs list of ETEs * * where ETE is an EdgeTableEntry data structure, * and there is one ScanLineList per scanline at * which an edge is initially entered. * */typedef struct { int x, y;} DDXPointRec, *DDXPointPtr;/* * Clean up our act. */voidmiFreeStorage(ScanLineListBlock *pSLLBlock){ register ScanLineListBlock *tmpSLLBlock; while (pSLLBlock) { tmpSLLBlock = pSLLBlock->next; free(pSLLBlock); pSLLBlock = tmpSLLBlock; }}boolmiCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock){ register DDXPointPtr top, bottom; register DDXPointPtr PrevPt, CurrPt; int iSLLBlock = 0; int dy; if (count < 2) return TRUE; /* * initialize the Active Edge Table */ AET->next = 0; AET->back = 0; AET->nextWETE = 0; AET->bres.minor = MININT; /* * initialize the Edge Table. */ ET->scanlines.next = 0; ET->ymax = MININT; ET->ymin = MAXINT; pSLLBlock->next = 0; PrevPt = &pts[count-1]; /* * for each vertex in the array of points. * In this loop we are dealing with two vertices at * a time -- these make up one edge of the polygon. */ while (count--) { CurrPt = pts++; /* * find out which point is above and which is below. */ if (PrevPt->y > CurrPt->y) { bottom = PrevPt, top = CurrPt; pETEs->ClockWise = 0; } else { bottom = CurrPt, top = PrevPt; pETEs->ClockWise = 1; } /* * don't add horizontal edges to the Edge table. */ if (bottom->y != top->y) { pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ /* * initialize integer edge algorithm */ dy = bottom->y - top->y; BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres) if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) { miFreeStorage(pSLLBlock->next); return FALSE; } ET->ymax = QMAX(ET->ymax, PrevPt->y); ET->ymin = QMIN(ET->ymin, PrevPt->y); pETEs++; } PrevPt = CurrPt; } return TRUE;}/* * loadAET * * This routine moves EdgeTableEntries from the * EdgeTable into the Active Edge Table, * leaving them sorted by smaller x coordinate. * */voidmiloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs){ register EdgeTableEntry *pPrevAET; register EdgeTableEntry *tmp; pPrevAET = AET; AET = AET->next; while (ETEs) { while (AET && (AET->bres.minor < ETEs->bres.minor)) { pPrevAET = AET; AET = AET->next; } tmp = ETEs->next; ETEs->next = AET; if (AET) AET->back = ETEs; ETEs->back = pPrevAET; pPrevAET->next = ETEs; pPrevAET = ETEs; ETEs = tmp; }}/* * computeWAET * * This routine links the AET by the * nextWETE (winding EdgeTableEntry) link for * use by the winding number rule. The final * Active Edge Table (AET) might look something * like: * * AET * ---------- --------- --------- * |ymax | |ymax | |ymax | * | ... | |... | |... | * |next |->|next |->|next |->... * |nextWETE| |nextWETE| |nextWETE| * --------- --------- ^-------- * | | | * V-------------------> V---> ... * */voidmicomputeWAET(EdgeTableEntry *AET){ register EdgeTableEntry *pWETE; register int inside = 1; register int isInside = 0; AET->nextWETE = 0; pWETE = AET; AET = AET->next; while (AET) { if (AET->ClockWise) isInside++; else isInside--; if ((!inside && !isInside) || ( inside && isInside)) { pWETE->nextWETE = AET; pWETE = AET; inside = !inside; } AET = AET->next; } pWETE->nextWETE = 0;}/* * InsertionSort * * Just a simple insertion sort using * pointers and back pointers to sort the Active * Edge Table. * */intmiInsertionSort(EdgeTableEntry *AET){ register EdgeTableEntry *pETEchase; register EdgeTableEntry *pETEinsert; register EdgeTableEntry *pETEchaseBackTMP; register int changed = 0; AET = AET->next; while (AET) { pETEinsert = AET; pETEchase = AET; while (pETEchase->back->bres.minor > AET->bres.minor) pETEchase = pETEchase->back; AET = AET->next; if (pETEchase != pETEinsert) { pETEchaseBackTMP = pETEchase->back; pETEinsert->back->next = AET; if (AET) AET->back = pETEinsert->back; pETEinsert->next = pETEchase; pETEchase->back->next = pETEinsert; pETEchase->back = pETEinsert; pETEinsert->back = pETEchaseBackTMP; changed = 1; } } return(changed);}/*! \overload */void QPolygonScanner::scan(const QPointArray& pa, bool winding, int index, int npoints){ scan( pa, winding, index, npoints, TRUE );}/*! \overload If \a stitchable is FALSE, the right and bottom edges of the polygon are included. This causes adjacent polygons to overlap. */void QPolygonScanner::scan(const QPointArray& pa, bool winding, int index, int npoints, bool stitchable){ scan( pa, winding, index, npoints, stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom) );}/*! Calls processSpans() for all scanlines of the polygon defined by \a npoints starting at \a index in \a pa. If \a winding is TRUE, the Winding algorithm rather than the Odd-Even rule is used. The \a edges is any bitwise combination of QPolygonScanner::Left, QPolygonScanner::Right, QPolygonScanner::Top, and QPolygonScanner::Bottom, and determines which edges are included. \warning The edges feature does not work properly*/void QPolygonScanner::scan( const QPointArray& pa, bool winding, int index, int npoints, Edge edges ){ DDXPointPtr ptsIn = (DDXPointPtr)pa.data(); ptsIn += index; register EdgeTableEntry *pAET; /* the Active Edge Table */ register int y; /* the current scanline */ register int nPts = 0; /* number of pts in buffer */ register EdgeTableEntry *pWETE; /* Winding Edge Table */ register ScanLineList *pSLL; /* Current ScanLineList */ register DDXPointPtr ptsOut; /* ptr to output buffers */ int *width; DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ int FirstWidth[NUMPTSTOBUFFER]; EdgeTableEntry *pPrevAET; /* previous AET entry */ EdgeTable ET; /* Edge Table header node */ EdgeTableEntry AET; /* Active ET header node */ EdgeTableEntry *pETEs; /* Edge Table Entries buff */ ScanLineListBlock SLLBlock; /* header for ScanLineList */ int fixWAET = 0; int edge_l = (edges & Left) ? 1 : 0; int edge_r = (edges & Right) ? 1 : 0; int edge_t = 1; //#### (edges & Top) ? 1 : 0; int edge_b = (edges & Bottom) ? 1 : 0; if (npoints == -1) npoints = pa.size(); if (npoints < 3) return; if(!(pETEs = (EdgeTableEntry *) malloc(sizeof(EdgeTableEntry) * npoints))) return; ptsOut = FirstPoint; width = FirstWidth; if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock)) { free(pETEs); return; } pSLL = ET.scanlines.next; if (!winding) { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->next->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer when its full */ if (nPts == NUMPTSTOBUFFER) { processSpans( nPts, (QPoint*)FirstPoint, FirstWidth ); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y) EVALUATEEDGEEVENODD(pAET, pPrevAET, y) } miInsertionSort(&AET); } } else /* default to WindingNumber */ { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); micomputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * if the next edge in the active edge table is * also the next edge in the winding active edge * table. */ if (pWETE == pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer */ if (nPts == NUMPTSTOBUFFER) { processSpans( nPts, (QPoint*)FirstPoint, FirstWidth ); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } pWETE = pWETE->nextWETE; while (pWETE != pAET) { EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } /* * reevaluate the Winding active edge table if we * just had to resort it or if we just exited an edge. */ if (miInsertionSort(&AET) || fixWAET) { micomputeWAET(&AET); fixWAET = 0; } } } /* * Get any spans that we missed by buffering */ processSpans( nPts, (QPoint*)FirstPoint, FirstWidth ); free(pETEs); miFreeStorage(SLLBlock.next);}/***** END OF X11-based CODE *****/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -