龙空技术网

c语言课程设计——Cyrus-Beck算法课程设计及源码

云炬网络 323

前言:

现在咱们对“c语言程序设计报告参考文献”都比较着重,兄弟们都需要学习一些“c语言程序设计报告参考文献”的相关文章。那么小编同时在网络上网罗了一些关于“c语言程序设计报告参考文献””的相关知识,希望大家能喜欢,看官们快快来了解一下吧!

课程名称: 计算机技术综合课程设计

题 目: 参数裁剪算法Cyrus-Beck的C语言实现

学 院: 信息工程 系: 计算机

专 业: 计算机科学与技术

班 级:

学 号:

学生姓名:

时 间:

目 录

第一章问题描述1

第二章 系统分析设计与实现2

2.1算法分析2

2.2程序算法描述4

2.3程序总结 5

2.4程序流程图6

2.5 程序模块和模块代码.........................................................................................................7

第三章 系统运行结果分析 14

第四章 总结15

第五章 主要参考资料16

附录1

7

问题描述

《计算机图形学》是一门实践性较强的计算机应用类课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。本课程设计的目的就是要达到理论与实际应用相结合,使同学们能够根据图形学算法的特性,学会具体实现它们的方法,加深对课程基本内容的理解。同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。

本课程设计是运用计算机图形学的技术与理论,设计参数裁剪算法Cyrus-Beck的程序,设计友好的GUI界面,要求达到windows绘图软件的基本功能,运用计算机图形学理论与技术设计程序, 每人一个题目,独立完成设计并撰写设计报告. 程序设计语言推荐使用C/C++,程序书写规范,源程序需加必要的注释; 每位同学需提交可独立运行的程序。

系统分析设计与实现

2.1算法分析:

图1 不规则多边形的裁剪

考虑如图1所示的一个凸多边形区域R和一条线段P1P2,要求计算线段在区域R中的部分。假定A是区域R边界L上一点。N区域边界在A点的内法向量。

线段P1P2用参数方程表示:

P( t)=(P2-P1)t+P1 (0=<t=<1) (1)

对于线段上任意一点P(t),P(t)和多边形边界L的关系有三种可能(此处t为一定值):

N*(P(t)-A)>0,则P(t)在L内侧。N*(P(t)-A)=0.则P(t)在L内侧。N*(P(t)-A)<0.则P(t)在L内侧。

由性质(1)知,P(t)在凸多边形内的充要条件是,对于凸多边形边界上任意一点A和该处内法向量N,都有N*(P(t)-A)>0。

先假设多边形有k条边,在每条边上取1个点Ai和该点处的内法向量Ni(i=1,2....,k),则可见线段的参数区间为下列不等式组的解Ni*(P(t)-Ai)>=0,0=<t=<1 (i=1,2,....,k) (2)

解的最小值ts和最大值te分别对应于可见线段的端点。

把式P(t)=(P2-P1)t+P1 (1)代人式(2),整理得

Ni*(P1-Ai)+Ni*(P2-P1)t>=0,0=<t=<1 (3)

若对于某个i,有Ni(P2-P1)=0,这时,Ni(P2-P1),P1P2与对应边平行,如图所示。这时有两种情况:线段在区域外侧或内侧。前一种情况对应于Ni(P1-Ai)<0可直接判断线段在多边形之外后一种情况对应于Ni(P1-Ai)>=0则不于考虑,继续处理其他边。

Ni(P1-Ai)+(P2-P1)t>=0, 0=<t=<1 (3)

注意到Ni(P2-P1)的正负性,所以式(3)等价于

Ni(P1-Ai)>0,t>=-ti

Ni(P2-P1)<0,t=<ti (4)

这里ti=Ni(P1-Ai)/Ni(P2-P1),是线段与第i条边(或延长线)的交点参数

显然,式(4)的解的最小值与最大值为

若ts=<te,则ts和te是可见线段的端点参数,否则整条线段在区域外部。

上式解的几何意义很明显。Ni(P2-P1)把ti分为两组:

起点组和终点组。

终点组以Ni(P2-P1)<0为特征,表示在该处沿P1P2方向前进进入多边形外侧起点组以Ni(P2-P1)>0为特征,表示在该外沿P1P2方向前进将进入多边形内侧的级联。

2.2算法程序描述:

成员函数CBClip()为这个程序的核心裁剪算法。这个算法就是Cyrus-Beck参数裁剪算法。该算法中t=number/den可用来计算直线段与窗口各边的t值。若所得t值位于0=<t=<1之外则可抛弃。虽然直线段与凸窗口最多交于两点,对应两个t值,但由t=number/den可以算出几个位于0=<t=<1范围之内的t值,每一个t值对应于窗口中不平行于线段的一条边。这些t值可分为两组,一组下限组,分布于线段起始点一侧,另一组为上限组,分布于线段的终点一侧。现需找出下限组中最大t值和上限组中最小t值。若den<0,则所求出t值靠近线段中最小t值。若den>0.则所得t值靠近线段的终点,属于上限组。再求出t值的上下限后可求出交点,从而裁剪。

算法程序的前部分是定义坐标点的数据结构(函数struct GLintPoint,struct GLfloatPoint,GLintPointArray,GLfloatPointArray)。然后是一些图形接口函数(drawDot(),drawIntPolygon(),drawFloatPolygon())。

接着是我配置图形参数的函数myInit()。然后是将图形接口中的数据读入主算法的函数(buildintPolygon(),buildfloatPolygon(),floatDotProduct(),

CalcNormals())。在myDisplay()函数中封装了之前写好的算法函数,数据结构,图形接口函数。最后主函数对函数进行调用,绘图。

2.3总结如下:

.开发技术确定:更具自己所学知识,决定用 C++ 来开发本项目。需要 软件有Microsoft visualstudio 2008。实现论证:由于使用的软件工具大部分是大学期间所学知识,所以在此部分不存在疑问。

(c).系统功能确定:对图形的剪裁功能。

(d).分析结果: 经过上诉分析此设计可立即执行。

2.4程序流程图

变量初始化

t1 0

t2 1

i 1

P*num 裁剪区域的边数

den=0

den=0

den=0

是 简单抛弃

t=number/den

den<0

den<0

是 否

t<0

t<0

t<0

找上限 否

是 否

t1 max(t.t1)

t2 min(t.t2)

i i+1

i>P*num

退出,不可见线段

正常退出

t1>t2

画从P(t1)到P(t2)线段

图2 算法的程序流程图

2.5程序模块和模块代码:

a.数据结构模块

struct GLintPoint

{ GLint x,y;

};//每个点的信息由横坐标x与纵坐标y组成

struct GLfloatPoint

{ GLfloat x,y;

};//每个点的信息由横坐标x与纵坐标y组成

const int MAX = 100;

class GLintPointArray

{

public:

int num;

GLintPoint pt[MAX];

};

class GLfloatPointArray

{

public:

int num;

GLfloatPoint pt[MAX];

};

b.图形接口模块

typedef GLfloat colorType[3];

void drawDot (GLint x, GLint y, GLfloat r, GLfloat g, GLfloat b)

{ glColor3f(r,g,b);

glBegin (GL_POINTS);

glVertex2i (x,y);

glEnd();

}

void drawIntPolygon (GLintPointArray P, colorType c)

{ glColor3fv (c);

glBegin(GL_LINE_LOOP);

for (int i=0;i<P.num;i++)

glVertex2i (P.pt[i].x,P.pt[i].y);

glEnd();

}//画多边形(画多边形,多边形的顶点坐标均为整型)

void drawFloatPolygon (GLfloatPointArray P, colorType c)

{ glColor3fv (c);

glBegin(GL_LINE_LOOP);

for (int i=0; i < P.num; i++)

glVertex2f (P.pt[i].x,P.pt[i].y);

glEnd();

}//画多边形(多边形的顶点坐标为float型)

c.配置图形参数模块

void myInit(void)

{

glClearColor(1.0,1.0,1.0,0.0); // set white background color

glColor3f (0.0f,0.0f,0.0f); //default color

//glPointSize(2.0); // a 'dot' is 4 by 4 pixels

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0, 640.0, 0.0, 480.0);

}

d.把图形中的数据读入核心算法模块

const int MaxN = 100;

typedef GLfloatPoint Normals[MaxN];

void buildintPolygon (GLintPointArray &P)

{ P.num = 4;

P.pt[0].x = 50; P.pt[0].y = 50;

P.pt[1].x = 150; P.pt[1].y = 100;

P.pt[2].x = 100; P.pt[2].y = 300;

P.pt[3].x = 10; P.pt[3].y = 400;

}//读入int型四边形剪裁窗口顶点坐标

void buildfloatPolygon (GLfloatPointArray &P)

{ P.num = 4;

P.pt[0].x = 50; P.pt[0].y = 50;

P.pt[1].x = 150; P.pt[1].y = 100;

P.pt[2].x = 100; P.pt[2].y = 300;

P.pt[3].x = 10; P.pt[3].y = 400;

}//读入float型四边形剪裁窗口顶点坐标

float DotProduct (GLfloatPoint v1, GLfloatPoint v2)

{

return v1.x*v2.x + v1.y*v2.y;

}//进行向量的点乘运算

void CalcNormals (GLfloatPointArray p, Normals & n)

{ int i,j,k;

GLfloatPoint v;

for (i = 0; i < p.num; i++)

{ j = (i+1)%p.num;

k = (i+2)%p.num;

n[i].x = -(p.pt[j].y - p.pt[i].y)/(p.pt[j].x - p.pt[i].x);

n[i].y = 1.0;//pjpi边的法向量(不考虑垂直和平行的情况)

v.x = p.pt[k].x - p.pt[i].x;

v.y = p.pt[k].y - p.pt[i].y;

if (DotProduct (n[i],v) > 0) // inner normal

{ n[i].x *= -1;

n[i].y = -1;

}

}

}//判断凸多边形每条边的外法向量

e.核心算法模块

void CBClip (GLfloatPoint p1, GLfloatPoint p2, Normals n, GLfloatPointArray p,

bool & visible, GLfloatPoint & rp, GLfloatPoint & q)

{ float t1,t2,t,numer,den;

GLfloatPoint dirV,F; // vectors

int i;

t1 = 0.0;

t2 = 1.0;//直线参数方程中参数t的取值范围

// compute the direction vector

dirV.x = p2.x - p1.x;

dirV.y = p2.y - p1.y;//由p1,p2确定直线段的方向向量

visible = true;

i = 0;

while ( (i < p.num) && visible)

{ F.x = p1.x - p.pt[i].x;

F.y = p1.y - p.pt[i].y;

numer = DotProduct (n[i],F);

den = DotProduct (n[i],dirV);//n[i]是边i的内法向量

if (den == 0.0) // Parallel or Point//p1p2平行于边i或p1=p2

{ // parallel - if outside then forget the line; if inside then there

// are no intersections with this side

// but there may be with other edges, so in this case just keep going

if (numer > 0.0)

visible = false; // Parallel and outside or point (p1 == p2) and outside(p1p2平行于边i或p1=p2且一定在边i外,故 落在窗口外,不可见)

}

else

{ t = -(numer/den);//直线段p1p2与边i不平行则必交点,求出焦点的参数t

if (den < 0.0) // entering(直线的方向向量是进入窗口的方向,参数t给t1做为可见部分的端点)

{ if (t <= 1.0)

if (t > t1)

t1 = t;

}

else if ( t >= 0.0) //exiting(直线的方向向量是出窗口的方向,参数t给t2做为可见部分的终点)

{ if (t < t2)

t2 = t;

}

}

i++;

}

if ( t1 <= t2)

{ rp.x = p1.x + t1*dirV.x;

rp.y = p1.y + t1*dirV.y;//(可见部分的起点坐标)

q.x = p1.x + t2*dirV.x;

q.y = p1.y + t2*dirV.y;//(可见部分的终点坐标)

}

else

visible = false;

}//剪裁核心算法

f.演示模块

void myDisplay(void)

{

GLfloatPointArray Poly;

colorType C = {0.0f,1.0f,0.0f};

bool visible;

GLfloatPoint p1 = {40,20},p2 = {200,400},cp1,cp2;//cp1,cp2是裁剪后可见部分的两端点,p1、p2是要剪裁的线段的端点

Normals Nor;

glClear(GL_COLOR_BUFFER_BIT); // clear the screen

// 1. create a polygon

buildfloatPolygon(Poly);//读入多边形的顶点坐标

drawFloatPolygon (Poly,C);//画多边形裁剪窗口

// 2. create intersecting lines

glColor3f (0.0f,0.0f,0.0f);

glBegin(GL_LINES);

glVertex2f (40,20);

glVertex2f (200,400);

glEnd();//画带裁剪的直线

// 3. Clip the line

CalcNormals (Poly,Nor);//求多边形窗口每条边的外法向量

CBClip (p1,p2,Nor,Poly,visible,cp1,cp2);//裁剪

if (visible)

{ glColor3f (1.0f,0.0f,0.0f);

glBegin(GL_LINES);

glVertex2f (cp1.x,cp1.y);

glVertex2f (cp2.x,cp2.y);

glEnd();

}//给可见部分上红色

glFlush();

}

第三章 系统运行结果分析

图3 程序执行结果

图3中的红色部分为上图的的最终裁剪结果程序,运行很正常,达到预期Cyrus-Beck算法的裁剪效果。

总结

本次课程设计是运用图形学理论知识与技术设计Cyrus-Beck算法的C语言实现。通过此次课程设计,温习了放下一段时间的计算机图形学与C++等知识

同时,又为以后更好的学习和工作打下了一定的基础,对以后的工作有所帮助同时也是在这次课程设计中使得我对自己的能力有一定了解,对以后的自己的能力提升作出了一次考验。尤其是关于GUI方面的知识。

第五章 参考文献

孙家广《计算机图形学》,北京,清华大学出版社,1998年(美)David F.Rogers《计算机图形学的算法基础(原书第2版)》

机械工业出版社

附:核心代码

#include <windows.h> // use as needed for your system

#include <gl/Gl.h>

#include "glut.h"

#include <iostream>

//********* Data structure

struct GLintPoint

{ GLint x,y;

};//每个点的信息由横坐标x与纵坐标y组成

struct GLfloatPoint

{ GLfloat x,y;

};//每个点的信息由横坐标x与纵坐标y组成

const int MAX = 100;

class GLintPointArray

{

public:

int num;

GLintPoint pt[MAX];

};

class GLfloatPointArray

{

public:

int num;

GLfloatPoint pt[MAX];

};

//********** Support subprograms

typedef GLfloat colorType[3];

void drawDot (GLint x, GLint y, GLfloat r, GLfloat g, GLfloat b)

{ glColor3f(r,g,b);

glBegin (GL_POINTS);

glVertex2i (x,y);

glEnd();

}

void drawIntPolygon (GLintPointArray P, colorType c)

{ glColor3fv (c);

glBegin(GL_LINE_LOOP);

for (int i=0;i<P.num;i++)

glVertex2i (P.pt[i].x,P.pt[i].y);

glEnd();

}//画多边形(画多边形,多边形的顶点坐标均为整型)

void drawFloatPolygon (GLfloatPointArray P, colorType c)

{ glColor3fv (c);

glBegin(GL_LINE_LOOP);

for (int i=0; i < P.num; i++)

glVertex2f (P.pt[i].x,P.pt[i].y);

glEnd();

}//画多边形(多边形的顶点坐标为float型)

//**************** myInit

void myInit(void)

{

glClearColor(1.0,1.0,1.0,0.0); // set white background color

glColor3f (0.0f,0.0f,0.0f); //default color

//glPointSize(2.0); // a 'dot' is 4 by 4 pixels

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0, 640.0, 0.0, 480.0);

}

//************** drawing subprograms go here

const int MaxN = 100;

typedef GLfloatPoint Normals[MaxN];

void buildintPolygon (GLintPointArray &P)

{ P.num = 4;

P.pt[0].x = 50; P.pt[0].y = 50;

P.pt[1].x = 150; P.pt[1].y = 100;

P.pt[2].x = 100; P.pt[2].y = 300;

P.pt[3].x = 10; P.pt[3].y = 400;

}//读入int型四边形剪裁窗口顶点坐标

void buildfloatPolygon (GLfloatPointArray &P)

{ P.num = 4;

P.pt[0].x = 50; P.pt[0].y = 50;

P.pt[1].x = 150; P.pt[1].y = 100;

P.pt[2].x = 100; P.pt[2].y = 300;

P.pt[3].x = 10; P.pt[3].y = 400;

}//读入float型四边形剪裁窗口顶点坐标

float DotProduct (GLfloatPoint v1, GLfloatPoint v2)

{

return v1.x*v2.x + v1.y*v2.y;

}//进行向量的点乘运算

void CalcNormals (GLfloatPointArray p, Normals & n)

{ int i,j,k;

GLfloatPoint v;

for (i = 0; i < p.num; i++)

{ j = (i+1)%p.num;

k = (i+2)%p.num;

n[i].x = -(p.pt[j].y - p.pt[i].y)/(p.pt[j].x - p.pt[i].x);

n[i].y = 1.0;//pjpi边的法向量(不考虑垂直和平行的情况)

v.x = p.pt[k].x - p.pt[i].x;

v.y = p.pt[k].y - p.pt[i].y;

if (DotProduct (n[i],v) > 0) // inner normal

{ n[i].x *= -1;

n[i].y = -1;

}

}

}//判断凸多边形每条边的外法向量

void CBClip (GLfloatPoint p1, GLfloatPoint p2, Normals n, GLfloatPointArray p,

bool & visible, GLfloatPoint & rp, GLfloatPoint & q)

{ float t1,t2,t,numer,den;

GLfloatPoint dirV,F; // vectors

int i;

t1 = 0.0;

t2 = 1.0;//直线参数方程中参数t的取值范围

// compute the direction vector

dirV.x = p2.x - p1.x;

dirV.y = p2.y - p1.y;//由p1,p2确定直线段的方向向量

visible = true;

i = 0;

while ( (i < p.num) && visible)

{ F.x = p1.x - p.pt[i].x;

F.y = p1.y - p.pt[i].y;

numer = DotProduct (n[i],F);

den = DotProduct (n[i],dirV);//n[i]是边i的内法向量

if (den == 0.0) // Parallel or Point//p1p2平行于边i或p1=p2

{ // parallel - if outside then forget the line; if inside then there

// are no intersections with this side

// but there may be with other edges, so in this case just keep going

if (numer > 0.0)

visible = false; // Parallel and outside or point (p1 == p2) and outside(p1p2平行于边i或p1=p2且一定在边i外,故 落在窗口外,不可见)

}

else

{ t = -(numer/den);//直线段p1p2与边i不平行则必交点,求出焦点的参数t

if (den < 0.0) // entering(直线的方向向量是进入窗口的方向,参数t给t1做为可见部分的端点)

{ if (t <= 1.0)

if (t > t1)

t1 = t;

}

else if ( t >= 0.0) //exiting(直线的方向向量是出窗口的方向,参数t给t2做为可见部分的终点)

{ if (t < t2)

t2 = t;

}

}

i++;

}

if ( t1 <= t2)

{ rp.x = p1.x + t1*dirV.x;

rp.y = p1.y + t1*dirV.y;//(可见部分的起点坐标)

q.x = p1.x + t2*dirV.x;

q.y = p1.y + t2*dirV.y;//(可见部分的终点坐标)

}

else

visible = false;

}//剪裁核心算法

//******************* myDisplay **********************

void myDisplay(void)

{

GLfloatPointArray Poly;

colorType C = {0.0f,1.0f,0.0f};

bool visible;

GLfloatPoint p1 = {40,20},p2 = {200,400},cp1,cp2;//cp1,cp2是裁剪后可见部分的两端点,p1、p2是要剪裁的线段的端点

Normals Nor;

glClear(GL_COLOR_BUFFER_BIT); // clear the screen

// 1. create a polygon

buildfloatPolygon(Poly);//读入多边形的顶点坐标

drawFloatPolygon (Poly,C);//画多边形裁剪窗口

// 2. create intersecting lines

glColor3f (0.0f,0.0f,0.0f);

glBegin(GL_LINES);

glVertex2f (40,20);

glVertex2f (200,400);

glEnd();//画带裁剪的直线

// 3. Clip the line

CalcNormals (Poly,Nor);//求多边形窗口每条边的外法向量

CBClip (p1,p2,Nor,Poly,visible,cp1,cp2);//裁剪

if (visible)

{ glColor3f (1.0f,0.0f,0.0f);

glBegin(GL_LINES);

glVertex2f (cp1.x,cp1.y);

glVertex2f (cp2.x,cp2.y);

glEnd();

}//给可见部分上红色

glFlush();

}

//******************* main **********************

void main(int argc, char** argv)

{

glutInit(&argc, argv); // initialize the toolkit

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // set display mode

glutInitWindowSize(640,480); // set window size

glutInitWindowPosition(100, 150); // set window position on screen

glutCreateWindow("Cyrus Beck Clipping"); // open the screen window

glutDisplayFunc(myDisplay); // register redraw function

myInit();

glutMainLoop(); // go into a perpetual loop

}

标签: #c语言程序设计报告参考文献