2011-09-21 9 views
7

EDIT: Non ero sicuro se questa dovrebbe essere una nuova domanda o no, quindi sto aggiornando questo per ora. Il fiocco di neve viene ora generato correttamente, a meno che non cambi le coordinate originali. Ad esempio, se il mio triangolo originale è come l'immagine 1, il risultato dopo 5 iterazioni è immagine 2:Impossibile ruotare il fiocco di neve Koch

enter image description here enter image description here

Tuttavia, se il mio triangolo originale è qualcosa di diverso, ad esempio foto 3, i risultati sono a privilegiare l':

enter image description here enter image description here

ho di nuovo che il problema è con i miei normali, ma sono davvero perso. Ho cercato per ore di capire le formule corrette per farlo, ma non sto facendo alcun progresso. Dato che sembra che molte volte il problema sia rappresentato dall'inversione dei nuovi triangoli, sospetto che atan mi stia dando un valore negativo quando dovrebbe darmi un valore positivo. C'è un modo matematico per aggirare questo? Grazie mille per il vostro aiuto!

Il mio codice (meno le porzioni openGL perché io non credo che siano il problema) è:

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"); 
} 

Attualmente sto cercando di implementare la curva di Koch in C++. Ho quasi funzionato correttamente. Ci sono fondamentalmente tre diversi casi che sto affrontando: il segmento di linea che ho bisogno di suddividere in quattro segmenti è orizzontale, verticale o altro.

Il problema è che quando il programma calcola quali sono i nuovi vertici per i segmenti di linea, ci sono due possibilità: il triangolo può essere rivolto verso l'alto o il triangolo può essere rivolto verso il basso. Ho cercato di tenerne conto normalizzando i vettori, ma l'ho fatto in modo errato o c'è qualcos'altro di leggermente fuori. Le immagini qui sotto sono due esempi; entrambi hanno 3 iterazioni del frattale.

Il codice per suddividere un segmento di linea non orizzontale e non verticale è inferiore, poiché i triangoli sembrano faccia nel modo giusto per segmenti orizzontali verticali /:

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 e b sono i vettori del segmento. NormalX e normalY sono:

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

Qualche idea di cosa posso fare per risolvere questo problema?

+0

Cosa sono qui 'a' e 'b'? Sarebbe più facile se pubblicassi più codice. – sinelaw

+0

GLfloat normalX ((b.x - a.x)/deltaX); GLfloat normalY ((b.y - a.y)/deltaY); dovrebbe essere GLfloat normalX ((b.x - a.x)/distance); GLfloat normalY ((b.y - a.y)/distance); - i tuoi valori saranno tutti +1 o -1 –

risposta

11

Il tuo problema è probabilmente atan(theta). Il dominio è troppo piccolo per essere utilizzato per la determinazione dell'angolo generico. Si dovrebbe invece usare 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)); 

(. Non ho provato questo codice, quindi ci potrebbero essere alcuni errori di segno)

Per saperne di più: Atan2 (Wikipedia)


EDIT:

La mia ipotesi è che si stanno dando le coordinate nell'ordine sbagliato.Se si pensa a un segmento dalla prospettiva del punto iniziale di fronte al punto finale, la curva verrà sempre estrusa alla propria destra. Se assegni le coordinate nell'ordine opposto, la curva verrà specchiata.

+0

Avevi ragione! Il problema era con l'abbronzatura e ora funziona perfettamente. Grazie mille! –

+0

Questa risposta ha risolto il mio problema originale, ma è sorto un nuovo problema (come descritto nella mia modifica sopra) :( –

+0

Grazie, avevi ragione: è divertente come una cosa così semplice possa causare così tanto angoscia :) –

1

Fornire tutti i vertici iniziali in senso antiorario e dovrebbe funzionare come previsto.