开发一个图形软件包,具有画直线、曲线、曲面填充、几何变换、裁剪等功能:
(1)bresenham画线模块:
void lineBres(int x0, int y0, int xEnd, int yEnd) {
int dx = fabs( xEnd - x0), dy = fabs( yEnd - y0);
float k = (float)dy / dx;// 斜率的绝对值
if(dx == 0) {
//如果斜率为零,可直接画直线
}
//判断斜率是否为整
if(xEnd > x0 && yEnd > y0 || xEnd < x0 && yEnd < y0) {
//斜率大于0
if(k < 1.0) {
//设定开始点(x, y)和结束的上界xEnd
//设定两个增量 twoDy = 2 * dy, twoDyMinusDx = 2 * ( dy - dx);
//设定初始判定p
while(x < xEnd) {
//x加1
//根据p来绘制(x,y),并计算下一个判定p
}
}
else {
斜率大于0的情况
}
}
else {
//斜率小于0的情况
}
(2)旋转模块:
/*旋转(base_x, base_y)为旋转中心,angle为旋转角度*/
void Rotation(const GLfloat base_x, const GLfloat base_y, const GLdouble angle) {
int i;
wcPoint newPoint;
for(i = 0; i < myImage.len; i++) {
newPoint.x = base_x + (myImage.point[i].x - base_x) * cos(angle) - (myImage.point[i].y - base_y) * sin(angle);
newPoint.y = base_y + (myImage.point[i].x - base_x) * sin(angle) + (myImage.point[i].y - base_y) * cos(angle);
myImage.point[i].x = newPoint.x;
myImage.point[i].y = newPoint.y;
}
}
(3)缩放模块:
/*缩放 (base_x, base_y)为固定点*/
void Scaling(const GLfloat base_x, const GLfloat base_y, const GLfloat Sx, const GLfloat Sy) {
for(int i = 0; i < myImage.len; i++) {
myImage.point[i].x = myImage.point[i].x * Sx + base_x * (1 - Sx);
myImage.point[i].y = myImage.point[i].y * Sy + base_y * (1 - Sy);
}
}
(4)平移模块:
void Translation(const GLfloat direction_x, const GLfloat direction_y) {
for(int i = 0; i < myImage.len; i++) {
myImage.point[i].x = myImage.point[i].x + direction_x;
myImage.point[i].y = myImage.point[i].y + direction_y;
}
}
(5)种子填充模块:
void boundaryFill4(int x, int y, float *fillColor, float *borderColor) {
float interiorColor[3];
getPixel(x, y, interiorColor);
glColor3fv(fillColor);
if(!colorEqual(interiorColor, fillColor) && !colorEqual(interiorColor, borderColor)) {
setPixel(x, y);
boundaryFill4(x + 1, y, fillColor, borderColor);
boundaryFill4(x - 1, y, fillColor, borderColor);
boundaryFill4(x, y + 1, fillColor, borderColor);
boundaryFill4(x, y - 1, fillColor, borderColor);
}
return ;
}
(6)Cohen-Sutherland线段裁剪模块:
void lineClipCohSuth(wcPoint winMin, wcPoint winMax, wcPoint &p1, wcPoint &p2) {
GLubyte code1, code2;
GLint done = false, plotLine = false;
GLfloat m;
while(!done) {
code1 = encode(p1, winMin, winMax);
code2 = encode(p2, winMin, winMax);
if(accept(code1, code2)) {
done = true;
plotLine = true;
}
else
if(reject(code1, code2))
done = true;
else {
if(inside(code1)) {
swapPts(&p1, &p2);
swapCodes(&code1, &code2);
}
if(p2.x != p1.x)
m = (p2.y - p1.y) / (p2.x - p1.x);
if(code1 & winLeftBitCode){
p1.y += (winMin.x - p1.x) * m;
p1.x = winMin.x;
}
else
if(code1 & winRightBitCode){
p1.y += (winMax.x - p1.x) * m;
p1.x = winMax.x;
}else
if(code1 & winBottomBitCode) {
if(p2.x != p1.x)
p1.x += (winMin.y - p1.y) / m;
p1.y = winMin.y;
}else
if(code1 & winTopBitCode) {
if(p2.x != p1.x)
p1.x += (winMax.y - p1.y) / m;
p1.y = winMax.y;
}
}
}
if(plotLine)
glutPostRedisplay();
}
Sutherland-Hodgman多边形裁剪:
wcPoint intersect(wcPoint p1, wcPoint p2, Boundary winEdge, wcPoint wMin, wcPoint wMax) {
wcPoint iPt;
GLfloat m;
if(p1.x != p2.x)
m = (p1.y - p2.y) / (p1.x - p2.x);
switch(winEdge) {
case Left:
iPt.x = wMin.x;
iPt.y = p2.y + (wMin.x - p2.x) * m;
break;
case Right:
iPt.x = wMax.x;
iPt.y = p2.y + (wMax.x - p2.x) * m;
break;
case Bottom:
iPt.y = wMin.y;
if(p1.x != p2.x)
iPt.x = p2.x + (wMin.y - p2.y) / m;
else
iPt.x = p2.x;
break;
case Top:
iPt.y = wMax.y;
if(p1.x != p2.x)
iPt.x = p2.x + (wMax.y - p2.y) / m;
else
iPt.x = p2.x;
break;
}
return iPt;
}
void clipPoint(wcPoint &p, Boundary winEdge, wcPoint wMin, wcPoint wMax,
wcPoint *pOut, int *cnt, wcPoint *first[], wcPoint *s) {
wcPoint iPt;
if(!first[winEdge])
first[winEdge] = &p;
else
if(cross(p, s[winEdge], winEdge, wMin, wMax)) {
iPt = intersect(p, s[winEdge], winEdge, wMin, wMax);
if(winEdge < Top)
clipPoint(iPt, (Boundary)(winEdge + 1), wMin, wMax, pOut, cnt, first, s);
else {
pOut[*cnt] = iPt;
(*cnt)++;
}
}
s[winEdge] = p;
if(inside(p, winEdge, wMin, wMax))
if(winEdge < Top)
clipPoint(p, (Boundary)(winEdge + 1), wMin, wMax, pOut, cnt, first, s);
else {
pOut[*cnt] = p;
(*cnt)++;
}
}
void closeClip(wcPoint wMin, wcPoint wMax,
wcPoint *pOut, int *cnt, wcPoint *first[], wcPoint *s) {
wcPoint pt;
Boundary winEdge;
for(int i = 0; i <= Top; i++) {
winEdge = (Boundary)i;
if(cross(s[winEdge], *first[winEdge], winEdge, wMin, wMax)){
pt = intersect(s[winEdge], *first[winEdge], winEdge, wMin, wMax);
if(winEdge < Top)
clipPoint(pt, (Boundary)(winEdge + 1), wMin, wMax, pOut, cnt, first, s);
else {
pOut[*cnt] = pt;
(*cnt)++;
}
}
}
}
GLint ploygonClipSuthHodg(wcPoint wMin, wcPoint wMax, GLint n, wcPoint *pIn, wcPoint *pOut) {
wcPoint* first[nClip] = {0, 0, 0, 0}, s[nClip];
GLint k, cnt = 0;
for(k = 0; k < n; k++)
clipPoint(pIn[k], Left, wMin, wMax, pOut, &cnt, first, s);
closeClip(wMin, wMax, pOut, &cnt, first, s);
return cnt;
}
(8)Bezier 曲线:
void bezier(wcPoint *ctrlPts, GLint nCtrlPts, GLint nBezCurvePts) {
wcPoint bezCurvePt;
GLfloat u;
GLint *C, k;
C = new GLint[nCtrlPts];
binomialCoeffs(nCtrlPts - 1, C);
for(k = 0; k <= nBezCurvePts; k++) {
u = GLfloat(k) / GLfloat(nBezCurvePts);
computeBezPt(u, &bezCurvePt, nCtrlPts, ctrlPts, C);
plotPoint(bezCurvePt);
}
delete [] C;
}
(9)2次B样条曲线
void BSplint2(wcPoint *ctrlPts, GLint nCtrlPts, GLint nBezCurvePts) {
wcPoint bezCurvePt;
for(int i = 0; i < nCtrlPts - 2; i++) {
for(int j = 0; j < nBezCurvePts; j++) {
float t = (float)j / nBezCurvePts;
float _t = 1.0f - t;
float B0 = _t * _t / 2.0f;
float B1 = (1 + 2 * t - 2 * t * t) / 2.0f ;
float B2 = (t * t) / 2.0f;
bezCurvePt.x = ctrlPts[i].x * B0 + ctrlPts[i + 1].x * B1 + ctrlPts[i + 2].x * B2;
bezCurvePt.y = ctrlPts[i].y * B0 + ctrlPts[i + 1].y * B1 + ctrlPts[i + 2].y * B2;
plotPoint(bezCurvePt);
}
}
}
(10)3次B样条曲线-:
void BSplint3(wcPoint *ctrlPts, GLint nCtrlPts, GLint nBezCurvePts) {
wcPoint bezCurvePt;
for(int i = 0; i < nCtrlPts - 3; i++) {
for(int j = 0; j < nBezCurvePts; j++) {
float t = (float)j / nBezCurvePts;
float _t = 1.0f - t;
float tt = t * t;
float ttt = t * t * t;
float B0 = _t * _t / 6.0f;
float B1 = (3 * ttt - 6 * tt + 4) / 6.0f ;
float B2 = (3 * tt - 3 * ttt + 3 * t + 1) / 6.0f;
float B3 = ttt / 6.0f;
bezCurvePt.x = ctrlPts[i].x * B0 + ctrlPts[i + 1].x * B1 + ctrlPts[i + 2].x * B2 + ctrlPts[i + 3].x * B3;
bezCurvePt.y = ctrlPts[i].y * B0 + ctrlPts[i + 1].y * B1 + ctrlPts[i + 2].y * B2 + ctrlPts[i + 3].y * B3;
plotPoint(bezCurvePt);
}
}
}
(11)主程序模块:
int main(int argc, char **argv) {
GLint colorMenu, rotationMenu, scalingMenu, drawMenu, fillColorMenu, clipMenu, dragPointMenu;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(200, 200);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("graphics");
init();
glutDisplayFunc(displayImage);
glutMouseFunc(mousePtPlot);
glutMotionFunc(mouseDrag);//鼠标按键并移动
//添加各个子菜单
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutReshapeFunc(reshapeFcn);
glutMainLoop();
return 0;
}
五、实验结果及分析