实验四
1、实验目的和要求
利用OpenGL实现实线,虚线,点划线的绘制,及kock曲线。
2、实验内容
1)用OpenGL程序绘制实现,虚线和点划线
2)用OpenGL程序,分别以直线和正三角形为初始生成员,实现迭代次数在6次以内的kock曲线,要求用键盘交互控制迭代次数。
3、实验步骤
1)相关算法及原理描述
①直线的绘制
在OpenGL中绘制直线通过指定直线段的端点来实现,用glVertex函数指定直线段端点的坐标位置,用glBegin/glEnd函数对
包含一系列的点坐标,并利用符号常量解释这些点构成直线的方式。
②虚线的绘制
绘制虚线需要先调用函数过了Enable(GL_LINE_STIPPLE);打开划线模式。然后,函数glLineStipple将建立用于划线的模式
glLineStipple(Glint factor, GLushort pattern);
③Kock曲线
Kock曲线的初始生成员是一条直线,生成规则是将直线段分为三等分,首尾两段保持不变,中间用两段等长且互成60°角的直线
段代替。这样,直线段被分成四段,每段长度都只有原来的1/3。Kock
曲线的分形维数为D=ln4/ln3≈1.26186
假设原直线的首尾点是P0(x0,y0),P1(x1,y1),则新的四段直线段的五个端点坐标分别为
(x0 , y0) (x0+(x1-x0)/3 , y0+(y1-y0)/3)
((x1+x0)/2±(y0-y1)√3/6 , (y1+y0)/2±(x1-x0)√3/6)
(x0+2(x1-x0)/3 , y0+2(y1-y0)/3) (x1 , y1)
其中,第三个点坐标公式中的正负号表示中间两条心直线段处于元直线段的哪一侧。根据这一规则迭代六次。
2)程序调试、测试与运行结果分析
①直线的绘制结果
②虚线的绘制结果
③Kock曲线绘制结果
4、实验总结
这次是两个实验,先做的是直线、虚线的绘制,这要相对简单的多,直线、虚线的绘制只需要调用相应的函数即可,这个程序和上次的橡皮筋技术很像,只是线的两端点是自己指定的,不需要鼠标或键盘的确定。
而Kock曲线就比较麻烦了,只是知道原理,程序的编写遇到些困难。我觉得其实这和直线的绘制差不多,只是各新端点的坐标不好确定,所以利用了循环语句实现点的坐标的赋予,最终实现了该算法。
这次的实验查了资料,也思考了很多,对直线、虚线、Kock曲线的绘制有了一定的了解与掌握,在下次实验中会继续认真完成的。
5、附录
1)直线的绘制
#include
int winWidth=400,winHeight=300;
void Initial(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
void ChangeSize(int w,int h)
{
winWidth=w; winHeight=h;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight );
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
glBegin(GL_LINES);
glVertex2i(50,50);
glVertex2i(300,250);
glEnd();
glutSwapBuffers();
}
int main(int argc,char*argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB);
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("Paint Line");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize);
Initial();
glutMainLoop();
return 0;
}
2)虚线的绘制
#include
int winWidth=400,winHeight=300;
void Initial(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
void ChangeSize(int w,int h)
{
winWidth=w; winHeight=h;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight );}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex2i(50,50);
glVertex2i(300,250);
glEnd();
glutSwapBuffers();
}
int main(int argc,char*argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB);
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("Paint Line");
glLineWidth(3);
glLineStipple(2,0x0f0f);
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize);
Initial();
glutMainLoop();
return 0;
}
3)Kock曲线
#include
#include
#include
#include
using namespace std;
#define PI 3.1415926
struct Point
{
float x;
float y;
};
int type = 0;
static vector
static int m = 0; //迭代次数
float line = 0.0f ; //线段的总长度
void first_state(vector
{
Point first = {-0.6f,0.0f},end = {0.6f,0.0f};
line = sqrt( pow(first.x - end.x,2) + pow(first.y - end.y,2) );
count.push_back(first);
count.push_back(end);
}
void first_triangle(vector
{
float sqrtThree = sqrt(3.0);
Point first = {0.2*sqrtThree,-0.2},second={-0.2*sqrtThree, -0.2},last={0,0.4};
line = sqrt( pow(first.x - second.x,2) + pow(first.y - second.y,2) );
count.push_back(first);
count.push_back(second);
count.push_back(last);
}
void Draw_pic(vector
分别对两种的情况进行考虑一个是闭合的,一个开放的
{
if(type ==1)
{
glBegin(GL_LINE_STRIP);
for (vector
{
glVertex2f(count[i].x, count[i].y);
}
glEnd();
}
else if(type==2)
{
glBegin(GL_LINE_LOOP);
for (vector
{
glVertex2f(count[i].x, count[i].y);
}
glEnd();
}
}
void Calculate_point(vector
{
vector
float pline = line /(float) pow((float)3,(int)m) ; //pline为三角形的边长,通过3的迭代次数次方来实现的
vector
for ( i= 0; i != (count.size() - 1); i++ )
{
Point p1 , p2 , pmid;
p1.x = count[i].x + (count[i+1].x - count[i].x) / 3;
p1.y = count[i].y + (count[i+1].y - count[i].y) / 3;
p2.x = count[i].x + 2*(count[i+1].x - count[i].x) / 3;
p2.y = count[i].y + 2*(count[i+1].y - count[i].y) / 3;
double alpha = atan((double) (count[i+1].y - count[i].y) / (count[i+1].x - count[i].x) );
if( count[i+1].x - count[i].x <= 0)
{
alpha += PI;
}
pmid.x = p1.x + pline * cos(alpha + PI / 3);
pmid.y = p1.y + pline * sin(alpha + PI / 3);
new_count.push_back(count[i]);
new_count.push_back(p1);
new_count.push_back(pmid);
new_count.push_back(p2);
}
new_count.push_back(count[i]);
count.clear();
count = new_count; //之前要清空}
void Calculate_triangle(vector
{
vector
float pline = line /(float) pow((float)3,(int)m) ;//pline为三角形的边长,通过3的迭代次数次方来实现的
vector
int countSize = count.size();
for ( i= 0; i != countSize; i++ )
{
Point p1 , p2 , pmid;
int next = i+1;
if(next >=countSize)
{
next = 0;
}
p1.x = count[i].x +
(count[next].x - count[i].x) / 3;
p1.y = count[i].y + (count[next].y - count[i].y) / 3;
p2.x = count[i].x + 2*(count[next].x - count[i].x) / 3;
p2.y = count[i].y + 2*(count[next].y - count[i].y) / 3;
double alpha = atan((double) (count[next].y - count[i].y) / (count[next].x - count[i].x) );
if( count[next].x - count[i].x <= 0)
{
alpha += PI;
}
pmid.x = p1.x + pline * cos(alpha + PI / 3);
pmid.y = p1.y + pline * sin(alpha + PI / 3);
new_count.push_back(count[i]);
new_count.push_back(p1);
new_count.push_back(pmid);
new_count.push_back(p2) ;
}
//new_count.push_back(count[i]);
count.clear();
count = new_count; //之前要清空}
void myDisplay() //自定义的图形绘制函数
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0.0f, 0.0f, 1.0f);
Draw_pic(count);
glFlush();
}
void SpecialKeys(int key,int x,int y) //键盘响应函数,当为UP的时候重绘和迭代
{
if (key ==GLUT_KEY_UP)
{
m++;
}
if(type == 1)
{
Calculate_point(count);
}
else if(type == 2)
{
Calculate_triangle(count);
}
glutPostRedisplay();
}
void Initial(void) //设定初始的窗口内容色
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void ProcessMenu(int value) //处理相应菜单按钮的函数,设定一个模式值,对效果进行控制
{
type = value;
if(type == 1)
{
line = 0.0f;
m = 0;
count.clear();
first_state(count);
}
else if(type == 2)
{
line = 0.0f;
m = 0;
count.clear();
first_triangle(count);
}
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(400,400);
glutCreateWindow("6次以内的Knock曲线绘制"); //创建菜单并定义菜单回调函数
int nGlutPolyMenu = glutCreateMenu(ProcessMenu);
glutAddMenuEntry("线段",1); //创建GLUT多面体绘制菜单
glutAddMenuEntry("正三角形",2);
int nMainMenu = glutCreateMenu(ProcessMenu); //创建主菜单
glutAddSubMenu("Koch图形制作", nGlutPolyMenu);
glutAttachMenu(GLUT_RIGHT_BUTT ON);
glutDisplayFunc(&myDisplay);
glutSpecialFunc(SpecialKeys);
Initial();
glutMainLoop();
return 0;
}