-
Notifications
You must be signed in to change notification settings - Fork 2
/
OpenSimImportGeometry.py
150 lines (130 loc) · 6.09 KB
/
OpenSimImportGeometry.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Addon Information
bl_info = {
"name": "Import an OpenSim geometry file",
"author": "Clay Anderson",
"location": "File > Import > OpenSim Geometry",
"description": "Imports an OpenSim geometry file",
"category": "OpenSim"}
import xml.dom.minidom
import bpy
from bpy.props import *
from bpy_extras.io_utils import ExportHelper, ImportHelper
# Operator for importing OpenSim geometry files
class IMPORT_OT_OpenSimGeometry(bpy.types.Operator, ImportHelper):
bl_idname = "import_scene.opensim_geometry"
bl_description = "Import an OpenSim geometry file"
bl_label = "Import OpenSim Geometry"
filename_ext = ".vtp"
filter_glob = StringProperty(default="*.vtp", options={'HIDDEN'})
filepath = StringProperty(name="File Path", description="Filepath used for importing OpenSim geometry.", maxlen=1024, default="")
# Open and parse the geometry file, then add the geometry as a mesh.
def execute(self, context):
# Open a debug file
#debugfilename = self.filepath + ".debug.txt"
#debugfile = open(debugfilename,'w')
#debugfile.write(debugfilename + "\n")
# Form the name of the geometry based on the file name.
filepathArray = self.filepath.split("\\")
filepathDepth = len(filepathArray)
filename = ""
if(filepathDepth>0):
filename = filepathArray[filepathDepth-1]
#debugfile.write("File path has a depth of " + str(filepathDepth) + ".\n")
#debugfile.write("Geometry file = " + filename + "\n")
filenameArray = filename.split(".")
if(len(filenameArray)==0):
return {'FINISHED'}
if(len(filenameArray[0])==0):
return {'FINISHED'}
geometryName = filenameArray[0]
# Parse the xml geometry file
dom = xml.dom.minidom.parse(self.filepath)
pieceElements = dom.documentElement.getElementsByTagName("Piece")
NumberOfPoints = pieceElements[0].getAttribute("NumberOfPoints")
NumberOfFaces = pieceElements[0].getAttribute("NumberOfPolys")
#debugfile.write("root name = " + dom.documentElement.tagName + "\n")
# Read the vertices
verts = []
pointsNodes = pieceElements[0].getElementsByTagName("Points")
np = len(pointsNodes)
#debugfile.write("Found " + str(np) + " Points node.\n")
if(np==1):
pointsDataNode = pointsNodes[0].getElementsByTagName("DataArray")
nd = len(pointsDataNode)
#debugfile.write("Found " + str(nd) + " DataArray node.\n")
if(nd==1):
# vertsStr is a string that needs to be parsed for the vertices
vertsStr = pointsDataNode[0].firstChild.data
vertsStrSplit = vertsStr.split()
nv = len(vertsStrSplit)
#debugfile.write("length of vertsStrSplit is " + str(nv) + "\n")
for i in range(0,nv,3):
x = float(vertsStrSplit[i])
z = float(vertsStrSplit[i+1])
y = -float(vertsStrSplit[i+2])
vertex = (x,y,z)
verts.append(vertex)
#debugfile.write(str(verts) + "\n")
# Read the faces (polygon connectivity)
polys = []
polysNodes = pieceElements[0].getElementsByTagName("Polys")
ny = len(polysNodes)
#debugfile.write("Found " + str(ny) + " Polys node.\n")
if(ny==1):
polysDataNodes = polysNodes[0].getElementsByTagName("DataArray")
nd = len(polysDataNodes)
#debugfile.write("Found " + str(nd) + " DataArray nodes in element Polys.\n")
for elemt in polysDataNodes:
name = elemt.getAttribute("Name")
if(name=="connectivity"):
poly = []
#debugfile.write("Found the connectivity DataArray.\n")
polysStr = elemt.firstChild.data
polysStrArray = polysStr.split("\n")
np = len(polysStrArray)
#debugfile.write("Found " + str(np) + " polygons.\n")
# Loop over the number of polygons
for i in range(0,np):
indexStrArray = polysStrArray[i].split()
nj = len(indexStrArray)
#debugfile.write("Found " + str(nj) + " indices in polygon " + str(i) + ".\n")
if(nj<3):
continue # The minimum number of vertices is in a polygon is 3
# Form the polygon as an array of integers
poly.clear()
for j in range(0,nj):
poly.append( int(indexStrArray[j]) )
# Append the polygon to the array of polygons
polys.append(tuple(poly))
#debugfile.write(str(polys) + "\n")
# Create the geometry
faces = [(0,1,2), (3,1,0)]
mesh = bpy.data.meshes.new(geometryName)
geometry = bpy.data.objects.new(geometryName,mesh)
geometry.location = context.scene.cursor_location
context.scene.objects.link(geometry)
mesh.from_pydata(verts,[],polys)
mesh.update(calc_edges=True)
# Cleanup
dom.unlink()
#debugfile.close
return {'FINISHED'}
# Create the file selector dialog.
# Once the file selector finishes, execute() is called.
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
# Function that specifies how the Operator behaves as a menu button.
def menu_func(self, context):
self.layout.operator(IMPORT_OT_OpenSimGeometry.bl_idname, text="OpenSim Geometry (.vtp)")
# Register the Operator
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_import.append(menu_func)
# Unregister the Operator
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_import.remove(menu_func)
# Entry point
if __name__ == "__main__":
register()