使用的是Cohen-Sutherland 裁线算法,先把区域编号,之后裁剪。
注意在移动的时候是用裁剪窗口去判断,而不是windows窗口。
// ====== 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 <stdio.h>
#include <math.h>
// 2D point class
class CPoint2D
{
public:
float x, y;
};
void swapCP(CPoint2D *p1, CPoint2D *p2)
{
CPoint2D tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void swapCodes(GLubyte *p1, GLubyte *p2)
{
GLubyte tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
// 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
const GLint winLeftBitCode = 0x1;
const GLint winRightBitCode = 0x2;
const GLint winBottomBitCode = 0x4;
const GLint winTopBitCode = 0x8;
// 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());
}
inline GLint roundx(const GLfloat a)
{
return GLint(a + 0.5);
}
inline GLint inside(GLint code)
{
return GLint(!code);
}
inline GLint reject(GLint code1, GLint code2)
{
return GLint(code1&code2);
}
inline GLint accept(GLint code1, GLint code2)
{
return GLint(!(code1 | code2));
}
GLubyte encode(CPoint2D pt)
{
GLubyte code = 0x00;
if (pt.x < clip_rect.xmin)
code |= winLeftBitCode;
if (pt.x > clip_rect.xmax)
code |= winRightBitCode;
if (pt.y < clip_rect.ymin)
code |= winBottomBitCode;
if (pt.y > clip_rect.ymax)
code |= winTopBitCode;
return code;
}
// 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
{
// Write your code here
GLubyte code1, code2;
int done = false, plotLine = false;
GLfloat m;/*
printf("%f~%f~%f~%f===\n", p1.x, p1.y, p2.x, p2.y);
printf("%f~%f~%f~%f===\n", window.xmax,window.xmin,window.ymax,window.ymin);
printf("%f~%f~%f~%f===\n", clip_rect.xmax, clip_rect.xmin, clip_rect.ymax, clip_rect.ymin);*/
while (!done)
{
code1 = encode(p1);
code2 = encode(p2);
if (accept(code1, code2))
{
done = true;
plotLine = true;
}
else if (reject(code1, code2))
{
done = true;
}
else
{
if (inside(code1))
{
swapCP(&p1, &p2);
swapCodes(&code1, &code2);
}
if (p2.x != p1.x)
m = (p2.y - p1.y) / (p2.x - p1.x);
if (code1&winLeftBitCode)
{
p1.y += (clip_rect.xmin - p1.x)*m;
p1.x = clip_rect.xmin;
}
else if (code1&winRightBitCode)
{
p1.y += (clip_rect.xmax - p1.x)*m;
p1.x = clip_rect.xmax;
}
else if (code1&winBottomBitCode)
{
if (p2.x != p1.x)
p1.x += (clip_rect.ymin - p1.y) / m;
p1.y = clip_rect.ymin;
}
else if (code1&winTopBitCode)
{
if (p2.x != p1.x)
p1.x += (clip_rect.ymax - p1.y) / m;
p1.y = clip_rect.ymax;
}
}
}
if (plotLine)
{
q1->x = roundx(p1.x);
q1->y = roundx(p1.y);
q2->x = roundx(p2.x);
q2->y = roundx(p2.y);
}
//printf("%f-%f-%f-%f\n", p1.x, p1.y, p2.x, p2.y);
return (bool)plotLine;
}
//Translate the clip rectangle
void Translaterect(int dx, int dy)
{
// Write your code here
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( )
{
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(0.0, 0.0, 0.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:
// Write your code here
Translaterect(-5.0, 0.0);
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
// Write your code here
Translaterect(5.0, 0.0);
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
// Write your code here
Translaterect(0.0, -5.0);
glutPostRedisplay();
break;
case GLUT_KEY_UP:
// Write your code here
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 Clipping and Viewing");
init();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special_key);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}