Files
geant4/source/analysis/g4tools/include/tools/zb/polygon
T
2017-12-08 12:52:30 +01:00

286 lines
7.5 KiB
Plaintext

// 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<EdgeTableEntry>(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<POINTBLOCK>(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<POINTBLOCK>(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