Unlimited Faxes, No Fees, Dedicated Phone Number
Curva de Von Koch Por Miguel Lou Moreno
Explicación del método
Partimos de una linea inicial, la cual dividimos en 3 partes iguales. Dejamos las dos partes laterales como están y la central la convertimos en dos segmentos con la longitud de la parte inicial. A partir de ahí repetimos el mismo proceso una y otra vez para cada nuevo segmento como se muestra a continuación:
Imagen extraida de www.matematicas.unal.edu.co
Lo he programado en C++ usando las
librerias de OpenGL para representarlo
GLfloat x;
GLfloat y;
GLfloat z; //La coordenada z no se usa por que estamos en
2D
} punto;
typedef struct { //Para cada segmento
punto p1;
punto p2;
} linea;
Variables globales:
GLfloat lado=6.0f;
//Para la
longitud del lado del triangulo
vector<linea> Segmentos; //En este vector
almacenamos todos los segmentos
bool dir=true;
//Para
indicar en qué dirección realizar los calculos
Metodo para crear el triangulo inicial:
void init(){
linea primera;//La linea con la que trabajaremos
/*Hacemos las lineas siguiendo el sentido contrario al de
las agujas del reloj, ya que afecta a la dirección en la que crece el fractal.*/
primera.p1.x=0.0f;
primera.p1.y=lado*sqrt(3.0f/4.0f);
primera.p1.z=0.0f;
primera.p2.x=-lado/2;
primera.p2.y=0.0f;
primera.p2.z=0.0f;
Segmentos.push_back(primera);
primera.p1.x=-lado/2;
primera.p1.y=0.0f;
primera.p1.z=0.0f;
primera.p2.x=lado/2;
primera.p2.y=0.0f;
primera.p2.z=0.0f;
Segmentos.push_back(primera);
primera.p1.x=lado/2;
primera.p1.y=0.0f;
primera.p1.z=0.0f;
primera.p2.x=0.0f;
primera.p2.y=lado*sqrt(3.0f/4.0f);
primera.p2.z=0.0f;
Segmentos.push_back(primera);
}
Para dibujar un segmento:
glColor3f(0.0f,0.0f,1.0f); //Color azul
glVertex3f(l.p1.x,l.p1.y,l.p1.z);
glColor3f(0.0f,1.0f,0.0f); //Color rojo
glVertex3f(l.p2.x,l.p2.y,l.p2.z);
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth( 1.0f );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Ajustamos la visión
glTranslatef(0.0f,-2.0f,-10.0f);
glBegin(GL_LINES);
for(int i=0;
i<Segmentos.size();i++)
pintar1(Segmentos[i]);
glEnd();
glutSwapBuffers();
glFlush();
}
glutInit(&argc, argv);
glutInitWindowPosition(50,50);
glutInitWindowSize (W_WIDTH, W_HEIGHT);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("Ventana con el Visual C++ y
glut");
//Funcion de dibujo
glutDisplayFunc(Display);
//Manejador de teclado
glutKeyboardFunc(tecla);
//Configuración de la matriz de proyeccion
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5.0f,5.0f,-5.0f,5.0f,-150.0,150.0f);
init(); //Creamos los 3 primeros segmentos
//Lazo principal
glutMainLoop();
return 0;
}
Manejador de teclado:
switch (c) {
case
'+':
hacerMas();
printf("Numero de segmentos: %d\n",Segmentos.size());
break;
case '*':
lado+=1.0;
Segmentos.clear();
init();
break;
case
27: // Se ha pulsado Esc.
exit(0); // Salimos del programa
break;
default:
break;
}
glutPostRedisplay();
}
Método para llevar a cabo la siguiente iteración:
En esta función, lo que hacemos
es recorrer la lista de segmentos existentes, y para cada uno de ellos hayamos los 3
nuevos puntos que harán que de un segmento, pasemos a tener 4 nuevos segmentos con la
forma característica del fractal.
Cada segmento nuevo que obtenemos,
lo almacenamos en una nueva lista de segmentos que al final del método sustituye a la
lista que teníamos anteriormente.
Existe una variable llamada
dir que es un booleano. La he puesto, porque nos permite jugar un poco con la
dirección e que crece nuestro fractal. si hacia fuera o hacia adentro.
//Nuevo vector de segmentos. Será el resultado final del
metodo
vector<linea> aux;
//Vector de 4 segmentos para controlar los 4 nuevos
linea lin[4];
//Todos los puntos del segmento y algunos auxiliares
punto A,B,C,D,E,F,EA,pEA;
//Para el calculo de nuevos puntos
GLfloat modulo,altura;
//Ahora leemos cada linea
for(int j=0;j<Segmentos.size();j++){
linea
leida=Segmentos[j];
/*Al cambiar el orden
de los puntos A y E, cambiamos la
dirección de
crecimiento. Estos dos puntos son los extremos
del segmento
principal.*/
if(dir){
A=leida.p1;
E=leida.p2;
}else{
A=leida.p2;
E=leida.p1;
}
//Calculo los puntos
del segmento leido
EA.x=A.x-E.x;
EA.y=A.y-E.y;
D.x=EA.x/3+E.x;
D.y=EA.y/3+E.y;
B.x=EA.x*2/3+E.x;
B.y=EA.y*2/3+E.y;
pEA.x=-EA.y;
pEA.y=EA.x;
modulo=sqrt(pEA.x*pEA.x+pEA.y*pEA.y);
pEA.x/=modulo;
pEA.y/=modulo;
F.x=(A.x+E.x)/2;
F.y=(A.y+E.y)/2;
modulo=sqrt(EA.x*EA.x+EA.y*EA.y);
altura=(modulo/6)*sqrt(3);
C.x=altura*pEA.x+F.x;
C.y=altura*pEA.y+F.y;
//La z vale 0 porque
estamos en 2D
A.z=0.0f;
B.z=0.0f;
C.z=0.0f;
D.z=0.0f;
E.z=0.0f;
lin[0].p1=A;
lin[0].p2=B;
aux.push_back(lin[0]);
lin[1].p1=B;
lin[1].p2=C;
aux.push_back(lin[1]);
lin[2].p1=C;
lin[2].p2=D;
aux.push_back(lin[2]);
lin[3].p1=D;
lin[3].p2=E;
aux.push_back(lin[3]);
}
Segmentos.clear();
Segmentos=aux;
aux.clear();
}
Jugando con la dirección, podemos
obtener todas las variantes.
Lo que he hecho en la siguiente
imagen es que para cada iteración hacer que crezca en los 2 sentidos, obteniendo el copo
de nieve:
Dejá un comentario, sugerencia u opinión