Page MenuHome

gdml_utils.py

gdml_utils.py

#**********************************************************************************************************
# Class: StlToGDML
# Created by: M M Reid and V Coco
# Date: 13-03-2012
# Version: v1.0
# Comments: Exports .stl file to a .gdml file format.
# Requires Blender v2.6, and a separate txt file with the gdml material descriptions contained inside
# To Run:
# ./blender -b -P gdml_exporter.py somestlfile.stl
#
#**********************************************************************************************************
from bpy.props import StringProperty, BoolProperty, IntProperty, FloatVectorProperty
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bpy
from mathutils import Vector
import mmap, itertools, struct, contextlib, os, decimal, inspect, time
if "bpy" in locals():
import imp
if "gdml_utils" in locals():
imp.reload(stl_utils)
class MeshToGDML(object):
"""
A class to convert a blender mesh into a Geant 4 readable GDML (Geometry Description Markup Langauage) file.
Typical usage of MeshToGDML:-
Instanciate an instance of the class specifyung a few parameters :
- convert = MeshToGDML("/outputpath/to/Mygdml.gdml", "/path/to/gdml.xsd", "mm", "gdml_materials.gdml")
Can only set one material type, note that materials must be defined in "gdml_materials.gdml" :
- convert.set_MeshMaterial("Aluminuim")
Make sure their are no conversion errors, set the decimal precision :
- convert.set_precision(4)
Set the world volume name, material and half box length size (x,y,z) :
- convert.set_world( "Air", x, y, z)
Finally write out the gdml file :
- convert.writeGDML()
"""
# *******************************************************************************
# Initalise the class
# *******************************************************************************
def __init__( self, fileP = None, schemaP = None, unit = "mm", matfile = "gdml_materials.gdml"):
self.fileName = fileP
self.schemaPath = schemaP
self.tessellatedvolumeName = ""
self.units = unit
self.size = Vector([100, 100, 100])
# open file to write out gdml
self.file = open(fileP, "w", encoding="utf8", newline="\n")
self.fw = self.file.write
# user input required for these
self.stlMaterial = ""
self.worldMaterial = ""
self.precision = 4
# To read in the materials
self.fmat = open(matfile, "r", encoding="utf8", newline="\n")
# Get the active mesh
def __repr__( self):
return "<StlToGDML>\n OutputFile:%s\n Schema:%s\n Volume Name:%s\n Units: %s\n" % (self.fileName, self.schemaPath, self.volName, self.units)
def __str__( self):
return "Instance of StlToGDML"
def load_mesh(self, context):
self.object = context.active_object
current_scene = context.scene
# get the modifiers
try:
self.mesh = self.object.to_mesh(current_scene, True, 'PREVIEW')
except RuntimeError:
raise StopIteration
self.set_tessellatedvolumeName( self.mesh.name.capitalize() )
# *******************************************************************************
# Define setter, getter functions
# *******************************************************************************
# Mesh material
def set_meshMaterial( self, material):
self._meshMaterial = material
def get_meshMaterial( self):
return self._meshMaterial
meshMaterial = property(get_meshMaterial, set_meshMaterial)
# world material
def set_worldMaterial( self, material):
self._worldMaterial = material
def get_worldMaterial( self):
return self._worldMaterial
worldMaterial = property(get_worldMaterial, set_worldMaterial)
# world information
#@overridable
def set_world( self, x, y, z):
self._size = Vector(2*x, 2*y, 2*z)
def get_world( self):
return ( self._size )
world = property(get_world, set_world)
# overloaded world information
#@overridable
def set_world( self, material, x, y, z):
self._worldMaterial = material
self._size = Vector([2*x, 2*y, 2*z])
def get_world( self):
return ( self._worldMaterial, self._size )
world = property(get_world, set_world)
# set the length of each side of the world box
def set_size( self, v):
self._size = v
def get_size( self):
return ( self._size )
size = property(get_size, set_size)
# export file name
def set_fileName( self, filename):
self._fileName = filename
def get_fileName( self):
return self._fileName
fileName = property(get_fileName, set_fileName)
# the output precision
def set_precision( self, new_precision):
self._precision = new_precision
def get_precision(self):
return self._precision
precision = property(get_precision, set_precision)
# the gdml schema location
def set_schemaPath( self, new_schemaPath):
self._schemaPath = new_schemaPath
def get_schemaPath( self):
return self._schemaPath
schemaPath = property(get_schemaPath, set_schemaPath)
# the gdml schema location
def set_tessellatedvolumeName( self, new_tessellatedvolumeName):
self._tessellatedvolumeName = new_tessellatedvolumeName
def get_tessellatedvolumeName( self):
return self._tessellatedvolumeName
tessellatedvolumeName = property(get_tessellatedvolumeName, set_tessellatedvolumeName)
# the units in which the mesh has been created
def set_units( self, new_units):
self._units = new_units
def get_units( self):
return self._units
units = property(get_units, set_units)
# Write out the MAIN gdml file
def writeGDML( self) :
# Set the schema and gdml type
self._writeHeaders()
# Material definitions need to be within the gdml for use in Gauss,
self._writeMaterials()
# Output the Mesh information to the gdml file
self._writeMesh()
# Output the Mesh information to the gdml file
self._writeStructure()
# finally write the setup and close the file
self._writeSetup()
def _writeHeaders( self):
self.fw('<?xml version="1.0" encoding="UTF-8"?>\n')
self.fw('<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n')
sp = self.get_schemaPath()
self.fw(' xsi:noNamespaceSchemaLocation="'+sp+'">\n\n')
def _writeMaterials( self):
"""
Material definitions need to go here! Defined in materials.txt, only Al and Air are defined by default
"""
for line in self.fmat.readlines():
self.fw(' '+line)
self.fw('\n')
self.fmat.close()
import itertools
def _writeMesh( self):
# Get the vertex information
vertices = self.mesh.vertices
counter = 0
print ('Reading in %s vertices...' % str(len(vertices)))
x = self.get_size()[0]
y = self.get_size()[1]
z = self.get_size()[2]
self.fw(' <!-- Vertex definitions -->\n')
self.fw(' <define>\n')
for i in range(len(vertices)) :
vx = self.prec( vertices[i].co[0] )
vy = self.prec( vertices[i].co[1] )
vz = self.prec( vertices[i].co[2] )
print( "(%s, %s, %s)" % (vertices[i].co[0],vertices[i].co[1],vertices[i].co[2] ) )
self.fw(' <position name = "v'+str(i)+'" unit="'+self.get_units()+'" x="'+str(vx)+'" y="'+str(vy)+'" z="'+str(vz)+'"/>\n')
self.fw(' <position name="p0" unit="mm" x="0" y="0" z="0"/> \n')
self.fw(' <rotation name="r0" unit="radian" x="0" y="0" z="0"/> \n')
self.fw(' </define>\n\n')
# Now we have the Vertex positions defined can now construct the tessellated solids
self.fw(' <!-- Construction of the tessellated Solids -->\n')
self.fw(' <solids>\n')
self.fw(' <box lunit="'+self.get_units()+'" name="worldBox" x="'+str(x)+'" y="'+str(y)+'" z="'+str(z)+'"/>\n')
self.fw(' <tessellated name="split_0" lunit="'+self.get_units()+'">\n')
for i, f in enumerate(self.mesh.tessfaces):
face = ''
for j, vidx in enumerate(f.vertices):
face = face + ' vertex'+str(j+1)+'="v'+str(vidx)+'"'
if j == 2 :
counter += 1
face = ' <triangular' + face + ' type="ABSOLUTE"/>\n'
elif j == 3 :
counter += 1
face = ' <quadrangular' + face + ' type="ABSOLUTE"/>\n'
else:
self.fw('ABORTED YOUR EXPORT HERE!! MESH CONTAINS POLYGONS OF TOO HIGH ORDER!\n')
raise Exception("Error, check your mesh, one face is not trigangular nor quadrangular")
self.fw(face)
self.fw(' </tessellated>\n')
self.fw(' </solids>\n\n')
print ('Exported %s tessellated solids to file...' % (str(counter)))
def _writeStructure( self):
self.fw(' <!-- Define the structure -->\n')
self.fw(' <structure>\n')
self.fw(' <volume name="'+self.get_tessellatedvolumeName()+'">\n')
self.fw(' <materialref ref="'+self.get_meshMaterial()+'"/>\n')
self.fw(' <solidref ref="split_0"/>\n')
self.fw(' </volume>\n')
self.fw(' <volume name="GdmlWorld">\n')
self.fw(' <materialref ref="'+self.get_worldMaterial()+'"/>\n')
self.fw(' <solidref ref="worldBox"/>\n')
self.fw(' <physvol>\n')
self.fw(' <volumeref ref="'+self.get_tessellatedvolumeName()+'"/>\n')
self.fw(' <positionref ref="p0"/>\n')
self.fw(' <rotationref ref="r0"/>\n')
self.fw(' <!-- <scaleref ref="scalex"/> -->\n')
self.fw(' </physvol>\n')
self.fw(' </volume>\n')
self.fw(' </structure>\n\n')
def _writeSetup( self):
self.fw(' <setup name="Default" version="1.0">\n')
self.fw(' <world ref="GdmlWorld"/>\n')
self.fw(' </setup>\n')
self.fw('</gdml>')
self.file.close()
def prec( self, number = 0. ) :
#nodps = decimal.Decimal(10) ** -self.privates['precision']
dp = self.get_precision()
nodps = decimal.Decimal(10) ** -dp
return decimal.Decimal(str(number)).quantize(nodps)
###### EXPORT OPERATOR #######
class Export_gdml(bpy.types.Operator, ExportHelper):
'''Exports the active Object to a Geant4 readable GDML File'''
bl_idname = "export_mesh.gdml"
bl_label = "Export GDML (.gdml)"
filename_ext = ".gdml"
path = os.path.dirname (inspect.stack()[0][1])
apply_modifiers = BoolProperty(name="Apply Modifiers",
description="Applies the Modifiers",
default=True)
filepath = StringProperty(name="File Path",
description="Filepath used for exporting the gdml file",
maxlen= 1024,
default= "export_mesh")
matfile = StringProperty(name = "Material File Path",
description = "Filepath used for importing the gdml material definitionse",
maxlen = 1024,
default = path + "/gdml_materials.gdml")
world_material = StringProperty(name="World Material",
description = "Define the name of the world material",
maxlen = 1024,
default = "Air")
units = StringProperty(name = "Units",
description = "Define the measurement units (SI units only)",
default = "mm")
schema_path = StringProperty(name = "Schema Path",
description = "Define the path to the schema you intend to use",
default = path + "/schema/gdml.xsd")
tessellated_material = StringProperty(name = "Tessellated Solid Material",
description = "Define the name of the tessellated solid material",
default = "Aluminium")
precision = IntProperty(name = "Output precision",
description = "Defines the number of decimal places to be written out",
default = 15)
world_box = FloatVectorProperty(name = "World Box (x/2,y/2,z/2)",
description = "Define the half lengths for the world volume (x/2,y/2,z/2)",
default = (50000.0, 50000.0, 50000.0))
@classmethod
def poll(cls, context):
return context.active_object.type in ['MESH']
def execute(self, context):
start_time = time.time()
print('\n_____START_____')
props = self.properties
filepath = self.filepath
filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
# Configure the class to export to gdml format
cnv = MeshToGDML( filepath, self.properties.schema_path, self.properties.units, self.properties.matfile)
cnv.load_mesh(context)
cnv.set_meshMaterial(self.properties.tessellated_material )
cnv.set_precision(self.properties.precision)
cnv.set_world(self.properties.world_material, self.properties.world_box[0], self.properties.world_box[1], self.properties.world_box[2])
cnv.writeGDML()
if cnv:
print('finished export in %s seconds' %((time.time() - start_time)))
print(filepath)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
if True:
# File selector
wm.fileselect_add(self) # will run self.execute()
return {'RUNNING_MODAL'}
elif True:
# search the enum
wm.invoke_search_popup(self)
return {'RUNNING_MODAL'}
elif False:
# Redo popup
return wm.invoke_props_popup(self, event) #
elif False:
return self.execute(context)
### REGISTER ###
def menu_func(self, context):
default_path = os.path.splitext(bpy.data.filepath)[0] + ".gdml"
self.layout.operator(Export_gdml.bl_idname, text="GDML (.gdml)")#.filepath = default_path
#self.layout.operator(Export_gdml.bl_idname, text="GDML (.gdml)")
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_export.append(menu_func)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_export.remove(menu_func)
# Main file configuration
if __name__ == "__main__":
register()

File Metadata

Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c2/7e/6cf1aff910633ab1170971dc0ae5

Event Timeline