# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Python Computer Graphics Kit.
#
# The Initial Developer of the Original Code is Matthias Baas.
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
# $Id: stlimport.py,v 1.1 2005/01/09 20:13:06 mbaas Exp $
import os.path, sys, struct
from cgtypes import *
from trimesh import TriMesh
import pluginmanager
# STLReader
class STLReader:
def __init__(self, filename):
self.filename = filename
# read
def read(self):
if self.isASCII():
self.read_ascii()
else:
self.read_bin()
# read_bin
def read_bin(self):
"""Read a binary STL file.
"""
f = file(self.filename, "rb")
s = f.read(80)
objname = s.split("\000")[0]
s = f.read(4)
numfaces = struct.unpack("<i", s)[0]
self.begin(objname)
for i in range(numfaces):
s = f.read(50)
normal = vec3(struct.unpack("<fff", s[:12]))
v = struct.unpack("<fffffffff", s[12:48])
verts = [vec3(v[0:3]), vec3(v[3:6]), vec3(v[6:9])]
self.triangle(normal, verts)
self.end(objname)
# read_ascii
def read_ascii(self):
"""Read a ASCII STL file.
"""
f = file(self.filename)
objname = "unnamed"
normal = vec3()
verts = []
state = 0
linenr = 0
for s in f:
linenr+=1
a = s.split()
if len(a)==0:
continue
# Begin of file
if state==0:
if a[0]=="solid":
if len(a)>1:
objname = a[1]
self.begin(objname)
state = 1
else:
raise SyntaxError, 'Keyword "solid" expected in line %d'%linenr
# Begin of a triangle ("facet") or end of file ("endsolid")
elif state==1:
if a[0]=="facet":
if len(a)!=5 or a[1]!="normal":
raise SyntaxError, 'Syntax error in line %d'%linenr
normal = vec3(float(a[2]), float(a[3]), float(a[4]))
verts = []
state = 2
elif a[0]=="endsolid":
self.end(objname)
state = 0
else:
raise SyntaxError, 'Syntax error in line %d. Facet or end of solid expected.'%linenr
# "outer loop"
elif state==2:
if len(a)!=2 or a[0]!="outer" or a[1]!="loop":
raise SyntaxError, 'Keyword "outer loop" expected in line %d.'%linenr
state = 3
# A vertex definition
elif state==3:
if len(a)!=4 or a[0]!="vertex":
raise SyntaxError, 'Syntax error in line %d: Vertex expected'%linenr
v = vec3(float(a[1]), float(a[2]), float(a[3]))
verts.append(v)
if len(verts)==3:
state = 4
# "endloop"
elif state==4:
if a[0]!="endloop":
raise SyntaxError, 'Keyword "endloop" expected in line %d.'%linenr
state = 5
# "endfacet"
elif state==5:
if a[0]!="endfacet":
raise SyntaxError, 'Keyword "endfacet" expected in line %d.'%linenr
self.triangle(normal, verts)
state = 1
# isASCII
def isASCII(self):
f = file(self.filename)
s1 = f.readline().strip()
s2 = f.readline().strip()
f.close()
if s1[:5]!="solid":
return False
if s2[:5]!="facet":
return False
return True
# begin
def begin(self, name):
"""Solid begin callback.
This callback is called before the triangles are read.
"""
pass
# end
def end(self, name):
"""Solid begin callback.
This callback is called after the triangles were read.
"""
pass
# triangle
def triangle(self, normal, verts):
"""Triangle callback.
normal is the normal vector as vec3 and verts is a list with the
three vertices (vec3s).
"""
pass
# STLImport
class STLImport(STLReader):
def __init__(self, filename):
STLReader.__init__(self, filename)
self.verts = []
self.numfaces = 0
# begin
def begin(self, name):
pass
# end
def end(self, name):
faces = []
for i in range(self.numfaces):
faces.append(range(i*3, i*3+3))
TriMesh(name=name, verts=self.verts, faces=faces)
# triangle
def triangle(self, normal, verts):
"""Triangle callback.
normal is the normal vector as vec3 and verts is a list with the
three vertices (vec3s).
"""
self.numfaces += 1
self.verts += verts
# STLImporter
class STLImporter:
_protocols = ["Import"]
# extension
def extension():
"""Return the file extensions for this format."""
return ["stl"]
extension = staticmethod(extension)
# description
def description(self):
"""Return a short description for the file dialog."""
return "StereoLithography"
description = staticmethod(description)
# importFile
def importFile(self, filename):
"""Import a STL file."""
reader = STLImport(filename)
reader.read()
######################################################################
# Register the Importer class as a plugin class
pluginmanager.register(STLImporter)
|