OpenGL计算机图形学——多边形裁剪

作业题目:

代码:

多边形裁剪
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <stdio.h>
#include <windows.h>
#include <gl/glut.h>
#include <math.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 = 200, minY = 200, maxX = 400, maxY = 400;
	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 = 8;
	wcPt2D pIn[8];
	pIn[0].setCoords(100, 150);
	pIn[1].setCoords(100, 500);
	pIn[2].setCoords(300, 500);
	pIn[3].setCoords(300, 350);
	pIn[4].setCoords(150, 450);
	pIn[5].setCoords(150, 250);
	pIn[6].setCoords(250, 250);
	pIn[7].setCoords(250, 150);

	//绘制原始多边形
	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[50];
	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("多边形裁剪");//设置窗口标题
	init();
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

运行截图:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值