2013-10-02 19 views
9

Quindi sto programmando un programma ricorsivo che dovrebbe disegnare il fiocco di neve di Koch usando OpenGL, e ho il programma fondamentalmente funzionante tranne un piccolo problema. Più profonda è la ricorsione, più 2 sono i particolari più strani. Immagini in basso.Piccolo bug in Koch's Snowflake Implementazione

EDIT: Non mi interessa davvero l'aspetto OpenGL, ho questa parte in basso. Se non conosci OpenGL, tutto ciò che fa glVertex è tracciare una linea tra i due vertici specificati nelle 2 chiamate di metodo. Fingere il suo drawLine (v1, v2). Stessa differenza.

Sospetto che il mio metodo per la ricerca di punti sia da incolpare, ma non riesco a trovare nulla che non sia corretto.

Sto seguendo il metodo di disegno sostanzialmente normale, qui il codice relativo tagli

(V è per vertice V1 è il basso a sinistra, v2 è basso a destra, v3 è l'angolo superiore):

 double dir = Math.PI; 
     recurse(V2,V1,n); 

     dir=Math.PI/3; 
     recurse(V1,V3,n); 

     dir= (5./3.)* Math.PI ; 
     recurse(V3,V2,n); 

metodo ricorsivo:

public void recurse(Point2D v1, Point2D v2, int n){ 
    double newLength = v1.distance(v2)/3.; 
    if(n == 0){ 
     gl.glVertex2d(v1.getX(),v1.getY()); 
     gl.glVertex2d(v2.getX(),v2.getY()); 

    }else{ 

     Point2D p1 = getPointViaRotation(v1, dir, newLength); 
     recurse(v1,p1,n-1); 
     dir+=(Math.PI/3.); 

     Point2D p2 = getPointViaRotation(p1,dir,newLength); 
     recurse(p1,p2,n-1); 
     dir-=(Math.PI*(2./3.)); 

     Point2D p3 = getPointViaRotation(p2, dir, newLength); 
     recurse(p2,p3,n-1); 
     dir+=(Math.PI/3.); 

     recurse(p3,v2,n-1); 
    } 

} 

ho davvero il sospetto che la mia matematica è il problema, ma questo sembra corretto a me:

public static Point2D getPointViaRotation(Point2D p1, double rotation, double length){ 
    double xLength = length * Math.cos(rotation); 
    double yLength = length * Math.sin(rotation); 
    return new Point2D.Double(xLength + p1.getX(), yLength + p1.getY()); 
} 

N = 0 (Tutto va bene):

enter image description here

N = 1 (Forse un po 'bendy, forse)

enter image description here

N = 5 (WAT)

enter image description here

+0

Senza conoscere l'algoritmo: potrebbe trattarsi di un problema di precisione "doppio". –

risposta

1

Quindi, risulta che sono l'uomo più stupido vivo.

Grazie a tutti per aver provato, apprezzo l'aiuto.

Questo codice è pensato per gestire un triangolo equilatero, è molto specifico su questo (si può dire dagli angoli).

Ho inserito un triangolo con l'altezza uguale alla base (non equilatero). Quando ho risolto il triangolo di input, tutto funziona alla grande.

4

Non riesco a vedere alcun problema ovvio in termini di codice. Tuttavia, ho una teoria su cosa succede.

Sembra che tutti i punti nel grafico si basino sulle posizioni dei punti precedenti. In quanto tale, eventuali errori di arrotondamento che si verificano durante questo processo iniziano ad accumularsi, finendo per finire con l'andare in tilt e in via di estinzione.

Quello che farei per gli avviatori è calcolare i punti iniziale e finale di ogni segmento prima di ricorrere, in modo da limitare l'impatto degli errori di arrotondamento delle chiamate interne.

+0

Bene, i punti finali di inizio di un'intera curva sono forniti dall'utente, sono V1, V2, V3 (il triangolo iniziale). È impossibile calcolare i punti interni prima della mano, questo è tutto ciò che fa la ricorsione. –

+0

Modificare il mio suggerimento un po 'ed essere più specifico: il modo in cui lo renderei è dividere questo in "pezzi" da disegnare. Il livello iniziale consiste di tre pezzi, rappresentati come linee se n = 0. Per n> 0, ogni pezzo dovrebbe invece fare quanto segue: Ottenere i punti di inizio A e il punto finale B (presumibilmente passati come parametri). Calcola i punti AB 'e AB' 'per i punti 1/3 e 2/3 del percorso. Definisci A-AB' e AB '' - B come due nuovi pezzi, quindi calcola il punto AB * del "picco" e definire AB'-AB * e AB * -AB '' come nuovi pezzi. Ricorso. Facendolo in questo modo si eviterebbero errori di arrotondamento su larga scala. – Smallhacker

2

Una cosa del fiocco di neve di Koch è che l'algoritmo porterà ad un problema di arrotondamento una volta (è ricorsivo e tutti gli errori di arrotondamento si sommano). Il trucco è, per mantenerlo il più a lungo possibile. Ci sono tre cose che potete fare:

  • Se si desidera ottenere maggiori dettagli, l'unico modo è quello di ampliare le possibilità di Double. Sarà necessario utilizzare il proprio intervallo di coordinate e trasformarle, ogni volta che si dipingerà sullo schermo, per visualizzare le coordinate. Le tue coordinate personali dovrebbero ingrandire e mostrare l'ultimo passo di ricorsione (l'ultimo triangolo) in un sistema di coordinamento di ad es. 100x100. Quindi calcola i tre nuovi triangoli sopra, trasformali in coordinate dello schermo e dipingi.
  • La riga dir=Math.PI/3; divide per 3 anziché (double) 3.Aggiungi . dopo il 3
  • Assicurati di utilizzare Point2D.Double ovunque. Il tuo codice dovrebbe farlo, ma lo scriverei esplicitamente ovunque.

Hai vinto il gioco, quando hai ancora un bel fiocco di neve ma ottieni un Stackoverflow.

+0

Ho dovuto fare questo piccolo scherzo con Stackoverflow. Sono stato costretto dai miei geni ;-) – jboi

+0

Il compilatore convertirà i 3 in 3.0; nessuna azione necessaria. – duffymo

+0

Probabilmente si. queste cose mi fanno sempre innervosire, quando le vedo. Il punto più importante è il primo. – jboi