# ***** 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: cmds.py,v 1.12 2006/02/16 17:49:38 mbaas Exp $
## \file cmds.py
## Contains builtin and user defined commands.
# (this line separates the \file comment from the module docs)
"""Commands.
"""
import sys, os, os.path, types, string
import pluginmanager
import eventmanager
import events
from scene import getScene
import worldobject
import draw, drawtextgeom
import trimeshgeom
import polyhedrongeom
import group as group_module
import _core
from cgtypes import *
class NoImporter(Exception): pass
class NoExporter(Exception): pass
# TriMeshPolyAdapter
class TriMeshPolyAdapter:
"""Provides the PolyhedronGeom interface for a TriMeshGeom.
This is a preliminary class that's used in the convFaceVarToVar()
function so that TriMeshGeoms can be handled the same way than
PolyhedronGeoms.
Todo: This class should be stored somewhere else and probably be made
available as a true adapter that can be used with the protocols framework.
Todo: Most Component methods are still missing.
"""
def __init__(self, tm):
self.tm = tm
self.verts = tm.verts
self.verts_slot = tm.verts_slot
def slot(self, name):
return self.tm.slot(name)
def boundingBox(self):
return self.tm.boundingBox()
def drawGL(self):
self.tm.drawGL()
def uniformCount(self):
return self.tm.uniformCount()
def vertexCount(self):
return self.tm.vertexCount()
def varyingCount(self):
return self.tm.varyingCount()
def faceVaryingCount(self):
return self.tm.faceVaryingCount()
def faceVertexCount(self):
return self.tm.faceVertexCount()
def newVariable(self, name, storage, type, multiplicity=1, user_n=0):
self.tm.newVariable(name, storage, type, multiplicity, user_n)
def deleteVariable(self, name):
self.tm.deleteVariable(name)
def deleteAllVariables(self):
self.tm.deleteAllVariables()
def findVariable(self, name):
return self.tm.findVariable(name)
def iterVariables(self):
return self.tm.iterVariables()
def convert(self, targetgeom):
self.tm.convert(targetgeom)
def hasPolysWithHoles(self):
return False
def getNumPolys(self):
return self.tm.faces.size()
def getNumLoops(self, poly):
return 1
def getNumVerts(self, poly, loop):
return 3
def setNumPolys(self, num):
self.tm.faces.resize(num)
def setNumLoops(self, poly, num):
if num>1:
raise RuntimeError, "Triangles cannot have holes"
def getLoop(self, poly, loop):
if loop==0:
return self.tm.faces[poly]
else:
raise RuntimeError, "Triangles have no holes"
def setLoop(self, poly, loop, vloop):
if loop==0:
self.tm.faces[poly] = vloop
else:
raise RuntimeError, "Triangles cannot have holes"
def getPoly(self, poly):
return [self.tm.faces[poly]]
def setPoly(self, poly, polydef):
self.tm.faces[poly] = polydef[0]
def convFaceVarToVar(geom):
"""Convert all facevarying into varying.
All facevarying variables are converted into varying variables and
all facevertex variables into vertex variables.
This is done by splitting the vertices in the mesh.
The number of values (and the values themselves) of the facevarying
variables do not change, only the verts and varying/vertex variables
are modified.
geom can be either a TriMeshGeom or a PolyhedronGeom.
The return value is the new geom object (the original object is not
modified).
"""
if isinstance(geom, trimeshgeom.TriMeshGeom):
newgeom = trimeshgeom.TriMeshGeom()
newgeom.faces.resize(geom.faces.size())
geom.faces.copyValues(0, geom.faces.size(), newgeom.faces, 0)
workinggeom = TriMeshPolyAdapter(newgeom)
elif isinstance(geom, polyhedrongeom.PolyhedronGeom):
newgeom = polyhedrongeom.PolyhedronGeom()
newgeom.setNumPolys(geom.getNumPolys())
workinggeom = newgeom
# Copy the polygons (even though the indices have to be modified
# afterwards), so that the variables can be created
for i in range(geom.getNumPolys()):
poly = geom.getPoly(i)
newgeom.setPoly(i, poly)
else:
raise TypeError, "geom must be a TriMeshGeom or PolyhedronGeom"
# Allocate storage for the vertices
workinggeom.verts.resize(geom.faceVaryingCount())
# This is a list with (oldslot,newslot) tuples. This is later used to
# initialize the new varying/vertex slots.
varyingvars = [(geom.verts, newgeom.verts)]
# Create a copy of all variables...
for name,storage,type,mult in geom.iterVariables():
# facevarying/facevertex will be converted to varying/vertex
if storage==_core.VarStorage.FACEVARYING:
newstorage = _core.VarStorage.VARYING
elif storage==_core.VarStorage.FACEVERTEX:
newstorage = _core.VarStorage.VERTEX
else:
newstorage = storage
slot = geom.slot(name)
workinggeom.newVariable(name, newstorage, type, mult, slot.size())
newslot = workinggeom.slot(name)
# Original varying/vertex variables will be initialized later,
# everything else is just a copy.
if storage==_core.VarStorage.VARYING or storage==_core.VarStorage.VERTEX:
varyingvars.append((slot, newslot))
else:
slot.copyValues(0, slot.size(), newslot, 0)
# Initialize the varying/vertex variables and update the vertex indices
# in the faces...
vidx = 0
for i in range(workinggeom.getNumPolys()):
poly = workinggeom.getPoly(i)
# ids: Flattened version of poly (i.e. all vertex ids)
ids = []
# newpoly: New polygon with new indices (sequentially numbered)
newpoly = []
vidx2 = vidx
for loop in poly:
ids += loop
newpoly.append(range(vidx2, vidx2+len(loop)))
vidx2 += len(loop)
workinggeom.setPoly(i, newpoly)
for id in ids:
for slot,newslot in varyingvars:
newslot[vidx] = slot[id]
vidx += 1
return newgeom
def removeIsolatedVertices(tm):
print >>sys.stderr, 'Removing isolated vertices...'
newgeom = trimeshgeom.TriMeshGeom()
newgeom.faces.resize(len(tm.faces))
# Key: Old vertex index Value: New vertex index
vert_used = {}
# Index: New id Value: Old id
newverts = []
for i in range(len(tm.faces)):
ai,bi,ci = tm.faces[i]
if ai not in vert_used:
vert_used[ai] = len(newverts)
newverts.append(ai)
if bi not in vert_used:
vert_used[bi] = len(newverts)
newverts.append(bi)
if ci not in vert_used:
vert_used[ci] = len(newverts)
newverts.append(ci)
newgeom.faces[i] = (vert_used[ai], vert_used[bi], vert_used[ci])
newgeom.verts.resize(len(newverts))
# Set new vertices
for i in range(len(newverts)):
newgeom.verts[i] = tm.verts[newverts[i]]
# Copy remaining variables...
for name,storage,type,mult in tm.iterVariables():
if storage==_core.VarStorage.VARYING:
newgeom.newVariable(name, _core.VarStorage.VARYING, type, mult)
src = tm.slot(name)
dst = newgeom.slot(name)
for i in range(len(newverts)):
oldid = newverts[i]
dst[i] = src[oldid]
else:
src = tm.slot(name)
# Create slot
if storage==_core.VarStorage.USER:
newgeom.newVariable(name, _core.VarStorage.USER, type, mult, len(src))
else:
newgeom.newVariable(name, storage, type, mult)
dst = newgeom.slot(name)
# Copy slot
src.copyValues(0, len(src), dst, 0)
# for i in range(len(src)):
# dst[i] = src[i]
return newgeom
# extractUniform
def extractUniform(tm, varname, value):
"""Extract a uniform variable from a TriMesh.
The resulting mesh will only contain faces that have the
given value.
"""
print >>sys.stderr, 'Extracting variable "%s"...'%(varname)
var_slot = tm.slot(varname)
# A list representing the new faces.
# Each entry newfaces[i] represents face i of the new mesh
# The value newfaces[i] is the index of the old face
newfaces = []
# Determine the new faces...
for i in range(len(tm.faces)):
if var_slot[i]==value:
newfaces.append(i)
newgeom = trimeshgeom.TriMeshGeom()
newgeom.faces.resize(len(newfaces))
newgeom.verts.resize(len(tm.verts))
# Initialize new faces...
for i in range(len(newfaces)):
oldid = newfaces[i]
newgeom.faces[i] = tm.faces[oldid]
# Copy vertices...
tm.verts.copyValues(0, len(tm.verts), newgeom.verts, 0)
# for i in range(len(tm.verts)):
# newgeom.verts[i] = tm.verts[i]
# Copy remaining variables...
for name,storage,type,mult in tm.iterVariables():
if storage==_core.VarStorage.UNIFORM:
newgeom.newVariable(name, _core.VarStorage.UNIFORM, type, mult)
src = tm.slot(name)
dst = newgeom.slot(name)
for i in range(len(newfaces)):
oldid = newfaces[i]
dst[i] = src[oldid]
elif (storage==_core.VarStorage.FACEVARYING or
storage==_core.VarStorage.FACEVERTEX):
newgeom.newVariable(name, storage, type, mult)
src = tm.slot(name)
dst = newgeom.slot(name)
for i in range(len(newfaces)):
oldid = newfaces[i]
dst[3*i] = src[3*oldid]
dst[3*i+1] = src[3*oldid+1]
dst[3*i+2] = src[3*oldid+2]
else:
src = tm.slot(name)
# Create slot
if storage==_core.VarStorage.USER:
newgeom.newVariable(name, _core.VarStorage.USER, type, mult, len(src))
else:
newgeom.newVariable(name, storage, type, mult)
dst = newgeom.slot(name)
# Copy slot
src.copyValues(0, len(src), dst, 0)
# for i in range(len(src)):
# dst[i] = src[i]
return newgeom
def _mapID(id, attrid, attr, attr_lut, newverts):
"""Determine new vertex ID.
attr_lut is a dictionary that servers as attribute lookup table.
Key is the vertex ID and the value is another dictionary that
has the attribute ID as key and the new ID as value.
\param id Old vertex ID
\param attrid Attribute ID
\param attr Attribute value
\param attr_lut Attribute lookup table
\partam newverts
\return New vertex ID
"""
if id not in attr_lut:
attr_lut[id] = {}
newid_lut = attr_lut[id]
if attrid in newid_lut:
return newid_lut[attrid]
else:
newid = len(newverts)
newid_lut[attrid] = newid
newverts.append((id, attr))
return newid
def convMeshAttr(tm, attrname, attrfacesname=None):
"""Convert attribute type.
attrname is the name of the attribute that should be turned into
a "varying" attribute.
attrfacesnames is the name of the corresponding attribute
faces. This must be a uniform variable.
The result is a copy of tm where the attribute attrname is a
"varying" variable. This means each vertex has a unique attribute.
The result has the same number of faces than tm, but the number
of vertices is usally higher.
\param tm TriMeshGeom
\param attrname Attribute
\param attrsfacesnames Faces attribute
\return New TriMeshGeom
"""
if attrfacesname==None:
attrfacesname = attrname+"faces"
print >>sys.stderr, 'Converting "%s"/"%s" into "varying %s"...'%(attrname,attrfacesname,attrname)
newgeom = trimeshgeom.TriMeshGeom()
attrdesc = tm.findVariable(attrname)
attr_slot = tm.slot(attrname)
attrfaces_slot = tm.slot(attrfacesname)
attr_lut = {}
# A list of tuples (Old vertex ID, Attribute ID)
# An entry newverts[i] represents vertex i of the new mesh
newverts = []
newgeom.faces.resize(len(tm.faces))
# Check each face...
for i in range(len(tm.faces)):
ai,bi,ci = tm.faces[i]
attrai,attrbi,attrci = attrfaces_slot[i]
# Get the 3 attributes associated to the current face
attra = attr_slot[attrai]
attrb = attr_slot[attrbi]
attrc = attr_slot[attrci]
newai = _mapID(ai, attrai, attra, attr_lut, newverts)
# print "A: %d -> %d"%(ai,newai)
newbi = _mapID(bi, attrbi, attrb, attr_lut, newverts)
# print "B: %d -> %d"%(bi,newbi)
newci = _mapID(ci, attrci, attrc, attr_lut, newverts)
# print "C: %d -> %d"%(ci,newci)
newgeom.faces[i] = (newai,newbi,newci)
# Set the new vertices...
numnewverts = len(newverts)
newgeom.verts.resize(numnewverts)
newgeom.newVariable(attrname, _core.VarStorage.VARYING, attrdesc[2], attrdesc[3])
newattr_slot = newgeom.slot(attrname)
for i in range(numnewverts):
oldid,attr = newverts[i]
newgeom.verts[i] = tm.verts[oldid]
newattr_slot[i] = attr
# Copy remaining variables...
for name,storage,type,mult in tm.iterVariables():
if name==attrname or name==attrfacesname:
continue
if storage==_core.VarStorage.VARYING:
newgeom.newVariable(name, _core.VarStorage.VARYING, type, mult)
src = tm.slot(name)
dst = newgeom.slot(name)
for i in range(numnewverts):
oldid,attr = newverts[i]
dst[i] = src[oldid]
else:
src = tm.slot(name)
# Create slot
if storage==_core.VarStorage.USER:
newgeom.newVariable(name, _core.VarStorage.USER, type, mult, len(src))
else:
newgeom.newVariable(name, storage, type, mult)
dst = newgeom.slot(name)
# Copy slot
src.copyValues(0, len(src), dst, 0)
# for i in range(len(src)):
# dst[i] = src[i]
return newgeom
# fitCone
def fitCone(pos, obj):
"""Compute a cone that has its apex at pos and that includes obj.
The generated cone is the minimal cone that entirely contains the
bounding box of obj (which must be a WorldObject).
pos is the apex of the cone given in world coordinates.
The return value is a tuple (n,w) where n is the axis direction of the
cone and w is the (full) angle in radians.
"""
pos = vec3(pos)
W = obj.worldtransform
Winv = W.inverse()
p = Winv*pos
bb = obj.boundingBox()
a,b,c,d,e,f,g,h = _bbCorners(bb)
a = (a-p).normalize()
b = (b-p).normalize()
c = (c-p).normalize()
d = (d-p).normalize()
e = (e-p).normalize()
f = (f-p).normalize()
g = (g-p).normalize()
h = (h-p).normalize()
n1,w1 = _cone(a,h)
n2,w2 = _cone(b,g)
n3,w3 = _cone(c,f)
n4,w4 = _cone(d,e)
w = max(w1,w2,w3,w4)
if w1==w:
n = n1
elif w2==w:
n = n2
elif w3==w:
n = n3
else:
n = n4
n = W.getMat3()*n
return n,w
# _cone
def _cone(a,b):
"""Create a cone from two directions.
a and b are two normalized directions that point along the generated
cone on two opposite directions, i.e. the returned cone is the minmal
cone that has the 'rays' a and b on its surface.
The return value is a tuple (n,w) where n is the cone axis and w
the (full) angle in radians.
This is a helper function for the fitCone() function.
"""
n = (a+b).normalize()
w = a.angle(b)
return n,w
# _bbCorners
def _bbCorners(bb):
"""Return the eight corners of a bounding box.
bb is a BoundingBox object. The index of the returned points is
such that bit 0 determines if the point is minmal or maximal in x
direction. Bit 1 is the y direction and bit 2 the z
direction. This means point n is opposite to point (~n)&0x7.
This is a helper function for the fitCone() function.
"""
a,h = bb.getBounds()
b = vec3(h.x, a.y, a.z)
c = vec3(a.x, h.y, a.z)
d = vec3(h.x, h.y, a.z)
e = vec3(a.x, a.y, h.z)
f = vec3(h.x, a.y, h.z)
g = vec3(a.x, h.y, h.z)
return a,b,c,d,e,f,g,h
# delete
def delete(objs):
"""Delete objects from the scene.
Currently, this only works on WorldObjects...
"""
objs = worldObjects(objs)
for obj in objs:
obj.parent.removeChild(obj)
# convertToTriMesh
def convertToTriMesh(objs):
"""Convert one or more objects into triangle meshes.
"""
objs = worldObjects(objs)
for obj in objs:
tm = trimeshgeom.TriMeshGeom()
obj.geom.convert(tm)
obj.geom = tm
# convertToPolyhedron
def convertToPolyhedron(objs):
"""Convert one or more objects into polyhedron objects.
"""
objs = worldObjects(objs)
for obj in objs:
pg = polyhedrongeom.PolyhedronGeom()
obj.geom.convert(pg)
obj.geom = pg
# setupObjectNames
def setupObjectNames():
"""Create a string that can be executed to 'import' all scene names.
"""
res = ""
valid_chars = string.ascii_letters + "_" + string.digits
for obj in getScene().item("WorldRoot").iterChilds():
varname = ""
for c in obj.name:
if c not in valid_chars:
c = "_"
varname += c
if varname=="":
continue
if varname[0] in string.digits:
varname = "_"+varname[1:]
res += '%s = worldObject("%s")\n'%(varname, obj.name)
return res
# importDefaultPlugins
def importDefaultPlugins():
"""Import the default plugins.
The plugin files/directories specified by the CGKIT_PLUGIN_PATH
environment variable (if it exists) are imported.
The function already outputs error messages and returns a list
of plugin descriptors.
"""
s = os.environ.get("CGKIT_PLUGIN_PATH", "")
plugins = splitPaths(s)
descs = pluginmanager.importPlugins(plugins)
for desc in descs:
if desc.status!=pluginmanager.STATUS_OK:
sys.stderr.write(70*"-"+"\n")
sys.stderr.write('ERROR: Loading plugin "%s" failed:\n'%os.path.basename(desc.filename))
sys.stderr.write("\n"+desc.traceback)
sys.stderr.write(70*"-"+"\n")
return descs
# splitPaths
def splitPaths(paths):
"""Split a string containing paths into the individual paths.
The paths can either be separated by ':' or ';'. Windows drive
letters are maintained, even when ':' is used as separator.
Example:
\code
>>> splitPaths("&:c:\\shaders:c:\\more_shaders;")
['&', 'c:\\shaders', 'c:\\more_shaders']
\endcode
\param paths (\c str) Paths string
\return A list with individual path strings.
"""
a = paths.split(";")
chunks = []
for s in a:
if s!="":
chunks += s.split(":")
pathlist = []
while len(chunks)>0:
# Is this item only a path drive?
if len(chunks[0])==1 and chunks[0] in string.letters:
pathlist.append(":".join(chunks[:2]))
chunks = chunks[2:]
else:
pathlist.append(chunks[0])
chunks = chunks[1:]
return map(lambda x: x.strip(), pathlist)
# group
def group(*children, **keyargs):
"""Group several world objects together.
All non keyword arguments somehow refer to world objects that will
all be grouped together. An argument may either be a WorldObject,
the name of a world object or as a sequence of world objects or names.
The name of the new group may be given via the \a name keyword
argument.
The return value is the new Group object.
\param name (\c str) Name of the group
\param children The world objects or their names.
"""
# Check the key arguments
for k in keyargs:
if k not in ["name"]:
raise TypeError, "Unknown keyword argument: '%s'"%k
# "Flatten" the children list...
childs = []
for c in children:
if isinstance(c, types.StringTypes):
childs += [c]
else:
# Is c a sequence?
try:
childs += list(c)
except TypeError:
# obviously not...
childs += [c]
childs = map(worldObject, childs)
name = keyargs.get("name", "group")
grp = group_module.Group(name=name, childs=childs)
return grp
# ungroup
def ungroup(group):
"""Break up a group in its individual components.
\param group (\c WorldObject or str) Group object
"""
group = worldObject(group)
if group.geom!=None:
raise ValueError, 'Object "%s" is not a mere group. Remove the geometry before ungrouping.'%group.name
# Move the children up one level
newparent = group.parent
for child in list(group.iterChilds()):
link(child, newparent)
# Remove the group
newparent.removeChild(group)
# replaceMaterial
def replaceMaterial(name, newmat):
"""Iterate over all world objects and replace a material with a new one.
\param name (\c str) The name of an already assigned material
\param newmat (\c Material) The new material
"""
for obj in getScene().walkWorld():
# Check all materials...
for i in range(obj.getNumMaterials()):
mat = obj.getMaterial(i)
if mat==None:
continue
if mat.name==name:
obj.setMaterial(newmat, i)
# link
def link(childs, parent=None, relative=False):
"""Link all childs to parent.
The function modifies the name of a child object if there would
be a clash with an existing object under the new parent.
\param childs (\c list or WorldObject) A single WorldObject or a sequence of WorldObjects
\param parent (\c WorldObject) Parent object or None (=unlink)
\param relative (\c bool) If True the local child transform is not modified (i.e. it is interpreted as a relative position)
"""
# Check if childs is a sequence (other than a string)...
try:
len(childs)
if isinstance(childs, types.StringTypes):
is_sequence = False
else:
is_sequence = True
except:
is_sequence = False
if not is_sequence:
childs = [childs]
# No parent given? Then use the world root (=unlink)
if parent==None:
parent = getScene().worldRoot()
else:
parent = worldObject(parent)
# Relink all childs...
for child in childs:
child = worldObject(child)
oldparent = child.parent
if oldparent!=None:
oldparent.removeChild(child)
if not relative:
Lp1 = oldparent.worldtransform
Lp2 = parent.worldtransform
child.transform = Lp2.inverse()*Lp1*child.transform
child.name = parent.makeChildNameUnique(child.name)
parent.addChild(child)
# drawClear
def drawClear():
"""Clear all drawing objects."""
# Clear all markers and lines
try:
drw = getScene().worldObject("Global_Draw")
drw.clear()
except KeyError:
pass
# Clear all texts
try:
drw = getScene().worldObject("Global_DrawText")
drw.geom.clear()
except KeyError:
pass
# drawMarker
def drawMarker(pos, color=(1,1,1), size=1):
"""Draw a marker.
\param pos Marker position
\param color Marker color
\param size Marker size (radius)
"""
try:
drw = getScene().worldObject("Global_Draw")
except KeyError:
drw = draw.Draw(name="Global_Draw")
drw.marker(pos, color, size)
# drawLine
def drawLine(pos1, pos2, color=(1,1,1), size=1):
"""Draw a line.
\param pos1 First line point
\param pos2 Second line point
\param color Line color
\param size Line width
"""
try:
drw = getScene().worldObject("Global_Draw")
except KeyError:
drw = draw.Draw(name="Global_Draw")
drw.line(pos1, pos2, color, size)
# drawText
def drawText(pos, txt, font=None, color=(1,1,1)):
"""Draw a text string.
font can be one of the constants defined in GLUT:
- GLUT_BITMAP_8_BY_13
- GLUT_BITMAP_9_BY_15 (default)
- GLUT_BITMAP_TIMES_ROMAN_10
- GLUT_BITMAP_TIMES_ROMAN_24
- GLUT_BITMAP_HELVETICA_10
- GLUT_BITMAP_HELVETICA_12
- GLUT_BITMAP_HELVETICA_18
\param pos Text position (3D)
\param txt The actual text
\param font A GLUT font constant
\param color Text color
"""
try:
drw = getScene().worldObject("Global_DrawText")
except KeyError:
drw = worldobject.WorldObject(name="Global_DrawText")
drw.geom = drawtextgeom.DrawTextGeom()
drw.geom.addText(pos, txt, font, color)
# listWorld
def listWorld():
"""List the contents of the world as a tree.
"""
scn = getScene()
print "Root"
_listWorld(scn.worldRoot(), "")
def _listWorld(obj, lines):
"""Helper function for the listWorld() command."""
childs = list(obj.iterChilds())
idx = 0
for child in childs:
if child.geom!=None:
g = child.geom.__class__.__name__
else:
g = "-"
print "%s+---%s (%s/%s)"%(lines,child.name,child.__class__.__name__, g)
if idx<len(childs)-1:
childlines = lines+"| "
else:
childlines = lines+" "
_listWorld(child, childlines)
idx += 1
# load
def load(filename, **options):
"""Load a file.
This function loads the given file without deleting the scene,
so the contents of the file is appended to the current scene.
To be able to load the file there must be an appropriate import class
(protocol: "Import") available in the plugin manager. The class is
determined by examining the file extension. If no importer is
found a NoImporter exception is thrown.
Any exception generated in the importer is passed to the caller.
\param filename (\c str) File name
\param options Options that are passed to the import plugin
"""
# Extract the extension (without '.') and make it lower case
ext = os.path.splitext(filename)[1][1:].lower()
# Find the appropriate import plugin class by comparing the extension
for objdesc in pluginmanager.iterProtoObjects("Import"):
if ext in objdesc.object.extension():
break
else:
raise NoImporter('No import plugin found for extension "%s".'%ext)
if not os.path.exists(filename):
raise IOError('File "%s" does not exist.'%filename)
# Change into the directory of the given file
oldpath = os.getcwd()
dir = os.path.dirname(os.path.abspath(filename))
os.chdir(dir)
# Import the file
imp = objdesc.object()
try:
imp.importFile(os.path.basename(filename), **options)
except:
os.chdir(oldpath)
raise
# Change back to the previous directory
os.chdir(oldpath)
# save
def save(filename, **options):
"""Save the scene to a file.
This function saves the current scene.
To be able to save the scene there must be an appropriate export class
(protocol: "Export") available in the plugin manager. The class is
determined by examining the file extension. If no exporter is
found a NoExporter exception is thrown.
Any exception generated in the exporter is passed to the caller.
\param filename (\c str) File name
\param options Options that are passed to the export plugin
"""
# Extract the extension (without '.') and make it lower case
ext = os.path.splitext(filename)[1][1:].lower()
# Find the appropriate export plugin class by comparing the extension
for objdesc in pluginmanager.iterProtoObjects("Export"):
if ext in objdesc.object.extension():
break
else:
raise NoExporter('No export plugin found for extension "%s".'%ext)
# Change into the directory of the given file
oldpath = os.getcwd()
dir = os.path.dirname(os.path.abspath(filename))
os.chdir(dir)
# Export the file
exp = objdesc.object()
exp.exportFile(os.path.basename(filename), **options)
# Change back to the previous directory
os.chdir(oldpath)
# reset
def reset():
"""Reset an animation/simulation.
Reset effectively sets the time back to 0.
"""
eventmanager.eventManager().event(events.RESET)
# worldObjects
def worldObjects(objs):
"""Return a list of world objects.
\a objs can be a string, a world object or a sequence of strings or
world objects. A string always referes to the world object with that
name. The return value is always a list, even when only an individual
object was specified as input.
\param objs A sequence of strings/world objects or an individual string
or world object.
\return A list of WorldObject objects.
"""
if isinstance(objs, types.StringTypes):
objs = [objs]
try:
it = iter(objs)
except TypeError:
it = iter([objs])
res = []
for obj in it:
res.append(worldObject(obj))
return res
# worldObject
def worldObject(obj):
"""Return a world object.
If \a obj is a string, the function returns the world object with
that name. Otherwise \a obj is returned.
\param obj An object or the name of an object.
"""
if isinstance(obj, types.StringTypes):
return getScene().worldObject(obj)
else:
return obj
# register
def register(*cmds):
"""Register functions in the cmds module.
The given functions will be added to the cmds module.
\code
import cmds
def func1():
...
def func2(v):
...
cmds.register(func1, func2)
\endcode
"""
# Add the commands to the
namespace = globals()
for c in cmds:
namespace[c.__name__] = c
|