2011-09-21 15 views
7

EDITAR: No estaba seguro de si esta debería ser una pregunta nueva o no, así que solo estoy actualizando esta por el momento. El copo de nieve ahora se está generando correctamente, a menos que cambie las coordenadas originales. Por ejemplo, si mi triángulo original es como la imagen 1, el resultado después de 5 iteraciones es cuadro 2:No se puede rotar el copo de nieve Koch

enter image description here enter image description here

Sin embargo, si mi triángulo original es algo diferente, por ejemplo la imagen 3, los resultados son asimétricos:

enter image description here enter image description here

vuelvo a pensar que el problema es con mis normales pero estoy realmente perdido. He intentado durante horas encontrar las fórmulas correctas para hacer esto, pero realmente no estoy progresando. Como parece que muchas veces el problema es que los triángulos nuevos se invierten, sospecho que atan me está dando un valor negativo cuando debería darme un valor positivo. ¿Hay alguna forma matemática que pueda evitar esto? ¡Muchas gracias por tu ayuda!

Mi código (menos las porciones OpenGL, porque no creo que ellos son el problema) es:

const int NumTimesToSubdivide = 5; 
const int NumSegments = 3072; // 3x4^n lines generated {3, 12, 48, 192, 768, 3072..} 
const int NumVertices = NumSegments * 2; // 2 vertices for each segment 

vec2 arrayA[NumVertices]; 
vec2 arrayB[NumVertices]; 

//---------------------------------------------------------------------------- 
void koch(const vec2 &a, const vec2 &b, vec2 * verts) {   

/* Calculate new segments. 
*   v1  
*   /\ 
*  /\ 
*  / \ 
* a----/  \----b 
*  v0  v2 
*/ 
vec2 v0; 
vec2 v1; 
vec2 v2; 

GLfloat distance(sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y,2))); 
GLfloat deltaX = abs(b.x - a.x); 
GLfloat deltaY = abs(b.y - a.y); 
GLfloat normalX((b.x - a.x)/deltaX); 
GLfloat normalY((b.y - a.y)/deltaY); 
GLfloat theta = atan2(b.y - a.y, b.x - a.x) - M_PI/3.0; 
cout << " theta = " << theta << endl; 

/************************* 
* Find trisection points 
*************************/ 
// horizontal line _____________ 
if(a.y == b.y) { 
    vec2 temp0(a.x + (deltaX * normalX/3) , a.y); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3) , a.y); 
    vec2 temp1((a.x + b.x)/2, a.y + distance * sin(theta)/3); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

//     | 
// vertical line | 
//     | 
else if(a.x == b.x){ 
    vec2 temp0(a.x , (a.y + (deltaY * normalY/3))); 
    vec2 temp2(a.x , (a.y + (deltaY * normalY * 2/3))); 
    vec2 temp1(a.x + distance * cos(theta)/3 , (a.y + b.y)/2); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

// slope != 0 && slope != 1 
else { 
    vec2 temp0(a.x + (deltaX * normalX/3), a.y + (deltaY * normalY/3)); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3), a.y + (deltaY * normalY * 2/3)); 
    // Andrew is the greatest! 
    vec2 temp1(temp0.x + distance * cos(theta)/3, 
       temp0.y + distance * sin(theta)/3);   
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

verts[0] = a; 
verts[1] = v0; 
verts[2] = v0; 
verts[3] = v1; 
verts[4] = v1; 
verts[5] = v2; 
verts[6] = v2; 
verts[7] = b; 

} 

//---------------------------------------------------------------------------- 

void divide_line(const vec2& a, const vec2& b, const vec2& c, int n) 
{ 

// arrayA = {a, b, b, c, c, a} i.e., the sides of the initial triangle 
arrayA[0] = a; 
arrayA[1] = b; 
arrayA[2] = b; 
arrayA[3] = c; 
arrayA[4] = c; 
arrayA[5] = a; 

// If at least one iteration: 
if(n > 0) { 
    // The current iteration, starting with 0 
    int currentIteration = 1; 
    // Do for every iteration from 0 - n: 
    while (currentIteration <= n) { 
     int i; 
     int j = 0; 
     int size = 3 * 2 * (pow(4,currentIteration-1)); 
     // Call koch() for each pair of vertices in arrayA 
     for(i = 0; i < size; i = i+2) { 
      vec2 verts[8]; 
      koch(arrayA[i], arrayA[i+1], verts); 
      // Store each vertex in arrayB 
      int k; 
      for(k = 0; k <= 7; k++) 
       arrayB[j++] = verts[k]; 
     } 
     // Copy arrayB to arrayA for next iteration. 
     size = 3 * 2 * pow(4, currentIteration); 
     for(i = 0; i < NumVertices; i++) { 
      arrayA[i] = arrayB[i]; 
     } 
     // Increase count of currentIteration. 
     currentIteration++; 
    } 
} else 
    printf("The number of iterations must be >= 0.\n"); 
} 

actualmente estoy tratando de poner en práctica la curva de Koch en C++. Lo tengo casi funcionando correctamente. Básicamente, hay tres casos diferentes a los que me estoy refiriendo: el segmento de línea que necesito dividir en cuatro segmentos es horizontal, vertical u otro.

El problema es que cuando el programa calcula qué son los nuevos vértices para los segmentos de línea, hay dos posibilidades: el triángulo puede mirar hacia "arriba" o el triángulo hacia "abajo". Traté de tener esto en cuenta al normalizar los vectores, pero o hice esto incorrectamente o hay algo más levemente apagado. Las imágenes a continuación son dos ejemplos; ambos tienen 3 iteraciones del fractal.

El código para dividir un segmento de línea no horizontal y no vertical está por debajo, ya que los triángulos parecen como la cara de la manera correcta para segmentos horizontales verticales /:

if(a.x == b.x) { 
    ... 
} 
else if (a.y == b.y) { 
    ... 
} 
// slope != 0 && slope != 1 
else { 
    GLfloat deltaX = abs(b.x - a.x); 
    GLfloat deltaY = abs(b.y - a.y); 
    vec2 temp0(a.x + (deltaX * normalX/3), a.y + (deltaY * normalY/3)); 
    vec2 temp2(a.x + (deltaX * normalX * 2/3), a.y + (deltaY * normalY * 2/3)); 
    GLfloat dist(sqrt(pow(temp2.x - temp0.x, 2) + pow(temp2.y - temp0.y,2))); 
    GLfloat theta = (a.x - b.x)/ (b.y - a.y); 
    vec2 temp1((a.x + b.x)/2 + dist * cos(atan(theta)) , 
       (a.y + b.y)/2 + dist * sin(atan(theta))); 
    v0 = temp0; 
    v2 = temp2; 
    v1 = temp1; 
} 

a y b son los vectores del segmento. El normalX y en principio son:

GLfloat normalX((b.x - a.x)/(abs(b.x - a.x))); 
GLfloat normalY((b.y - a.y)/(abs(b.y - a.y))); 

¿Alguna idea de lo que puedo hacer para solucionar este problema?

+0

¿Qué son 'a' y 'b' aquí? Sería más fácil si publicaras más código. – sinelaw

+0

GLfloat normalX ((b.x - a.x)/deltaX); GLfloat normalY ((b.y - a.y)/deltaY); debería ser GLfloat normalX ((b.x - a.x)/distancia); GLfloat normalY ((b.y - a.y)/distancia); - tus valores serán todos +1 o -1 –

Respuesta

11

Tu problema es probablemente atan(theta). Su dominio es demasiado pequeño para ser utilizado para la determinación genérica de ángulos. En su lugar debe usar atan2(y,x):

GLfloat theta = atan2(b.y - a.y, a.x - b.x); 
vec2 temp1((a.x + b.x)/2 + dist * cos(theta) , 
      (a.y + b.y)/2 + dist * sin(theta)); 

(. No he probado este código, por lo que podría haber algunos errores de signos)

Leer más: Atan2 (Wikipedia)


EDIT:

Supongo que está dando las coordenadas en el orden incorrecto.Si piensa en un segmento desde la perspectiva del punto de inicio que enfrenta el punto final, la curva siempre se extruirá a su derecha. Si das las coordenadas en el orden opuesto, la curva se reflejará.

+0

¡Tenías razón! El problema fue con el bronceado y ahora está funcionando perfectamente. Muchas gracias! –

+0

Esta respuesta resolvió mi problema original, pero ha surgido un nuevo problema (como se detalla en mi edición anterior) :( –

+0

¡Gracias! Tenías razón. Es curioso cómo una cosa tan simple puede causar tanto dolor :) –

1

Proporcione todos sus vértices iniciales en el sentido contrario a las agujas del reloj y debería funcionar de la manera que espera.

Cuestiones relacionadas