计算机图形学5——Two-Dimensional Viewing and Clipping(二维线段裁剪算法)
采用Cohen-Sutherland算法裁剪线段
核心代码有:
bool line_clipping(CPoint2D p1, CPoint2D p2, CRect *cw,
CPoint2D *q1, CPoint2D *q2)
// p1, p2: End points of input line segment
// cw: Clipping rectangle
// q1, q2: End points of output line segment
// Return value: true --- accept, false --- reject
{
GLubyte code1,code2;
GLint done=false,poltLine=false;
GLfloat m;
while(!done)
{
code1=encode(p1,cw);//起点
code2=encode(p2,cw);//终点
if(accept(code1,code2))
{
done=true;
poltLine=true;
}
else if(reject(code1,code2))
{
done=true;
}
else
{
if(inside(code1))//return GLint(!code);起点为0000,则交换起点和终点
{
swapPts(&p1,&p2);
swapCodes(&code1,&code2);
}
if(p2.x!=p1.x)//斜率存在,便求斜率
m=(p2.y-p1.y)/(p2.x-p1.x);//这里之前打错字了,导致显示不全
//从右向左检查R1(起点且为外端点)
if(code1&left){
p1.y+=(cw->xmin-p1.x)*m;
p1.x=cw->xmin;
}
else if(code1&right)
{
p1.y+=(cw->xmax-p1.x)*m;
p1.x=cw->xmax;
}
else if(code1&bottom)
{
if(p2.x!=p1.x)
p1.x+=(cw->ymin-p1.y)/m;
p1.y=cw->ymin;
}
else if(code1&top)
{
if(p2.x!=p1.x)
p1.x+=(cw->ymax-p1.y)/m;
p1.y=cw->ymax;
}
}
}
*q1=p1;
*q2=p2;
return poltLine;
}
完整代码如下:
// ====== Computer Graphics Experiment #6 ======
// | Two-Dimensional Viewing and Clipping |
// =============================================
//
// Requirement:
// (1) Implement Cohen-Sutherland line clipping algorithm.
// (2) Change position and size of window and viewport
// and observe the effects.
#include <windows.h>
#include <GL/glut.h>
#include <math.h>
// 2D point class
class CPoint2D
{
public:
float x, y;
};
// Rectangle class
class CRect
{
public:
float xmin, ymin, xmax, ymax;
float width(void) { return xmax-xmin; }
float height(void) { return ymax-ymin; }
// Make (xmin, ymin) the lower left corner
void normalize(void);
// Draw the rectangle
void draw(GLenum mode);
};
void CRect::normalize(void)
{
float ftemp;
if (xmin > xmax)
{ftemp=xmin; xmin=xmax; xmax=ftemp;}
if (ymin > ymax)
{ftemp=ymin; ymin=ymax; ymax=ftemp;}
}
void CRect::draw(GLenum mode)
{
glBegin(mode);
glVertex2f(xmin, ymin);
glVertex2f(xmax, ymin);
glVertex2f(xmax, ymax);
glVertex2f(xmin, ymax);
glEnd();
}
#define PI 3.14159265359
int running_state=0;
// 0 --- Normal state.
// 1 --- Rubber-band state.
// Size of the scene
float scene_size=1000.0;
CRect clip_rect; // Clipping rectangle
CRect window; // Window
CRect viewport; // Viewport
// Program window size
int pw_width, pw_height;
// Set window
void set_window(CRect *cw)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (cw->xmin, cw->xmax, cw->ymin, cw->ymax);
}
// Set viewport
void set_viewport(CRect *vp)
{
glViewport(vp->xmin, vp->ymin,
vp->width(), vp->height());
}
const GLint left=0x1;
const GLint right=0x2;
const GLint bottom=0x4;
const GLint top=0x8;
GLint inside(GLint code)
{
return GLint(!code);
}
GLint reject(GLint code1,GLint code2)
{
return GLint(code1&code2);
}
GLint accept(GLint code1,GLint code2)
{
return GLint(!(code1|code2));
}
GLubyte encode(CPoint2D pt,CRect *cw1)/////////////////
{
GLubyte code=0x00;
if(pt.x<cw1->xmin)
code=code|left;
if(pt.x>cw1->xmax)
code=code|right;
if(pt.y<cw1->ymin)
code=code|bottom;
if(pt.y>cw1->ymax)
code=code|top;
return(code);
}
void swapPts(CPoint2D *p1,CPoint2D *p2)
{
CPoint2D temp;
temp=*p1;*p1=*p2;*p2=temp;
}
void swapCodes(GLubyte *p1,GLubyte*p2)
{
GLubyte temp;
temp=*p1;*p1=*p2;*p2=temp;
}
// Cohen-Sutherland line clipping algorithm.
bool line_clipping(CPoint2D p1, CPoint2D p2, CRect *cw,
CPoint2D *q1, CPoint2D *q2)
// p1, p2: End points of input line segment
// cw: Clipping rectangle
// q1, q2: End points of output line segment
// Return value: true --- accept, false --- reject
{
GLubyte code1,code2;
GLint done=false,poltLine=false;
GLfloat m;
while(!done)
{
code1=encode(p1,cw);//起点
code2=encode(p2,cw);//终点
if(accept(code1,code2))
{
done=true;
poltLine=true;
}
else if(reject(code1,code2))
{
done=true;
}
else
{
if(inside(code1))//return GLint(!code);起点为0000,则交换起点和终点
{
swapPts(&p1,&p2);
swapCodes(&code1,&code2);
}
if(p2.x!=p1.x)//斜率存在,便求斜率
m=(p2.y-p1.y)/(p2.x-p1.x);//这里之前打错字了,导致显示不全
//从右向左检查R1(起点且为外端点)
if(code1&left){
p1.y+=(cw->xmin-p1.x)*m;
p1.x=cw->xmin;
}
else if(code1&right)
{
p1.y+=(cw->xmax-p1.x)*m;
p1.x=cw->xmax;
}
else if(code1&bottom)
{
if(p2.x!=p1.x)
p1.x+=(cw->ymin-p1.y)/m;
p1.y=cw->ymin;
}
else if(code1&top)
{
if(p2.x!=p1.x)
p1.x+=(cw->ymax-p1.y)/m;
p1.y=cw->ymax;
}
}
}
*q1=p1;
*q2=p2;
return poltLine;
}
//Translate the clip rectangle
void Translaterect(int dx,int dy)
{
clip_rect.xmin+=dx;
clip_rect.xmax+=dx;
clip_rect.ymin+=dy;
clip_rect.ymax+=dy;
}
// Initialization function
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glEnable(GL_LINE_STIPPLE);
}
// Display callback function
void display(void)
{
int i;
CPoint2D p1, p2, q1, q2;
double a, r;
glClear (GL_COLOR_BUFFER_BIT);
// Draw blue rectangle to fill the background
glColor3f(0.0, 0.0, 0.5);
window.draw(GL_POLYGON);
// Draw unclipped lines in green color
p1.x=0.0; p1.y=0.0;
r=0.5*scene_size;
glLineStipple(1, 0x0f0f);
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
for (i=0; i<360; i+=15)
{
a=(double)i/180.0*PI;
p2.x=r*cos(a);
p2.y=r*sin(a);
if (i==0 || i==180) p2.y=0;
if (i==90 || i==270) p2.x=0;
p2.x+=p1.x;
p2.y+=p1.y;
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
}
glEnd();
glLineStipple(1, 0xffff);
// Draw clipped lines in white color
if (running_state == 0) {
glColor3f(1.0, 1.0, 1.0);
glLineWidth(2.0);
glBegin(GL_LINES);
for (i=0; i<360; i+=15)
{
a=(double)i/180.0*PI;
p2.x=r*cos(a);
p2.y=r*sin(a);
if (i==0 || i==180) p2.y=0;
if (i==90 || i==270) p2.x=0;
p2.x+=p1.x;
p2.y+=p1.y;
if(line_clipping(p1, p2, &clip_rect, &q1, &q2))
{
glVertex2f(q1.x, q1.y);
glVertex2f(q2.x, q2.y);
}
}
glEnd();
glLineWidth(1.0);
}
// Draw clipping rectangle
glLineStipple(1, 0x0f0f);
glColor3f(1.0, 1.0, 0.0);
clip_rect.draw(GL_LINE_LOOP);
glLineStipple(1, 0xffff);
glutSwapBuffers();
}
// Reshape callback function
void reshape(int w, int h)
{
// Store program window size
pw_width=w;
pw_height=h;
// set viewport
viewport.xmin=0;
viewport.xmax=w;
viewport.ymin=0;
viewport.ymax=h;
set_viewport(&viewport);
// set clipping window
window.xmin=-0.6*scene_size;
window.xmax=0.6*scene_size;
window.ymin=-0.6*scene_size;
window.ymax=0.6*scene_size;
set_window(&window);
// set clipping rectangle
clip_rect.xmin=0.5*window.xmin;
clip_rect.xmax=0.5*window.xmax;
clip_rect.ymin=0.5*window.ymin;
clip_rect.ymax=0.5*window.ymax;
}
// Keyboard callback function
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
}
}
// Special keyboard callback function
void special_key(int key, int x, int y)
{
switch (key) {
case GLUT_KEY_LEFT:
Translaterect(-5,0);
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
Translaterect(5.0,0.0);
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
Translaterect(0.0,-5.0);
glutPostRedisplay();
break;
case GLUT_KEY_UP:
Translaterect(0.0,5.0);
glutPostRedisplay();
break;
}
}
// Main program entrance
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(500, 500);
glutCreateWindow("Test 2D Clippig and Viewing");
init();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special_key);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
考虑到我修改出这篇文章的代码花了不少时间,
应该算是原创的一种了
(っ °Д °;)っ