Sutherland-Hodgeman 多边形裁剪的实现。这两个语句的声明顺序给出了正确的输出,反向没有。
int numberOfVertices = 5;
Point pointList[] = { {50,50}, {200,300}, {310,110}, {130,90}, {70,40} };
颠倒声明时出现的确切错误是底部剪裁器产生一组空的顶点,因此剪裁后不显示多边形。
这个错误的原因是什么?
代码:
#include <iostream>
#include <GL/glut.h>
#define MAXVERTICES 10
#define LEFT 0
#define RIGHT 1
#define TOP 2
#define BOTTOM 3
using namespace std;
/* Clipping window */
struct Window {
double xmin;
double xmax;
double ymin;
double ymax;
};
struct Point {
double x;
double y;
};
/* If I interchange these two lines, the code doesn't work. */
/**************/
int numberOfVertices = 5;
Point pointList[] = { {50,50}, {200,300}, {310,110}, {130,90}, {70,40} };
/**************/
const Window w = { 100, 400, 60, 200 };
/* Checks whether a point is inside or outside a window side */
int isInside(Point p, int side) {
switch(side) {
case LEFT:
return p.x >= w.xmin;
case RIGHT:
return p.x <= w.xmax;
case TOP:
return p.y <= w.ymax;
case BOTTOM:
return p.y >= w.ymin;
}
}
/* Calculates intersection of a segment and a window side */
Point intersection(Point p1, Point p2, int side) {
Point temp;
double slope, intercept;
bool infinite;
/* Find slope and intercept of segment, taking care of inf slope */
if(p2.x - p1.x != 0) {
slope = (p2.y - p1.y) / (p2.x - p1.x);
infinite = false;
} else {
infinite = true;
}
intercept = p1.y - p1.x * slope;
/* Calculate intersections */
switch(side) {
case LEFT:
temp.x = w.xmin;
temp.y = temp.x * slope + intercept;
break;
case RIGHT:
temp.x = w.xmax;
temp.y = temp.x * slope + intercept;
break;
case TOP:
temp.y = w.ymax;
temp.x = infinite ? p1.x : (temp.y - intercept) / slope;
break;
case BOTTOM:
temp.y = w.ymin;
temp.x = infinite ? p1.x : (temp.y - intercept) / slope;
break;
}
return temp;
}
/* Clips polygon against a side, updating the point list
(called once for each side) */
void clipAgainstSide(int sideToClip) {
int i, j=0;
Point s,p;
Point outputList[MAXVERTICES];
/* Main algorithm */
s = pointList[numberOfVertices-1];
for(i=0 ; i<numberOfVertices ; i++) {
p = pointList[i];
if(isInside(p, sideToClip)) {
/* p inside */
if(!isInside(s, sideToClip)) {
/* p inside, s outside */
outputList[j] = intersection(p, s, sideToClip);
j++;
}
outputList[j] = p;
j++;
}
else if(isInside(s, sideToClip)) {
/* s inside, p outside */
outputList[j] = intersection(s, p, sideToClip);
j++;
}
s = p;
}
/* Updating number of points and point list */
numberOfVertices = j;
/* ERROR: In last call with BOTTOM argument, numberOfVertices becomes 0 */
/* all earlier 3 calls have correct output */
cout<<numberOfVertices<<endl;
for(i=0 ; i<numberOfVertices ; i++) {
pointList[i] = outputList[i];
}
}
void SutherlandHodgemanPolygonClip() {
clipAgainstSide(LEFT);
clipAgainstSide(RIGHT);
clipAgainstSide(TOP);
clipAgainstSide(BOTTOM);
}
void init() {
glClearColor(1,1,1,0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0,1000,0,500);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
/* Displaying ORIGINAL box and polygon */
glColor3f(0,0,1);
glBegin(GL_LINE_LOOP);
glVertex2i(w.xmin, w.ymin);
glVertex2i(w.xmin, w.ymax);
glVertex2i(w.xmax, w.ymax);
glVertex2i(w.xmax, w.ymin);
glEnd();
glColor3f(1,0,0);
glBegin(GL_LINE_LOOP);
for(int i=0 ; i<numberOfVertices ; i++) {
glVertex2i(pointList[i].x, pointList[i].y);
}
glEnd();
/* Clipping */
SutherlandHodgemanPolygonClip();
/* Displaying CLIPPED box and polygon, 500px right */
glColor3f(0,0,1);
glBegin(GL_LINE_LOOP);
glVertex2i(w.xmin+500, w.ymin);
glVertex2i(w.xmin+500, w.ymax);
glVertex2i(w.xmax+500, w.ymax);
glVertex2i(w.xmax+500, w.ymin);
glEnd();
glColor3f(1,0,0);
glBegin(GL_LINE_LOOP);
for(int i=0 ; i<numberOfVertices ; i++) {
glVertex2i(pointList[i].x+500, pointList[i].y);
}
glEnd();
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(1000,500);
glutCreateWindow("Sutherland-Hodgeman polygon clipping");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}