写在前面
本人刚开始学习计算机图形学小白一枚,最近刚学了梁永栋先生的经典裁剪算法,故写一篇笔记总结一下该算法,篇中如有错误之处,敬请各位指正。
基本思想
将裁剪线段及裁剪窗口均看作点集,裁剪结果即为两点集的交集,那么算法就应该从如何求交集出发。在图例中,从uB, uL和P0三点中找出最靠近P1的点P0(即求入边的终点,入边的点集的△x均大于0),然后再从uT, uR和P1中找出最靠近P0的点: uT(即求出边的起点,出边的点集的△x均小于0),最终将求出的P0,uT的u带入参数方程,就得到了P0、uT两点的坐标值,裁剪结果为线段P0 uT。
具体步骤
● 给定参数方程P0P1 : P= P0 +u*(P1 – P0),x=x0+u△x,y=y0+u△y,△x=x1-x0 ,△y=y1-y0,设直线与裁剪窗口的4个交点为B点、L点、T点、R点。
令:
QL= -△x DL= x0-xL QR= △x DR= xR-x0
QB= -△y DB= y0-yB QT = △y DT= yT -y0
并计算参数: ui= Di / Qi (i=L,R,B,T)
● 确定始参us与终参ue : 当Qi <0时,ui为始参us;当Qi >0时,ui为终参ue;当Qi =0时,若Di <0 ,该线段不可见,舍弃该线段并结束;若Di >0 , 分析另一点的Di值。
● 最后确定交集:us=max(usx,usy,0), ue=min(uex,uey,1),若us<=ue,则裁剪结果为区间[us, ue],显示裁剪结果线段,否则结果为空集,则舍弃线段并结束。
图例
给定图例:
Qi =0 ,Di >0时的一种情况:
C++代码实现
#include <GL/glut.h>
#include <iostream>
/* 初始化显示窗口大小 */
GLsizei winWidth = 400, winHeight = 400;
class wcPt2D {
private:
GLfloat x, y;
public:
wcPt2D() {
x = y = 0;
}
wcPt2D(double xd,double yd) {
x = xd;
y = yd;
}
void setCoords(GLfloat xCoord, GLfloat yCoord) {
x = xCoord;
y = yCoord;
}
GLfloat getx()const {
return x;
}
GLfloat gety()const {
return y;
}
};
inline GLint rounds(const GLfloat a) {
return GLint(a + 0.5);
}
void init() {
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵
gluOrtho2D(-200.0, 200.0, -200.0, 200.0);
}
/*根据p、q来判断是舍弃线段还是改变交点的参数*/
GLint clipTest(GLfloat p, GLfloat q, GLfloat *u1, GLfloat *u2) {
GLfloat r;
GLint returnValue = true;
if (p < 0.0) {
r = q / p;
if (r > *u2)
returnValue = false;
else if (r > *u1)
*u1