c186461391e4a27c758c3f917aed8bb6186c1fc8
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):
25 class ThreeDee(object):
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
):
85 self
.verts
.append(self
.__vector
(line
))
88 class BinaryStlModel(ThreeDee
):
90 Parser for ascii-encoded stl files. File format reference:
91 http://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL
94 def load(self
, fileob
):
95 fileob
.seek(80) # skip the header
96 count
= struct
.unpack("<I", fileob
.read(4))[0]
97 for i
in range(count
):
98 fileob
.read(12) # skip the normal vector
100 self
.verts
.append(struct
.unpack("<3f", fileob
.read(12)))
101 fileob
.read(2) # skip the attribute bytes
104 def auto_detect(fileob
, hint
):
106 Attempt to divine which parser to use to divine information about
107 the model / verify the file."""
109 if hint
== "obj" or not hint
:
111 return ObjModel(fileob
)
112 except ThreeDeeParseError
:
115 if hint
== "stl" or not hint
:
117 # HACK Ascii formatted stls are similar enough to obj
118 # files that we can just use the same parser for both.
119 # Isn't that something?
120 return ObjModel(fileob
)
121 except ThreeDeeParseError
:
128 # It is pretty important that the binary stl model loader
129 # is tried second, because its possible for it to parse
130 # total garbage from plaintext =)
131 return BinaryStlModel(fileob
)
132 except ThreeDeeParseError
:
137 raise ThreeDeeParseError("Could not successfully parse the model :(")