# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
import struct
class ThreeDeeParseError(Exception):
pass
class ThreeDee():
"""
3D model parser base class. Derrived classes are used for basic
analysis of 3D models, and are not intended to be used for 3D
rendering.
"""
def __init__(self, fileob):
self.verts = []
self.average = [0, 0, 0]
self.min = [None, None, None]
self.max = [None, None, None]
self.width = 0 # x axis
self.depth = 0 # y axis
self.height = 0 # z axis
self.load(fileob)
if not len(self.verts):
raise ThreeDeeParseError("Empty model.")
for vector in self.verts:
for i in range(3):
num = vector[i]
self.average[i] += num
if not self.min[i]:
self.min[i] = num
self.max[i] = num
else:
if self.min[i] > num:
self.min[i] = num
if self.max[i] < num:
self.max[i] = num
for i in range(3):
self.average[i]/=len(self.verts)
self.width = abs(self.min[0] - self.max[0])
self.depth = abs(self.min[1] - self.max[1])
self.height = abs(self.min[2] - self.max[2])
def load(self, fileob):
"""Override this method in your subclass."""
pass
class ObjModel(ThreeDee):
"""
Parser for textureless wavefront obj files. File format
reference: http://en.wikipedia.org/wiki/Wavefront_.obj_file
"""
def __vector(self, line, expected=3):
nums = map(float, line.strip().split(" ")[1:])
return tuple(nums[:expected])
def load(self, fileob):
for line in fileob:
line = line.strip()
if line[0] == "v":
self.verts.append(self.__vector(line))
class BinaryStlModel(ThreeDee):
"""
Parser for ascii-encoded stl files. File format reference:
http://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL
"""
def load(self, fileob):
fileob.seek(80) # skip the header
count = struct.unpack("