// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_zb_polygon #define tools_zb_polygon #include "edge_table" #include "../mnmx" namespace tools { namespace zb { class polygon { static const int NUMPTSTOBUFFER = 200; typedef struct _POINTBLOCK { point pts[NUMPTSTOBUFFER]; struct _POINTBLOCK* next; } POINTBLOCK; int m_pETEn; EdgeTableEntry* m_pETEs; int m_numAllocPtBlocks; POINTBLOCK m_FirstPtBlock; public: polygon():m_pETEn(0),m_pETEs(NULL),m_numAllocPtBlocks(0){} virtual ~polygon(){clear();} protected: polygon(const polygon&){} polygon& operator=(const polygon&){return *this;} public: void clear(){ POINTBLOCK* curPtBlock; cmem_free(m_pETEs); m_pETEn = 0; for(curPtBlock = m_FirstPtBlock.next; --m_numAllocPtBlocks >= 0;){ POINTBLOCK* tmpPtBlock; tmpPtBlock = curPtBlock->next; cmem_free(curPtBlock); curPtBlock = tmpPtBlock; } m_numAllocPtBlocks = 0; } typedef void (*scan_func)(void*,int,int,int); void scan(int Count, /* number of pts */ const point* Pts, /* the pts */ int rule, /* winding rule */ scan_func a_proc,void* a_tag){ // polytoregion // Scan converts a polygon by returning a run-length // encoding of the resultant bitmap -- the run-length // encoding is in the form of an array of rectangles. EdgeTableEntry* pAET; /* Active Edge Table */ int y; /* current scanline */ int iPts = 0; /* number of pts in buffer */ EdgeTableEntry* pWETE; /* Winding Edge Table Entry*/ ScanLineList* pSLL; /* current scanLineList */ EdgeTableEntry* pPrevAET; /* ptr to previous AET */ EdgeTable ET; /* header node for ET */ EdgeTableEntry AET; /* header node for AET */ ScanLineListBlock SLLBlock; /* header for scanlinelist */ int fixWAET = 0; POINTBLOCK* curPtBlock; int numFullPtBlocks = 0; if(a_proc==NULL) return; if(Count==0) return; /* special case a rectangle */ point* pts = (point*)Pts; if (((Count == 4) || ((Count == 5) && (pts[4].x == pts[0].x) && (pts[4].y == pts[0].y))) && (((pts[0].y == pts[1].y) && (pts[1].x == pts[2].x) && (pts[2].y == pts[3].y) && (pts[3].x == pts[0].x)) || ((pts[0].x == pts[1].x) && (pts[1].y == pts[2].y) && (pts[2].x == pts[3].x) && (pts[3].y == pts[0].y)))) { int xmin,xmax,ymin,ymax; xmin = (int)mn(pts[0].x, pts[2].x); ymin = (int)mn(pts[0].y, pts[2].y); xmax = (int)mx(pts[0].x, pts[2].x); ymax = (int)mx(pts[0].y, pts[2].y); if ((xmin != xmax) && (ymin != ymax)) { for(y=ymin;y<=ymax;y++) a_proc(a_tag,xmin ,xmax ,y); } return; } if(Count>m_pETEn) { cmem_free(m_pETEs); m_pETEn = Count; m_pETEs = cmem_alloc(m_pETEn); if(m_pETEs==NULL) { m_pETEn = 0; return; } } CreateETandAET (Count,(point*)Pts, &ET, &AET, m_pETEs, &SLLBlock); pSLL = ET.scanlines.next; curPtBlock = &m_FirstPtBlock; pts = m_FirstPtBlock.pts; if (rule==0) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { LoadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { pts->x = pAET->bres.minor_axis; pts->y = y; pts++; iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { if(numFullPtBlocks < m_numAllocPtBlocks) { curPtBlock = curPtBlock->next; } else { POINTBLOCK* tmpPtBlock = cmem_alloc(1); if(tmpPtBlock==NULL) { FreeStorage(SLLBlock.next); return; } tmpPtBlock->next = NULL; /*Barrand*/ curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; m_numAllocPtBlocks++; } numFullPtBlocks++; pts = curPtBlock->pts; iPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y) } (void) InsertAndSort(&AET); } } else { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { LoadAET(&AET, pSLL->edgelist); ComputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * add to the buffer only those edges that * are in the Winding active edge table. */ if (pWETE == pAET) { pts->x = pAET->bres.minor_axis; pts->y = y; pts++; iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { if(numFullPtBlocks < m_numAllocPtBlocks) { curPtBlock = curPtBlock->next; } else { POINTBLOCK* tmpPtBlock = cmem_alloc(1); if(tmpPtBlock==NULL) { FreeStorage(SLLBlock.next); return; } tmpPtBlock->next = NULL; /*Barrand*/ curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; m_numAllocPtBlocks++; } numFullPtBlocks++; pts = curPtBlock->pts; iPts = 0; } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } /* * recompute the winding active edge table if * we just resorted or have exited an edge. */ if ( (InsertAndSort(&AET)!=0) || (fixWAET!=0) ) { ComputeWAET(&AET); fixWAET = 0; } } } FreeStorage (SLLBlock.next); ScanPoints (numFullPtBlocks, iPts, &m_FirstPtBlock,a_proc,a_tag); } protected: void ScanPoints (int numFullPtBlocks, int iCurPtBlock, POINTBLOCK* FirstPtBlock, scan_func a_proc,void* a_tag) { point* pts; POINTBLOCK* CurPtBlock; int i; CurPtBlock = FirstPtBlock; for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) { /* the loop uses 2 points per iteration */ i = numFullPtBlocks!=0 ? NUMPTSTOBUFFER >> 1 : iCurPtBlock >> 1 ; for (pts = CurPtBlock->pts; i--; pts += 2) { a_proc (a_tag,(int)(pts->x),(int)pts[1].x,(int)pts->y); } CurPtBlock = CurPtBlock->next; } } }; }} #endif