30.3.15

Avanzando en programación_30.03_

Después de escribir la última entrada de como avanza el programa, me puse a solventar un error que no me gustaba nada, y era que al probar el programa, la pantalla del OpenGL estaba trabada, la intentaba mover y ponía "No responde", y solo cuando realizaba la estrella y tenía que volver a dibujar era cuando se movía al punto que le había indicado antes pero no había hecho.

Este fallo como ya me suponía era por utilizar el comando getch(), ya que ese comando espera a que pulses una tecla para continuar, y mientras se queda en ese punto y no atiende al resto del programa(al menos así es como lo entiendo), así que informé sobre como insertar números y letras con el teclado en opengl y encontré el comando glutKeyboardFunc(teclado), el cual utiliza la tecla presionada en la función teclado, la cual, tras unos cuantos intentos logré que funcionase como el getch() lo hacía.

Y a partir de este momento, para insertar los números lo hay que hacer teniendo la pantalla de opengl seleccionada y no la ventana de comandos.

Ese fue un problema menor comparado con el siguiente, el cual me estuvo rompiendo la cabeza más de dos días.

Resulta que, dado que en un futuro pretendo usar el mismo programa para hacer estrellas de diferente cantidad de puntas, intento usar en el máximo número de casos comandos en los que uso la variable tamanho, que ahora está igualada a 7, con lo cual, si cambiara el 7 por otro número me tendría que realizar estrellas de ese otro número.

El problema surge al intentar que el programa calcule las coordenadas de los vértices, que anteriormente los escribí a mano ayudándome del programa AutoCAD y tenía las siguientes:

#define P1 0,10
#define P2 8,6
#define P3 10,-2
#define P4 4,-9
#define P5 -4,-9
#define P6 -10,-2
#define P7 -8,6

y luego en la función que me dibuja las líneas tenía esto:

          switch(i){
                case 0:
                glBegin(GL_LINES);          //dibujar líneas
                glVertex2i(P1);                    //1er punto
                glVertex2i(P2);                    //2o punto
                glEnd();                              //terminar de dibujar
                break;

                case 1:
                glBegin(GL_LINES);          //dibujar líneas
                glVertex2i(P1);                    //1er punto
                glVertex2i(P3);                    //2o punto
                glEnd();                              //terminar de dibujar
                break;
... (hasta case 21)

La parte de los case no la adapté aún, pero si en parte, ya que ahora es del estilo:
         
 switch(i){
     case 0:
     glBegin(GL_LINES);                              //dibujar líneas
     glVertex2i(puntox[1],puntoy[1]);          //1er punto
     glVertex2i(puntox[2],puntoy[2]);          //2o punto
     glEnd();                                                  //terminar de dibujar     break;

     case 1:
     glBegin(GL_LINES);                              //dibujar líneas
     glVertex2i(puntox[1],puntoy[1]);          //1er punto
     glVertex2i(puntox[3],puntoy[3]);          //2o punto
     glEnd();                                                  //terminar de dibujar
     break;
...(igual hasta case 21)

el cambio está en que usar una variable(mas bien un define) pasé a usar 2 variables(mas bien dos arrays) para los vértices, y esto tuvo que ser así por la manera de calcularlos.



Después de buscar bastante sobre como hacerlo, mirar páginas sobre trigonometría (que a parte de un coseno o seno facilillo no había mirado desde la ESO), hacer mis apuntes en papel, etc... encontré esta pagina:
 http://www.wikivia.org/wikivia/images/3/3b/1.1.2.3._Intersecci%C3%B3n_de_dos_arcos_circulares.pdf

En la cual aparecen las fórmulas para averiguar I1 e I2 a partir de C1 y C2; C1 sería el centro de la estrella y C2 el punto anterior a I2.


Y me puse a ello, usando la librería math.h traducí las fórmulas a C++

int distancia=sqrt(pow(puntox[1]-centrox,2)+pow(puntoy[1]-centroy,2));
int acimut=atan((puntox[1]-centrox)/(puntoy[1]-centroy));
int beta=acos((pow(radio,2)+pow(distancia,2)-pow(radio2,2))/(2*radio*distancia));
puntox[2]=centrox+radio*sin(acimut+beta);
puntoy[2]=centrox+radio*cos(acimut+beta);

Pero no había hecho más que empezar, más tarde me di cuenta de que esos int en realidad debían ser double, y aún más tarde (muuuucho más tarde) me di cuenta de que las funciones de seno, coseno, etc no operan con grados sexagesimales sino con radianes, con lo cual creé otras dos variables para pasar de grados a radianes y viceversa:

    double rad=pi/180;  //pasar de grados a radianes
    double gra=180/pi;  //pasar de radianes a grados

Peeeero (otro pero, siempre hay peros) no tenía el radio 2, es decir, la distancia entre un punto y otro punto, y buscando y buscando encontré la siguiente página:
http://www.aritor.com/trigonometria/triangulo_trigonometria.html

Y así lo traducí a C++:

    double angul = 360/tamanho;
    double angulo=angul*rad;
    double radio2=(radio*sin(angulo/2))*2;

Lo de angul sobra, lo podía poner todo en angulo, pero lo dejé por si lo usaba en otra cosa.

Luego probé que tal funcionaba todo y voilá!! un desastre... NADA TENÍA SENTIDO!!

El proceso para pulir la función puntos fue largo, laborioso y desesperante, aunque también divertido(en parte) e instructivo.

Probando y probando salieron cosas de los más raras en pantalla, aquí algunos ejemplos:

Starmie, eres tú?
El diamante
7 puntas si, pero no en su sitio 
 Estas si que no están en su sitio
WTF!! 
Creo que hay un cubo de rubick muy parecido



Hasta que, después de aparecerme esta estrella con una combinación de lo más simple me paré un poco en ella y observé que la mayoría de las distancias entre puntos son correctas, pero estaban todos agolpados en el primer cuadrante(la imagen está recortada, es de la parte superior derecha de la pantallita), y al observar las coordenadas de los puntos y compararlas con las que tenía fijadas en los define, observé que la diferencia era muy pequeña, pero el punto 4, el maldito punto 4.... siempre me torcía los planes (y la estrella), pese a tener mis sospechas no sé porqué siempre a partir del punto 3 todo era muy raro.

En este caso la coordenada de la Y estaba cambiada de signo ( y algo variada si, lo sé), con lo cual, y tomando medidas drásticas que no creo que funcionen para una estrella de otro tamaño, decidí multiplicar la Y del punto 4 por -1, y hacer un espejo con los restantes puntos.

De modo que igualé los valores en Y del punto 2 y el 7, del 3 y el 6 y del 4 y el 5, y los valores en X los igualé pero multiplicándolos por -1, es decir, cambiándoles el signo, con lo cual la simetría estaba asegurada.

Eso es lo que muestra en iniciar, los puntos no están exactamente con las coordenadas perfectas, pero si que muy aproximadas, y ese es el trozo de programa que tantos problemas me dio, espero que al menos ayude a alguien que intente hacer algo parecido.

Aunque ahí lo oculté en la ventana de comandos, debajo de la estrella hice un rectángulo, lo siguiente que intentaré será que muestre ahí los números que voy insertando, así como la estrella al resolverla, e intentaré deshacerme de la ventana de comandos, espero que no sea muy complicado xD



No hay comentarios:

Publicar un comentario