All rites reversed. Reprint what you like.
Salvo diversa indicazione

lunedì 22 marzo 2010

Disegniamo la luna...

Ora che ci siamo procurati i dati li dobbiamo visualizzare.
Iniziamo con la mappa completa.
Se analizziamo con un editor il file scaricato, (ne esistono di gratuiti, per esempio qui: HexEditor), vediamo che il file è diviso in 2 parti. La prima parte è composta da testo che spiega il contenuto del file e come sono strutturati i dati, la seconda parte, contiene i dati veri e propri.

Nella prima parte, di importante c'è il commento che riepiloga i dati salienti:

"LALT GGT_MAP is a lunar global topographic MAP data extracted            
from LALT_GGT_NUM that is processed from the LALT_LGT_TS created         
by 'surface' command in Generic Mapping Tool (Wessel and Smith, 1991).   
Altitude values were rounded off to the third decimal place.             
Data are ordered from +89.96875 to -89.96875 degrees in latitude         
and from +0.03125 to +359.96875 degrees in longitude. They are           
referenced to the sphere of 1737.4km radius based on the gravity center of the Mean                                           
Earth/Polar Axis body-fixed coordinates of the Moon. Grid resolution is 0.0625 (1/16) degree.                                 
PI: Dr. Hiroshi ARAKI (arakih@miz.nao.ac.jp)."  

In sintesi, dice che i dati sono ordinati da +89.96875 a -89.96875 gradi di latitude e da +0.03125 to +359.96875 gradi di longitude, la risoluzione della griglia è 1/16 di grado, e che i dati sono riferiti a una sfera di 1737,4 Km di raggio.
Proseguendo si legge la voce Image=9559 BYTE, che ci dice che i dati veri e propri iniziano dopo 9559 BYTE dall'inizio del file.
Poi si legge che i dati sono formati da 2880 linee composte da 5760 punti, praticamente ci sono 2880 paralleli e 5760 meridiani.
Più avanti si legge che i dati sono in formato di Float (4 byte) e che l'unità di miusura è in KM, quello che non è spiegato, è che i dati rappresentano l'altezza rispetto alla sfera di prima, praticamente, se il dato è uguale a 0, il punto dista 1737,4 Km dal centro.

Sapendo come è formato il file non ci resta che darlo in "pasto" in qualche maniera a Blender.
Quello che ci serve è creare un elenco di vertici con coordinate x, y e z dove z rappresenta la distanza dal centro della luna e x e y la latitudine e la longitudine del punto.
Fino a venerdì l'unico metodo che mi era venuto in mente era fare un programma in Visual Basic, che conosco,  per leggere dal file i dati e poi scriverlo in un altro file in formato obj come indicato nel post del 18/03, ma pi mi sono detto che non tutti posseggono visual basic anche se esiste una versione free (http://www.microsoft.com/express/Downloads/#2008-Visual-Basic), e allora mi sono preso il fine settimana pèer studiare un po' di Python, liguaggio per poter fare degli script direttamente utilizzabili dentro BLENDER senza strumentio aggiuntivi. Dopo un po' di tentativi ho ottenuto il seguente programmino:


import math
import Blender
import bpy
import array


from Blender import *


Vertice=[] #Matrice che conterrà i vertici della luna
Facce=[] #Matrice che conterrà l'ordine dei vertici per creare le facce
AngularStep=0.0625*10 #Risoluzione della griglia
StartLat=0+AngularStep/2 #Latitudine del primo punto
StartLong=90-AngularStep/2 #Longitudine del primo punto
Raggio=1737.4/10


#Con le seguenti 4 righe carico il dati in una matrice.
#Il primo read mi posiziona diretamente al primno byte di dati
f = open("E:\Apollo 11\Mappa completa\LALT_GGT_MAP.img", 'rb')
b = f.read(9558) #Salto direttamente al byte n° 9559 byte
s = f.read() # Leggo tutti i bytes
a = array.array("f", s) #Creo un array di float
f.close()


#Nel seguente loop Creo i valori di latitudine , longitudine e
#il valore di altezza assegnato  z
contatore=0
Latitudine=StartLat
while Latitudine<180: #180:
    Latitudine=Latitudine+AngularStep
    Longitudine=StartLong #+AngularStep
    while Longitudine>-270:
        Longitudine=Longitudine-(AngularStep)
        Raggio=(a[contatore]+1737.4)/10
        contatore=contatore+10
        x=Raggio*math.sin(Latitudine*math.pi/180)*math.cos(Longitudine*math.pi/180)
        y=Raggio*math.sin(Latitudine*math.pi/180)*math.sin(Longitudine*math.pi/-180)
        z=Raggio*math.cos(Latitudine*math.pi/180)
        Vertice.append((float(x),float(y),float(z)))
me = Mesh.New('Sfera')
me.verts.extend(Vertice)
print Raggio


#Qui unisco i vertici per creare le facce
for r in range(1, 287):
    for c in range (1, 576):
        v0=c+(r-1)*576
        v1=v0-1
        v2=v0+576-1
        v3=v2+1
        Facce.append((int(v0),
                      int(v1),
                      int(v2),
                      int(v3)))


#Chiudo l'ultima fila di faccie
for r in range (1,287):
v0=576*(r-1)
v1=576*r-1
v2=v1+576
v3=v1+1
Facce.append((int(v0),
                      int(v1),
                      int(v2),
                      int(v3)))


me.faces.extend(Facce)
Scene.GetCurrent().objects.new(me,"Sfera")
Blender.Redraw()



Serve ricalcolare le normali forse c'è un errore nella creazione delle facce

Può essere che questo non sia il modo migliore, ma tenendo conto che fino a 2 giorni fa praticamente non sapevo niente di Python posso considerarmi soddisfatto per ora.
Da notare che ho ridotto il tutto di un fattore 10 (la sfera anzichè un raggio di 1737.4 ha un raggio di 173.74), e che ho disegnato solo 1 punto ogni dieci e quindi la già bassa risoluzione si è ridotta ulteriormente.
Ho provato a fare una lettura di tutti di dati ma va in errore per mancanza di memoria (dopotutto si tratta di 16,588,800 punti), forse con un sistema a 64 bit si riesce a fare.

Se una volta eseguito lo script, non vedete niente, aumentate il clipping.

Questo un render di prova.

Il prossimo passo sarà quello di realizzare un script per ricreare solo una parte di questa griglia a piacere, ma alla massima risoluzione.

Ciao
VB

Nessun commento:

Posta un commento