• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Terrain Modification
 

Terrain Modification

on

  • 541 views

The objective of this project is the extension of the framework WorldWind to allow the user to interact directly with the terrain through a series of specially developed tools.

The objective of this project is the extension of the framework WorldWind to allow the user to interact directly with the terrain through a series of specially developed tools.

Statistics

Views

Total Views
541
Views on SlideShare
536
Embed Views
5

Actions

Likes
0
Downloads
5
Comments
0

1 Embed 5

http://www.graphitech.it 5

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Terrain Modification Terrain Modification Document Transcript

    • Principles of Computer Graphics Raffaele De Amicis, Giuseppe Conti Anno accademico 2008/2009 Terrain Modification Gabriele Seppi 137506 Michele Dalla Torre 121824 Pagina 1/25
    • Indice generale Descrizione ed analisi del problema................................................................................................................................................................3 Presentazione del problema.....................................................................................................................................................................3 Gestione del dettaglio...............................................................................................................................................................................3 Applicazione delle modifiche.....................................................................................................................................................................4 Memorizzazione delle modifiche...............................................................................................................................................................4 Generazione di nuove modifiche...............................................................................................................................................................6 Aggiunta di nuove modifiche.....................................................................................................................................................................9 Gestione asincrona.................................................................................................................................................................................10 Eccezioni all'utilizzo della cache.............................................................................................................................................................12 Generazione della matrice dei tool.........................................................................................................................................................12 Interfaccia grafica..........................................................................................................................................................................................12 Gestione tasti.................................................................................................................................................................................................13 Modalità modifica....................................................................................................................................................................................13 Modalità movimento................................................................................................................................................................................13 Strumenti sviluppati.......................................................................................................................................................................................14 Crater......................................................................................................................................................................................................15 Hollow (circular hole)..............................................................................................................................................................................16 Gaussian hole..........................................................................................................................................................................................17 Plateau (down).......................................................................................................................................................................................18 Circular plateau (down)..........................................................................................................................................................................19 Hill...........................................................................................................................................................................................................20 Gaussian mountain..................................................................................................................................................................................21 Plateau (up)............................................................................................................................................................................................22 Circular plateau (up)...............................................................................................................................................................................23 Noise (random elevation).......................................................................................................................................................................24 Miglioramenti futuri.......................................................................................................................................................................................25 Pagina 2/25
    • Descrizione ed analisi del problema Presentazione del problema Obiettivo di questo progetto è l'ampliamento del framework WorldWind al fine di permettere all'utente di interagire direttamente con il terreno, attraverso una serie di strumenti appositamente sviluppati. In concreto viene data all'utente la possibilità di modificare la morfologia del terreno visualizzato aggiungendo montagne, colline, crateri ed altri tipi di conformazioni intervenendo a piacimento sull'altezza e dimensione di questi strumenti. Gestione del dettaglio L'idea alla base di WorldWind è la suddivisione dell'intero pianeta in un determinato numero di tile, ovvero delle porzioni rettangolari di terreno. L'intero pianeta è composto da 50 tile a livello 0, quello più “esterno”. Più si avvicina la visuale al terreno però, più il numero di tile “virtuali” aumenta: ogni tile al livello x sarà composto da 4 tile posti a scacchiera a livello x + 1. In tal modo, mantenendo lo stesso numero di poligoni per ogni tile è possibile aumentare il dettaglio renderizzando i 4 tile “figli” al posto del padre, ove necessario. Figura 1: Un tile di WorldWind con la densità base. A livello massimo (livello 11), il dettaglio diventa sufficientemente elevato da visualizzare discretamente la morfologia del terreno. Se vogliamo dare la possibilità all'utente di modificare il terreno però, è opportuno riuscire ad incrementare la densità dei tile in cui tali modifiche saranno presenti, in modo da poter aumentare il dettaglio attorno alle features introdotte dall'utente. Ovviamente aumentare la densità di tutti i tile presenti nella visualizzazione comporta un incremento notevole della pesantezza dell'applicazione, sia per quanto riguarda il tempo di rendering (tra l'altro piuttosto costoso già nella versione normale), sia per l'impatto sulla memoria. È importante quindi riuscire ad aumentare la densità in maniera selettiva, ovvero solamente nei tile in cui sono state applicate delle modifiche. Pagina 3/25
    • Figura 2: Lo stesso tile mostrato in figura 1 ma con la densità aumentata in modo da po- ter ospitare le modifiche dell'utente e visualizzarle con maggior dettaglio. Applicazione delle modifiche Per visualizzare le modifiche desiderate dall'utente bisogna pertanto tenere conto sia del fatto che il terreno subirà delle modifiche di al- tezza rispetto all'elevazione base, sia del fatto che vogliamo aumentare il dettaglio dei soli tile interessati. Una possibilità sta nel modificare l'elevation model già presente in WorldWind, facendo in modo che alla richiesta dell'elevazione di un determinato punto si tenga conto anche delle possibili modifiche dell'utente. Quest'approccio ha il principale svantaggio di essere ad un livello piuttosto basso dell'applicazione, e quindi la gestione delle varie opzioni e possibilità di visualizzazione che il software finale potrà avere, tende ad essere parecchio complessa. Un approccio più semplice ed intuitivo sta invece nell'apportare delle modifiche al tessellator, in modo tale che, durante la creazione dei vertici, si tenga conto sia della differente densità dei tile, sia dell'aggiunta o sottrazione di elevazione dovuta alle modifiche dell'utente. Supponendo quindi di conoscere a priori quali saranno i tile che dovranno accettare le modifiche dell'utente possiamo, in fase di crea- zione dei vertici relativi al tile, come prima cosa aumentare la densità (mantenendo sempre una griglia regolare) e poi procedere a set- tare l'altezza di ogni punto, definita come il valore restituito dall'elevation model più (o meno) il valore di differenza rispetto al terreno base, definito dallo strumento utilizzato dall'utente. Si tratta quindi come prima cosa di separare quello che è il terreno base dal “terre- no” costituito dalla differenza di altezza dovuta alle modifiche, ed in seguito di fondere assieme le due cose per ottenere un unico risul- tato. Mantenere le due strutture separate ci permette sicuramente una maggiore flessibilità in quanto possiamo, per esempio, abilitare o disabilitare la visualizzazione delle modifiche a piacere. Memorizzazione delle modifiche Come spiegato nel paragrafo precedente, lo scopo è quello di creare un “terreno” a parte che possa lavorare come maschera di diffe- renza quando viene fatto interagire con il terreno base. La nostra soluzione prevede la creazione di una nuova classe, chiamata Ter- rainModificationInfo (d'ora in avanti TMI), che possa essere istanziata come i singoli tile ed essere associata ad ognuno di essi. Lo sco- po principale di un TMI è mantenere una matrice di punti – relativi ad un singolo tile – che rappresentino proprio la differenza di eleva- zione che stiamo cercando. Inoltre, tenendo conto del fatto che vogliamo aggiungere dettaglio ai tile in cui sono presenti le modifiche, la matrice associata al TMI avrà la densità finale che useremo anche nel tile, ovvero densità base del tile + densità di dettaglio. In tal modo, durante la creazione dei vertici di un tile riusciamo a raggiungere facilmente lo scopo che ci eravamo preposti, ovvero quello di aggiungere dettaglio ai tile sottoposti a modifiche dell'utente ed aggiungere tali modifiche prendendole da una struttura di memorizza- zione separata. Pagina 4/25
    • Abbiamo modificato la funzione del tessellator per la creazione dei vertici in modo tale da tener conto di queste nuove funzionalità: nel caso in cui il TMI associato e, come vedremo in seguito, la matrice di elevazione siano presenti, il tile viene generato con densità mag- giore e all'elevazione in ogni punto viene aggiunto il valore del corrispettivo punto nella matrice del TMI, eccezion fatta per le skirt. In figura 3 possiamo vedere un semplice esempio di applicazione di un TMI ad un tile. La struttura dei TMI ha anche un ulteriore vantaggio: quando un tile trova in memoria il proprio TMI subirà un incremento della densità di dettaglio, se invece in memoria tale TMI non è presente allora il tile manterrà la propria densità di base. Questo ci permette, come era nostra intenzione, di risparmiare risorse di computazione in fase di renderizzazione, aggiungendo dettaglio solo ai tile affetti da modifi- che. In seguito mostreremo come, attraverso un piccolo accorgimento, sarà possibile ottimizzare ulteriormente quest'idea ed evitare che alcuni tile mantengano dettaglio elevato qualora non sia necessario. Figura 3: Applicazione di un generico TMI ad un tile. Il TMI rappresenta la differenza di altezza, rispetto al terreno base, desiderata dal- l'utente (attraverso i tool di modifica). In tal modo per ogni vertice del terreno base possiamo aggiungere il corrispondente vertice del TMI (positivo o negativo a seconda che vogliamo un incremento o una diminuzione di altezza) ed ottenere il risultato voluto. In questa immagine non viene mostrato il fatto che il TMI ha una densità maggiore rispetto al tile associato. Un'ottimizzazione delle risorse utilizzata da WorldWind è la cache: ogni tile (escludendo le texture che sono in una cache a parte) – o, più propriamente, i vertici che lo rappresentano – viene mantenuto in una memoria su disco, in modo da evitare di dover chiedere nuo- vamente attraverso la rete risorse appena scaricate. Questo approccio ha il vantaggio di mantenere in memoria i tile più recentemente o più frequentemente visitati, per ottenere migliori prestazioni. Ovviamente, una volta cancellati dalla cache, questi tile devono nuovamente essere ricreati. Dal momento che un TMI è associato ad un singolo tile, l'idea più immediata è quella di associare un puntatore ad ogni tile in modo che Pagina 5/25
    • punti al proprio TMI associato, se esistente. Il problema di questo approccio, però, sta proprio nel fatto che i tile possono essere cancel- lati dalla memoria, e di conseguenza il TMI associato va a scomparire. Se il tile può essere recuperato dalla rete, però, questo non vale per il TMI, che rappresenta solo delle modifiche a livello di macchina locale. È stato necessario pertanto utilizzare una hashmap che me- morizzasse i TMI associandoli ai tile corretti; si è scelto di mantenere questa hashmap direttamente nella memoria ram per motivi pretta- mente prestazionali, basandosi sulla supposizione che la quantità di modifiche, e di conseguenza di memoria utilizzata, è mediamente abbastanza limitata. La chiave di accesso alla hasmap è la classe TileKey, già presente nel pacchetto base di WorldWind; per semplificare il processo è stato aggiunto alla classe RectTile un metodo che restituisce la relativa TileKey. Generazione di nuove modifiche Finora abbiamo discusso come memorizzare ed applicare delle modifiche al terreno. Ora è necessario analizzare come creare tali modi- fiche e giungere al punto in cui in memoria possiamo trovare una sequenza di TMI da applicare ai relativi tile. Un punto importante da tenere a mente è il fatto che dobbiamo implementare un metodo che sia abbastanza generico da supportare più di un tipo di tool, come anche la possibilità di nuovi tool in futuro. La struttura alla base dei TMI è una semplice matrice di elevazione, di conseguenza possiamo pensare di applicare le modifiche al TMI attraverso un'altra matrice di elevazione. Se pensiamo al TMI come ad un terreno già presente e al tool in uso come ad una matrice di elevazione (una sorta di TMI del TMI), allora possiamo ricondurci all'idea descritta precedentemente per l'applicazione di un singolo TMI al proprio tile. Vediamo però quali sono le differenze. Figura 4: Area comune (gialla) fra matrice del tool (blu) e TMI (verde). I valori presenti nel TMI verrano modificati in base a quelli del tool, ma solo per quanto riguarda la zona di intersezione. Un primo punto da considerare è il fatto che, mentre il TMI corrisponde perfettamente al tile a cui è associato (ovviamente supponendo di aumentare la densità del tile in maniera appropriata), questo non vale necessariamente per la matrice di un tool con un TMI. Dal mo- mento che il punto di applicazione di un tool è a discrezione dell'utente, come anche le dimensioni del tool stesso, è possibile che un TMI sia affetto solo parzialmente dalla matrice del tool. Un altro esempio in cui l'equivalenza perfetta non è presente è quando l'esten- Pagina 6/25
    • sione del tool supera quella del TMI. In figura 4 viene mostrato un esempio di intersezione fra tool e TMI, e qual è la zona interessata dalle modifiche. È stato inoltre deciso di supportare due diversi tipi di applicazione delle modifiche: additivo e sostitutivo. Il primo prevede di aggiungere le nuove modifiche sopra quelle già presenti (esattamente come avviene per l'applicazione dei TMI ai tile), mentre il secondo prevede di sostituire la zona interessata con i nuovi valori specificati. A prima vista quest'ultimo metodo pare non avere una vera e propria utilità. Si pensi però allo strumento Plateau: questo strumento semplicemente alza di un certo valore una porzione rettangolare di terreno; atti- vando la modalità sostitutiva è possibile generare delle zone più grandi delle dimensioni massime del tool in cui il terreno viene alzato di un valore costante ed uniforme, permettendo un'applicazione più semplice e rapida attraverso il dragging. Le figure 5 e 6 mostrano una semplice applicazione dei due metodi (rispettivamente additivo e sostitutivo). Figura 5: Metodo additivo di applicazione di nuove modifiche: ogni punto della matrice del tool rappresenta una differenza di elevazione che verrà aggiunta al rispettivo valore già presente nel TMI. Pagina 7/25
    • Figura 6: Metodo sostitutivo di applicazione di nuove modifiche: ogni punto della matrice del tool rappresenta un valore di elevazione che verrà sostituito al rispettivo valore già presente nel TMI. Un ulteriore problema che si presenta è la gestione dei diversi livelli a cui si trovano i tile. Come prima cosa è importante trovare un me - todo per applicare un tool dal livello 0 al livello massimo (11), mantenendo la stessa zona di applicazione, in modo tale da permettere all'utente di navigare con lo zoom attraverso i diversi livelli di tile senza che ci si accorga di differenze nelle feature introdotte, non con- siderando la riduzione o l'aumento di dettaglio ovviamente. La soluzione a questo problema verrà descritta più avanti, ma in questo pa- ragrafo vediamo come è stata gestita la fase finale di questo processo. Per motivi prestazionali non è conveniente creare più di una matrice per ogni tool (una per livello), ma solo una che venga sfruttata ad ogni livello per l'applicazione delle modifiche. È necessario quindi decidere a quale livello generare la matrice quando l'utente desidera applicare una modifica. Dopo alcune proposte siamo giunti alla conclusione che generare la matrice del tool con precisione pari a quella di un tile a livello massimo e con delle modifiche già presenti (ovvero con la densità maggiorata rispetto al valore iniziale) rappresenta la soluzione migliore. Come primo punto a supporto di questa tesi poniamo il fatto che le modifiche non vengono generalmente introdotte a livello planetario, e quindi è più probabile che si voglia modificare piccole porzioni di terreno al massimo del dettaglio. Come secondo punto possiamo considerare il fatto che la modifica del terreno ad un livello di dettaglio inferiore a quello massimo comporta una perdita (permanente) di informazioni per quanto riguarda la visualizzazione di tile con dettaglio superiore a quello di creazione. Se consideriamo inoltre il fatto che ogni tile (eccetto quelli a livello 11) sono composti da 4 figli posti a scacchiera, diventa semplice re- perire le informazioni da applicare al TMI anche se ci troviamo ad un livello inferiore rispetto a quello rappresentato dalla matrice del tool. Procedendo in modo analogo (per quanto riguarda l'idea) al reperimento dell'elevazione del terreno nella versione base di World- Wind, è sufficiente “saltare” un determinato numero di punti nella matrice del tool pari a 2 (differenza di livello) per ogni punto del TMI in esame. Pagina 8/25
    • Per esempio, se la matrice del tool è a livello 11 ed il TMI a livello 9, la differenza di livello è pari a 2 e quindi ci troveremo a “saltare” 2 2 = 4 punti della matrice del tool per ognuno del TMI; il punto (0,0) del TMI equivarrà al punto (0,0) della matrice del tool, il punto (0,1) al punto (0,4), il punto (0,2) al punto (0,8) e così via. Un ultimo punto da considerare è l'effetto dell'applicazione di nuove modifiche. È possibile che, applicando nuove modifiche, un punto del TMI torni ad essere 0, ovvero a rappresentare una differenza di elevazione di 0 metri rispetto al terreno di base. Se portiamo que- sto ragionamento anche per tutti gli altri punti dello stesso TMI (fatto assolutamente possibile, soprattutto se si implementano tool del tipo gomma, oppure se si dà la possibilità all'utente di cancellare tutte le modifiche effettuate sino ad ora), è possibile che un TMI si trovi ad avere una matrice con tutti i valori pari a 0. Come si era accennato nei precedenti paragrafi, è possibile prendere un piccolo accorgi- mento: al termine dell'applicazione delle modifiche di un tile è opportuno controllare i valori della matrice del TMI. Se tutti i valori sono 0 allora possiamo cancellare l'intera matrice, sia per risparmiare memoria, sia per indicare al tile, in fase di creazione, che non è necessa- rio aggiungere del dettaglio. Riusciamo quindi ad aggiungere dettaglio solo ai tile interessati in ogni istante: se le modifiche non sono più presenti in un tile allora torniamo allo stato precedente in cui il numero di vertici è inferiore. Aggiunta di nuove modifiche Come introdotto nel paragrafo precedente, è stato necessario sviluppare un metodo che permettesse di trasmettere le modifiche gene- rate da un tool attraverso tutti i livelli, da 0 a 11, nei tile affetti da tali modifiche. È inoltre importante considerare che non tutti i livelli, anche se all'interno dell'area del tool, possono subire le modifiche in quanto il dettaglio massimo che possono supportare non è suffi- ciente. Ritorneremo in seguito su questo punto. Una volta generata la matrice del tool (quando l'utente ha cliccato sul punto desiderato) e i valori di latitudine e longitudine minimi e massimi che rappresentano l'area di applicazione del tool, possiamo cominciare a modificare i TMI associati ai vari tile per aggiungere le nuove modifiche come descritto precedentemente. Figura 7: Rappresentazione del metodo ricorsivo di aggiunta delle modifiche: solo i tile che sono all'interno dell'area di modifica del tool subiranno le modifiche. Ogni tile a livello x è composto da 4 tile posti a scacchiera a livello x + 1, ma non è necessariamente vero che ogni tile figlio verrà affetto dal tool. Pagina 9/25
    • Un possibile metodo di applicazione può avvenire durante la fase di renderizzazione, quando il tessellator procede a generare i tile da visualizzare e recuperarne i punti. Questo approccio ha due principali svantaggi. Il primo consiste nella possibile lentezza della renderiz- zazione, dovuta ad un ulteriore carico dato al calcolo delle nuove modifiche (vedremo poi la soluzione adottata per risolvere questo pro- blema). Il secondo, e più problematico, sta nel fatto che si andrebbe a modificare i TMI dei soli tile all'interno del campo visivo, assieme ai padri; i tile figli ed eventuali tile affetti dal tool ma fuori dal campo visivo non subirebbero tali modifiche. L'alternativa implementata prevede invece di distaccarsi dal processo di rendering per l'applicazione delle modifiche. Partendo dai tile di livello 0 possiamo procedere in questo modo: function apply(tile) if (tile = null) return end if if (tile.isAffectedByTool()) tmi ← getTMI() if (tmi = null) tmi ← create TMI tmi.applyModifications() children[] = tile.split() apply(children[0]) apply(children[1]) apply(children[2]) apply(children[3]) end if Una rappresentazione dell'idea è presente in figura 7. Questo approccio ci permette, dal momento che partiamo dal livello 0, ovvero dai 50 tile che coprono l'interno pianeta, di applicare le modifiche a tutti e i soli TMI che verranno affetti dal tool, dal livello 0 al livello 11. Se teniamo in considerazione quanto descritto nel pa- ragrafo precedente riguardo l'applicazione dei valori di elevazione ai punti del TMI in caso di differenza di livello con la matrice del tool, risulta chiaro che i tile a livelli inferiori all'11 (10, 9, 8 e così via) subiranno delle modifiche meno precise, ma comunque equivalenti in dimensione a quelle dei livelli con più dettaglio. Quanto detto fino ad ora non è però sufficiente. Supponiamo che le dimensioni del tool siano più piccole della distanza tra due punti adiacenti in un determinato tile: in questo caso le modifiche non verranno applicate al tile in questione. Questo comportamento è chiara- mente corretto se consideriamo una singola applicazione di un tool, in quanto se ci troviamo in queste condizioni significa che siamo troppo distanti dal terreno perchè le modifiche siano visibili. Dobbiamo però tenere presente che le modifiche sono cumulative. Applican- do due volte lo stesso tool (supponendolo troppo piccolo per la visualizzazione attuale), uno adiacente all'altro, potrebbe accadere che le dimensioni totali siano effettivamente più grandi della distanza fra due punti adiacenti nel tile. Appare chiaro che con l'approccio at- tuale tali modifiche non verranno visualizzate, quando in realtà dovrebbero esserlo. Per risolvere questo problema abbiamo sfruttato i vantaggi dell'approccio ricorsivo: nel caso in cui un TMI non venga aggiornato da un tool troppo piccolo, al ritorno dell'applicazione del tool ai figli siamo sicuri, per ricorsione, che i figli avranno il proprio TMI aggiornato. Di conseguenza possiamo aggiornare il TMI del tile in questione prendendo i valori dei figli e sfruttando la stessa regola del “salto” pre- sentata precedentemente quando si discuteva dell'applicazione della matrice del tool al TMI. Per poter sfruttare in maniera corretta que- sta soluzione, però, è necessario un ulteriore piccolo accorgimento: dal momento che il TMI verrà aggiornato dai 4 TMI figli e che i figli hanno dei lati in comune, è necessario che la dimensione del TMI (più propriamente, il numero di righe e colonne di punti) sia dispari, per tenere conto della riga e della colonna che i figli hanno “in comune”. Possiamo quindi aggiungere il seguente codice al termine della funzione presentata precedentemente: if (tmi.notModified()) childrenTMIs[] ← getChildrenTMIs() tmi.updateFromChildren(childrenTMIs[]) end if Gestione asincrona La soluzione adottata per l'aggiornamento dei TMI, presentata nel paragrafo precedente, ci pone di fronte ad un nuovo problema: come e quando applicare le modifiche? Ovviamente è necessario iniziare non appena il mouse viene cliccato, ma richiamare direttamente la funzione, soprattutto su macchine lente, può rendere l'applicazione non reattiva fino a quando la computazione non è terminata. Sicura- mente questo non è il miglior comportamento che ci si possa aspettare, quindi l'unica alternativa sembra quella di creare un nuovo th- Pagina 10/25
    • read che si prenda l'incarico di applicare le modifiche. Risolto un problema, ecco comparirne un altro: dal momento che i TMI possono aggiornarsi dai figli al ritorno dalla ricorsione (come de- scritto precedentemente), se creiamo un thread separato per ogni tool che deve essere applicato (più precisamente, per ogni click) possono sorgere delle inconsistenze nell'elevazione dei punti, dovute all'accesso concorrente ai TMI. Dobbiamo quindi trovare un metodo che gestisca quest'eventualità. La soluzione implementata prevede l'utilizzo di una coda: ad ogni nuovo click il tool viene aggiunto alla coda. Implementando la coda come un nuovo thread, è possibile lasciare l'applicazione libera di continuare mentre si attende la terminazione dell'applicazione delle modifiche. Ogni modifica viene presa, una alla volta, dalla coda; a questo punto si procede a creare un nuovo thread di modifica che si prenderà cura di compiere le operazioni descritte precedentemen- te. Al termine della computazione si può ricominciare, prelevando un nuovo elemento dalla coda. In figura 8 è mostrata una schematizzazione di questo processo, che permette di applicare una serie di modifiche al terreno senza che ci siano situazioni di inconsistenza ed al tempo stesso lasciando libertà all'utente di continuare la navigazione all'interno del mondo e/o l'applicazione di nuove modifiche. Quando un nuovo elemento viene aggiunto alla coda è sufficiente controllare se il thread sta già lavorando; in caso negativo basta farlo partire e la nuova modifica verrà applicata. Nel caso di macchine più lente, la gestione asincrona ha l'ulteriore vantaggio di mostrare le modifiche già apportate qualora un passag- gio di rendering venga richiesto. Questo è sicuramente un ulteriore fattore che aiuta a rendere l'applicazione più reattiva e con un feed- back più immediato anche dove le limitazioni hardware mettono alla prova le funzionalità. Figura 8: Diagramma di gestione delle modifiche: ogni modifica viene aggiunta alla coda, e solo una alla volta viene applicata, utilizzan- do un nuovo thread per non bloccare l'applicazione. Quando l'applicazione di una modifica termina, si procede con la successiva. Pagina 11/25
    • Eccezioni all'utilizzo della cache È stato necessario prendere alcuni provvedimenti anche per quanto riguarda la fase di renderizzazione che interessa il tessellator. Come introdotto precedentemente, se il tile è già in cache non viene ricreato. Nel nostro caso questo rimane essenziale, ma è necessario ge- stire alcuni casi particolari in cui è comunque necessario ricreare i vertici del tile. Il caso più esemplare accade quando vengono appor - tate delle modifiche al terreno: se il tile è stato creato prima di queste modifiche (e quindi è già in cache) dobbiamo necessariamente ri- crearlo per rispecchiare le modifiche fatte. Inoltre le opzioni che permettono di modificare la visualizzazione (come ad esempio la can- cellazione di tutte modifiche fatte, la possibilità di nascondere le modifiche e lo switch per il wireframe) possono richiedere una nuova creazione dei vertici dei tile, che non possono essere quindi riutilizzati se già presenti in cache. Generazione della matrice dei tool Fino ad ora si è presupposto che la matrice del tool fosse già pronta quando necessaria. È importante però analizzare anche come que- sta viene creata. Ci sono vari aspetti da prendere in considerazione, tra i quali la conversione fra dimensione in metri e dimensione in “numero di punti”. Per semplicità e maggiore intuitività dell'applicazione, si è deciso di dare la possibilità all'utente di specificare le dimensioni dei tool in metri. Questo implica, ovviamente, che è necessario trovare una corrispondenza fra metri e numero di vertici, per lo meno a livello mas- simo, che corrisponde al livello al quale la matrice del tool viene creata. La distanza fra due punti adiacenti, l'unità base che ci interessa, è conosciuta e stabilita dal livello e dalla densità del tile; se quindi sappiamo che la matrice del tool viene creata come i tile a livello 11 e con densità pari a densità base + densità di dettaglio allora conosciamo anche quanti gradi ci sono tra due vertici adiacenti. Il problema che ha posto vari ostacoli sulla nostra strada è stato trovare una conversione tra metri e gradi di latitudine/longitudine, con- siderando il fatto che la terra non è sferica e che, soprattutto, la corrispondenza fra 1° di longitudine e quantità di metri è fortemente dipendente dalla latitudine a cui ci troviamo. Una volta trovata la funzione di conversione, quindi, le operazioni si semplificano notevolmente, in quanto è possibile stabilire in ogni momento la quantità di vertici per dimensione che sono necessari alla creazione della matrice. Una volta creata la matrice è anche sem- plice generare i valori di bound del tool, i quali verranno utilizzati per stabilire se un tile viene affetto dal tool. Interfaccia grafica L'interfaccia grafica da noi sviluppata, come si può vedere nell'immagine sottostante, è composta da una finestra suddivisa in quattro aree. Nella parte superiore sono presenti numerose opzioni per cambiare il comportamento dello strumento selezionato, modificandone le di- mensioni (altezza, larghezza, diametro, ed eventuali altri fattori che variano in base allo strumento), la possibilità di usare o no il “drag- ging”, ovvero di applicare in modo continuo le modifiche semplicemente tenendo premuto il pulsante del mouse, la possibilità di cambia- re tra la modalità “aggiungi” o “sostituisci” (la prima modifica il terreno aggiungendo a quello esistente l'azione associata allo strumen- to, la seconda invece sostituisce il terreno esistente con l'azione associata allo strumento), la possibilità di usare dei “presets”, cioè de- gli strumenti predefiniti, oppure di creare di nuovi, la possibilità di cambiare il colore dello strumento ed infine l'angolo di “snap” che vincola lo strumento, qualora lo si applichi premendo in contemporanea il tasto “SHIFT”, a seguire l'angolo impostato. Nella parte sinistra della finestra sono presenti diverse icone per selezionare lo strumento desiderato (la lista degli strumenti sviluppati è descritta in dettaglio nel prossimo paragrafo) oppure per compiere particolari azioni. E' possibile inoltre selezionare lo strumento “gomma”, il quale permette di cancellare zona per zona le modifiche apportate o lo stru- mento “cestino”, il quale mostra una finestra modale per confermare la cancellazione di tutte le modifiche apportate. Si può poi passare alla modalità “modifica” o alla modalità “movimento” (la prima permette di applicare modifiche al terreno, la seconda di muoversi all'interno del mondo), mostrare o nascondere le modifiche apportate, attivare o disattivare la modalità wireframe ed infine salvare/caricare tutte le modifiche effettuate. Nella parte inferiore della finestra, sulla sinistra è visualizzato il nome dello strumento attualmente in uso, sulla parte destra invece è possibile muoversi in un punto preciso del mondo impostando le relative coordinate (latitudine e longitudine) nei campi di testo e pre- mendo sul pulsante “go”. E' anche possibile premere sul pulsante “go and do” che sposta la visualizzazione del mondo alle coordinate impostate e nello stesso tempo applica lo strumento selezionato nel punto corrispondente a tali coordinate. Infine nella parte centrale della finestra è visualizzato il mondo, il quale viene gestito da WorldWind; nella parte superiore destra è visibile una bussola che permette di capire dove si trova il nord ed inoltre l'”inclinazione” della vista rispetto al mondo; nella parte inferiore de- stra è visualizzata una scala per rapportare la visualizzazione alle distanze reali in metri. Pagina 12/25
    • Figura 9: L'interfaccia Gestione tasti La gestione dei tasti è diversa a seconda che ci si trovi in modalità movimento o modalità modifica. Per cambiare modalità è sufficiente cliccare sul pulsante relativo oppure premere il tasto destro del mouse. L'icona associata sulla barra laterale sinistra cambierà per indi- care in quale modalità si è attualmente. Modalità modifica Si è in modalità modifica quando è visualizzata una forma colorata (di base il colore è rosso) nella parte centrale della finestra e l'icona relativa alla modalità sulla barra laterale sinistra assume la forma di una paletta. La forma colorata indica l'area che sarà influenzata dallo strumento selezionato. Cliccando con il tasto sinistro del mouse verrà eseguita l'azione associata allo strumento, nel caso poi quest'ultimo abbia abilitata l'op- zione “draggable” allora sarà possibile tenere premuto il tasto sinistro del mouse e muoversi per continuare ad effettuare le modifiche. Tenendo premuto il tasto destro del mouse e muovendosi verso l'alto o il basso verrà invece modificata l'”inclinazione della vista” rispet- to al terreno, invece muovendosi verso destra e sinistra la vista ruoterà intorno al punto visualizzato; in alternativa si possono usare i tasti “PAGE DOWN” e “PAGE UP” della tastiera oppure tenere premuto il tasto “SHIFT” e poi premere le frecce. Con la rotellina del mouse è possibile infine zoomare avanti ed indietro la visuale, in alternativa si possono usare i tasti “+” e “-” della tastiera. Modalità movimento Si è in modalità movimento quando l'icona associata sulla barra laterale sinistra assume la forma di quattro frecce rosse. Per muoversi è possibile usare le frecce della tastiera oppure cliccare con il tasto sinistro del mouse su un punto: in questo modo la vi- sta sarà centrata sul punto cliccato. Pagina 13/25
    • Tenendo premuto il tasto sinistro del mouse e muovendolo nelle quattro direzioni, ci si muoverà similmente nel mondo. Tenendo premuto il tasto destro del mouse e muovendosi verso l'alto o il basso verrà invece modificata l'”inclinazione della vista” rispet- to al terreno, invece muovendosi verso destra e sinistra la vista ruoterà intorno al punto visualizzato; in alternativa si possono usare i tasti “PAGE DOWN” e “PAGE UP” della tastiera oppure tenere premuto il tasto “SHIFT” e poi premere le frecce. Con la rotellina del mouse è possibile infine zoomare avanti ed indietro la visuale, in alternativa si possono usare i tasti “+” e “-” della tastiera. Strumenti sviluppati Nello sviluppo degli strumenti abbiamo deciso di creare un'interfaccia (Tool.java) che viene poi implementata da ciascuno degli strumen- ti. In questo modo possiamo dichiarare tutti i metodi che implementeremo per i vari tool all'interno dell'interfaccia, rendendo il codice più semplice da capire e gestire. Questo approccio ci permette inoltre di accedere ai metodi dei tool attraverso l'interfaccia in qualsiasi parte del codice, rendendolo semplice da espandere con lo sviluppo di nuovi tool. Inoltre abbiamo deciso di creare classi separate per tool “speculari”, come per esempio Plateau up e Plateau down, altrimenti sarebbe stato necessario raddoppiare le variabili per mantenere in memoria i valori di default dello strumento quando viene generata l'interfac- cia. La nostra scelta pertanto ci ha portato da una parte ad avere più codice, ma dall'altra questo è meglio organizzato e più facilmente modificabile. Per ognuno dei dieci strumenti sviluppati presentiamo ora una breve descrizione insieme ad un'immagine esemplificativa. Non analizziamo invece lo strumento “gomma” e lo strumento “cestino”, poiché riteniamo ovvio il loro comportamento, già accennato nella sezione precedente. Nella barra laterale degli strumenti sono presenti anche i pulsanti di due strumenti mirati alla modifica della visualizzazione: il primo per- mette di visualizzare/nascondere le modifiche fatte fino ad ora; il secondo di visualizzare/nascondere il wireframe. L'implementazione di quest'ultimo è stata dettata per motivi pratici: il fatto che in WorldWind non siano presenti sorgenti di luce e che lo shader utilizzato è di tipo flat, le differenze di altitudine del terreno sono visibili esclusivamente grazie alle ombre sulle stesse texture. Trovandosi a modificare il terreno in punti in cui tali ombre non esistono, la visualizzazione delle nuove features diventa difficoltosa, se non impossibile. A questo scopo è stato introdotto il wireframe, che permette di dare una sorta di “profondità di campo” alla nuova morfologia del terreno. Nel capitolo di spiegazione sull'implementazione alla base delle modifiche si era parlato di dover ricreare i tile quando si cambia la visua- lizzazione attivando o disattivando il wireframe. Questo è dovuto al fatto che, con il wireframe attivo, non è possibile visualizzare anche le skirts, altrimenti la visualizzazione diventa un ammasso di righe bianche incomprensibili. Disattivando le skirt quando visualizziamo il wireframe ci consente di mantenere una visualizzazione più pulita e comprensibile, al prezzo di “strappi” nel terreno a cavallo fra tile di diversa risoluzione. Le skirt, infatti, simulano il riempimento di questi spazi vuoti ponendo dei “piani” verticali fra i tile, ma riescono bene nel loro intento solo nel caso di shader di tipo flat. Pagina 14/25
    • Crater Questo strumento circolare crea un cratere del diametro e della profondità desiderata. Figura 10: Strumento Crater Pagina 15/25
    • Hollow (circular hole) Questo strumento crea un buco circolare della profondità e del diametro desiderato. Si differenzia dallo strumento cratere per il bordo della buca, come si può vedere dall'immagine sottostante: nel cratere infatti viene alzato rispetto al terreno precedentemente esistente, nel buco circolare invece rimane a livello del terreno precedentemente esistente. Figura 11: Strumento Hollow (circular hole) Pagina 16/25
    • Gaussian hole Questo strumento crea un buco usando la formula matematica della gaussiana. E' possibile specificarne la profondità, la dimensione ed il fattore. Quest'ultimo incide sul calcolo della gaussiana rendendola più o meno “allargata”. Figura 12: Strumento Gaussian hole Pagina 17/25
    • Plateau (down) Questo strumento abbassa un'area rettangolare, specificata tramite i due parametri di lunghezza e larghezza, del terreno secondo la profondità desiderata. Figura 13: Strumento Plateau (down) Pagina 18/25
    • Circular plateau (down) Questo strumento abbassa un'area circolare, specificata tramite il diametro, del terreno secondo la profondità desiderata. Figura 14: Strumento Circular plateau (down) Pagina 19/25
    • Hill Questo strumento crea una collina circolare del diametro e dell'altezza desiderata. Figura 15: Strumento Hill Pagina 20/25
    • Gaussian mountain Questo strumento alza il terreno usando la formula matematica della gaussiana. E' possibile specificarne l'altezza, la dimensione ed il fattore. Quest'ultimo incide sul calcolo della gaussiana rendendola più o meno “allargata”. Figura 16: Strumento Gaussian mountain Pagina 21/25
    • Plateau (up) Questo strumento alza un'area rettangolare, specificata tramite i due parametri di lunghezza e larghezza, del terreno secondo l'altezza desiderata. Figura 17: Strumento Plateau (up) Pagina 22/25
    • Circular plateau (up) Questo strumento alza un'area circolare, specificata tramite il diametro, del terreno secondo l'altezza desiderata. Figura 18: Strumento Circular plateau (up) Pagina 23/25
    • Noise (random elevation) Questo strumento modifica un'area rettangolare, specificata tramite i due parametri di lunghezza e larghezza, del terreno generando delle altezze casuali comprese tra l'altezza specificata ed il suo valore negativo. Figura 19: Strumento Noise (random elevation) Pagina 24/25
    • Miglioramenti futuri Un possibile miglioramento all'applicazione, con un sufficiente tempo per poterlo implementare, consiste nel dare la possibilità all'utente di conservare una “storia” delle modifiche. Abbiamo provato ad implementare una versione per lo meno basilare (come mostrato in fi- gura 20), ma abbiamo subito incontrato dei problemi. La nostra idea consisteva nel mantenere in memoria un buffer con le ultime n mo- difiche applicate, in modo che si potessero reinserire nella coda di applicazione con i valori inversi se l'operazione voleva essere quella di tornare indietro, con gli stessi valori se l'operazione era quella di ripetere un'operazione annullata. Nel caso di tool basilari con modalità additiva questo approccio non ha problemi, in quanto non fa altro che applicare un'operazione che è l'esatto opposto di quella normale. Nel caso di strumenti con modalità sostitutiva oppure nel caso della gomma, invece, il risultato non è quello desiderato. Abbiamo provato a implementare una soluzione che prevedeva di simulare lo strumento – ovviamente a valori in- versi – questa volta in modalità additiva (in quanto se lasciato in modalità sostitutiva i risultati sono disastrosi) quando si tratta di torna- re indietro con la storia, ma rimane comunque il problema dell'area comune a più tool aggiunti con modalità sostitutiva: nel momento stesso in cui un tool con modalità sostitutiva viene applicato, tutte le informazioni di elevazione precedentemente presenti nel zona oc- cupata sono perse definitivamente, e quindi simulare un'azione di rollback con strumento additivo non fa altro che aggiungere o togliere terreno nelle aree sovrapposte, in maniera cumulativa. Il problema maggiore di questo approccio alla funzionalità sta nel fatto che memorizziamo i tool applicati e non le configurazioni del ter- reno prima e dopo l'applicazione di ogni singolo tool. Per passare a questa soluzione, però, bisognerebbe memorizzare una quantità eccessiva di TMI, causando un overhead di memoria non da poco. Una soluzione impraticabile a nostro avviso. Un ulteriore problema che si sviluppa nel cercare un'implementazione di questa funzionalità è il metodo con cui trattiamo la possibilità di trascinare i tool. Quando il puntatore mouse viene trascinato, simuliamo questo evento aggiungendo una serie di copie del tool alla coda di applicazione, in modo tale che vengano applicate una in seguito all'altra simulando il trascinamento. Ovviamente l'idea di memorizzare un buffer delle ultime n modifiche non si presta bene a quest'eventualità, in quanto si riempie piuttosto rapidamente con modifiche di poco conto per quanto riguarda il risultato finale. Pagina 25/25