1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 class ThreeDeeParseError(Exception):
27 3D model parser base class. Derrived classes are used for basic
28 analysis of 3D models, and are not intended to be used for 3D
32 def __init__(self
, fileob
):
34 self
.average
= [0, 0, 0]
35 self
.min = [None, None, None]
36 self
.max = [None, None, None]
37 self
.width
= 0 # x axis
38 self
.depth
= 0 # y axis
39 self
.height
= 0 # z axis
42 if not len(self
.verts
):
43 raise ThreeDeeParseError("Empty model.")
45 for vector
in self
.verts
:
48 self
.average
[i
] += num
59 self
.average
[i
]/=len(self
.verts
)
61 self
.width
= abs(self
.min[0] - self
.max[0])
62 self
.depth
= abs(self
.min[1] - self
.max[1])
63 self
.height
= abs(self
.min[2] - self
.max[2])
66 def load(self
, fileob
):
67 """Override this method in your subclass."""
71 class ObjModel(ThreeDee
):
73 Parser for textureless wavefront obj files. File format
74 reference: http://en.wikipedia.org/wiki/Wavefront_.obj_file
77 def __vector(self
, line
, expected
=3):
78 nums
= map(float, line
.strip().split(" ")[1:])
79 return tuple(nums
[:expected
])
81 def load(self
, fileob
):
84 self
.verts
.append(self
.__vector
(line
))
87 class BinaryStlModel(ThreeDee
):
89 Parser for ascii-encoded stl files. File format reference:
90 http://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL
93 def load(self
, fileob
):
94 fileob
.seek(80) # skip the header
95 count
= struct
.unpack("<I", fileob
.read(4))[0]
96 for i
in range(count
):
97 fileob
.read(12) # skip the normal vector
99 self
.verts
.append(struct
.unpack("<3f", fileob
.read(12)))
100 fileob
.read(2) # skip the attribute bytes
103 def auto_detect(fileob
, hint
):
105 Attempt to divine which parser to use to divine information about
106 the model / verify the file."""
108 if hint
== "obj" or not hint
:
110 return ObjModel(fileob
)
111 except ThreeDeeParseError
:
114 if hint
== "stl" or not hint
:
116 # HACK Ascii formatted stls are similar enough to obj
117 # files that we can just use the same parser for both.
118 # Isn't that something?
119 return ObjModel(fileob
)
120 except ThreeDeeParseError
:
125 # It is pretty important that the binary stl model loader
126 # is tried second, because its possible for it to parse
127 # total garbage from plaintext =)
128 return BinaryStlModel(fileob
)
129 except ThreeDeeParseError
:
134 raise ThreeDeeParseError("Could not successfully parse the model :(")