Page Menu
Home
Search
Configure Global Search
Log In
Files
F19806
gdml_utils.py
Public
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
Matthew Reid (mattreid9956)
Nov 13 2013, 4:20 PM
Size
14 KB
Subscribers
None
gdml_utils.py
View Options
#**********************************************************************************************************
# 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
Details
Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c2/7e/6cf1aff910633ab1170971dc0ae5
Event Timeline
Log In to Comment