作业题目:
代码:
多边形裁剪
#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;
}
运行截图: