[图形学] 习题8.6 线段旋转后使用Cohen-Sutherland算法裁剪

时间:2022-09-27 09:26:24

习题8.6 生成一条比观察窗口对角线还长的线段动画,线段重点位于观察窗口中心,每一帧的线段在上一帧基础上顺时针旋转一点,旋转后用Cohen-Sutherland线段裁剪算法进行裁剪。

步骤:

  • 1 视口范围:(-100, -100)到(100, 100);
  • 2 裁剪窗口区域:winMin(-50, -50) 到 winMax(50, 50),原始端点:p0(-100, 0)到 p1(100, 0)
  • 3 使用Bresenham算法画原始线段,使用Cohen-Sutherland算法画裁剪线段;
  • 4 theta += delta,其中 theta为累计旋转角度,delta为每次变化的角度;
  • 5 计算旋转后的新的原始线段端点:p0'和p1'。x' = x * cos(theta) - y * sin(theta), y' = x * sin(theta) +y * cos(theta);
  • 6 每帧重复步骤3-5.
 #include <GLUT/GLUT.h>
#include <math.h>
#include <iostream>
#include "linebres.h"
#include "linecohsuth.h" const GLdouble PI = 3.1416;
GLdouble theta = 0.0;
const GLdouble delta = - PI / ; void init (void)
{
glClearColor(0.0, 0.0, 0.0, 1.0); glMatrixMode(GL_PROJECTION);
gluOrtho2D(-, , -, ); glMatrixMode(GL_MODELVIEW);
} void clippingWindow (void)
{
glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_LOOP);
glVertex2i(-, -);
glVertex2i(-, );
glVertex2i(, );
glVertex2i(, -);
glEnd();
} void displayFcn (void)
{
glClear(GL_COLOR_BUFFER_BIT); clippingWindow(); glColor3f(1.0, 1.0, 1.0); wcPt2D winMin, winMax;
winMin.setCoords(-, -);
winMax.setCoords(, ); wcPt2D p0, p1;
p0.setCoords(-, );
p1.setCoords(, ); wcPt2D p00, p01;
p00.setCoords(p0.getx() * cos(theta) - p0.gety() * sin(theta), p0.getx() * sin(theta) + p0.gety() * cos(theta));
p01.setCoords(p1.getx() * cos(theta) - p1.gety() * sin(theta), p1.getx() * sin(theta) + p1.gety() * cos(theta)); // std::cout << "p00 : " << p00.getx() << "," << p00.gety() << std::endl;
// std::cout << "p01 : " << p01.getx() << "," << p01.gety() << std::endl; glColor3f(1.0, 1.0, 0.0);
lineBres(round(p00.getx()), round(p00.gety()), round(p01.getx()), round(p01.gety()));
glColor3f(0.0, 1.0, 1.0);
lineClipCohSuth(winMin, winMax, p00, p01); glutSwapBuffers();
} void idleFcn (void)
{
theta += delta;
displayFcn();
} int main(int argc, char * argv[]) { glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowPosition(-, );
glutInitWindowSize(, );
glutCreateWindow("Exercise 8.6"); init();
glutDisplayFunc(displayFcn);
glutIdleFunc(idleFcn); glutMainLoop(); return ;
}

  因为theta一直在变化,每次重新计算cos(theta)和sin(theta)会影响效率,因此p0和p1每次更新为旋转后的坐标,修改代码如下:

 #include <GLUT/GLUT.h>
#include <math.h>
#include <iostream>
#include "linebres.h"
#include "linecohsuth.h" const GLdouble PI = 3.1416;
const GLdouble delta = - PI / ;
GLint initialized = ;
GLdouble cosDelta, sinDelta;
wcPt2D p0, p1, winMin, winMax; void init (void)
{
glClearColor(0.0, 0.0, 0.0, 1.0); glMatrixMode(GL_PROJECTION);
gluOrtho2D(-, , -, ); glMatrixMode(GL_MODELVIEW);
} void clippingWindow (void)
{
glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_LOOP);
glVertex2i(-, -);
glVertex2i(-, );
glVertex2i(, );
glVertex2i(, -);
glEnd();
} void displayFcn (void)
{
glClear(GL_COLOR_BUFFER_BIT); clippingWindow(); glColor3f(1.0, 1.0, 1.0); if(!initialized)
{
initialized = ;
cosDelta = cos(delta);
sinDelta = sin(delta);
winMin.setCoords(-, -);
winMax.setCoords(, );
p0.setCoords(-, );
p1.setCoords(, );
} p0.setCoords(p0.getx() * cosDelta - p0.gety() * sinDelta, p0.getx() * sinDelta + p0.gety() * cosDelta);
p1.setCoords(p1.getx() * cosDelta - p1.gety() * sinDelta, p1.getx() * sinDelta + p1.gety() * cosDelta); glColor3f(1.0, 1.0, 0.0);
lineBres(round(p0.getx()), round(p0.gety()), round(p1.getx()), round(p1.gety()));
glColor3f(0.0, 1.0, 1.0);
lineClipCohSuth(winMin, winMax, p0, p1); glutSwapBuffers();
} int main(int argc, char * argv[]) { glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowPosition(-, );
glutInitWindowSize(, );
glutCreateWindow("Exercise 8.6"); init();
glutDisplayFunc(displayFcn);
glutIdleFunc(displayFcn); glutMainLoop(); return ;
}

  本来想使用glRotatef(delta, 0.0, 0.0, 1.0)这个转换矩阵进行旋转,但使用C-S裁剪算法时传入的端点坐标依然不是旋转后的,先裁剪后旋转导致裁剪区域不对。不知道是否可以用glRotatef来解答这道题目。

commit: 6ee4159541b305fadd2bf88b1dbd950558e12e8e 

[图形学] 习题8.6 线段旋转后使用Cohen-Sutherland算法裁剪