Difference between revisions of "Scripting Export Mesh"
(14 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
==Export a mesh== | ==Export a mesh== | ||
− | In the [[Scripting | + | In the [[Scripting Create Models]] section you learnt how to create TexGen models from Python scripts. In this tutorial I will explain how to get a volume mesh of the textile and save it to an arbitrary file format. This is a fairly common task but unfortunately one that must often be repeated due to the fact that there is very little standardisation on the file format for meshes. Each software package uses its own mesh file format and so we must learn to read and write to these different formats. Fortunately the Python language is ideal for performing these tasks with relative ease. |
==Standalone scripts== | ==Standalone scripts== | ||
Line 11: | Line 11: | ||
from TexGen.Core import * | from TexGen.Core import * | ||
− | + | Note that by adding this line does not prevent you from running your scripts through the GUI as well. | |
==Getting started== | ==Getting started== | ||
Line 24: | Line 24: | ||
textile = GetTextile() | textile = GetTextile() | ||
</pre> | </pre> | ||
− | The variable <code>textile</code> now contains an instance of the [http://texgen.sourceforge.net/api/class_tex_gen_1_1_c_textile.html CTextile] class representing the textile model. | + | The variable <code>textile</code> now contains an instance of the [http://texgen.sourceforge.net/api/class_tex_gen_1_1_c_textile.html CTextile] class representing the textile model. Let's now extract a mesh for this textile, fortunately TexGen has some built-in functionality to do this: |
+ | |||
+ | <pre> | ||
+ | # Create a mesh instance | ||
+ | mesh = CMesh() | ||
+ | # Add the volume of the textile to the mesh and trim the mesh to the domain | ||
+ | textile.AddVolumeToMesh(mesh, True) | ||
+ | </pre> | ||
+ | |||
+ | We declare <code>mesh</code> to be an instance of [http://texgen.sourceforge.net/api/class_tex_gen_1_1_c_mesh.html CMesh] and then use it to store a volume mesh of the textile. So with just a few lines of code we now have a volume mesh of the textile stored in memory. Note that this is just a mesh of the yarns, the volume between the yarns (i.e. the matrix volume) is not meshed. If you wanted to get a mesh of the yarns and matrix together you need to use the <code>CMesher</code> class instead, like this: | ||
+ | |||
+ | <pre> | ||
+ | # Create an instance of the mesher class | ||
+ | mesher = CMesher() | ||
+ | # Create the mesh | ||
+ | mesher.CreateMesh(textile) | ||
+ | # Get the mesh | ||
+ | mesh = mesher.GetMesh() | ||
+ | </pre> | ||
+ | |||
+ | This was a bit of a divergence from the tutorial, don't put this in your script unless you specifically wanted a mesh of the matrix as well. If you do use this, please be aware that it will generate a tetrahedral mesh and the code below will need to be extended to accommodate these elements. | ||
+ | |||
+ | The problem we are now faced with is how do we transfer this mesh from memory to the hard disk in the file format that we want so that it can be understood by our software of choice? Read on to find out. | ||
+ | |||
+ | ==Defining the file format== | ||
+ | |||
+ | In this example I will be showing you how to save to the [http://www.vtk.org/pdf/file-formats.pdf VTK legacy file format]. I have chosen this file format because it is simple and well documented. Unfortunately, in a lot of cases, file formats are poorly documented (if at all) and are complex due to poor design. | ||
+ | |||
+ | Note that TexGen already has a function to export to the VTK XML file format along with a number of other common file formats, and can be called in a single line of code like so: <code>mesh.SaveToVTK("mesh.vtu")</code>. But in this tutorial I want to explain how to actually write the data out line by line so that you can hopefully translate that to any other file format of your choice. | ||
+ | |||
+ | ==Writing the data to file== | ||
+ | |||
+ | Now that we have decided what format the data will be written in, let's get down to actually writing it. First we will open a file for writing: | ||
+ | file = open("mesh.vtk", "w") | ||
+ | See the [http://docs.python.org/tut/node9.html#SECTION009200000000000000000 Python tutorial section 7.2] for more details on writing to files in Python. Next we need to write the header: | ||
+ | <pre> | ||
+ | # Write the header | ||
+ | file.write("# vtk DataFile Version 2.0\n") | ||
+ | file.write("Textile mesh data\n") | ||
+ | file.write("ASCII\n") | ||
+ | file.write("DATASET UNSTRUCTURED_GRID\n") | ||
+ | </pre> | ||
+ | As defined in the [http://www.vtk.org/pdf/file-formats.pdf VTK legacy file format documentation]. A mesh consists of a number of nodes (or points) and a number of elements (or cells). Each corner of an element is defined as an index into the list of points. An index of 0 refers to the first point, index 1 refers to the second and so on. So first of all we shall write the list of points to the file in the correct format: | ||
+ | <pre> | ||
+ | # Write the points | ||
+ | file.write("POINTS %d float\n" % mesh.GetNumNodes()) | ||
+ | for node in mesh.GetNodes(): | ||
+ | file.write("%g %g %g\n" % (node.x, node.y, node.z)) | ||
+ | </pre> | ||
+ | The % operator is known as the string formatting or interpolation operator. It is important to understand how this works when writing data to files in ASCII format. Read the [http://docs.python.org/tut/node9.html#SECTION009100000000000000000 Python tutorial section 7.1] and [http://docs.python.org/lib/typesseq-strings.html Python library reference 3.6.2] for more information on this. | ||
+ | |||
+ | At this point, if you run the script it should create a valid VTK file that you can load into the free [http://www.paraview.org/ ParaView] visualisation software. You may want to try this now to check that what you have done so far works correctly. Initially you will not see anything when loaded into ParaView because we have just defined points and nothing else. In order to visualise these points you must apply the Glyph filter. Assuming this works, let's continue and write the elements. | ||
+ | |||
+ | Defining the elements is a little more tricky because there are different types of elements. When meshing the yarns TexGen will use a mix of wedge and hexahedral elements, so we only need to deal with these element types. The [http://texgen.sourceforge.net/api/class_tex_gen_1_1_c_mesh.html CMesh] class stores a long list of indices for each element type. For example, a mesh containing 2 wedge elements and 3 hex elements would contain a list of 12 indices for the wedges and a list of 24 for the hex elements. The first thing to do is to define some variables to contain this data: | ||
+ | <pre> | ||
+ | wedgeIndices = list(mesh.GetIndices(CMesh.WEDGE)) | ||
+ | hexIndices = list(mesh.GetIndices(CMesh.HEX)) | ||
+ | numWedges = len(wedgeIndices)/6 | ||
+ | numHexes = len(hexIndices)/8 | ||
+ | </pre> | ||
+ | Next we actually write the data to the file similarly to the way the points were written: | ||
+ | <pre> | ||
+ | file.write("CELLS %d %d\n" % (numWedges+numHexes, numWedges*7+numHexes*9)) | ||
+ | for i in range(numWedges): | ||
+ | file.write("6 %d %d %d %d %d %d\n" % tuple(wedgeIndices[i*6:(i+1)*6])) | ||
+ | for i in range(numHexes): | ||
+ | file.write("8 %d %d %d %d %d %d %d %d\n" % tuple(hexIndices[i*8:(i+1)*8])) | ||
+ | </pre> | ||
+ | Here I have made use of slicing (wedgeIndices'''['''i*6''':'''(i+1)*6''']''') to reduce the amount of code necessary to output the data. See the [http://docs.python.org/tut/node5.html#SECTION005140000000000000000 Python tutorial section 3.1.4] for information about how slicing works. | ||
+ | |||
+ | And finally we need to output the type of each of these elements: | ||
+ | <pre> | ||
+ | file.write("CELL_TYPES %d\n" % (numWedges+numHexes)) | ||
+ | for i in range(numWedges): | ||
+ | file.write("13\n") | ||
+ | for i in range(numHexes): | ||
+ | file.write("12\n") | ||
+ | </pre> | ||
+ | The VTK file format defines wedges to be of element type 13 and hexes to be of element type 12. | ||
+ | |||
+ | That's it, you should now have a script which reads a TexGen tg3 file, extracts a mesh from it and writes the contents to a file in the VTK legacy file format. Your Python script should look like this: | ||
+ | |||
+ | <pre> | ||
+ | from TexGen.Core import * | ||
+ | |||
+ | # Read in the textile | ||
+ | ReadFromXML('textile.tg3') | ||
+ | |||
+ | # Get a hold of the textile we just loaded in | ||
+ | textile = GetTextile() | ||
+ | |||
+ | # Create a mesh instance | ||
+ | mesh = CMesh() | ||
+ | # Add the volume of the textile to the mesh | ||
+ | textile.AddVolumeToMesh(mesh, True) | ||
+ | |||
+ | file = open("mesh.vtk", "w") | ||
+ | |||
+ | # Write the header | ||
+ | file.write("# vtk DataFile Version 2.0\n") | ||
+ | file.write("Textile mesh data\n") | ||
+ | file.write("ASCII\n") | ||
+ | file.write("DATASET UNSTRUCTURED_GRID\n") | ||
+ | |||
+ | # Write the points | ||
+ | file.write("POINTS %d float\n" % mesh.GetNumNodes()) | ||
+ | for node in mesh.GetNodes(): | ||
+ | file.write("%g %g %g\n" % (node.x, node.y, node.z)) | ||
+ | |||
+ | # Get element information from the mesh | ||
+ | wedgeIndices = list(mesh.GetIndices(CMesh.WEDGE)) | ||
+ | hexIndices = list(mesh.GetIndices(CMesh.HEX)) | ||
+ | numWedges = len(wedgeIndices)/6 | ||
+ | numHexes = len(hexIndices)/8 | ||
+ | |||
+ | # Write the element information | ||
+ | file.write("CELLS %d %d\n" % (numWedges+numHexes, numWedges*7+numHexes*9)) | ||
+ | for i in range(numWedges): | ||
+ | file.write("6 %d %d %d %d %d %d\n" % tuple(wedgeIndices[i*6:(i+1)*6])) | ||
+ | for i in range(numHexes): | ||
+ | file.write("8 %d %d %d %d %d %d %d %d\n" % tuple(hexIndices[i*8:(i+1)*8])) | ||
+ | |||
+ | file.write("CELL_TYPES %d\n" % (numWedges+numHexes)) | ||
+ | for i in range(numWedges): | ||
+ | file.write("13\n") | ||
+ | for i in range(numHexes): | ||
+ | file.write("12\n") | ||
+ | </pre> | ||
+ | |||
+ | ==Verification== | ||
+ | |||
+ | The first thing to do now is to run the script from the command line like so: | ||
+ | |||
+ | python myscript.py | ||
+ | |||
+ | replacing <code>myscript.py</code> with the name of the script your created and ensuring you have a textile model named <code>textile.tg3</code> in the some folder as the script. If it ran successfully you should see a file named <code>mesh.vtk</code> being created. Load this up into [http://www.paraview.org/ ParaView] and you should see a mesh of your textile. | ||
+ | |||
+ | When writing your own scripts it is unlikely that they will work straight away (even for professional programmers), so it is a good idea to check the output of your script at each step with a text editor to ensure that it is writing exactly what you want. This will enable you to isolate bugs early on and one at a time rather than having to fix a long script containing numerous bugs. The [http://docs.python.org/tut/node5.html#SECTION005200000000000000000 print statement] is your friend when it comes to debugging, it can be used to print out values and verify that they are what you expect. |
Latest revision as of 11:36, 14 May 2008
Export a mesh
In the Scripting Create Models section you learnt how to create TexGen models from Python scripts. In this tutorial I will explain how to get a volume mesh of the textile and save it to an arbitrary file format. This is a fairly common task but unfortunately one that must often be repeated due to the fact that there is very little standardisation on the file format for meshes. Each software package uses its own mesh file format and so we must learn to read and write to these different formats. Fortunately the Python language is ideal for performing these tasks with relative ease.
Standalone scripts
I am going to diverge a bit from this tutorial to talk about standalone scripts. In the previous guide it was assumed that the scripts you were writing would be run from within TexGen. However in some situations you may find it useful to simply run the scripts on their own from the command line without loading up the graphical user interface. In order to do this you must have installed Python and installed the non-bundle version of TexGen (see Windows Installation for more details). To run your script you can then type the following from the command line:
python myscript.py
However before your scripts will work on their own, you must import the TexGen modules at the start of your script. In order to do that simply add the following line to the top of your script:
from TexGen.Core import *
Note that by adding this line does not prevent you from running your scripts through the GUI as well.
Getting started
I'm going to assume you already have a textile model you want to get a mesh of and have saved it to a .tg3 file named "textile.tg3". So the first step is to load this model so that we can go about extracting a mesh from it:
from TexGen.Core import * # Read in the textile ReadFromXML('textile.tg3') # Get a hold of the textile we just loaded in textile = GetTextile()
The variable textile
now contains an instance of the CTextile class representing the textile model. Let's now extract a mesh for this textile, fortunately TexGen has some built-in functionality to do this:
# Create a mesh instance mesh = CMesh() # Add the volume of the textile to the mesh and trim the mesh to the domain textile.AddVolumeToMesh(mesh, True)
We declare mesh
to be an instance of CMesh and then use it to store a volume mesh of the textile. So with just a few lines of code we now have a volume mesh of the textile stored in memory. Note that this is just a mesh of the yarns, the volume between the yarns (i.e. the matrix volume) is not meshed. If you wanted to get a mesh of the yarns and matrix together you need to use the CMesher
class instead, like this:
# Create an instance of the mesher class mesher = CMesher() # Create the mesh mesher.CreateMesh(textile) # Get the mesh mesh = mesher.GetMesh()
This was a bit of a divergence from the tutorial, don't put this in your script unless you specifically wanted a mesh of the matrix as well. If you do use this, please be aware that it will generate a tetrahedral mesh and the code below will need to be extended to accommodate these elements.
The problem we are now faced with is how do we transfer this mesh from memory to the hard disk in the file format that we want so that it can be understood by our software of choice? Read on to find out.
Defining the file format
In this example I will be showing you how to save to the VTK legacy file format. I have chosen this file format because it is simple and well documented. Unfortunately, in a lot of cases, file formats are poorly documented (if at all) and are complex due to poor design.
Note that TexGen already has a function to export to the VTK XML file format along with a number of other common file formats, and can be called in a single line of code like so: mesh.SaveToVTK("mesh.vtu")
. But in this tutorial I want to explain how to actually write the data out line by line so that you can hopefully translate that to any other file format of your choice.
Writing the data to file
Now that we have decided what format the data will be written in, let's get down to actually writing it. First we will open a file for writing:
file = open("mesh.vtk", "w")
See the Python tutorial section 7.2 for more details on writing to files in Python. Next we need to write the header:
# Write the header file.write("# vtk DataFile Version 2.0\n") file.write("Textile mesh data\n") file.write("ASCII\n") file.write("DATASET UNSTRUCTURED_GRID\n")
As defined in the VTK legacy file format documentation. A mesh consists of a number of nodes (or points) and a number of elements (or cells). Each corner of an element is defined as an index into the list of points. An index of 0 refers to the first point, index 1 refers to the second and so on. So first of all we shall write the list of points to the file in the correct format:
# Write the points file.write("POINTS %d float\n" % mesh.GetNumNodes()) for node in mesh.GetNodes(): file.write("%g %g %g\n" % (node.x, node.y, node.z))
The % operator is known as the string formatting or interpolation operator. It is important to understand how this works when writing data to files in ASCII format. Read the Python tutorial section 7.1 and Python library reference 3.6.2 for more information on this.
At this point, if you run the script it should create a valid VTK file that you can load into the free ParaView visualisation software. You may want to try this now to check that what you have done so far works correctly. Initially you will not see anything when loaded into ParaView because we have just defined points and nothing else. In order to visualise these points you must apply the Glyph filter. Assuming this works, let's continue and write the elements.
Defining the elements is a little more tricky because there are different types of elements. When meshing the yarns TexGen will use a mix of wedge and hexahedral elements, so we only need to deal with these element types. The CMesh class stores a long list of indices for each element type. For example, a mesh containing 2 wedge elements and 3 hex elements would contain a list of 12 indices for the wedges and a list of 24 for the hex elements. The first thing to do is to define some variables to contain this data:
wedgeIndices = list(mesh.GetIndices(CMesh.WEDGE)) hexIndices = list(mesh.GetIndices(CMesh.HEX)) numWedges = len(wedgeIndices)/6 numHexes = len(hexIndices)/8
Next we actually write the data to the file similarly to the way the points were written:
file.write("CELLS %d %d\n" % (numWedges+numHexes, numWedges*7+numHexes*9)) for i in range(numWedges): file.write("6 %d %d %d %d %d %d\n" % tuple(wedgeIndices[i*6:(i+1)*6])) for i in range(numHexes): file.write("8 %d %d %d %d %d %d %d %d\n" % tuple(hexIndices[i*8:(i+1)*8]))
Here I have made use of slicing (wedgeIndices[i*6:(i+1)*6]) to reduce the amount of code necessary to output the data. See the Python tutorial section 3.1.4 for information about how slicing works.
And finally we need to output the type of each of these elements:
file.write("CELL_TYPES %d\n" % (numWedges+numHexes)) for i in range(numWedges): file.write("13\n") for i in range(numHexes): file.write("12\n")
The VTK file format defines wedges to be of element type 13 and hexes to be of element type 12.
That's it, you should now have a script which reads a TexGen tg3 file, extracts a mesh from it and writes the contents to a file in the VTK legacy file format. Your Python script should look like this:
from TexGen.Core import * # Read in the textile ReadFromXML('textile.tg3') # Get a hold of the textile we just loaded in textile = GetTextile() # Create a mesh instance mesh = CMesh() # Add the volume of the textile to the mesh textile.AddVolumeToMesh(mesh, True) file = open("mesh.vtk", "w") # Write the header file.write("# vtk DataFile Version 2.0\n") file.write("Textile mesh data\n") file.write("ASCII\n") file.write("DATASET UNSTRUCTURED_GRID\n") # Write the points file.write("POINTS %d float\n" % mesh.GetNumNodes()) for node in mesh.GetNodes(): file.write("%g %g %g\n" % (node.x, node.y, node.z)) # Get element information from the mesh wedgeIndices = list(mesh.GetIndices(CMesh.WEDGE)) hexIndices = list(mesh.GetIndices(CMesh.HEX)) numWedges = len(wedgeIndices)/6 numHexes = len(hexIndices)/8 # Write the element information file.write("CELLS %d %d\n" % (numWedges+numHexes, numWedges*7+numHexes*9)) for i in range(numWedges): file.write("6 %d %d %d %d %d %d\n" % tuple(wedgeIndices[i*6:(i+1)*6])) for i in range(numHexes): file.write("8 %d %d %d %d %d %d %d %d\n" % tuple(hexIndices[i*8:(i+1)*8])) file.write("CELL_TYPES %d\n" % (numWedges+numHexes)) for i in range(numWedges): file.write("13\n") for i in range(numHexes): file.write("12\n")
Verification
The first thing to do now is to run the script from the command line like so:
python myscript.py
replacing myscript.py
with the name of the script your created and ensuring you have a textile model named textile.tg3
in the some folder as the script. If it ran successfully you should see a file named mesh.vtk
being created. Load this up into ParaView and you should see a mesh of your textile.
When writing your own scripts it is unlikely that they will work straight away (even for professional programmers), so it is a good idea to check the output of your script at each step with a text editor to ensure that it is writing exactly what you want. This will enable you to isolate bugs early on and one at a time rather than having to fix a long script containing numerous bugs. The print statement is your friend when it comes to debugging, it can be used to print out values and verify that they are what you expect.