计算机图形学の多边形裁剪算法(openGL)

二维图形裁剪算法:

参考博客:

https://blog.csdn.net/m0_46359746/article/details/106392352

image-20200930153345235

Liang-Barsky 线段裁剪算法:

//Liang-Barsky 线段裁剪算法

class wcPt2D {

public:
	GLfloat x,y;
public:
	/*
Default Constructor:initalize position 48(0.0,0.0).*/
	wcPt2D(){
		x=y=0.0;
	}

	wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}

	wcPt2D(const wcPt2D& pCopy){
		this->x=pCopy.x;
		this->y=pCopy.y;
	}

	void setCoords(GLfloat xCoord,GLfloat yCoord){
		x = xCoord;
		y = yCoord;
		return ;
	}

	wcPt2D& operator= (wcPt2D p2){
		this->x=p2.getx ();
		this->y=p2.gety ();
		return *this;
	}


	GLfloat getx()const{
		return x;
	}
	GLfloat gety ( ) const {
		return y;
	}
};

inline GLint round(const GLfloat a){
	return GLint(a + 0.5);
}

GLint clipTest(GLfloat p, GLfloat q, GLfloat * u1, GLfloat *u2){
	GLfloat r;
	GLint returnValue=true;
	if(p<0.0){
		r=q/p;
		if(r>*u2){
			returnValue = false;
		}else if(r>*u1){
			*u1=r;
		}
	}else{
		if(p>0.0){
			r=q/p;
			if(r<*u1){
				returnValue=false;
			}else if(r<*u2){
				*u2=r;
			}
		}else{

			if(q<0.0){
				returnValue=false;
			}
		}
	}
	return (returnValue);
}


void lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2){
	GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
	if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
		if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
			dy=p2.gety ()-p1.gety ();
			if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
				if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
					if(u2<1.0){
						p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
					}
					if(u1>0.0){
						p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
					}
					lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
				}
			}
		}
	}

	return ;
}

display:

//	Liang-Barsky线段裁剪算法
//初始直线
glColor3f (0.0,0.0,1.0);
lineBres (0,100,400,300);
glFlush ();

//可视化边界:
glColor3f(1.0,0.0,0.0);
lineBres (100,100,100,300);
lineBres (100,100,300,100);
lineBres (300,300,100,300);
lineBres (300,300,300,100);


glColor3f (0.0,1.0,0.0);
lineClipLiangBrask (wcPt2D(100,100), wcPt2D(300, 300), wcPt2D(0,100),wcPt2D(400, 300));
glFlush ();

Liang-Barsky 多边形裁剪算法:

//-----------------------------------------
//Liang-Barsky 线段裁剪算法

class wcPt2D {

public:
	GLfloat x,y;
public:
	/*
Default Constructor:initalize position 48(0.0,0.0).*/
	wcPt2D(){
		x=y=0.0;
	}

	wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}

	wcPt2D(const wcPt2D& pCopy){
		this->x=pCopy.x;
		this->y=pCopy.y;
	}

	void setCoords(GLfloat xCoord,GLfloat yCoord){
		x = xCoord;
		y = yCoord;
		return ;
	}

	wcPt2D& operator= (wcPt2D p2){
		this->x=p2.getx ();
		this->y=p2.gety ();
		return *this;
	}


	GLfloat getx()const{
		return x;
	}
	GLfloat gety ( ) const {
		return y;
	}
};

inline GLint round(const GLfloat a){
	return GLint(a + 0.5);
}

GLint clipTest(GLfloat p, GLfloat q, GLfloat * u1, GLfloat *u2){
	GLfloat r;
	GLint returnValue=true;
	if(p<0.0){
		r=q/p;
		if(r>*u2){
			returnValue = false;
		}else if(r>*u1){
			*u1=r;
		}
	}else{
		if(p>0.0){
			r=q/p;
			if(r<*u1){
				returnValue=false;
			}else if(r<*u2){
				*u2=r;
			}
		}else{

			if(q<0.0){
				returnValue=false;
			}
		}
	}
	return (returnValue);
}


void lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2){
	GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
	if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
		if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
			dy=p2.gety ()-p1.gety ();
			if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
				if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
					if(u2<1.0){
						p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
					}
					if(u1>0.0){
						p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
					}
					lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
					//					return 2;
				}
			}
		}
	}

	return ;
}

int lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2, wcPt2D pOut[]){
	GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
	if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
		if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
			dy=p2.gety ()-p1.gety ();
			if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
				if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
					if(u2<1.0){
						p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
					}
					if(u1>0.0){
						p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
					}
					pOut[0]=p1;
					pOut[1]=p2;
//					lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
					return 2;
				}
			}
		}
	}

	return 0;
}
void display(){
	glClear (GL_COLOR_BUFFER_BIT);
	//可视化边界:
	const int minX=100, minY=100, maxX=300, maxY=300;
	glColor3f(1.0,0.0,0.0);
	lineDDA (minX,minY,minX,maxY);
	lineDDA (minX,minY,maxX,minY);
	lineDDA (maxX,maxY,minX,maxY);
	lineDDA (maxX,maxY,maxX,minY);

	glColor3f(0.0,1.0,0.0);
	GLint n=5;
	wcPt2D pIn[n];
	pIn[0].setCoords (0,200);
	pIn[1].setCoords (150,250);
	pIn[2].setCoords (250,250);
	pIn[3].setCoords (400,200);
	pIn[4].setCoords (200,50);

	for(int i=0;i<n;++i){
		lineDDA (pIn[i].x,pIn[i].y,pIn[(i+1)%n].x,pIn[(i+1)%n].y);
	}


	wcPt2D pOut[20];
	wcPt2D tempPOut[2];
	int outCount=0;
	int flag=0;
	for(int i=0;i<n;++i){
		flag=lineClipLiangBrask (wcPt2D(minX,minY), wcPt2D(maxX, maxY), pIn[i],pIn[(i+1)%n],tempPOut);
		if(flag==2){
			for(int j=0;j<2;++j){
				pOut[outCount++]=tempPOut[j];
			}
		}
	}

	glColor3f(0.0,0.0,1.0);
	int i=1;
	for(;i<=outCount;++i){
		lineDDA (pOut[i-1].x,pOut[i-1].y,pOut[i%outCount].x,pOut[i%outCount].y);
	}

	glFlush ();


	return ;
}

效果:

image-20201009120216266

Sutherland-Hodgman多边形裁剪算法

#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
#include <stdio.h>

const int windowWidge=600, windowHeight=600;


void setPixel(GLint xCoord, GLint yCoord){
	glBegin (GL_POINTS);
	glVertex2i (xCoord, yCoord);
	glEnd();
}


//-----------------------------------------

void lineDDA (int x0, int y0, int xEnd, int yEnd){
	int dx=xEnd-x0,dy=yEnd-y0,steps,k;
	float xIncrement,yIncrement,x=x0,y=y0;
	if(fabs(dx)> fabs(dy)){
		steps = fabs(dx);
	}else {
		steps = fabs(dy);
	}
	xIncrement = float(dx)/float(steps);
	yIncrement = float(dy)/ float(steps);
	setPixel(round(x),round(y));
	for(k = 0;k< steps;k++){
		x += xIncrement;
		y += yIncrement;
		setPixel(round(x),round(y));
	}
	return ;
}



//---------------------------------------------
//Sutherland-Hodgman多边形裁剪算法

class wcPt2D {

public:
	GLfloat x,y;
public:
	/*
Default Constructor:initalize position 48(0.0,0.0).*/
	wcPt2D(){
		x=y=0.0;
	}

	wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}

	wcPt2D(const wcPt2D& pCopy){
		this->x=pCopy.x;
		this->y=pCopy.y;
	}

	void setCoords(GLfloat xCoord,GLfloat yCoord){
		x = xCoord;
		y = yCoord;
		return ;
	}

	wcPt2D& operator= (wcPt2D p2){
		this->x=p2.getx ();
		this->y=p2.gety ();
		return *this;
	}


	GLfloat getx()const{
		return x;
	}
	GLfloat gety ( ) const {
		return y;
	}
};


//枚举类的替代, C++中enum的操作与C有很大不同
const int Left=0, Right=1, Bottom=2, Top=3;

//typedef enum{
//	Left, Right, Bottom, Top
//} Boundary;

using namespace std;

const GLint nClip = 4;


//判断点p是否在显示框内
GLint inside(wcPt2D p, int b, wcPt2D wMin, wcPt2D wMax){
	int flag=true;
	switch(b){
		case Left:{
			if(p.getx ()<wMin.getx ()){
				flag=false;
			}
			break;
		}
		case Right:{
			if(p.getx ()>wMax.getx ()){
				flag=false;
			}
			break;
		}
		case Bottom:{
			if(p.gety ()<wMin.gety ()){
				flag=false;
			}
			break;
		}
		case Top:{
			if(p.gety ()>wMax.gety ()){
				flag=false;
			}
			break;
		}
	}
	return flag;
}

//判断向量(p1, p2)是否与边界相交
GLint cross(wcPt2D p1, wcPt2D p2, int winEdge, wcPt2D wMin, wcPt2D wMax){
	if(inside (p1,winEdge,wMin,wMax)==inside (p2, winEdge, wMin, wMax)){
		return false;
	}else{
		return true;
	}
}

//返回向量(p1, p2)与相应边界的交点
wcPt2D intersect(wcPt2D p1, wcPt2D p2, int winEdge, wcPt2D wMin, wcPt2D wMax){
	wcPt2D iPt;
	GLfloat m;

	if(p1.x!= p2.x){
		m=(p1.gety ()-p2.gety ())/(p1.getx ()-p2.getx ());
	}
	switch (winEdge) {
		case Left:{
			iPt.x=wMin.x;
			iPt.y=p2.y+(wMin.x-p2.x)*m;
			break;
		}
		case Right:{
			iPt.x=wMax.x;
			iPt.y=p2.y+(wMax.x-p2.x)*m;
			break;
		}
		case Bottom:{
			iPt.y=wMin.y;
			if(p1.x!=p2.x){
				iPt.x=p2.x+(wMin.y-p2.y)/m;
			}else{
				iPt.x=p2.x;
			}
			break;
		}
		case Top:{
			iPt.y=wMax.y;
			if(p1.x!=p2.x){
				iPt.x=p2.x+(wMax.y-p2.y)/m;
			}else{
				iPt.x=p2.x;
			}
			break;
		}
	}
	return iPt;
}

void clipPoint(wcPt2D &p, int winEdge, wcPt2D wMin, wcPt2D wMax, wcPt2D * pOut,
			   int *cnt, wcPt2D first[], wcPt2D *s){
	wcPt2D iPt;

	//判断first[winEdge]为nullPtr
	if(first[winEdge].x==0 && first[winEdge].y==0){
		first[winEdge]=p;
	}else{
		if(cross(p,s[winEdge], winEdge, wMin, wMax)){
			iPt=intersect (p, s[winEdge], winEdge, wMin, wMax);
			if(winEdge<Top){
				clipPoint (iPt, winEdge+1, wMin, wMax, pOut, cnt, first, s);
			}else{
				//存交点
				pOut[*cnt] =iPt;
				(*cnt)++;
			}
		}
	}
	s[winEdge]=p;
	if(inside (p,winEdge, wMin, wMax)){
		if(winEdge<Top){
			clipPoint (p, winEdge+1, wMin, wMax, pOut, cnt, first, s);
		}else{
			pOut[*cnt]=p;
			(*cnt)++;
		}
	}
}

void closeClip(wcPt2D wMin, wcPt2D wMax, wcPt2D *pOut, GLint *cnt,
			   wcPt2D first[],wcPt2D *s){
	wcPt2D pt;
	int winEdge;
	for(winEdge=Left; winEdge<=Top;winEdge++){
		if(cross(s[winEdge],first[winEdge],winEdge, wMin, wMax)){
			pt=intersect (s[winEdge], first[winEdge], winEdge, wMin, wMax);
			if(winEdge<Top){
				clipPoint (pt, winEdge+1, wMin, wMax, pOut, cnt, first, s);
			}else{
				pOut[*cnt]=pt;
				(*cnt)++;
			}
		}
	}
}

GLint polygonClipSuthHodg(wcPt2D wMin, wcPt2D wMax, GLint n, wcPt2D *pIn, wcPt2D *pOut){
	wcPt2D first[nClip] , s[nClip];
	GLint k, cnt=0;
	for(k=0;k<n;k++){
		clipPoint (pIn[k],Left, wMin, wMax, pOut, &cnt, first, s);
	}
	closeClip (wMin, wMax, pOut, &cnt, first, s);
	return cnt;
}


//---------------------------------------------


//绘制程序
void display(){

	//Sutherland-Hodgman多边形裁剪算法
	glClear (GL_COLOR_BUFFER_BIT);
	//可视化边界:
	const int minX=100, minY=100, maxX=300, maxY=300;
	glColor3f(1.0,0.0,0.0);
	lineDDA (minX,minY,minX,maxY);
	lineDDA (minX,minY,maxX,minY);
	lineDDA (maxX,maxY,minX,maxY);
	lineDDA (maxX,maxY,maxX,minY);

	//定义多边形的颜色和顶点
	glColor3f(0.0,1.0,0.0);
	GLint n=6;
	wcPt2D pIn[n];
	pIn[0].setCoords (50,200);
	pIn[1].setCoords (150,250);
	pIn[2].setCoords (250,250);
	pIn[3].setCoords (350,200);
	pIn[4].setCoords (250,50);
	pIn[5].setCoords (150,50);
	//绘制原始多边形
	for(int i=0;i<n;++i){
		lineDDA (pIn[i].x,pIn[i].y,pIn[(i+1)%n].x,pIn[(i+1)%n].y);
	}

	//获取裁剪后的点集
	wcPt2D pOut[20];
	int count=polygonClipSuthHodg (wcPt2D(minX,minY),wcPt2D(maxX,maxY),n,pIn,pOut);

	//定义裁剪后的多边形颜色
	glColor3f(0.0,0.0,1.0);
	//绘制裁剪后的多边形
	for(int i=1;i<=count;++i){
		lineDDA (pOut[i-1].x,pOut[i-1].y,pOut[i%count].x,pOut[i%count].y);
	}

	glFlush ();


	return ;
}

//初始化绘制
void init(){
	glClearColor(1.0,1.0,1.0,0.0);//清除颜色设置
	glMatrixMode(GL_PROJECTION);//设置投影方式
	gluOrtho2D (0.0,windowWidge*1.0,0.0,windowHeight*1.0);
	return ;
}

int main(int argc, char** argv){
	glutInit(&argc, argv);//初始化glut
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置显示模式为单缓冲,RGB模式
	glutInitWindowPosition(0,0);//设置窗口位置
	glutInitWindowSize(windowWidge,windowHeight);//设置窗口大小
	glutCreateWindow("lineClipLiangBrask");//设置窗口标题
	init();
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

效果:

image-20201009153730699

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值