# ***** 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: asfamc.py,v 1.3 2005/02/06 22:24:27 mbaas Exp $
## \file asfamc.py
## Contains the ASFReader and AMCReader class.
import string
# ReaderBase
class ReaderBase:
"""Base class for the ASFReader and AMCReader classes.
A derived class must implement readXyz() method where Xyz is
the section name (the keyword in the file is ':xyz').
If such a read method is not implemented, the corresponding
section is ignored.
"""
def __init__(self, filename):
self.filename = filename
# A list of unprocessed tokens (strings)
self.tokenlist = []
# The last returned token (string)
self.lasttok = None
self.lastline = None
self.undoline = None
# The current line number
self.linenr = 0
# read
def read(self):
"""Read the entire file.
"""
self.fhandle = file(self.filename)
while 1:
try:
tok = self.token()
except StopIteration:
break
# Check if the keyword starts with ':' (a new section)
if tok[0]!=":":
raise SyntaxError, "Syntax error in line %d: Invalid keyword '%s'"%(self.linenr, tok)
# Read the current section...
# Determine the method name (only letters and digits allowed,
# everything else will be removed)
mn = tok[1:].capitalize()
methodname = ""
for c in mn:
if c not in string.ascii_letters and c not in string.digits:
continue
methodname += c
handler = getattr(self, "read"+methodname, None)
if handler!=None:
handler()
else:
try:
self.skipSection()
except:
break
# intToken
def intToken(self):
"""Return the next token which must be an int.
"""
tok = self.token()
try:
return int(tok)
except ValueError:
raise SyntaxError, "Syntax error in line %d: Integer expected, got '%s' instead"%(self.linenr, tok)
# floatToken
def floatToken(self):
"""Return the next token which must be a float.
"""
tok = self.token()
try:
return float(tok)
except ValueError:
raise SyntaxError, "Syntax error in line %d: Float expected, got '%s' instead"%(self.linenr, tok)
# token
def token(self):
"""Return the next token."""
# Are there still some tokens left? then just return the next one
if self.tokenlist!=[]:
tok = self.tokenlist[0]
self.lasttok = tok
self.tokenlist = self.tokenlist[1:]
return tok
# Read a new line
s = self.readLine()
self.createTokens(s)
return self.token()
# undoToken
def undoToken(self):
"""Put back the last token.
"""
self.tokenlist = [self.lasttok]+self.tokenlist
self.lasttok = None
# undoLine
def undoLine(self):
"""Put back the last line.
"""
self.undoline = self.lastline
self.lastline = None
self.tokenlist = []
# skipSection
def skipSection(self):
"""Read and ignore data until the next section is reached.
The next call of token() will result in a ':' keyword.
"""
while 1:
s = self.readLine().strip()
if s[0]==':':
self.createTokens(s)
return
# readLine
def readLine(self):
"""Return the next line containing data.
Empty lines and comments are skipped. If the end of the file
has been reached, a StopIteration exception is thrown.
The return value is the next line containing data (this will
never be an empty string).
"""
# Discard any remaining tokens
self.tokenlist = []
# Is there a line that was undone?
if self.undoline!=None:
self.lastline = self.undoline
self.undoline = None
return self.lastline
# Read the next line
while 1:
s = self.fhandle.readline()
self.linenr += 1
if s=="":
raise StopIteration
if s[0]!="#":
self.lastline = s
return s
# createTokens
def createTokens(self, s):
"""Populate the token list from the content of s.
"""
s = s.strip()
s = s.replace("(", " ")
s = s.replace(")", " ")
s = s.replace(",", " ")
a = s.split()
self.tokenlist = a
######################################################################
# ASFReader
class ASFReader(ReaderBase):
"""Read Acclaim Skeleton File Definition (ASF) files.
This class serves as base class for reading ASF files.
Derived classes may implement the following methods:
- onVersion(ver)
- onName(name)
- onUnits(units)
- onDocumentation(doc)
- onRoot(data)
- onBonedata(bones)
- onHierarchy(links)
"""
def __init__(self, filename):
ReaderBase.__init__(self, filename)
def onVersion(self, ver): pass
def onName(self, name): pass
def onUnits(self, units): pass
def onDocumentation(self, doc): pass
def onRoot(self, data): pass
def onBonedata(self, bones): pass
def onHierarchy(self, links): pass
# readVersion
def readVersion(self):
ver = self.floatToken()
self.onVersion(ver)
# readName
def readName(self):
name = self.token()
self.onName(name)
# readUnits
def readUnits(self):
units = {}
while 1:
s = self.readLine()
if s[0]==':':
self.undoLine()
self.onUnits(units)
return
a = s.strip().split()
# Get the argument
if len(a)>1:
val = a[1]
# Try to convert to float. If it doesn't work, use the string value
try:
val = float(val)
except ValueError:
pass
units[a[0]] = val
# readDocumentation
def readDocumentation(self):
lines = []
while 1:
s = self.readLine()
if s[0]==':':
self.undoLine()
doc = "\n".join(lines)
self.onDocumentation(doc)
return
lines += [s[:-1]]
# readRoot
def readRoot(self):
data = {}
while 1:
s = self.readLine()
if s[0]==':':
self.undoLine()
self.onRoot(data)
return
a = s.strip().split()
val = tuple(a[1:])
data[a[0]] = val
# readBonedata
def readBonedata(self):
bones = []
while 1:
stop = False
try:
# Get the next token
begintok = self.token()
except StopIteration:
stop = True
# Is it already the begin of the next section?
if begintok[0]==':':
self.undoToken()
stop = True
# End of file or next section? -> no more bone data
if stop:
self.onBonedata(bones)
return
if begintok!="begin":
raise SyntaxError, "Syntax error in line %d: 'begin' expected, got '%s'"%(self.linenr, begintok)
data = {}
while 1:
s = self.readLine().strip()
if s=='end':
break
a = s.strip().split()
# Check for 'limits' which is a special case as it might
# span several lines.
if a[0]=="limits":
if not data.has_key("dof"):
raise ValueError, "Line %d: 'dof' settings must appear before the 'limits' settings"%(self.linenr)
dof = data["dof"]
# Put back the line and use the token mechanism
self.undoLine()
# Read the 'limits' token
tok = self.token()
limits = []
for i in range(len(dof)):
minval = self.token()
maxval = self.token()
if minval.lower()!="-inf":
try:
minval = float(minval)
except ValueError:
raise SyntaxError, "Syntax error in line %d: Float or '-inf' expected, got '%s'"%(self.linenr, minval)
if maxval.lower()!="inf":
try:
maxval = float(maxval)
except ValueError:
raise SyntaxError, "Syntax error in line %d: Float or 'inf' expected, got '%s'"%(self.linenr, maxval)
limits.append((minval,maxval))
data["limits"] = limits
else:
val = tuple(a[1:])
data[a[0]] = val
bones.append(data)
# readHierarchy
def readHierarchy(self):
links = []
while 1:
stop = False
try:
# Get the next token
begintok = self.token()
except StopIteration:
stop = True
# Is it already the begin of the next section?
if begintok[0]==':':
self.undoToken()
stop = True
# End of file or next section? -> no more bone data
if stop:
self.onHierarchy(links)
return
if begintok!="begin":
raise SyntaxError, "Syntax error in line %d: 'begin' expected, got '%s'"%(self.linenr, begintok)
while 1:
s = self.readLine().strip()
if s=='end':
break
a = s.strip().split()
links.append((a[0], a[1:]))
# AMCReader
class AMCReader(ReaderBase):
"""Read Acclaim Motion Capture Data (AMC) files.
This class serves as base class for reading AMC files.
Derived classes have to implement the following method:
- onFrame(framenr, data)
"""
def __init__(self, filename):
ReaderBase.__init__(self, filename)
def onFrame(self, framenr, data):
pass
# print framenr, data
# read
def read(self):
self.fhandle = file(self.filename)
while 1:
try:
tok = self.token()
except StopIteration:
return
# Check if the keyword starts with ':'. If it does, ignore it
if tok[0]!=":":
self.undoToken()
break
# Read the motion data...
while 1:
try:
framenr = self.intToken()
except StopIteration:
return
data = []
while 1:
try:
s = self.readLine()
except StopIteration:
self.onFrame(framenr, data)
return
a = s.strip().split()
# Check if it was a frame number
try:
int(a[0])
self.undoLine()
self.onFrame(framenr, data)
break
except ValueError:
pass
bone = a[0]
values = map(lambda x: float(x), a[1:])
data.append((bone, values))
|