www.pudn.com > glGraph.rar > glPolygon.cpp
// glPolygon.cpp: implementation of the glPolygon class.
//
//////////////////////////////////////////////////////////////////////
#include "glPolygon.h"
#include "gl/glut.h"
#include "math.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
glPolygon::glPolygon()
{
type = POLYGON;
tail = head = 0;
num = 0;
ET = 0;
ymin = 60000;
ymax = -60000;
AEL = 0;
}
glPolygon::~glPolygon()
{
}
void glPolygon::AddPoint(float x, float y,double width,double height)
{
point* p = new point;//创建一新节点
p->nod[0] = (x-width/2);
p->nod[1] = ((int)(height/2)-y);
p->m_next = 0;
num++;
if(head == 0)//如果为第一节点
{
tail = head = p;//加入链手
if(p->nod[1] < ymin)
ymin = p->nod[1];//保留新的y的最小值
if(p->nod[1] > ymax)
ymax = p->nod[1];//保留新的y的最大值
return;
}
else
{//其它节点
tail->m_next = p;//加入链尾
}
if(IsAble() == 0)//判断是否为自交多边形
{
tail->m_next = 0;
delete p;//如果不是删除刚节点
num--;
}
else
tail = tail->m_next;//如果是确定链尾
if(p->nod[1] < ymin)
{
// DeleteET();
ymin = p->nod[1];//保留新的y的最小值
// CreatET();//重建边分类表
}
if(p->nod[1] > ymax)
{
// DeleteET();
ymax = p->nod[1];//保留新的y的最大值
// CreatET();//重建边分类表
}
}
void glPolygon::Draw()
{
point* p = head;
glColor3fv(color);
glLineWidth(scale);
glBegin(GL_LINE_LOOP);
while(p)//画多边形的各边
{
glVertex2fv(p->nod);
p = p->m_next;
}
glEnd();
Fill();
}
int glPolygon::IsAble()
{//判断是否为自交多边形
return 1;
int flag = 0;//标志向量的乘积是否大于0
point* p1;
point* p2;
point* p3;
float x1[2];//记录一向量
float x2[2];//记录一向量
if(num < 3)
return 1;
p1 = head->m_next->m_next;
p2 = head->m_next;
p3 = head;
while(p1)
{
//确定两向量
x1[0] = p2->nod[0] - p3->nod[0];
x1[1] = p2->nod[1] - p3->nod[1];
x2[0] = p1->nod[0] - p2->nod[0];
x2[1] = p1->nod[1] - p2->nod[1];
if(flag == 0)
{//如果是第一个向量则修改flag
if(x1[0]*x2[1]-x1[1]*x2[0] > 0)
{
flag = 1;//大于0,置1
}
else
{
flag = -1;//小于0,置-1
}
}
if(x1[0]*x2[1]-x1[1]*x2[0] > 0)
{
if(flag == -1)//在当前大于0的乘积下,如果之前小于0
return 0;//返回0
}
if(x1[0]*x2[1]-x1[1]*x2[0] < 0)
{
if(flag == 1)//在当前小于0的乘积下,如果之前大于0
return 0;//返回0
}
p1 = p1->m_next;
p2 = p2->m_next;
p3 = p3->m_next;
}
p1 = head;//判断从最后点到开始点的向量
//确定两向量
x1[0] = p2->nod[0] - p3->nod[0];
x1[1] = p2->nod[1] - p3->nod[1];
x2[0] = p1->nod[0] - p2->nod[0];
x2[1] = p1->nod[1] - p2->nod[1];
if(x1[0]*x2[1]-x1[1]*x2[0] > 0)
{
if(flag == -1)//在当前大于0的乘积下,如果之前小于0
return 0;//返回0
}
if(x1[0]*x2[1]-x1[1]*x2[0] < 0)
{
if(flag == 1)//在当前小于0的乘积下,如果之前大于0
return 0;//返回0
}
p1 = p1->m_next;
p2 = head;
p3 = p3->m_next;
//确定两向量
x1[0] = p2->nod[0] - p3->nod[0];
x1[1] = p2->nod[1] - p3->nod[1];
x2[0] = p1->nod[0] - p2->nod[0];
x2[1] = p1->nod[1] - p2->nod[1];
if(x1[0]*x2[1]-x1[1]*x2[0] > 0)
{
if(flag == -1)//在当前大于0的乘积下,如果之前小于0
return 0;//返回0
}
if(x1[0]*x2[1]-x1[1]*x2[0] < 0)
{
if(flag == 1)//在当前小于0的乘积下,如果之前大于0
return 0;//返回0
}
return 1;
}
void glPolygon::CreatET()
{
int a = ymax-ymin+1;
ET = new struct EDGE[a];
for(int i = 0;inextEdge = 0;//将分类表各项置空
point* p1;//指向当前分析边的首点
point* p2;//指向当前分析边的末点
float x1,x2,y1,y2;//用于保存当前分析边两个点的横竖坐标
p1 = head;//获得第一条边的一点
p2 = head->m_next;//获得第一条边的另一点
while(p2)
{
//保存当前分析边两个点的横竖坐标
y1 = p1->nod[1];
x1 = p1->nod[0];
y2 = p2->nod[1];
x2 = p2->nod[0];
if(y1 < y2)
{
EDGE* e = new EDGE;
e->ymax = y2;
e->x = x1;
e->deltax = (x1-x2)/(y1-y2);
e->nextEdge = 0;
a = y1 - ymin;
InsertEdgeToET(a,e);
}
if(y1 > y2)
{
EDGE* e = new EDGE;
e->ymax = y1;
e->x = x2;
e->deltax = (x1-x2)/(y1-y2);
e->nextEdge = 0;
a = y2 - ymin;
InsertEdgeToET(a,e);
}
p1 = p1->m_next;//获得下一条边的一点
p2 = p2->m_next;//获得下一条边的另一点
}
if(num == 2)//只有一条边直接返回
return;
//处理末点到首点的边
p2 = head;
y1 = p1->nod[1];
y2 = p2->nod[1];
x1 = p1->nod[0];
x2 = p2->nod[0];
if(y1 < y2)
{
EDGE* e = new EDGE;
e->ymax = y2;
e->x = x1;
e->deltax = (x1-x2)/(y1-y2);
e->nextEdge = 0;
a = y1 - ymin;
InsertEdgeToET(a,e);
}
if(y1 > y2)
{
EDGE* e = new EDGE;
e->ymax = y1;
e->x = x2;
e->deltax = (x1-x2)/(y1-y2);
e->nextEdge = 0;
a = y2 - ymin;
InsertEdgeToET(a,e);
}
}
point* glPolygon::GetPrePointForY(float y)
{//通过给定y值,返回找到节点的上一point
point* p1;
point* p2;
p2 = head;
p1 = head->m_next;
if(head->nod[1] == y)//第一节点的y为所求,则返回末节点
return tail;
while(p1)
{
if(p1->nod[1] == y)
return p2;
p2 = p2->m_next;
p1 = p1->m_next;
}
return 0;
}
point* glPolygon::GetNextPointForY(float y)
{//通过给定y值,返回找到节点的下一point
point* p1;
point* p2;
p2 = head->m_next;
p1 = head;
while(p2)
{
if(p1->nod[1] == y)
return p2;
p2 = p2->m_next;
p1 = p1->m_next;
}
if(p1->nod[1] == y)//末点的y为所求,则返回头节点
return head;
return 0;
}
point* glPolygon::GetPointForY(float y)
{
return 0;
}
void glPolygon::InsertEdgeToET(int kind, EDGE *e)
{
EDGE* et1;//一临时辅助指针
EDGE* et2;//一临时辅助指针
if((ET + kind)->nextEdge == 0)//如果当前类的边没有,则直接插入分类表
{
(ET + kind)->nextEdge = e;
return;
}
else
{//如果已经有当前类的边,进行以下处理
et1 = (ET+kind)->nextEdge;//获得此类的第一条边
et2 = (ET+kind);//获得此类链首
while(et1)
{
if(et1->x > e->x)
{//如果新边的x小于当前边ex1的x,则插入当前位
et2->nextEdge = e;
e->nextEdge = et1;
return;
}
if(et1->x == e->x)
{
if(et1->deltax > e->deltax)
{//如果新边的x==当前边ex1的x 且新边的deltax于当前边ex1的deltax,则插入
et2->nextEdge = e;
e->nextEdge = et1;
return;
}
else//否则
{//插入到下一位置
et1 = et1->nextEdge;
et2 = et2->nextEdge;
et2->nextEdge = e;
e->nextEdge = et1;
return;
}
}
et1 = et1->nextEdge;
et2 = et2->nextEdge;
}
if(et1 == 0)
et2->nextEdge = e;
}
}
void glPolygon::DeleteET()
{//释放当前分类表空间
if(ET == 0)
return;
/* EDGE* t1;
EDGE* t2;
for(int j = 0;jnextEdge;
while(t2)
{
t1 = t2;
t2 = t2->nextEdge;
delete t1;
}
}*/
delete [] ET;//释放表
}
void glPolygon::Fill()
{//扫描线填充多边性
AEL = 0;
DeleteET();
CreatET();//重建边分类表
float x1;//填充时存放x的临时值
float x2;//填充时存放x的临时值
EDGE* e;
EDGE* e1;
glBegin(GL_LINES);
if((ET+0)->nextEdge != 0)
{//初始AEL表
InsetEdgeToAEL(0);
}
for(int y = 0;y<=ymax-ymin;y++)
{//扫描填充
e1 = e = AEL;
while(e)
{
glVertex2f(e->x,ymin+y);
e->x += e->deltax;//x = x+deltax
if(e->ymax == ymin+y)
{//如果y值大于ymax值,则将当前边从AEL中移出
if(e == AEL)
{
AEL = AEL->nextEdge;
delete e;
e1 = e = AEL;
continue;
}
e1->nextEdge = e->nextEdge;
delete e;
e = e1->nextEdge;
continue;
}
e1 = e;
e = e->nextEdge;
}
if((ET+y)->nextEdge != 0 && y != 0)
{//如果有新点,则将边插入AEL表
InsetEdgeToAEL(y);
}
}
glEnd();
}
void glPolygon::InsetEdgeToAEL(int y)
{//将分类表中的边移到活化边表中
EDGE* e;
EDGE* et;
EDGE* e1;
EDGE* e2;
e = et = (ET+y)->nextEdge;//取出边链
(ET+y)->nextEdge = 0;//当前类置空
if(AEL == 0)
{
AEL = e;
return;
}
while(e)
{
e1 = AEL;
e2 = AEL->nextEdge;
while(e2)
{
if(e1->x > et->x)
{//AEL的第一条边的x大于插入边的x
e = e->nextEdge;//插入的队列指针后移
et->nextEdge = AEL;//将插入边插入到AEL队首
AEL = et;
break;
}
if(e2->x > e->x)
{
e = e->nextEdge;//插入的队列指针后移
e1->nextEdge = et;
et->nextEdge = e2;
break;
}
e1 = e1->nextEdge;
e2 = e2->nextEdge;
}
if(e2 == 0)
{
e1->nextEdge = e;//将插入边插入到AEL队尾
e = e->nextEdge;//插入的队列指针后移
et->nextEdge = 0;
}
et = e;
}
}
void glPolygon::DeleteLastPoint()
{
point* p;
p = head;
if(head == tail)
{
delete head;
head = 0;
return;
}
while(p)
{
if(p->m_next == tail)
break;
p = p->m_next;
}
if(p == 0)
return;
tail = p;
p = p->m_next;
tail->m_next = 0;
delete p;
}