Full moon map 3d (no normal map)

Here there is my first experiment with elevation data of the moon. These data are obtained from the probe LRO-LOLA by NASA.
The grid consists of 265.420.800 vertices and this grid is the most detailed available for now (64 px/deg)
I have used Blender 2.49 for import datatset and video editing. The video is composed by 50 group of rendering every group is composed by the date of 3 degree of latitude.

Ciao
VB

http://moonmaplab.blogspot.com/ (Italian version)

Dang, I thought you were posting the map.

Some details:
Here you can find the dataset: http://imbrium.mit.edu/DATA/LOLA_GDR/

LDEM_4.IMG: 4 px/deg
LDEM_16.IMG: 16 px/deg
LDEM_32.IMG: 32 px/deg (Like Kaguya spacecraft)
LDEM_64.IMG: 64 px/deg

On the bottom you can see the UI: You can choose the coordinates that you want.

Here you can see the script for import the data (you must change the path of the file in the script):

#!BPY

"""
Name: 'Moon importer'
Blender: 249
Group: 'Misc'
Tooltip: 'Import altimetric date from LALT_GGT_MAP.IMG'
"""
#Script by ValterVB
#Italian blog: http://moonmaplab.blogspot.com/
#Web site (Work in progress): https://sites.google.com/site/moonmaplab/home

import math, array, bpy, Blender, gc
from Blender import Draw, BGL
from Blender import *

############################################################
# CHANGE HERE PATH AND FILE NAME
############################################################
NomeDelFile="L:\Nasa LRO\LOLA\DEM 64\LDEM_64.IMG"

#Variables for User interface management #################
#Assign a number for every event
evtNumDaLat=1
evtNumALat=2
evtNumDaLong=3
evtNumALong=4
evtPushEsegui=5

#Set starting value for the control
numberDaLat = Draw.Create(21)
numberALat = Draw.Create(15)
numberDaLong = Draw.Create(0.0078125)
numberALong = Draw.Create(359.9921875)

#Date inside the map file
GRID_RES=0.015625    #Grid resolution
START_LONG=0.0078125 #Westernmost longitude
START_LAT=89.9921875 #Max latitude
RAGGIO_LUNA=1737.400 #Radius of the moon
PUNTI=23040         #Line samples

TO_RAD=math.pi/180 #From degrees to radians

Vertici=[] #Vertex array
Facce=[]   #Faces arrays

DatiAltezza=[] #Altitude array

#Input: Longitude
#Output: Number of the point on row (or column)
def Punto(Long):
	tmpPunto=round((Long-START_LONG)/GRID_RES+1)
	if tmpPunto>23040:tmpPunto=23040
	return tmpPunto

#Input: Latitude
#Output: Number of the line (or row)
def Linea(Lat):
	tmpLinea=round((START_LAT-Lat)/GRID_RES+1)
	if tmpLinea>11520:tmpLinea=11520
	return tmpLinea

#Input: Line number (or row)
#Output: Latitude
def Lat(Linea):
	return START_LAT-(Linea-1)*GRID_RES

#Input: Point (or column)
#Output: Longitude
def Long(Punto):
	return START_LONG+(Punto-1)*GRID_RES

#Input: Latitude and Longitude
#Output: Height of the Coordinate
def Altezza(Lat,Long):
	return DatiAltezza[int((Linea(Lat)-1)*PUNTI+Punto(Long))]/0.5/1000


#Function for load the data from file #######################
def LeggoFile(NomeFile):
	#Open the file
	f=open(NomeFile,'rb')
	#Read all the data
	DatiLetti=f.read()
	#Assign the data to the short array
	DatiTemp=array.array("h",DatiLetti)
	f.close
	return DatiTemp

#Here the function that draw the moon
def DisegnaLuna(Da_Lat, A_Lat, Da_Long, A_Long):
	Window.WaitCursor(1)
	tmpDa_Long=Da_Long
	#Number of the lines to read
	NumeroLinee=int(Linea(A_Lat)-Linea(Da_Lat)+1)
    #Number of the points to read
	NumeroPunti=int(Punto(A_Long)-Punto(Da_Long)+1)
	#Loop on the latitude. X and Y from shere equation
	while (Da_Lat>=A_Lat):
	    #Loop on the longitude
		while (Da_Long<=A_Long):
			Raggio=Altezza(Da_Lat,Da_Long)+RAGGIO_LUNA
			RaggioCorrente=Raggio*(math.cos(Da_Lat*TO_RAD))
			X=RaggioCorrente*(math.sin(Da_Long*TO_RAD))
			Y=Raggio*math.sin(Da_Lat*TO_RAD)
			Z=RaggioCorrente*math.cos(Da_Long*TO_RAD)
			#Assign the values to the vertex
			Vertici.append((float(X),float(Y),float(Z)))
			Da_Long = Da_Long+GRID_RES
		Da_Long=tmpDa_Long
		Da_Lat=Da_Lat-GRID_RES
    #Draw the vertex
	me=Mesh.New('Luna')
	me.verts.extend(Vertici)
	Vertici[:]=[]
	DatiAltezza=None
	gc.collect()
	print "Fine Vertici"
	#Loop for create the faces
	for Linee in range(1,NumeroLinee):
		for Punti in range(1, NumeroPunti):
			v1=Punti+(Linee-1)*NumeroPunti
			v2=v1-1
			v3=v1+NumeroPunti-1
			v4=v3+1
			Facce.append((v1,v2,v3,v4))
	#To close last column
	#If you don't draw all the circumference you must comment
	#the following 9 lines
	for r in range (1,NumeroLinee):
		v0=NumeroPunti*(r-1)
		v1=NumeroPunti*r-1
		v2=v1+NumeroPunti
		v3=v1+1
		Facce.append((int(v0),
                     int(v1),
                      int(v2),
                      int(v3)))
	me.faces.extend(Facce)
	Scene.GetCurrent().objects.new(me,"Luna")
	#Some garbace, but i'm not shure that is useful
	Facce[:]=[]
	gc.collect()
	print "Fine Facce"
	Luna = bpy.data.objects["Luna"]
	Luna.setSize(0.01,0.01,0.01) #Scaling
	Luna.select("Luna")
	#Resolve the problem with the normal. I don't know why
	#Window.EditMode(1)
	#Window.EditMode(0)
	me.update
	Blender.Redraw()
	Window.WaitCursor(0)

#Here we draw the interface
def gui():
	global numberDaLat
	global numberALat
	global numberDaLong
	global numberALong
	BGL.glRasterPos2i(10,600)
	Draw.Text("Press Q or ESC to quit.") #Scrivo
	BGL.glRasterPos2i(10,550)
	Draw.Text("Select latitude and longitude of the point of interest")

	#Choice of "From latitude"
	numberDaLat = Draw.Number("From Latitude", evtNumDaLat, 10, 525, 200, 18, numberDaLat.val, -90, 90, "From latitude")

	#Choice of "To Latitude"
	numberALat = Draw.Number("To Latitude", evtNumALat, 10, 500, 200, 18, numberALat.val, -90, 90, "To Latitude")

	#Choice of "From longitude"
	numberDaLong = Draw.Number("From Longitude", evtNumDaLong, 10, 475, 200, 18, numberDaLong.val, 0, 360, "From Longitud")

	#Choice of "To longitude"
	numberALong = Draw.Number("To Longitude", evtNumALong, 10, 450, 200, 18, numberALong.val, 0, 360, "To Longitude")

	#Caluclate the vertex numbers
	BGL.glRasterPos2i(10,400)
	NumeroVertici=(((numberDaLat.val-numberALat.val)*64)+1)*((numberALong.val-numberDaLong.val)*64+1)
	Draw.Text("Number of vertex: %i" % NumeroVertici)
	#Check the coordinate
	if NumeroVertici<0:
		BGL.glRasterPos2i(10,350)
		Draw.Text("ATTENTION CHECK THE COORDINATES.")
		BGL.glRasterPos2i(10,325)
		Draw.Text("From Latitude must be highest than To Latitude")
		BGL.glRasterPos2i(10,305)
		Draw.Text("From Longitude must be highest than To Longitude")
	#Draw the button
	Draw.Button("Import", evtPushEsegui, 10, 200, 160, 18, "Import the file")

#Mouse and keyboard events
def event(evt, val):
    if evt == Draw.ESCKEY or evt == Draw.QKEY:
        stop = Draw.PupMenu("OK?%t|Stop the script %x1")
        if stop == 1:
            Draw.Exit()
            return

#Control events
def buttonEvt(evt):
	global DatiAltezza
	if evt == evtPushEsegui:
		print "Leggi"
		DatiAltezza=LeggoFile(NomeDelFile)
		print "Fine Leggi Inizio Disegno"
		DisegnaLuna(Lat(Linea(numberDaLat.val)),Lat(Linea(numberALat.val)),Long(Punto(numberDaLong.val)),Long(Punto(numberALong.val)))
		print "Fine Disegno"
		Draw.Exit()
	if evt: #Redraw the window
		Draw.Redraw()

#Main entry
Draw.Register(gui, event, buttonEvt)

Ciao
VB

Attachments


Thanks very much for sharing your script. The data set link is broken in your post.

http://imbrium.mit.edu/DATA/LOLA_GDR/ (fixed)

Also, this file does not exist:

LDEM_32.IMG: 32 px/deg (Like Kaguya spacecraft)

Not Found

The requested URL /DATA/LOLA_GDR/LDEM_32.IMG was not found on this server.

Thanks, fixed in the post.

Ciao
VB

I am getting memory errors on line 85:

DatiLetti=f.read()

I am running Windows XP 32-bit with 2GB RAM. I searched for solutions to this error and the solution seems to be reading the file in smaller chunks. I tried to make some changes in Python, but my skills are very basic and my changes didn’t work.

Here’s an example (NOT WORKING) of what I was trying to do. Maybe you have a better solution.

# Chunk reader to avoid memory errors (code from Tim Chase)
def chunk_file(fp, chunksize=4096):
     s = fp.read(chunksize)
     while s:
         yield s
         s = fp.read(chunksize)


#Function for load the data from file #######################
def LeggoFile(NomeFile):
	#Open the file
	#f=open(NomeFile,'rb')
	#Read all the data
	#DatiLetti=f.read()
    #DatiLetti = ""
    i = 0
	#replaced above code to avoid memory errors
    with open(NomeFile, 'rb') as f:
        for portion in chunk_file(f):
            if i == 0:
                DatiLetti = portion
                i = 1
            else:
                DatiLetti += portion			
		f.close
	
	#Assign the data to the short array
	DatiTemp=array.array("h",DatiLetti)
	#f.close
	return DatiTemp

I found this link for slicing files, which might help:

http://thatslinux.blog.co.uk/2009/10/10/slicing-and-dicing-files-with-python-7137358/

Yes,I know, I fighted with memory problem for 2 week, then I updated windows at 64bit.
I have 4 giga ram, perhaps with 2 Giga you can process the dataset but you must use 64 bit S.O. because Blender 32 bit have problem with more 1,5 G.
In any case I can try to modify the script for read only the date that you need not all the file (not today but next day :yes:)

Ciao
VB

Sorry for my poor english :o

Your English is good, no need to apologize. :slight_smile:

I have a Windows 7 64-bit system, with 4GB RAM, but limited to 3GB by the old motherboard. I haven’t installed Blender on that system yet, but I will try it for this.

I will also try to see if I can do anything to make it work on 2GB and 32-bit.

Hmm…

I pulled down the “LDEM_4.IMG” thinking it might be the same data at a lower resolution, but that file does not work with the script. I keep getting “array index out of range” error. I also tried the “LDEM_16.IMG” with the same results. Still pulling down the 64.

Did you use Blender 64-bit and Python 64-bit or 32-bit?

I am just testing on my Windows 7 64-bit, with 32-bit Blender and 32-bit Python and I can now run your script. It works now, so I haven’t tried 64-bit Blender/Python yet.

I spent some more time trying different file reading options on my 2GB Windows XP 32-bit system without any success.

I tried two approaches, one was similar to what I posted before, reading smaller chunks and the other was trying mmap memory map function, but neither worked. In both cases, I think the reading isn’t the problem, but the DatiTemp array is also taking too much memory. I watched the Task Manager and the errors came when Blender was using around 500MB memory, even though there was much more free physical and virtual memory left over. I think there must be a lot of overhead which isn’t shown in Task Manager.

I think the only solution will be to read limited segments of the IMG file, based on the user input and read and draw in smaller segments.

Python mmap – Memory-mapped file support

Here is a portion of my start on trying to read segments, in 8 parts. This DOES NOT WORK. The Draw function def DisegnaLuna(Da_Lat, A_Lat, Da_Long, A_Long) must be re-written to read, compute verticies and draw limited segments, based on the file read segment and user selection.

import os, mmap, math, array, bpy, Blender, gc
FileSize = os.path.getsize(NomeDelFile) #530841600
#Function for load the data from file #######################
def LeggoFile(NomeFile,SegmentLength,SegmentOffset):
    #print FileSize
    DatiTemp=array.array("h")
    with open(NomeFile, 'rb') as f:
        map = mmap.mmap(f.fileno(), SegmentLength, None, mmap.ACCESS_READ, SegmentOffset)
        DatiTemp = array.array("h",map.read(SegmentLength))
        map.close
    f.close
    return DatiTemp
def buttonEvt(evt):
    global DatiAltezza
    # divide process into segments
    Segments = 8
    SegmentLength = FileSize / Segments # 66,355,200
    if evt == evtPushEsegui:
        print "Leggi"
        for i in range(0, Segments):
            SegmentOffset = i * SegmentLength
            DatiAltezza=LeggoFile(NomeDelFile,SegmentLength,SegmentOffset)
            print "Fine Leggi Inizio Disegno"
            DisegnaLuna(Lat(Linea(numberDaLat.val)),Lat(Linea(numberALat.val)),Long(Punto(numberDaLong.val)),Long(Punto(numberALong.val)))
        print "Fine Disegno"
        Draw.Exit()

Here’s a quick render of a small segment from my Windows 7 PC with subsurf 2 (subsurf 3 crashes).

Attachments


I finally got the DEM_64.IMG pulled down. The script does work on Windows XP64. I used the default settings for the script. It took a while ( I assume this python is still single threaded) but made a ring with displacement.

My next question is what settings do I use to get the entire moon?

Obvious enhancements to the script might be to simply skip some data upon generation… I would be willing to accept a coarser representation of the moon.

EDIT:
I discovered this variable:

GRID_RES=0.25 #Grid resolution increased by Atom.
This speeds up generation quite a bit.

I also set my latitude from:90 to:1. This only produces a hemisphere. however. I still wonder how to get the entire sphere?

I thought latitude went from -90 to 90. But this script does not accept those values?

Some quick answer (more detail when I arrived to home):

Atom

I thought latitude went from -90 to 90. But this script does not accept those values?

Try with -89.999 and 89.999 (pheraphs there is a little bug)

Atom

My next question is what settings do I use to get the entire moon?

I think that it’s impossible get all the moon with 1 render, to much point (>264.000.000) or perhaps it’s only a problem of ram and power of processor.:smiley:

Atom

I pulled down the “LDEM_4.IMG” thinking it might be the same data at a lower resolution, but that file does not work with the script. I keep getting “array index out of range” error. I also tried the “LDEM_16.IMG” with the same results. Still pulling down the 64.

Yes, some thing are hard coded, but isn’t so hard to change. It’s important to know the format used in the dataset. In the directory where you founded the IMG file, you can see some files with extension= LBL, if you open it, you can see details of the dataset

harveen

Did you use Blender 64-bit and Python 64-bit or 32-bit?

I have Windows 7 64 bit with Blender 64 bit, I don’t know about Python version.
harveen

I think the only solution will be to read limited segments of the IMG file, based on the user input and read and draw in smaller segments.

Yes, it’s my idea, I’ll try to do it this evening or tomorrow.

Ciao
VB

Try with -89.999 and 89.999 (pheraphs there is a little bug)

Just some more feedback. The From Lat and To Lat fields do not accept anything but integers. When I try values like -89.99 they are converted to 89 only. Also I did manage to type in 89 and -89. But the script crashes. I assume it is having problems when crossing the 0 boundary. I get a KeyError: ‘index out of range’.

So you don’t think it is possible, even with a high GRID_RES = 0.4915625 to generate the entire moon in a low detail form? My 3GB computer seems to handle the hemisphere just fine.

Done
Here the modified script


#!BPY

"""
Name: 'Moon importer'
Blender: 249
Group: 'Misc'
Tooltip: 'Import altimetric date from LALT_GGT_MAP.IMG'
"""
#Script by ValterVB
#Italian blog: http://moonmaplab.blogspot.com/
#Web site (Work in progress): https://sites.google.com/site/moonmaplab/home

import math, array, bpy, Blender, gc
from Blender import Draw, BGL
from Blender import *

############################################################
# CHANGE HERE PATH AND FILE NAME
############################################################
NomeDelFile="L:\Nasa LRO\LOLA\DEM 64\LDEM_64.IMG"

#Variables for User interface management #################
#Assign a number for every event
evtNumDaLat=1
evtNumALat=2
evtNumDaLong=3
evtNumALong=4
evtPushEsegui=5

#Set starting value for the control
#You can insert here the decimal value
numberDaLat = Draw.Create(3.0) 
numberALat = Draw.Create(0.0)
numberDaLong = Draw.Create(0.0078125)
numberALong = Draw.Create(359.9921875)

#Date inside the map file. Che if you use different map
START_LONG=0.0078125 #Westernmost longitude
START_LAT=89.9921875 #Max latitude
MOON_RADIUS=1737.400 #Radius of the moon
GRID_RES=0.015625    #Grid resolution: 1/64 of degrades. Change if you use a different map
PUNTI=23040          #Point for line. Change if you use a different map
LINEE=11520          #Total number of line.
SCALING_FACTOR=0.5   #Factor to use for correct the Value.  Change if you use a different map

TO_RAD=math.pi/180   #From degrees to radians

Vertici=[]           #Vertex array
Facce=[]             #Faces arrays

#Input: Longitude
#Output: Number of the point on row (or column)
def Punto(Long):
	tmpPunto=round((Long-START_LONG)/GRID_RES+1)
	if tmpPunto>PUNTI:tmpPunto=PUNTI
	return tmpPunto

#Input: Latitude
#Output: Number of the line (or row)
def Linea(Lat):
	tmpLinea=round((START_LAT-Lat)/GRID_RES+1)
	if tmpLinea>LINEE:tmpLinea=LINEE
	return tmpLinea

#Input: Line number (or row)
#Output: Latitude
def Lat(Linea):
	return START_LAT-(Linea-1)*GRID_RES

#Input: Point (or column)
#Output: Longitude
def Long(Punto):
	return START_LONG+(Punto-1)*GRID_RES

#Here the function that draw the moon
def DisegnaLuna(Da_Lat, A_Lat, Da_Long, A_Long):
	Window.WaitCursor(1)
	tmpDa_Long=Da_Long
		
	NumeroLinee=int(Linea(A_Lat)-Linea(Da_Lat)+1)   #Number of the lines to read
	NumeroPunti=int(Punto(A_Long)-Punto(Da_Long)+1) #Number of the points to read

	f=open(NomeDelFile,'rb')          #Open the file
	f.seek((Linea(Da_Lat)-1)*PUNTI*2) #Skip the first n line of point
	print "Start vertex"	
	#Loop on the latitude
	while (Da_Lat>=A_Lat):
	    #Loop on the longitude
		DatiAltezza=f.read(PUNTI*2) #Read all the point of the line
		DatiAltezza=array.array("h",DatiAltezza) #Change to Array of short
		while (Da_Long<=A_Long):
			Raggio=DatiAltezza[int(Punto(Da_Long))-1]/SCALING_FACTOR/1000+MOON_RADIUS			
			RaggioCorrente=Raggio*(math.cos(Da_Lat*TO_RAD))
			
			X=RaggioCorrente*(math.sin(Da_Long*TO_RAD))
			Y=Raggio*math.sin(Da_Lat*TO_RAD)
			Z=RaggioCorrente*math.cos(Da_Long*TO_RAD)
			
			#Assign the values to the vertex
			Vertici.append((float(X),float(Y),float(Z)))
			Da_Long = Da_Long+GRID_RES
		Da_Long=tmpDa_Long
		Da_Lat=Da_Lat-GRID_RES
	DatiAltezza=[]    #I hope that free the memory
    #Draw the vertex
	me=Mesh.New('Luna')
	me.verts.extend(Vertici)
	Vertici[:]=[]     #I hope that free the memory
	DatiAltezza=None  #I hope that free thememory
	gc.collect()
	print "End Vertex and Start face"
	#Loop for create the faces
	for Linee in range(1,NumeroLinee):
		for Punti in range(1, NumeroPunti):
			v1=Punti+(Linee-1)*NumeroPunti
			v2=v1-1
			v3=v1+NumeroPunti-1
			v4=v3+1
			Facce.append((v1,v2,v3,v4))

	#To close last column
	#If you don't draw all the circumference you must comment the following 9 lines
	for r in range (1,NumeroLinee):
		v0=NumeroPunti*(r-1)
		v1=NumeroPunti*r-1
		v2=v1+NumeroPunti
		v3=v1+1
		Facce.append((int(v0),
                     int(v1),
                      int(v2),
                      int(v3)))
	me.faces.extend(Facce)
	print "End face And Start Drawing"
	Scene.GetCurrent().objects.new(me,"Luna")
	Facce[:]=[]  #I hope that free memory
	gc.collect() #I hope that free memory
	Luna = bpy.data.objects["Luna"]
	Luna.setSize(0.01,0.01,0.01) #Scaling all the moon
	Luna.select("Luna")
	#Resolve the problem with the normal. I don't know why
	#Window.EditMode(1)
	#Window.EditMode(0)
	me.update
	Blender.Redraw()
	print "End drawing"
	Window.WaitCursor(0)

#Here we draw the interface
def gui():
	global numberDaLat
	global numberALat
	global numberDaLong
	global numberALong
	BGL.glRasterPos2i(10,600)
	Draw.Text("Press Q or ESC to quit.") 
	BGL.glRasterPos2i(10,550)
	Draw.Text("Select latitude and longitude of the point of interest")

	#Choice of "From latitude"
	numberDaLat = Draw.Number("From Latitude", evtNumDaLat, 10, 525, 200, 18, numberDaLat.val, -90, 90, "From latitude")

	#Choice of "To Latitude"
	numberALat = Draw.Number("To Latitude", evtNumALat, 10, 500, 200, 18, numberALat.val, -90, 90, "To Latitude")

	#Choice of "From longitude"
	numberDaLong = Draw.Number("From Longitude", evtNumDaLong, 10, 475, 200, 18, numberDaLong.val, 0, 360, "From Longitud")

	#Choice of "To longitude"
	numberALong = Draw.Number("To Longitude", evtNumALong, 10, 450, 200, 18, numberALong.val, 0, 360, "To Longitude")

	#Caluclate the vertex numbers
	BGL.glRasterPos2i(10,400)
	NumeroVertici=(((numberDaLat.val-numberALat.val)*64)+1)*((numberALong.val-numberDaLong.val)*64+1)
	Draw.Text("Number of vertex: %i" % NumeroVertici)
	#Check the coordinate
	if NumeroVertici<0:
		BGL.glRasterPos2i(10,350)
		Draw.Text("ATTENTION CHECK THE COORDINATES.")
		BGL.glRasterPos2i(10,325)
		Draw.Text("From Latitude must be > than To Latitude")
		BGL.glRasterPos2i(10,305)
		Draw.Text("From Longitude must be > than To Longitude")
	#Draw the button
	Draw.Button("Import", evtPushEsegui, 10, 200, 160, 18, "Import the file")

#Mouse and keyboard events
def event(evt, val):
    if evt == Draw.ESCKEY or evt == Draw.QKEY:
        stop = Draw.PupMenu("OK?%t|Stop the script %x1")
        if stop == 1:
            Draw.Exit()
            return

#Control events
def buttonEvt(evt):
	global DatiAltezza
	if evt == evtPushEsegui:
		DisegnaLuna(Lat(Linea(numberDaLat.val)),Lat(Linea(numberALat.val)),Long(Punto(numberDaLong.val)),Long(Punto(numberALong.val)))
		Draw.Exit()
	if evt: #Redraw the window
		Draw.Redraw()

#Main entry
Draw.Register(gui, event, buttonEvt)

This version is less memory hungry and is more flexible, I read only the line that I need. It’s possible do it better, now i read all the point of the line but I can saving memory reading only the points that i need.

Now I can read also the other versions less detailed, You must change the value in these row:

GRID_RES=0.015625    #Grid resolution: 1/64 of degrades. Change it if you use a different map
PUNTI=23040          #Point for line. Change it if you use a different map
LINEE=11520          #Total number of line. Change it if you use a different map
SCALING_FACTOR=0.5   #Factor to use for correct the Value.  Change it if you use a different map

For ex. for the file LDEM 16:
PUNTI=5760
LINEE=2880
GRID_RES=1/16

One trick for saving memory: disable UNDO
Lat max and min for LDEM 64 are: 89.9921875 and -89.9921875
Max is 90-(GRID_RES/2), Min is -90+(GRID_RES/2)

Now you can use decimal value for coordinate.

If you like exagerate thing, you can play with Scaling Factor

If you want do a global map don’t change the grid resolution, you may have problem with the junction of the first and last column, it’s better change dataset (less detailed), alternatively, you must render some strip, save it with RGBA and then join the strips in video editor or GIMP. This is the tecnique that I have used for the video.
Attached an example, here for a more bigger rendering(4000x4000) http://picasaweb.google.com/valtervb1/MoonMapLaboratory02#5457524837239164066

At the end, if you like MARS, here you can found the dataset of MARS (max resolution 128 px/deg). I found it yesterday, if you try with these dataset remember that you must change also the MOON_RADIUS in the script. I think that the right dataset are Map type=Topography

I can’t Try, because I must finish my Moon I must landing :slight_smile:

Ciao
VB

Attachments


Thanks for the code update and taking the time to explain the function of the LBL file.

I modified the code a little so it will accept either of the IMG files. 4,16 or 64. I also added some feedback print statements to offer some progress information in the console.


#!BPY

"""
Name: 'Moon importer'
Blender: 249
Group: 'Misc'
Tooltip: 'Import altimetric date from LALT_GGT_MAP.IMG'
"""
#Script by ValterVB
#Italian blog: http://moonmaplab.blogspot.com/
#Web site (Work in progress): https://sites.google.com/site/moonmaplab/home

import math, array, bpy, Blender, gc
from Blender import Draw, BGL
from Blender import *

############################################################
# CHANGE HERE PATH AND FILE NAME
############################################################
NomeDelFile="L:\Nasa LRO\LOLA\DEM 64\LDEM_64.IMG"
NomeDelFile = "C:\Documents and Settings\Developer\My Documents\Blender\python\LDEM_16.IMG"

#Variables for User interface management #################
#Assign a number for every event
evtNumDaLat=1
evtNumALat=2
evtNumDaLong=3
evtNumALong=4
evtPushEsegui=5

#Set starting value for the control
#You can insert here the decimal value
numberDaLat = Draw.Create(89.99) 
numberALat = Draw.Create(-89.99)
numberDaLong = Draw.Create(0.0078125)
numberALong = Draw.Create(359.9921875)

#Date inside the map file. Che if you use different map
START_LONG=0.0078125 #Westernmost longitude
START_LAT=89.9921875 #Max latitude
MOON_RADIUS=1737.400 #Radius of the moon

#GRID_RES=0.015625 * 10    #Grid resolution: 1/64 of degrades. Change if you use a different map

n = 2                    #Controls which IMG to use.
if n == 0:
    NomeDelFile = "C:\Documents and Settings\Developer\My Documents\Blender\python\LDEM_64.IMG"
    GRID_RES=0.015625    #Grid resolution: 1/64 of degrades. Change if you use a different map
    PUNTI=23040          #Point for line. Change if you use a different map
    LINEE=11520          #Total number of line.
    SCALING_FACTOR=0.5   #Factor to use for correct the Value.  Change if you use a different map
if n == 1:
    NomeDelFile = "C:\Documents and Settings\Developer\My Documents\Blender\python\LDEM_16.IMG"
    PUNTI=5760
    LINEE=2880
    GRID_RES=float(1.0/16.0)
    SCALING_FACTOR=0.5   #Factor to use for correct the Value.  Change if you use a different map
if n == 2:
    NomeDelFile = "C:\Documents and Settings\Developer\My Documents\Blender\python\LDEM_4.IMG"
    PUNTI=1440
    LINEE=720
    GRID_RES=float(1.0/4.0)
    SCALING_FACTOR=0.5   #Factor to use for correct the Value.  Change if you use a different map
TO_RAD=math.pi/180   #From degrees to radians

Vertici=[]           #Vertex array
Facce=[]             #Faces arrays

#Input: Longitude
#Output: Number of the point on row (or column)
def Punto(Long):
    tmpPunto=round((Long-START_LONG)/GRID_RES+1)
    if tmpPunto>PUNTI:tmpPunto=PUNTI
    return tmpPunto

#Input: Latitude
#Output: Number of the line (or row)
def Linea(Lat):
    tmpLinea=round((START_LAT-Lat)/GRID_RES+1)
    if tmpLinea>LINEE:tmpLinea=LINEE
    return tmpLinea

#Input: Line number (or row)
#Output: Latitude
def Lat(Linea):
    return START_LAT-(Linea-1)*GRID_RES

#Input: Point (or column)
#Output: Longitude
def Long(Punto):
    return START_LONG+(Punto-1)*GRID_RES

#Here the function that draw the moon
def DisegnaLuna(Da_Lat, A_Lat, Da_Long, A_Long):
    print ("--> Begin Make Moon.")
    print ("    Using data file [" + NomeDelFile +"].")
    Window.WaitCursor(1)
    tmpDa_Long=Da_Long
        
    NumeroLinee=int(Linea(A_Lat)-Linea(Da_Lat)+1)   #Number of the lines to read
    NumeroPunti=int(Punto(A_Long)-Punto(Da_Long)+1) #Number of the points to read

    f=open(NomeDelFile,'rb')          #Open the file
    f.seek((Linea(Da_Lat)-1)*PUNTI*2) #Skip the first n line of point
    print ("    Reading data from file...")    
    #Loop on the latitude
    myCounter = 1
    while (Da_Lat>=A_Lat):
        print ("        Working on latitude " + str(Da_Lat) + ".")
        myCounter = myCounter + 1
        #Loop on the longitude
        DatiAltezza=f.read(PUNTI*2) #Read all the point of the line
        DatiAltezza=array.array("h",DatiAltezza) #Change to Array of short
        while (Da_Long<=A_Long):
            Raggio=DatiAltezza[int(Punto(Da_Long))-1]/SCALING_FACTOR/1000+MOON_RADIUS            
            RaggioCorrente=Raggio*(math.cos(Da_Lat*TO_RAD))
            
            X=RaggioCorrente*(math.sin(Da_Long*TO_RAD))
            Y=Raggio*math.sin(Da_Lat*TO_RAD)
            Z=RaggioCorrente*math.cos(Da_Long*TO_RAD)
            
            #Assign the values to the vertex
            Vertici.append((float(X),float(Y),float(Z)))
            Da_Long = Da_Long+GRID_RES
        Da_Long=tmpDa_Long
        Da_Lat=Da_Lat-GRID_RES
    DatiAltezza=[]    #I hope that free the memory
    #Draw the vertex
    me=Mesh.New('Luna')
    me.verts.extend(Vertici)
    Vertici[:]=[]     #I hope that free the memory
    DatiAltezza=None  #I hope that free thememory
    gc.collect()
    print ("    Begin face creation...")
    #Loop for create the faces
    for Linee in range(1,NumeroLinee):
        print ("        Working on face line #" + str(Linee) + " of " + str(NumeroLinee) + ".")
        for Punti in range(1, NumeroPunti):
            v1=Punti+(Linee-1)*NumeroPunti
            v2=v1-1
            v3=v1+NumeroPunti-1
            v4=v3+1
            Facce.append((v1,v2,v3,v4))

    #To close last column
    #If you don't draw all the circumference you must comment the following 9 lines
    for r in range (1,NumeroLinee):
        v0=NumeroPunti*(r-1)
        v1=NumeroPunti*r-1
        v2=v1+NumeroPunti
        v3=v1+1
        Facce.append((int(v0),
                     int(v1),
                      int(v2),
                      int(v3)))
    me.faces.extend(Facce)
    print "End face And Start Drawing"
    Scene.GetCurrent().objects.new(me,"Luna")
    Facce[:]=[]  #I hope that free memory
    gc.collect() #I hope that free memory
    Luna = bpy.data.objects["Luna"]
    Luna.setSize(0.01,0.01,0.01) #Scaling all the moon
    Luna.select("Luna")
    #Resolve the problem with the normal. I don't know why
    #Window.EditMode(1)
    #Window.EditMode(0)
    me.update
    Blender.Redraw()
    print "<-- End Make Moon."
    Window.WaitCursor(0)

#Here we draw the interface
def gui():
    global numberDaLat
    global numberALat
    global numberDaLong
    global numberALong
    global NomeDelFile
    
    BGL.glRasterPos2i(10,615)
    Draw.Text(NomeDelFile) 
        
    BGL.glRasterPos2i(10,600)
    Draw.Text("Press Q or ESC to quit.") 
    BGL.glRasterPos2i(10,550)
    Draw.Text("Select latitude and longitude of the point of interest")

    #Choice of "From latitude"
    numberDaLat = Draw.Number("From Latitude", evtNumDaLat, 10, 525, 200, 18, numberDaLat.val, -90, 90, "From latitude")

    #Choice of "To Latitude"
    numberALat = Draw.Number("To Latitude", evtNumALat, 10, 500, 200, 18, numberALat.val, -90, 90, "To Latitude")

    #Choice of "From longitude"
    numberDaLong = Draw.Number("From Longitude", evtNumDaLong, 10, 475, 200, 18, numberDaLong.val, 0, 360, "From Longitud")

    #Choice of "To longitude"
    numberALong = Draw.Number("To Longitude", evtNumALong, 10, 450, 200, 18, numberALong.val, 0, 360, "To Longitude")

    #Caluclate the vertex numbers
    BGL.glRasterPos2i(10,400)
    NumeroVertici=(((numberDaLat.val-numberALat.val)*64)+1)*((numberALong.val-numberDaLong.val)*64+1)
    Draw.Text("Number of vertex: %i" % NumeroVertici)
    #Check the coordinate
    if NumeroVertici<0:
        BGL.glRasterPos2i(10,350)
        Draw.Text("ATTENTION CHECK THE COORDINATES.")
        BGL.glRasterPos2i(10,325)
        Draw.Text("From Latitude must be > than To Latitude")
        BGL.glRasterPos2i(10,305)
        Draw.Text("From Longitude must be > than To Longitude")
    #Draw the button
    Draw.Button("Import", evtPushEsegui, 10, 200, 160, 18, "Import the file")

#Mouse and keyboard events
def event(evt, val):
    if evt == Draw.ESCKEY or evt == Draw.QKEY:
        stop = Draw.PupMenu("OK?%t|Stop the script %x1")
        if stop == 1:
            Draw.Exit()
            return

#Control events
def buttonEvt(evt):
    global DatiAltezza
    if evt == evtPushEsegui:
        DisegnaLuna(Lat(Linea(numberDaLat.val)),Lat(Linea(numberALat.val)),Long(Punto(numberDaLong.val)),Long(Punto(numberALong.val)))
        Draw.Exit()
    if evt: #Redraw the window
        Draw.Redraw()

#Main entry
Draw.Register(gui, event, buttonEvt)

You were correct in the fact that a full moon would probably not fit in memory. But using the LDEM_4.IMG file, it does fit in memory and the final does not have the seams on the bands like your more detailed image does. For my final fixup on the model after generation, I removed doubles and converted all triangles to quads.

I guess it is made of cheese!:wink:

Now I wonder which side is actually the dark side of the moon?

Attachments


This is a lot of fun. Now I can fly around and land on the moon.

The quarter resolution starts to show up when you get this close, however.

Attachments



Thanks very much. I also disabled undo and now your script is running on my Windows XP 32-bit with 2GB RAM. Thanks for the extra details on LDEM data as well.

Atom, thanks for your modification too.

I’d like to try converting to a normal map as well as combining it with a diffuse image map texture of the moon.

atom

Now I wonder which side is actually the dark side of the moon?

Set the front view (pad key 1) an see the attached image
Then set the right view (pad key 3) north is on the right, south is on the left.

Thanks for the changes.

harven:

I’d like to try converting to a normal map as well as combining it with a diffuse image map texture of the moon.
Perhaps do you need somthing like the second attachment?
If your answer is yes, in the same directory where you found the IMG file, you can find a JP2 file. It’s a Jpeg2000 file that you can use for normal map.

I’m happy that now you can read the dataset :slight_smile:

Ciao
VB

Attachments



Yes, that’s it. I have already saved those files as well. Thanks again.

That is so cool!

Is there any way to process the original data to remove the lines?

I know you can get data sets of terrestrial locations, what other extraterrestrial ones are there? Now Cassini data from Titan would rock!