生成Sierpinski 镂垫算法描述:
(1)在三角形内部随机选取一个点作为初始点
(2)在三角形的3个顶点中随机选取一个,求出该顶点与初始点连线的中点,画出该中点
(3)将(2)中的中点作为初始点,转到(2)
下面是OpenGL的具体实现:
#include
#include
#define N 5000
typedef GLfloat point[2];
point vertex[3] = {{5.0,5.0},{50.0,90.0},{95.0,5.0}};
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
int i,j;
point p = {50.0,50.0};
glBegin(GL_POINTS);
for(i = 0 ; i <
N ; ++i)
{
j = rand()%3;
p[0] = (p[0] + vertex[j][0]) / 2;
p[1] = (p[1] + vertex[j][1]) / 2;
glVertex2fv(p);
}
glEnd();
glFlush();
}
void myinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(0,1.0,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,100.0,0,100.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(500,500);
glutCreateWindow("Sierpinsk 镂垫");
glutDisplayFunc(display);
myinit();
glutMainLoop();
return
0;
}
运行程序,可得Sierpinski 镂垫,如下:
可见,在次数N较大时,它并没表现出随机性;分析最原始的三角形,连结三边的中点,将原三角形分成4个小三角形,无论你如何选择初始点,要画出的点都不会出现在中间那个倒立的三角区域中。基于此,可以通过递归的方式生成Sierpinski
镂垫,对于每个三角形,去掉其中间的那个三角形部分。
实现如下:
#include
#include
#define N 5
typedef GLfloat point[2];
point vertex[3] = {{5.0,5.0},{50.0,90.0},{95.0,5.0}};
void draw_triangle(point v1,point v2,point v3)
{
glBegin(GL_TRIANGLES);
glVertex2fv(v1);
glVertex2fv(v2);
glVertex2fv(v3);
glEnd();
}
void divide_triangle(point v1,point v2,point v3,int n)
{
point p[3];
if(n)
{
for(int i = 0 ; i
< 2 ; ++i)
{
p[0][i] =
(v1[i] + v2[i]) / 2;
p[1][i] =
(v2[i] + v3[i]) / 2;
p[2][i] =
(v3[i] + v1[i]) / 2;
}
divide_triangle(p[0],v2,p[1],n-1);
divide_triangle(p[0],v1,p[2],n-1);
divide_triangle(p[1],v3,p[2],n-1);
}
else
draw_triangle(v1,v2,v3);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(vertex[0],vertex[1],vertex[2],N);
glFlush();
}
void myinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(0,1.0,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,100.0,0,100.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(500,500);
glutCreateWindow("Sierpinsk 镂垫");
glutDisplayFunc(display);
myinit();
glutMainLoop();
return
0;
}
下面将这个2维的Sierpinski 镂垫转换为3维的Sierpinski
镂垫,上面的两种方式均可以完成转换,这里采用递归的方式,实现如下:
#include
#define N 4
typedef float point[3];
point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405,
-0.333333}};
void triangle( point a, point b, point c)
{
glBegin(GL_TRIANGLES);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd();
}
void divide_triangle(point a, point b, point c, int m)
{
point
v[3];
if(m)
{
for(int j=0; j<3; j++)
{
v[0][j]=(a[j]+b[j])/2;
v[1][j]=(a[j]+c[j])/2;
v[2][j]=(b[j]+c[j])/2;
}
divide_triangle(a, v[0], v[1], m-1);
divide_triangle(c, v[1], v[2], m-1);
divide_triangle(b, v[2], v[0], m-1);
}
else
triangle(a,b,c);
}
void tetrahedron(int m)
{
glColor3f(1.0,0.0,0.0);
divide_triangle(v[0], v[1], v[2], m);
glColor3f(0.0,1.0,0.0);
divide_triangle(v[3], v[2], v[1], m);
glColor3f(0.0,0.0,1.0);
divide_triangle(v[0], v[3], v[1], m);
glColor3f(0.0,0.0,0.0);
divide_triangle(v[0], v[2], v[3], m);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
tetrahedron(N);
glFlush();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w
<= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
void myinit()
{
glEnable(GL_DEPTH_TEST);
glClearColor
(1.0, 1.0, 1.0, 1.0);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Sierpinski 镂垫");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
myinit();
glutMainLoop();
}
运行结果如下: