Initial revision
This commit is contained in:
1
intern/python/modules/vrml/__init__.py
Normal file
1
intern/python/modules/vrml/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""The VRML import module"""
|
974
intern/python/modules/vrml/basenodes.py
Normal file
974
intern/python/modules/vrml/basenodes.py
Normal file
@@ -0,0 +1,974 @@
|
||||
from scenegraph import Prototype, NULL, sceneGraph, IS, Script, ExternalPrototype, ROUTE
|
||||
PROTO = Prototype
|
||||
EXTERNPROTO = ExternalPrototype
|
||||
|
||||
Anchor = Prototype( "Anchor",
|
||||
{
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'children':('children', 'MFNode', 1),
|
||||
'parameter':('parameter', 'MFString', 1),
|
||||
'url':('url', 'MFString', 1),
|
||||
'description':('description', 'SFString', 1),
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
},
|
||||
{
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'children':[],
|
||||
'parameter':[],
|
||||
'url':[],
|
||||
'description':'',
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
},
|
||||
{
|
||||
'addChildren':('addChildren', 'MFNode', 0),
|
||||
'removeChildren':('removeChildren', 'MFNode', 0),
|
||||
},
|
||||
)
|
||||
Appearance = Prototype( "Appearance",
|
||||
{
|
||||
'material':('material', 'SFNode', 1),
|
||||
'texture':('texture', 'SFNode', 1),
|
||||
'textureTransform':('textureTransform', 'SFNode', 1),
|
||||
},
|
||||
{
|
||||
'material':NULL,
|
||||
'texture':NULL,
|
||||
'textureTransform':NULL,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
AudioClip = Prototype( "AudioClip",
|
||||
{
|
||||
'pitch':('pitch', 'SFFloat', 1),
|
||||
'loop':('loop', 'SFBool', 1),
|
||||
'description':('description', 'SFString', 1),
|
||||
'stopTime':('stopTime', 'SFTime', 1),
|
||||
'startTime':('startTime', 'SFTime', 1),
|
||||
'url':('url', 'MFString', 1),
|
||||
},
|
||||
{
|
||||
'pitch':1.0,
|
||||
'loop':0,
|
||||
'description':'',
|
||||
'stopTime':0.0,
|
||||
'startTime':0.0,
|
||||
'url':[],
|
||||
},
|
||||
{
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'duration_changed':('duration_changed', 'SFTime', 1),
|
||||
},
|
||||
)
|
||||
Background = Prototype( "Background",
|
||||
{
|
||||
'groundAngle':('groundAngle', 'MFFloat', 1),
|
||||
'skyAngle':('skyAngle', 'MFFloat', 1),
|
||||
'frontUrl':('frontUrl', 'MFString', 1),
|
||||
'bottomUrl':('bottomUrl', 'MFString', 1),
|
||||
'groundColor':('groundColor', 'MFColor', 1),
|
||||
'backUrl':('backUrl', 'MFString', 1),
|
||||
'skyColor':('skyColor', 'MFColor', 1),
|
||||
'topUrl':('topUrl', 'MFString', 1),
|
||||
'rightUrl':('rightUrl', 'MFString', 1),
|
||||
'leftUrl':('leftUrl', 'MFString', 1),
|
||||
},
|
||||
{
|
||||
'groundAngle':[],
|
||||
'skyAngle':[],
|
||||
'frontUrl':[],
|
||||
'bottomUrl':[],
|
||||
'groundColor':[],
|
||||
'backUrl':[],
|
||||
'skyColor':[[0.0, 0.0, 0.0]],
|
||||
'topUrl':[],
|
||||
'rightUrl':[],
|
||||
'leftUrl':[],
|
||||
},
|
||||
{
|
||||
'isBound':('isBound', 'SFBool', 1),
|
||||
'set_bind':('set_bind', 'SFBool', 0),
|
||||
},
|
||||
)
|
||||
Billboard = Prototype( "Billboard",
|
||||
{
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'children':('children', 'MFNode', 1),
|
||||
'axisOfRotation':('axisOfRotation', 'SFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'children':[],
|
||||
'axisOfRotation':[0.0, 1.0, 0.0],
|
||||
},
|
||||
{
|
||||
'addChildren':('addChildren', 'MFNode', 0),
|
||||
'removeChildren':('removeChildren', 'MFNode', 0),
|
||||
},
|
||||
)
|
||||
Box = Prototype( "Box",
|
||||
{
|
||||
'size':('size', 'SFVec3f', 0),
|
||||
},
|
||||
{
|
||||
'size':[2.0, 2.0, 2.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Collision = Prototype( "Collision",
|
||||
{
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'children':('children', 'MFNode', 1),
|
||||
'collide':('collide', 'SFBool', 1),
|
||||
'proxy':('proxy', 'SFNode', 0),
|
||||
},
|
||||
{
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'children':[],
|
||||
'collide':1,
|
||||
'proxy':NULL,
|
||||
},
|
||||
{
|
||||
'addChildren':('addChildren', 'MFNode', 0),
|
||||
'removeChildren':('removeChildren', 'MFNode', 0),
|
||||
'collideTime':('collideTime', 'SFTime', 1),
|
||||
},
|
||||
)
|
||||
Color = Prototype( "Color",
|
||||
{
|
||||
'color':('color', 'MFColor', 1),
|
||||
},
|
||||
{
|
||||
'color':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
ColorInterpolator = Prototype( "ColorInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFColor', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'SFColor', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
Cone = Prototype( "Cone",
|
||||
{
|
||||
'bottomRadius':('bottomRadius', 'SFFloat', 0),
|
||||
'side':('side', 'SFBool', 0),
|
||||
'bottom':('bottom', 'SFBool', 0),
|
||||
'height':('height', 'SFFloat', 0),
|
||||
},
|
||||
{
|
||||
'bottomRadius':1.0,
|
||||
'side':1,
|
||||
'bottom':1,
|
||||
'height':2.0,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Coordinate = Prototype( "Coordinate",
|
||||
{
|
||||
'point':('point', 'MFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'point':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
CoordinateInterpolator = Prototype( "CoordinateInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'MFVec3f', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
Cylinder = Prototype( "Cylinder",
|
||||
{
|
||||
'bottom':('bottom', 'SFBool', 0),
|
||||
'side':('side', 'SFBool', 0),
|
||||
'radius':('radius', 'SFFloat', 0),
|
||||
'top':('top', 'SFBool', 0),
|
||||
'height':('height', 'SFFloat', 0),
|
||||
},
|
||||
{
|
||||
'bottom':1,
|
||||
'side':1,
|
||||
'radius':1.0,
|
||||
'top':1,
|
||||
'height':2.0,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
CylinderSensor = Prototype( "CylinderSensor",
|
||||
{
|
||||
'maxAngle':('maxAngle', 'SFFloat', 1),
|
||||
'autoOffset':('autoOffset', 'SFBool', 1),
|
||||
'minAngle':('minAngle', 'SFFloat', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
'offset':('offset', 'SFFloat', 1),
|
||||
'diskAngle':('diskAngle', 'SFFloat', 1),
|
||||
},
|
||||
{
|
||||
'maxAngle':-1.0,
|
||||
'autoOffset':1,
|
||||
'minAngle':0.0,
|
||||
'enabled':1,
|
||||
'offset':0.0,
|
||||
'diskAngle':0.262,
|
||||
},
|
||||
{
|
||||
'rotation_changed':('rotation_changed', 'SFRotation', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'trackPoint_changed':('trackPoint_changed', 'SFVec3f', 1),
|
||||
},
|
||||
)
|
||||
DirectionalLight = Prototype( "DirectionalLight",
|
||||
{
|
||||
'color':('color', 'SFColor', 1),
|
||||
'ambientIntensity':('ambientIntensity', 'SFFloat', 1),
|
||||
'intensity':('intensity', 'SFFloat', 1),
|
||||
'on':('on', 'SFBool', 1),
|
||||
'direction':('direction', 'SFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'color':[1.0, 1.0, 1.0],
|
||||
'ambientIntensity':0.0,
|
||||
'intensity':1.0,
|
||||
'on':1,
|
||||
'direction':[0.0, 0.0, -1.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
ElevationGrid = Prototype( "ElevationGrid",
|
||||
{
|
||||
'xSpacing':('xSpacing', 'SFFloat', 0),
|
||||
'zSpacing':('zSpacing', 'SFFloat', 0),
|
||||
'xDimension':('xDimension', 'SFInt32', 0),
|
||||
'colorPerVertex':('colorPerVertex', 'SFBool', 0),
|
||||
'height':('height', 'MFFloat', 0),
|
||||
'texCoord':('texCoord', 'SFNode', 1),
|
||||
'normalPerVertex':('normalPerVertex', 'SFBool', 0),
|
||||
'ccw':('ccw', 'SFBool', 0),
|
||||
'color':('color', 'SFNode', 1),
|
||||
'normal':('normal', 'SFNode', 1),
|
||||
'creaseAngle':('creaseAngle', 'SFFloat', 0),
|
||||
'solid':('solid', 'SFBool', 0),
|
||||
'zDimension':('zDimension', 'SFInt32', 0),
|
||||
},
|
||||
{
|
||||
'xSpacing':0.0,
|
||||
'zSpacing':0.0,
|
||||
'xDimension':0,
|
||||
'colorPerVertex':1,
|
||||
'height':[],
|
||||
'texCoord':NULL,
|
||||
'normalPerVertex':1,
|
||||
'ccw':1,
|
||||
'color':NULL,
|
||||
'normal':NULL,
|
||||
'creaseAngle':0.0,
|
||||
'solid':1,
|
||||
'zDimension':0,
|
||||
},
|
||||
{
|
||||
'set_height':('set_height', 'MFFloat', 0),
|
||||
},
|
||||
)
|
||||
Extrusion = Prototype( "Extrusion",
|
||||
{
|
||||
'endCap':('endCap', 'SFBool', 0),
|
||||
'scale':('scale', 'MFVec2f', 0),
|
||||
'ccw':('ccw', 'SFBool', 0),
|
||||
'crossSection':('crossSection', 'MFVec2f', 0),
|
||||
'solid':('solid', 'SFBool', 0),
|
||||
'convex':('convex', 'SFBool', 0),
|
||||
'creaseAngle':('creaseAngle', 'SFFloat', 0),
|
||||
'spine':('spine', 'MFVec3f', 0),
|
||||
'beginCap':('beginCap', 'SFBool', 0),
|
||||
'orientation':('orientation', 'MFRotation', 0),
|
||||
},
|
||||
{
|
||||
'endCap':1,
|
||||
'scale':[[1.0, 1.0]],
|
||||
'ccw':1,
|
||||
'crossSection':[[1.0, 1.0], [1.0, -1.0], [-1.0, -1.0], [-1.0, 1.0], [1.0, 1.0]],
|
||||
'solid':1,
|
||||
'convex':1,
|
||||
'creaseAngle':0.0,
|
||||
'spine':[[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
|
||||
'beginCap':1,
|
||||
'orientation':[[0.0, 0.0, 1.0, 0.0]],
|
||||
},
|
||||
{
|
||||
'set_scale':('set_scale', 'MFVec2f', 0),
|
||||
'set_spine':('set_spine', 'MFVec3f', 0),
|
||||
'set_orientation':('set_orientation', 'MFRotation', 0),
|
||||
'set_crossSection':('set_crossSection', 'MFVec2f', 0),
|
||||
},
|
||||
)
|
||||
Fog = Prototype( "Fog",
|
||||
{
|
||||
'fogType':('fogType', 'SFString', 1),
|
||||
'color':('color', 'SFColor', 1),
|
||||
'visibilityRange':('visibilityRange', 'SFFloat', 1),
|
||||
},
|
||||
{
|
||||
'fogType':'LINEAR',
|
||||
'color':[1.0, 1.0, 1.0],
|
||||
'visibilityRange':0.0,
|
||||
},
|
||||
{
|
||||
'isBound':('isBound', 'SFBool', 1),
|
||||
'set_bind':('set_bind', 'SFBool', 0),
|
||||
},
|
||||
)
|
||||
FontStyle = Prototype( "FontStyle",
|
||||
{
|
||||
'justify':('justify', 'MFString', 0),
|
||||
'leftToRight':('leftToRight', 'SFBool', 0),
|
||||
'spacing':('spacing', 'SFFloat', 0),
|
||||
'horizontal':('horizontal', 'SFBool', 0),
|
||||
'language':('language', 'SFString', 0),
|
||||
'topToBottom':('topToBottom', 'SFBool', 0),
|
||||
'size':('size', 'SFFloat', 0),
|
||||
'style':('style', 'SFString', 0),
|
||||
'family':('family', 'SFString', 0),
|
||||
},
|
||||
{
|
||||
'justify':['BEGIN'],
|
||||
'leftToRight':1,
|
||||
'spacing':1.0,
|
||||
'horizontal':1,
|
||||
'language':'',
|
||||
'topToBottom':1,
|
||||
'size':1.0,
|
||||
'style':'PLAIN',
|
||||
'family':'SERIF',
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Group = Prototype( "Group",
|
||||
{
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'children':('children', 'MFNode', 1),
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
},
|
||||
{
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'children':[],
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
},
|
||||
{
|
||||
'addChildren':('addChildren', 'MFNode', 0),
|
||||
'removeChildren':('removeChildren', 'MFNode', 0),
|
||||
},
|
||||
)
|
||||
ImageTexture = Prototype( "ImageTexture",
|
||||
{
|
||||
'repeatS':('repeatS', 'SFBool', 0),
|
||||
'url':('url', 'MFString', 1),
|
||||
'repeatT':('repeatT', 'SFBool', 0),
|
||||
},
|
||||
{
|
||||
'repeatS':1,
|
||||
'url':[],
|
||||
'repeatT':1,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
IndexedFaceSet = Prototype( "IndexedFaceSet",
|
||||
{
|
||||
'texCoordIndex':('texCoordIndex', 'MFInt32', 0),
|
||||
'normalIndex':('normalIndex', 'MFInt32', 0),
|
||||
'coordIndex':('coordIndex', 'MFInt32', 0),
|
||||
'convex':('convex', 'SFBool', 0),
|
||||
'texCoord':('texCoord', 'SFNode', 1),
|
||||
'normalPerVertex':('normalPerVertex', 'SFBool', 0),
|
||||
'coord':('coord', 'SFNode', 1),
|
||||
'ccw':('ccw', 'SFBool', 0),
|
||||
'color':('color', 'SFNode', 1),
|
||||
'normal':('normal', 'SFNode', 1),
|
||||
'creaseAngle':('creaseAngle', 'SFFloat', 0),
|
||||
'solid':('solid', 'SFBool', 0),
|
||||
'colorPerVertex':('colorPerVertex', 'SFBool', 0),
|
||||
'colorIndex':('colorIndex', 'MFInt32', 0),
|
||||
},
|
||||
{
|
||||
'texCoordIndex':[],
|
||||
'normalIndex':[],
|
||||
'coordIndex':[],
|
||||
'convex':1,
|
||||
'texCoord':NULL,
|
||||
'normalPerVertex':1,
|
||||
'coord':NULL,
|
||||
'ccw':1,
|
||||
'color':NULL,
|
||||
'normal':NULL,
|
||||
'creaseAngle':0.0,
|
||||
'solid':1,
|
||||
'colorPerVertex':1,
|
||||
'colorIndex':[],
|
||||
},
|
||||
{
|
||||
'set_normalIndex':('set_normalIndex', 'MFInt32', 0),
|
||||
'set_colorIndex':('set_colorIndex', 'MFInt32', 0),
|
||||
'set_texCoordIndex':('set_texCoordIndex', 'MFInt32', 0),
|
||||
'set_coordIndex':('set_coordIndex', 'MFInt32', 0),
|
||||
},
|
||||
)
|
||||
IndexedLineSet = Prototype( "IndexedLineSet",
|
||||
{
|
||||
'coordIndex':('coordIndex', 'MFInt32', 0),
|
||||
'coord':('coord', 'SFNode', 1),
|
||||
'colorIndex':('colorIndex', 'MFInt32', 0),
|
||||
'colorPerVertex':('colorPerVertex', 'SFBool', 0),
|
||||
'color':('color', 'SFNode', 1),
|
||||
},
|
||||
{
|
||||
'coordIndex':[],
|
||||
'coord':NULL,
|
||||
'colorIndex':[],
|
||||
'colorPerVertex':1,
|
||||
'color':NULL,
|
||||
},
|
||||
{
|
||||
'set_colorIndex':('set_colorIndex', 'MFInt32', 0),
|
||||
'set_coordIndex':('set_coordIndex', 'MFInt32', 0),
|
||||
},
|
||||
)
|
||||
Inline = Prototype( "Inline",
|
||||
{
|
||||
'url':('url', 'MFString', 1),
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
},
|
||||
{
|
||||
'url':[],
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
LOD = Prototype( "LOD",
|
||||
{
|
||||
'level':('level', 'MFNode', 1),
|
||||
'range':('range', 'MFFloat', 0),
|
||||
'center':('center', 'SFVec3f', 0),
|
||||
},
|
||||
{
|
||||
'level':[],
|
||||
'range':[],
|
||||
'center':[0.0, 0.0, 0.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Material = Prototype( "Material",
|
||||
{
|
||||
'emissiveColor':('emissiveColor', 'SFColor', 1),
|
||||
'transparency':('transparency', 'SFFloat', 1),
|
||||
'shininess':('shininess', 'SFFloat', 1),
|
||||
'diffuseColor':('diffuseColor', 'SFColor', 1),
|
||||
'ambientIntensity':('ambientIntensity', 'SFFloat', 1),
|
||||
'specularColor':('specularColor', 'SFColor', 1),
|
||||
},
|
||||
{
|
||||
'emissiveColor':[0.0, 0.0, 0.0],
|
||||
'transparency':0.0,
|
||||
'shininess':0.2,
|
||||
'diffuseColor':[0.8, 0.8, 0.8],
|
||||
'ambientIntensity':0.2,
|
||||
'specularColor':[0.0, 0.0, 0.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
MovieTexture = Prototype( "MovieTexture",
|
||||
{
|
||||
'loop':('loop', 'SFBool', 1),
|
||||
'speed':('speed', 'SFFloat', 1),
|
||||
'repeatT':('repeatT', 'SFBool', 0),
|
||||
'repeatS':('repeatS', 'SFBool', 0),
|
||||
'url':('url', 'MFString', 1),
|
||||
'startTime':('startTime', 'SFTime', 1),
|
||||
'stopTime':('stopTime', 'SFTime', 1),
|
||||
},
|
||||
{
|
||||
'loop':0,
|
||||
'speed':1.0,
|
||||
'repeatT':1,
|
||||
'repeatS':1,
|
||||
'url':[],
|
||||
'startTime':0.0,
|
||||
'stopTime':0.0,
|
||||
},
|
||||
{
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'duration_changed':('duration_changed', 'SFFloat', 1),
|
||||
},
|
||||
)
|
||||
NavigationInfo = Prototype( "NavigationInfo",
|
||||
{
|
||||
'avatarSize':('avatarSize', 'MFFloat', 1),
|
||||
'speed':('speed', 'SFFloat', 1),
|
||||
'headlight':('headlight', 'SFBool', 1),
|
||||
'visibilityLimit':('visibilityLimit', 'SFFloat', 1),
|
||||
'type':('type', 'MFString', 1),
|
||||
},
|
||||
{
|
||||
'avatarSize':[0.25, 1.6, 0.75],
|
||||
'speed':1.0,
|
||||
'headlight':1,
|
||||
'visibilityLimit':0.0,
|
||||
'type':['WALK'],
|
||||
},
|
||||
{
|
||||
'isBound':('isBound', 'SFBool', 1),
|
||||
'set_bind':('set_bind', 'SFBool', 0),
|
||||
},
|
||||
)
|
||||
Normal = Prototype( "Normal",
|
||||
{
|
||||
'vector':('vector', 'MFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'vector':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
NormalInterpolator = Prototype( "NormalInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'MFVec3f', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
OrientationInterpolator = Prototype( "OrientationInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFRotation', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'SFRotation', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
PixelTexture = Prototype( "PixelTexture",
|
||||
{
|
||||
'repeatS':('repeatS', 'SFBool', 0),
|
||||
'image':('image', 'SFImage', 1),
|
||||
'repeatT':('repeatT', 'SFBool', 0),
|
||||
},
|
||||
{
|
||||
'repeatS':1,
|
||||
'image':[0, 0, 0],
|
||||
'repeatT':1,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
PlaneSensor = Prototype( "PlaneSensor",
|
||||
{
|
||||
'offset':('offset', 'SFVec3f', 1),
|
||||
'autoOffset':('autoOffset', 'SFBool', 1),
|
||||
'minPosition':('minPosition', 'SFVec2f', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
'maxPosition':('maxPosition', 'SFVec2f', 1),
|
||||
},
|
||||
{
|
||||
'offset':[0.0, 0.0, 0.0],
|
||||
'autoOffset':1,
|
||||
'minPosition':[0.0, 0.0],
|
||||
'enabled':1,
|
||||
'maxPosition':[-1.0, -1.0],
|
||||
},
|
||||
{
|
||||
'translation_changed':('translation_changed', 'SFVec3f', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'trackPoint_changed':('trackPoint_changed', 'SFVec3f', 1),
|
||||
},
|
||||
)
|
||||
PointLight = Prototype( "PointLight",
|
||||
{
|
||||
'ambientIntensity':('ambientIntensity', 'SFFloat', 1),
|
||||
'color':('color', 'SFColor', 1),
|
||||
'location':('location', 'SFVec3f', 1),
|
||||
'radius':('radius', 'SFFloat', 1),
|
||||
'attenuation':('attenuation', 'SFVec3f', 1),
|
||||
'intensity':('intensity', 'SFFloat', 1),
|
||||
'on':('on', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'ambientIntensity':0.0,
|
||||
'color':[1.0, 1.0, 1.0],
|
||||
'location':[0.0, 0.0, 0.0],
|
||||
'radius':100.0,
|
||||
'attenuation':[1.0, 0.0, 0.0],
|
||||
'intensity':1.0,
|
||||
'on':1,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
PointSet = Prototype( "PointSet",
|
||||
{
|
||||
'coord':('coord', 'SFNode', 1),
|
||||
'color':('color', 'SFNode', 1),
|
||||
},
|
||||
{
|
||||
'coord':NULL,
|
||||
'color':NULL,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
PositionInterpolator = Prototype( "PositionInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'SFVec3f', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
ProximitySensor = Prototype( "ProximitySensor",
|
||||
{
|
||||
'size':('size', 'SFVec3f', 1),
|
||||
'center':('center', 'SFVec3f', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'size':[0.0, 0.0, 0.0],
|
||||
'center':[0.0, 0.0, 0.0],
|
||||
'enabled':1,
|
||||
},
|
||||
{
|
||||
'enterTime':('enterTime', 'SFTime', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'orientation_changed':('orientation_changed', 'SFRotation', 1),
|
||||
'exitTime':('exitTime', 'SFTime', 1),
|
||||
'position_changed':('position_changed', 'SFVec3f', 1),
|
||||
},
|
||||
)
|
||||
ScalarInterpolator = Prototype( "ScalarInterpolator",
|
||||
{
|
||||
'key':('key', 'MFFloat', 1),
|
||||
'keyValue':('keyValue', 'MFFloat', 1),
|
||||
},
|
||||
{
|
||||
'key':[],
|
||||
'keyValue':[],
|
||||
},
|
||||
{
|
||||
'value_changed':('value_changed', 'SFFloat', 1),
|
||||
'set_fraction':('set_fraction', 'SFFloat', 0),
|
||||
},
|
||||
)
|
||||
Shape = Prototype( "Shape",
|
||||
{
|
||||
'appearance':('appearance', 'SFNode', 1),
|
||||
'geometry':('geometry', 'SFNode', 1),
|
||||
},
|
||||
{
|
||||
'appearance':NULL,
|
||||
'geometry':NULL,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Sound = Prototype( "Sound",
|
||||
{
|
||||
'spatialize':('spatialize', 'SFBool', 0),
|
||||
'maxFront':('maxFront', 'SFFloat', 1),
|
||||
'minBack':('minBack', 'SFFloat', 1),
|
||||
'maxBack':('maxBack', 'SFFloat', 1),
|
||||
'minFront':('minFront', 'SFFloat', 1),
|
||||
'location':('location', 'SFVec3f', 1),
|
||||
'intensity':('intensity', 'SFFloat', 1),
|
||||
'direction':('direction', 'SFVec3f', 1),
|
||||
'source':('source', 'SFNode', 1),
|
||||
'priority':('priority', 'SFFloat', 1),
|
||||
},
|
||||
{
|
||||
'spatialize':1,
|
||||
'maxFront':10.0,
|
||||
'minBack':1.0,
|
||||
'maxBack':10.0,
|
||||
'minFront':1.0,
|
||||
'location':[0.0, 0.0, 0.0],
|
||||
'intensity':1.0,
|
||||
'direction':[0.0, 0.0, 1.0],
|
||||
'source':NULL,
|
||||
'priority':0.0,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Sphere = Prototype( "Sphere",
|
||||
{
|
||||
'radius':('radius', 'SFFloat', 0),
|
||||
},
|
||||
{
|
||||
'radius':1.0,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
SphereSensor = Prototype( "SphereSensor",
|
||||
{
|
||||
'offset':('offset', 'SFRotation', 1),
|
||||
'autoOffset':('autoOffset', 'SFBool', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'offset':[0.0, 1.0, 0.0, 0.0],
|
||||
'autoOffset':1,
|
||||
'enabled':1,
|
||||
},
|
||||
{
|
||||
'rotation_changed':('rotation_changed', 'SFRotation', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'trackPoint_changed':('trackPoint_changed', 'SFVec3f', 1),
|
||||
},
|
||||
)
|
||||
SpotLight = Prototype( "SpotLight",
|
||||
{
|
||||
'attenuation':('attenuation', 'SFVec3f', 1),
|
||||
'ambientIntensity':('ambientIntensity', 'SFFloat', 1),
|
||||
'cutOffAngle':('cutOffAngle', 'SFFloat', 1),
|
||||
'direction':('direction', 'SFVec3f', 1),
|
||||
'color':('color', 'SFColor', 1),
|
||||
'location':('location', 'SFVec3f', 1),
|
||||
'radius':('radius', 'SFFloat', 1),
|
||||
'intensity':('intensity', 'SFFloat', 1),
|
||||
'beamWidth':('beamWidth', 'SFFloat', 1),
|
||||
'on':('on', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'attenuation':[1.0, 0.0, 0.0],
|
||||
'ambientIntensity':0.0,
|
||||
'cutOffAngle':0.785398,
|
||||
'direction':[0.0, 0.0, -1.0],
|
||||
'color':[1.0, 1.0, 1.0],
|
||||
'location':[0.0, 0.0, 0.0],
|
||||
'radius':100.0,
|
||||
'intensity':1.0,
|
||||
'beamWidth':1.570796,
|
||||
'on':1,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Switch = Prototype( "Switch",
|
||||
{
|
||||
'choice':('choice', 'MFNode', 1),
|
||||
'whichChoice':('whichChoice', 'SFInt32', 1),
|
||||
},
|
||||
{
|
||||
'choice':[],
|
||||
'whichChoice':-1,
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
Text = Prototype( "Text",
|
||||
{
|
||||
'maxExtent':('maxExtent', 'SFFloat', 1),
|
||||
'string':('string', 'MFString', 1),
|
||||
'fontStyle':('fontStyle', 'SFNode', 1),
|
||||
'length':('length', 'MFFloat', 1),
|
||||
},
|
||||
{
|
||||
'maxExtent':0.0,
|
||||
'string':[],
|
||||
'fontStyle':NULL,
|
||||
'length':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
TextureCoordinate = Prototype( "TextureCoordinate",
|
||||
{
|
||||
'point':('point', 'MFVec2f', 1),
|
||||
},
|
||||
{
|
||||
'point':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
TextureTransform = Prototype( "TextureTransform",
|
||||
{
|
||||
'center':('center', 'SFVec2f', 1),
|
||||
'scale':('scale', 'SFVec2f', 1),
|
||||
'rotation':('rotation', 'SFFloat', 1),
|
||||
'translation':('translation', 'SFVec2f', 1),
|
||||
},
|
||||
{
|
||||
'center':[0.0, 0.0],
|
||||
'scale':[1.0, 1.0],
|
||||
'rotation':0.0,
|
||||
'translation':[0.0, 0.0],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
||||
TimeSensor = Prototype( "TimeSensor",
|
||||
{
|
||||
'loop':('loop', 'SFBool', 1),
|
||||
'cycleInterval':('cycleInterval', 'SFTime', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
'stopTime':('stopTime', 'SFTime', 1),
|
||||
'startTime':('startTime', 'SFTime', 1),
|
||||
},
|
||||
{
|
||||
'loop':0,
|
||||
'cycleInterval':1.0,
|
||||
'enabled':1,
|
||||
'stopTime':0.0,
|
||||
'startTime':0.0,
|
||||
},
|
||||
{
|
||||
'fraction_changed':('fraction_changed', 'SFFloat', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'time':('time', 'SFTime', 1),
|
||||
'cycleTime':('cycleTime', 'SFTime', 1),
|
||||
},
|
||||
)
|
||||
TouchSensor = Prototype( "TouchSensor",
|
||||
{
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'enabled':1,
|
||||
},
|
||||
{
|
||||
'hitNormal_changed':('hitNormal_changed', 'SFVec3f', 1),
|
||||
'hitPoint_changed':('hitPoint_changed', 'SFVec3f', 1),
|
||||
'touchTime':('touchTime', 'SFTime', 1),
|
||||
'hitTexCoord_changed':('hitTexCoord_changed', 'SFVec2f', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'isOver':('isOver', 'SFBool', 1),
|
||||
},
|
||||
)
|
||||
Transform = Prototype( "Transform",
|
||||
{
|
||||
'bboxSize':('bboxSize', 'SFVec3f', 0),
|
||||
'children':('children', 'MFNode', 1),
|
||||
'scaleOrientation':('scaleOrientation', 'SFRotation', 1),
|
||||
'rotation':('rotation', 'SFRotation', 1),
|
||||
'translation':('translation', 'SFVec3f', 1),
|
||||
'bboxCenter':('bboxCenter', 'SFVec3f', 0),
|
||||
'center':('center', 'SFVec3f', 1),
|
||||
'scale':('scale', 'SFVec3f', 1),
|
||||
},
|
||||
{
|
||||
'bboxSize':[-1.0, -1.0, -1.0],
|
||||
'children':[],
|
||||
'scaleOrientation':[0.0, 0.0, 1.0, 0.0],
|
||||
'rotation':[0.0, 0.0, 1.0, 0.0],
|
||||
'translation':[0.0, 0.0, 0.0],
|
||||
'bboxCenter':[0.0, 0.0, 0.0],
|
||||
'center':[0.0, 0.0, 0.0],
|
||||
'scale':[1.0, 1.0, 1.0],
|
||||
},
|
||||
{
|
||||
'addChildren':('addChildren', 'MFNode', 0),
|
||||
'removeChildren':('removeChildren', 'MFNode', 0),
|
||||
},
|
||||
)
|
||||
Viewpoint = Prototype( "Viewpoint",
|
||||
{
|
||||
'jump':('jump', 'SFBool', 1),
|
||||
'orientation':('orientation', 'SFRotation', 1),
|
||||
'fieldOfView':('fieldOfView', 'SFFloat', 1),
|
||||
'position':('position', 'SFVec3f', 1),
|
||||
'description':('description', 'SFString', 0),
|
||||
},
|
||||
{
|
||||
'jump':1,
|
||||
'orientation':[0.0, 0.0, 1.0, 0.0],
|
||||
'fieldOfView':0.785398,
|
||||
'position':[0.0, 0.0, 10.0],
|
||||
'description':'',
|
||||
},
|
||||
{
|
||||
'isBound':('isBound', 'SFBool', 1),
|
||||
'set_bind':('set_bind', 'SFBool', 0),
|
||||
'bindTime':('bindTime', 'SFTime', 1),
|
||||
},
|
||||
)
|
||||
VisibilitySensor = Prototype( "VisibilitySensor",
|
||||
{
|
||||
'size':('size', 'SFVec3f', 1),
|
||||
'center':('center', 'SFVec3f', 1),
|
||||
'enabled':('enabled', 'SFBool', 1),
|
||||
},
|
||||
{
|
||||
'size':[0.0, 0.0, 0.0],
|
||||
'center':[0.0, 0.0, 0.0],
|
||||
'enabled':1,
|
||||
},
|
||||
{
|
||||
'exitTime':('exitTime', 'SFTime', 1),
|
||||
'isActive':('isActive', 'SFBool', 1),
|
||||
'enterTime':('enterTime', 'SFTime', 1),
|
||||
},
|
||||
)
|
||||
WorldInfo = Prototype( "WorldInfo",
|
||||
{
|
||||
'title':('title', 'SFString', 0),
|
||||
'info':('info', 'MFString', 0),
|
||||
},
|
||||
{
|
||||
'title':'',
|
||||
'info':[],
|
||||
},
|
||||
{
|
||||
},
|
||||
)
|
310
intern/python/modules/vrml/fieldcoercian.py
Normal file
310
intern/python/modules/vrml/fieldcoercian.py
Normal file
@@ -0,0 +1,310 @@
|
||||
'''
|
||||
Field coercian routines.
|
||||
|
||||
To replace the field coercian routines, you must edit
|
||||
basenodes.py and node.py to import some other coercian
|
||||
routines. Basenodes.py is for use by the parser, node
|
||||
is used by each node as it checks the validity of its
|
||||
attributes.
|
||||
'''
|
||||
|
||||
import types, sys, string
|
||||
from utils import typeclasses, collapse
|
||||
|
||||
class FieldCoercian:
|
||||
'''
|
||||
A Field Coercian class allows for creating new behaviours
|
||||
when dealing with the conversion of fields to-and-from
|
||||
particular field types. This allows the programmer to
|
||||
use alternate representations of fields (such as matrix arrays)
|
||||
'''
|
||||
def SFString( self, someobj, targetType=types.StringType, targetName='SFString', convertfunc=str ):
|
||||
'''
|
||||
Allowable types:
|
||||
simple string -> unchanged
|
||||
instance ( an IS ) -> unchanged
|
||||
sequence of length == 1 where first element is a string -> returns first element
|
||||
sequence of length > 1 where all elements are strings -> returns string.join( someobj, '')
|
||||
'''
|
||||
t = type(someobj)
|
||||
if t is targetType:
|
||||
return someobj
|
||||
if t in typeclasses.SequenceTypes:
|
||||
if len( someobj) == 1 and type( someobj[0] ) is targetType:
|
||||
return someobj[0] #
|
||||
elif len(someobj) > 1:
|
||||
try:
|
||||
return string.join( someobj, '')
|
||||
except:
|
||||
pass # is not a sequence of strings...
|
||||
### if we get here, then an incorrect value was passed
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
|
||||
def MFString( self, someobj, targetType=types.StringType, targetName='SFString', convertfunc=str ):
|
||||
'''
|
||||
Allowable Types:
|
||||
simple string -> wrapped in a list
|
||||
instance (an IS ) -> unchanged
|
||||
sequence of strings (of any length) -> equivalent list returned
|
||||
'''
|
||||
t = type(someobj)
|
||||
if t is targetType: # a bare string...
|
||||
return [someobj]
|
||||
elif t in typeclasses.SequenceTypes: # is a sequence
|
||||
if not filter( lambda x, t=targetType: x is not t, map( type, someobj) ): # are all strings...
|
||||
if t is not types.ListType:
|
||||
return list( someobj )
|
||||
else:
|
||||
return someobj
|
||||
### if we get here, then an incorrect value was passed
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
|
||||
def SFBool( self, someobj, targetType=types.IntType, targetName='SFBool', convertfunc=int):
|
||||
'''
|
||||
Allowable Types:
|
||||
instance (an IS) -> unchanged
|
||||
Any object which is testable for truth/falsehood -> 1 or 0 respectively
|
||||
SFBool should always succeed
|
||||
'''
|
||||
if (type(someobj) in typeclasses.SequenceTypes):
|
||||
try:
|
||||
if hasattr( someobj[0], '__gi__'):
|
||||
return someobj[0]
|
||||
else:
|
||||
someobj = someobj[0]
|
||||
except IndexError: # is a null MFNode
|
||||
pass
|
||||
if someobj:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def SFNode( self, someobj, targetType=types.InstanceType, targetName='SFNode', convertfunc=None):
|
||||
'''
|
||||
Allowable Types:
|
||||
instance of a Node -> unchanged
|
||||
instance (an IS or USE) -> unchanged
|
||||
sequence of length == 1 where first element is as above -> return first element
|
||||
'''
|
||||
if hasattr( someobj, '__gi__'): # about the only test I have without requiring that elements inherit from Node
|
||||
return someobj
|
||||
elif (type(someobj) in typeclasses.SequenceTypes):
|
||||
try:
|
||||
if hasattr( someobj[0], '__gi__'):
|
||||
return someobj[0]
|
||||
except IndexError: # is a null MFNode
|
||||
pass
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
|
||||
def MFNode( self, someobj, targetType=types.InstanceType, targetName='MFNode', convertfunc=None):
|
||||
'''
|
||||
Allowable Types:
|
||||
instance (an IS) -> unchanged
|
||||
instance of a Node -> wrapped with a list
|
||||
sequence where all elements are nodes -> returned as list of same
|
||||
'''
|
||||
if hasattr( someobj, '__gi__') and someobj.__gi__ != "IS":
|
||||
# is this a bare SFNode? wrap with a list and return
|
||||
return [someobj]
|
||||
elif hasattr( someobj, "__gi__"): # is this an IS node
|
||||
return someobj
|
||||
elif type(someobj) in typeclasses.SequenceTypes:
|
||||
try:
|
||||
map( getattr, someobj, ['__gi__']*len(someobj) )
|
||||
# is this an IS node wrapped in a list?
|
||||
if len(someobj) == 1 and someobj[0].__gi__ == "IS":
|
||||
return someobj[0]
|
||||
# okay, assume is really nodes...
|
||||
if type(someobj) is types.ListType:
|
||||
return someobj
|
||||
else:
|
||||
return list(someobj)
|
||||
except AttributeError: # something isn't a node
|
||||
pass
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
|
||||
def SFNumber( self, someobj, targetType, targetName, convertfunc=int ):
|
||||
'''
|
||||
Allowable Types:
|
||||
bare number -> numerically coerced to correct type
|
||||
instance ( an IS ) -> unchanged
|
||||
sequence of length == 1 where first element is a string -> returns first element
|
||||
'''
|
||||
t = type(someobj)
|
||||
if t is targetType or t is types.InstanceType:
|
||||
return someobj
|
||||
elif t in typeclasses.NumericTypes:
|
||||
return convertfunc( someobj)
|
||||
elif t in typeclasses.SequenceTypes:
|
||||
if len( someobj) == 1 and type( someobj[0] ):
|
||||
return convertfunc( someobj[0] ) #
|
||||
### if we get here, then an incorrect value was passed
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
def MFInt32 ( self, someobject ):
|
||||
''' Convert value into a MFInt32 field value (preferably an array, otherwise a list of integers) '''
|
||||
t = type(someobject)
|
||||
value = None
|
||||
if t in typeclasses.SequenceTypes: # is a sequence
|
||||
try:
|
||||
value = map( int, someobject)
|
||||
except:
|
||||
try:
|
||||
value = map( int, collapse.collapse2_safe( someobject) )
|
||||
except:
|
||||
pass
|
||||
elif t in typeclasses.NumericTypes or t is types.StringType:
|
||||
value = [int(someobject)]
|
||||
if value is None:
|
||||
### if we get here, then an incorrect value was passed
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
return value
|
||||
SFImage = MFInt32
|
||||
def MFFloat( self, someobject ):
|
||||
''' Convert value into a MFFloat field value (preferably an array, otherwise a list of integers) '''
|
||||
t = type(someobject)
|
||||
value = None
|
||||
if t in typeclasses.SequenceTypes: # is a sequence
|
||||
try:
|
||||
value = map( float, someobject)
|
||||
except:
|
||||
try:
|
||||
value = map( float, collapse.collapse2_safe( someobject))
|
||||
except:
|
||||
pass
|
||||
elif t in typeclasses.NumericTypes or t is types.StringType:
|
||||
value = [float(someobj)]
|
||||
if value is None:
|
||||
### if we get here, then an incorrect value was passed
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
return value
|
||||
def SFVec3f (self, value):
|
||||
''' Create a new SFVec3f value from value '''
|
||||
t = type(value)
|
||||
try:
|
||||
value = x,y,z = map (float, value)
|
||||
except ValueError:
|
||||
try:
|
||||
value = (x,y,z) = map( float, value[0] )
|
||||
except (IndexError, ValueError):
|
||||
raise ValueError (''' Invalid value for field type SFVec3f: %s'''%(value))
|
||||
return value
|
||||
def SFRotation(self, value):
|
||||
''' Create a new SFRotation value from value '''
|
||||
t = type(value)
|
||||
try:
|
||||
value = x,y,z, a = map (float, value)
|
||||
except ValueError:
|
||||
try:
|
||||
value = (x,y,z, a) = map( float, value[0] )
|
||||
except (IndexError, ValueError):
|
||||
raise ValueError (''' Invalid value for field type SFRotation: %s'''%(value))
|
||||
# get the normalized vector for x,y,z
|
||||
## length = (x*x+y*y+z*z)**.5 or 0.0000
|
||||
## value = (x/length,y/length,z/length, a)
|
||||
return value
|
||||
def SFVec2f (self, value):
|
||||
''' Create a new SFVec3f value from value '''
|
||||
t = type(value)
|
||||
try:
|
||||
value = x,y = map (float, value)
|
||||
except ValueError:
|
||||
try:
|
||||
value = (x,y) = map( float, value[0] )
|
||||
except (IndexError, ValueError):
|
||||
raise ValueError (''' Invalid value for field type SFVec3f: %s'''%(value))
|
||||
return value
|
||||
def SFColor(self, value):
|
||||
''' Create a new SFVec3f value from value '''
|
||||
t = type(value)
|
||||
try:
|
||||
r,g,b = map (float, value)
|
||||
except ValueError:
|
||||
try:
|
||||
r,g,b = map( float, value[0] )
|
||||
except (IndexError, ValueError):
|
||||
raise ValueError (''' Invalid value for field type SFColor: %s'''%(value))
|
||||
r = max( (0.0, min((r,1.0))) )
|
||||
g = max( (0.0, min((g,1.0))) )
|
||||
b = max( (0.0, min((b,1.0))) )
|
||||
return value
|
||||
|
||||
def MFCompoundNumber( self, someobj, targetName='SFVec3f', convertfunc=float, type=type):
|
||||
'''
|
||||
Allowable Types:
|
||||
instance ( an IS ) -> unchanged
|
||||
# instance ( a matrix ) -> reshaped (eventually)
|
||||
list of lists, sub-sequences of proper length -> unchanged
|
||||
sequence of numeric types of proper length -> converted to list, diced
|
||||
'''
|
||||
## if targetName == 'SFColor':
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
converter = getattr( self, targetName )
|
||||
t = type( someobj)
|
||||
reporterror = 0
|
||||
if t is types.InstanceType:
|
||||
return someobj
|
||||
elif t in typeclasses.SequenceTypes:
|
||||
if not someobj:
|
||||
return []
|
||||
if type( someobj[0] ) is not types.StringType and type( someobj[0] ) in typeclasses.SequenceTypes:
|
||||
try:
|
||||
return map( converter, someobj )
|
||||
except ValueError:
|
||||
pass
|
||||
elif type( someobj[0] ) in typeclasses.NumericTypes or type( someobj[0] ) is types.StringType:
|
||||
# a single-level list?
|
||||
base = map( convertfunc, someobj )
|
||||
# if we get here, someobj is a list
|
||||
if targetName[-2:] == '2f': # vec2f
|
||||
tlen = 2
|
||||
elif targetName[-2:] == 'on': # rotation
|
||||
tlen = 4
|
||||
else:
|
||||
tlen = 3
|
||||
value = []
|
||||
while base:
|
||||
value.append( converter( base[:tlen]) )
|
||||
del base[:tlen]
|
||||
return value
|
||||
raise ValueError, """Attempted to set value for an %s field which is not compatible: %s"""%( targetName, `someobj` )
|
||||
def __call__( self, someobj, targetName):
|
||||
func, args = self.algomap[targetName]
|
||||
## try:
|
||||
## if targetName == 'SFInt32':
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
if hasattr( someobj, "__gi__") and someobj.__gi__ == "IS":
|
||||
return someobj
|
||||
else:
|
||||
return apply( func, (self, someobj)+args )
|
||||
## except TypeError:
|
||||
## print someobj, targetName
|
||||
## print func, args
|
||||
## raise
|
||||
|
||||
algomap = { \
|
||||
'SFString': (SFString, (types.StringType, 'SFString', str)), \
|
||||
'MFString': (MFString, (types.StringType, 'MFString', str)), \
|
||||
'SFInt32': (SFNumber, (types.IntType, 'SFInt32', int)), \
|
||||
'SFFloat': (SFNumber, (types.FloatType, 'SFFloat', float)), \
|
||||
'SFTime': (SFNumber, (types.FloatType, 'SFFloat', float)), \
|
||||
'SFColor': (SFColor, ()), \
|
||||
'SFVec2f': (SFVec2f, ()), \
|
||||
'SFVec3f': (SFVec3f, ()), \
|
||||
'SFNode': (SFNode, (types.InstanceType, 'SFNode', None)), \
|
||||
'SFBool': (SFBool, (types.IntType, 'SFBool', int)), \
|
||||
'SFNode': (SFNode, (types.InstanceType, 'SFNode', None)), \
|
||||
'MFInt32': (MFInt32, ()), \
|
||||
'SFImage': (MFInt32, ()), \
|
||||
'MFTime': (MFFloat, ()), \
|
||||
'MFFloat': (MFFloat, ()), \
|
||||
'MFColor': (MFCompoundNumber, ('SFColor', float)), \
|
||||
'MFVec2f': (MFCompoundNumber, ('SFVec2f', float)), \
|
||||
'MFVec3f': (MFCompoundNumber, ('SFVec3f', float)), \
|
||||
'SFRotation': (SFRotation, ()), \
|
||||
'MFRotation': (MFCompoundNumber, ('SFRotation', float)), \
|
||||
'MFNode': (MFNode, (types.InstanceType, 'MFNode', None)) \
|
||||
}
|
||||
|
||||
FIELDCOERCE = FieldCoercian ()
|
97
intern/python/modules/vrml/loader.py
Normal file
97
intern/python/modules/vrml/loader.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# The VRML loader
|
||||
# supports gzipped files
|
||||
#
|
||||
# TODO: better progress monitoring
|
||||
|
||||
import parser
|
||||
|
||||
def quiet(txt):
|
||||
pass
|
||||
|
||||
debug = quiet
|
||||
|
||||
def debug1(txt):
|
||||
print "Loader:", txt
|
||||
|
||||
g_last = 0
|
||||
|
||||
def getFileType(file):
|
||||
"returns the file type string from 'file'"
|
||||
file.seek(0)
|
||||
magic = file.readline()
|
||||
if magic[:3] == '\037\213\010':
|
||||
file.seek(0)
|
||||
return "gzip"
|
||||
elif magic[:10] == '#VRML V2.0':
|
||||
file.seek(0)
|
||||
return "vrml"
|
||||
else:
|
||||
file.seek(0)
|
||||
return ""
|
||||
|
||||
class Loader:
|
||||
def __init__(self, url, progress = None):
|
||||
self.url = url
|
||||
self.debug = debug
|
||||
self.fail = debug
|
||||
self.monitor = debug
|
||||
self.progress = progress
|
||||
self.nodes = 0 # number of nodes parsed
|
||||
|
||||
def getGzipFile(self, file):
|
||||
'''Return gzip file (only called when gzip type is recognised)'''
|
||||
# we now have the local filename and the headers
|
||||
# read the first few bytes, check for gzip magic number
|
||||
self.monitor( "gzip-encoded file... loading gzip library")
|
||||
try:
|
||||
import gzip
|
||||
file = gzip.open(file,"rb")
|
||||
return file
|
||||
except ImportError, value:
|
||||
self.fail("Gzip library unavailable, compressed file cannot be read")
|
||||
except:
|
||||
self.fail("Failed to open Gzip file")
|
||||
|
||||
return None
|
||||
|
||||
def load(self):
|
||||
self.debug("try: load file from %s" % self.url)
|
||||
url = self.url
|
||||
|
||||
# XXX
|
||||
try:
|
||||
file = open(url, 'rb')
|
||||
except IOError, val:
|
||||
self.debug("couldn't open file %s" % url)
|
||||
return None
|
||||
|
||||
if getFileType(file) == 'gzip':
|
||||
file.close()
|
||||
file = self.getGzipFile(url)
|
||||
try:
|
||||
data = file.read()
|
||||
except MemoryError, value:
|
||||
self.fail("Insufficient memory to load file as string", value)
|
||||
return None
|
||||
except IOError, value:
|
||||
self.fail("I/O Error while reading data from file %s "% url)
|
||||
p = parser.Parser(data)
|
||||
if self.progress:
|
||||
scenegraph = p.parse(self.progress)
|
||||
print "progress"
|
||||
else:
|
||||
scenegraph = p.parse()
|
||||
|
||||
self.nodes = p.progresscount # progress
|
||||
del p
|
||||
return scenegraph
|
||||
|
||||
|
||||
def load(url, progress = None):
|
||||
l = Loader(url, progress)
|
||||
return l.load()
|
||||
|
||||
def test(name = None):
|
||||
if not name:
|
||||
name = '/tmp/gna.wrl'
|
||||
return load(name)
|
426
intern/python/modules/vrml/parser.py
Normal file
426
intern/python/modules/vrml/parser.py
Normal file
@@ -0,0 +1,426 @@
|
||||
from TextTools import TextTools
|
||||
|
||||
from simpleparse import generator
|
||||
|
||||
import scenegraph as proto
|
||||
import strop as string
|
||||
|
||||
IMPORT_PARSE_TIME = 0.4
|
||||
PROGRESS_DEPTH = 5
|
||||
|
||||
class UnfinishedError(Exception):
|
||||
pass
|
||||
|
||||
class Parser:
|
||||
def __init__( self, data ):
|
||||
self.data = data
|
||||
self.position = 0
|
||||
self.result = proto.sceneGraph()
|
||||
self.finalised = None
|
||||
self.sceneGraphStack = [self.result]
|
||||
self.prototypeStack = []
|
||||
self.nodeStack = []
|
||||
self.fieldTypeStack = []
|
||||
self.readHeader()
|
||||
self.depth = 0
|
||||
self.progresscount = 0
|
||||
def _lines( self, index=None ):
|
||||
if index is None:
|
||||
index = self.position
|
||||
return TextTools.countlines (self.data[:index])
|
||||
def parse( self, progressCallback=None ):
|
||||
datalength = float( len( self.data ))
|
||||
while self.readNext():
|
||||
if progressCallback:
|
||||
if not progressCallback(IMPORT_PARSE_TIME * self.position/datalength ):
|
||||
raise UnfinishedError(
|
||||
"Did not complete parsing, cancelled by user. Stopped at line %s" %(self._lines())
|
||||
)
|
||||
if self.position < len( self.data ):
|
||||
raise UnfinishedError(
|
||||
'''Unable to complete parsing of file, stopped at line %s:\n%s...'''%(self._lines(), self.data[self.position:self.position+120])
|
||||
)
|
||||
return self.result
|
||||
def readHeader( self ):
|
||||
'''Read the file header'''
|
||||
success, tags, next = TextTools.tag( self.data, HEADERPARSER, self.position )
|
||||
if success:
|
||||
self.datalength = len( self.data )
|
||||
#print "header ok"
|
||||
return success
|
||||
else:
|
||||
try:
|
||||
self.decompress()
|
||||
success, tags, next = TextTools.tag( self.data, HEADERPARSER, self.position )
|
||||
self.datalength = len( self.data )
|
||||
return success
|
||||
except:
|
||||
raise ValueError( "Could not find VRML97 header in file!" )
|
||||
def readNext( self):
|
||||
'''Read the next root-level construct'''
|
||||
success, tags, next = TextTools.tag( self.data, ROOTITEMPARSER, self.position )
|
||||
## print 'readnext', success
|
||||
if self.position >= self.datalength:
|
||||
print 'reached file end'
|
||||
return None
|
||||
if success:
|
||||
# print ' successful parse'
|
||||
self.position = next
|
||||
map (self.rootItem_Item, tags )
|
||||
return success
|
||||
else:
|
||||
return None
|
||||
def rootItem (self, (type, start, stop, (item,))):
|
||||
''' Process a single root item '''
|
||||
self.rootItem_Item( item )
|
||||
def rootItem_Item( self, item ):
|
||||
result = self._dispatch(item)
|
||||
if result is not None:
|
||||
## print "non-null result"
|
||||
## print id( self.sceneGraphStack[-1] ), id(self.result )
|
||||
self.sceneGraphStack[-1].children.append( result )
|
||||
def _getString (self, (tag, start, stop, sublist)):
|
||||
''' Return the raw string for a given interval in the data '''
|
||||
return self.data [start: stop]
|
||||
|
||||
def _dispatch (self, (tag, left, right, sublist)):
|
||||
''' Dispatch to the appropriate processing function based on tag value '''
|
||||
## print "dispatch", tag
|
||||
self.depth += 1
|
||||
if self.depth < PROGRESS_DEPTH:
|
||||
self.progresscount += 1
|
||||
try:
|
||||
meth = getattr (self, tag)
|
||||
except AttributeError:
|
||||
raise AttributeError("Unknown parse tag '%s' found! Check the parser definition!" % (tag))
|
||||
ret = meth( (tag, left, right, sublist) )
|
||||
self.depth -= 1
|
||||
return ret
|
||||
|
||||
def Proto(self, (tag, start, stop, sublist)):
|
||||
''' Create a new prototype in the current sceneGraph '''
|
||||
# first entry is always ID
|
||||
ID = self._getString ( sublist [0])
|
||||
print "PROTO",ID
|
||||
newNode = proto.Prototype (ID)
|
||||
## print "\t",newNode
|
||||
setattr ( self.sceneGraphStack [-1].protoTypes, ID, newNode)
|
||||
self.prototypeStack.append( newNode )
|
||||
# process the rest of the entries with the given stack
|
||||
map ( self._dispatch, sublist [1:] )
|
||||
self.prototypeStack.pop( )
|
||||
def fieldDecl(self,(tag, left, right, (exposure, datatype, name, field))):
|
||||
''' Create a new field declaration for the current prototype'''
|
||||
# get the definition in recognizable format
|
||||
exposure = self._getString (exposure) == "exposedField"
|
||||
datatype = self._getString (datatype)
|
||||
name = self._getString (name)
|
||||
# get the vrml value for the field
|
||||
self.fieldTypeStack.append( datatype )
|
||||
field = self._dispatch (field)
|
||||
self.fieldTypeStack.pop( )
|
||||
self.prototypeStack[-1].addField ((name, datatype, exposure), field)
|
||||
def eventDecl(self,(tag, left, right, (direction, datatype, name))):
|
||||
# get the definition in recognizable format
|
||||
direction = self._getString (direction) == "eventOut"
|
||||
datatype = self._getString (datatype)
|
||||
name = self._getString (name)
|
||||
# get the vrml value for the field
|
||||
self.prototypeStack[-1].addEvent((name, datatype, direction))
|
||||
def decompress( self ):
|
||||
pass
|
||||
def ExternProto( self, (tag, start, stop, sublist)):
|
||||
''' Create a new external prototype from a tag list'''
|
||||
# first entry is always ID
|
||||
ID = self._getString ( sublist [0])
|
||||
newNode = proto.Prototype (ID)
|
||||
setattr ( self.sceneGraphStack [-1].protoTypes, ID, newNode)
|
||||
self.prototypeStack.append( newNode )
|
||||
# process the rest of the entries with the given stack
|
||||
map ( self._dispatch, sublist [1:] )
|
||||
self.prototypeStack.pop( )
|
||||
def ExtProtoURL( self, (tag, start, stop, sublist)):
|
||||
''' add the url to the external prototype '''
|
||||
## print sublist
|
||||
values = self.MFString( sublist )
|
||||
self.prototypeStack[-1].url = values
|
||||
return values
|
||||
def extFieldDecl(self, (tag, start, stop, (exposure, datatype, name))):
|
||||
''' An external field declaration, no default value '''
|
||||
# get the definition in recognizable format
|
||||
exposure = self._getString (exposure) == "exposedField"
|
||||
datatype = self._getString (datatype)
|
||||
name = self._getString (name)
|
||||
# get the vrml value for the field
|
||||
self.prototypeStack[-1].addField ((name, datatype, exposure))
|
||||
def ROUTE(self, (tag, start, stop, names )):
|
||||
''' Create a new route object, add the current sceneGraph '''
|
||||
names = map(self._getString, names)
|
||||
self.sceneGraphStack [-1].addRoute( names )
|
||||
def Node (self, (tag, start, stop, sublist)):
|
||||
''' Create new node, returning the value to the caller'''
|
||||
## print 'node'
|
||||
|
||||
if sublist[0][0] == 'name':
|
||||
name = self._getString ( sublist [0])
|
||||
ID = self._getString ( sublist [1])
|
||||
rest = sublist [2:]
|
||||
else:
|
||||
name = ""
|
||||
ID = self._getString ( sublist [0])
|
||||
rest = sublist [1:]
|
||||
try:
|
||||
prototype = getattr ( self.sceneGraphStack [-1].protoTypes, ID)
|
||||
except AttributeError:
|
||||
#raise NameError ('''Prototype %s used without declaration! %s:%s'''%(ID, start, stop) )
|
||||
print ('''### Prototype %s used without declaration! %s:%s'''%(ID, start, stop) )
|
||||
|
||||
return None
|
||||
newNode = prototype(name)
|
||||
if name:
|
||||
self.sceneGraphStack [-1].regDefName( name, newNode )
|
||||
self.nodeStack.append (newNode)
|
||||
map (self._dispatch, rest)
|
||||
self.nodeStack.pop ()
|
||||
## print 'node finished'
|
||||
return newNode
|
||||
def Attr(self, (tag, start, stop, (name, value))):
|
||||
''' An attribute of a node or script '''
|
||||
name = self._getString ( name )
|
||||
self.fieldTypeStack.append( self.nodeStack[-1].PROTO.getField( name ).type )
|
||||
value = self._dispatch( value )
|
||||
self.fieldTypeStack.pop()
|
||||
if hasattr( self.nodeStack[-1], "__setattr__" ):
|
||||
self.nodeStack[-1].__setattr__( name, value, raw=1 )
|
||||
else:
|
||||
# use slower coercing versions...
|
||||
setattr( self.nodeStack[-1], name, value )
|
||||
def Script( self, (tag, start, stop, sublist)):
|
||||
''' A script node (can be a root node)'''
|
||||
# what's the DEF name...
|
||||
if sublist and sublist[0][0] == 'name':
|
||||
name = self._getString ( sublist [0])
|
||||
rest = sublist [1:]
|
||||
else:
|
||||
name = ""
|
||||
rest = sublist
|
||||
# build the script node...
|
||||
newNode = proto.Script( name )
|
||||
# register with sceneGraph
|
||||
if name:
|
||||
self.sceneGraphStack [-1].regDefName( name, newNode )
|
||||
self.nodeStack.append (newNode)
|
||||
map( self._dispatch, rest )
|
||||
self.nodeStack.pop ()
|
||||
return newNode
|
||||
def ScriptEventDecl( self,(tag, left, right, sublist)):
|
||||
# get the definition in recognizable format
|
||||
direction, datatype, name = sublist[:3] # must have at least these...
|
||||
direction = self._getString (direction) == "eventOut"
|
||||
datatype = self._getString (datatype)
|
||||
name = self._getString (name)
|
||||
# get the vrml value for the field
|
||||
self.nodeStack[-1].PROTO.addEvent((name, datatype, direction))
|
||||
if sublist[3:]:
|
||||
# will this work???
|
||||
setattr( self.nodeStack[-1], name, self._dispatch( sublist[3] ) )
|
||||
def ScriptFieldDecl(self,(tag, left, right, (exposure, datatype, name, field))):
|
||||
''' Create a new field declaration for the current prototype'''
|
||||
# get the definition in recognizable format
|
||||
exposure = self._getString (exposure) == "exposedField"
|
||||
datatype = self._getString (datatype)
|
||||
name = self._getString (name)
|
||||
# get the vrml value for the field
|
||||
self.fieldTypeStack.append( datatype )
|
||||
field = self._dispatch (field)
|
||||
self.fieldTypeStack.pop( )
|
||||
self.nodeStack[-1].PROTO.addField ((name, datatype, exposure))
|
||||
setattr( self.nodeStack[-1], name, field )
|
||||
def SFNull(self, tup):
|
||||
''' Create a reference to the SFNull node '''
|
||||
## print 'hi'
|
||||
return proto.NULL
|
||||
def USE( self, (tag, start, stop, (nametuple,) )):
|
||||
''' Create a reference to an already defined node'''
|
||||
name = self._getString (nametuple)
|
||||
if self.depth < PROGRESS_DEPTH:
|
||||
self.progresscount += 1
|
||||
try:
|
||||
node = self.sceneGraphStack [-1].defNames [name]
|
||||
return node
|
||||
except KeyError:
|
||||
raise NameError ('''USE without DEF for node %s %s:%s'''%(name, start, stop))
|
||||
def IS(self, (tag, start, stop, (nametuple,))):
|
||||
''' Create a field reference '''
|
||||
name = self._getString (nametuple)
|
||||
if not self.prototypeStack [-1].getField (name):
|
||||
raise Exception (''' Attempt to create IS mapping of non-existent field %s %s:%s'''%(name, start, stop))
|
||||
return proto.IS(name)
|
||||
def Field( self, (tag, start, stop, sublist)):
|
||||
''' A field value (of any type) '''
|
||||
|
||||
if sublist and sublist[0][0] in ('USE','Script','Node','SFNull'):
|
||||
if self.fieldTypeStack[-1] == 'SFNode':
|
||||
return self._dispatch( sublist[0] )
|
||||
else:
|
||||
return map( self._dispatch, sublist )
|
||||
elif self.fieldTypeStack[-1] == 'MFNode':
|
||||
return []
|
||||
else:
|
||||
# is a simple data type...
|
||||
function = getattr( self, self.fieldTypeStack[-1] )
|
||||
try:
|
||||
return function( sublist )
|
||||
except ValueError:
|
||||
traceback.print_exc()
|
||||
print sublist
|
||||
raise
|
||||
|
||||
def SFBool( self, (tup,) ):
|
||||
'''Boolean, in Python tradition is either 0 or 1'''
|
||||
return self._getString(tup) == 'TRUE'
|
||||
def SFFloat( self, (x,) ):
|
||||
return string.atof( self._getString(x) )
|
||||
SFTime = SFFloat
|
||||
def SFInt32( self, (x,) ):
|
||||
return string.atoi( self._getString(x), 0 ) # allow for non-decimal numbers
|
||||
def SFVec3f( self, (x,y,z) ):
|
||||
return map( string.atof, map(self._getString, (x,y,z)) )
|
||||
def SFVec2f( self, (x,y) ):
|
||||
return map( string.atof, map(self._getString, (x,y)) )
|
||||
def SFColor( self, (r,g,b) ):
|
||||
return map( string.atof, map(self._getString, (r,g,b)) )
|
||||
def SFRotation( self, (x,y,z,a) ):
|
||||
return map( string.atof, map(self._getString, (x,y,z,a)) )
|
||||
|
||||
def MFInt32( self, tuples ):
|
||||
result = []
|
||||
# localisation
|
||||
atoi = string.atoi
|
||||
append = result.append
|
||||
data = self.data
|
||||
for tag, start, stop, children in tuples:
|
||||
append( atoi( data[start:stop], 0) )
|
||||
return result
|
||||
SFImage = MFInt32
|
||||
def MFFloat( self, tuples ):
|
||||
result = []
|
||||
# localisation
|
||||
atof = string.atof
|
||||
append = result.append
|
||||
data = self.data
|
||||
for tag, start, stop, children in tuples:
|
||||
append( atof( data[start:stop]) )
|
||||
return result
|
||||
MFTime = MFFloat
|
||||
def MFVec3f( self, tuples, length=3, typename='MFVec3f'):
|
||||
result = []
|
||||
# localisation
|
||||
atof = string.atof
|
||||
data = self.data
|
||||
while tuples:
|
||||
newobj = []
|
||||
for tag, start, stop, children in tuples[:length]:
|
||||
newobj.append( atof(data[start:stop] ))
|
||||
if len(newobj) != length:
|
||||
raise ValueError(
|
||||
'''Incorrect number of elements in %s field at line %s'''%(typename, self._lines(stop))
|
||||
)
|
||||
result.append( newobj )
|
||||
del tuples[:length]
|
||||
return result
|
||||
def MFVec2f( self, tuples):
|
||||
return self.MFVec3f( tuples, length=2, typename='MFVec2f')
|
||||
def MFRotation( self, tuples ):
|
||||
return self.MFVec3f( tuples, length=4, typename='MFRotation')
|
||||
def MFColor( self, tuples ):
|
||||
return self.MFVec3f( tuples, length=3, typename='MFColor')
|
||||
|
||||
def MFString( self, tuples ):
|
||||
bigresult = []
|
||||
for (tag, start, stop, sublist) in tuples:
|
||||
result = []
|
||||
for element in sublist:
|
||||
if element[0] == 'CHARNODBLQUOTE':
|
||||
result.append( self.data[element[1]:element[2]] )
|
||||
elif element[0] == 'ESCAPEDCHAR':
|
||||
result.append( self.data[element[1]+1:element[2]] )
|
||||
elif element[0] == 'SIMPLEBACKSLASH':
|
||||
result.append( '\\' )
|
||||
bigresult.append( string.join( result, "") )
|
||||
return bigresult
|
||||
## result = []
|
||||
## for tuple in tuples:
|
||||
## result.append( self.SFString( tuple) )
|
||||
## return result
|
||||
def SFString( self, tuples ):
|
||||
'''Return the (escaped) string as a simple Python string'''
|
||||
if tuples:
|
||||
(tag, start, stop, sublist) = tuples[0]
|
||||
if len( tuples ) > 1:
|
||||
print '''Warning: SFString field has more than one string value''', self.data[tuples[0][1]:tuples[-1][2]]
|
||||
result = []
|
||||
for element in sublist:
|
||||
if element[0] == 'CHARNODBLQUOTE':
|
||||
result.append( self.data[element[1]:element[2]] )
|
||||
elif element[0] == 'ESCAPEDCHAR':
|
||||
result.append( self.data[element[1]+1:element[2]] )
|
||||
elif element[0] == 'SIMPLEBACKSLASH':
|
||||
result.append( '\\' )
|
||||
return string.join( result, "")
|
||||
else:
|
||||
raise ValueError( "NULL SFString parsed???!!!" )
|
||||
def vrmlScene( self, (tag, start, stop, sublist)):
|
||||
'''A (prototype's) vrml sceneGraph'''
|
||||
newNode = proto.sceneGraph (root=self.sceneGraphStack [-1])
|
||||
self.sceneGraphStack.append (newNode)
|
||||
#print 'setting proto sceneGraph', `newNode`
|
||||
self.prototypeStack[-1].sceneGraph = newNode
|
||||
results = filter (None, map (self._dispatch, sublist))
|
||||
if results:
|
||||
# items which are not auto-magically inserted into their parent
|
||||
for result in results:
|
||||
newNode.children.append( result)
|
||||
self.sceneGraphStack.pop()
|
||||
|
||||
PARSERDECLARATION = r'''header := -[\n]*
|
||||
rootItem := ts,(Proto/ExternProto/ROUTE/('USE',ts,USE,ts)/Script/Node),ts
|
||||
vrmlScene := rootItem*
|
||||
Proto := 'PROTO',ts,nodegi,ts,'[',ts,(fieldDecl/eventDecl)*,']', ts, '{', ts, vrmlScene,ts, '}', ts
|
||||
fieldDecl := fieldExposure,ts,dataType,ts,name,ts,Field,ts
|
||||
fieldExposure := 'field'/'exposedField'
|
||||
dataType := 'SFBool'/'SFString'/'SFFloat'/'SFTime'/'SFVec3f'/'SFVec2f'/'SFRotation'/'SFInt32'/'SFImage'/'SFColor'/'SFNode'/'MFBool'/'MFString'/'MFFloat'/'MFTime'/'MFVec3f'/'MFVec2f'/'MFRotation'/'MFInt32'/'MFColor'/'MFNode'
|
||||
eventDecl := eventDirection, ts, dataType, ts, name, ts
|
||||
eventDirection := 'eventIn'/'eventOut'
|
||||
ExternProto := 'EXTERNPROTO',ts,nodegi,ts,'[',ts,(extFieldDecl/eventDecl)*,']', ts, ExtProtoURL
|
||||
extFieldDecl := fieldExposure,ts,dataType,ts,name,ts
|
||||
ExtProtoURL := '['?,(ts,SFString)*, ts, ']'?, ts # just an MFString by another name :)
|
||||
ROUTE := 'ROUTE',ts, name,'.',name, ts, 'TO', ts, name,'.',name, ts
|
||||
Node := ('DEF',ts,name,ts)?,nodegi,ts,'{',ts,(Proto/ExternProto/ROUTE/Attr)*,ts,'}', ts
|
||||
Script := ('DEF',ts,name,ts)?,'Script',ts,'{',ts,(ScriptFieldDecl/ScriptEventDecl/Proto/ExternProto/ROUTE/Attr)*,ts,'}', ts
|
||||
ScriptEventDecl := eventDirection, ts, dataType, ts, name, ts, ('IS', ts, IS,ts)?
|
||||
ScriptFieldDecl := fieldExposure,ts,dataType,ts,name,ts,(('IS', ts,IS,ts)/Field),ts
|
||||
SFNull := 'NULL', ts
|
||||
|
||||
# should really have an optimised way of declaring a different reporting name for the same production...
|
||||
USE := name
|
||||
IS := name
|
||||
nodegi := name
|
||||
Attr := name, ts, (('IS', ts,IS,ts)/Field), ts
|
||||
Field := ( '[',ts,((SFNumber/SFBool/SFString/('USE',ts,USE,ts)/Script/Node),ts)*, ']', ts )/((SFNumber/SFBool/SFNull/SFString/('USE',ts,USE,ts)/Script/Node),ts)+
|
||||
|
||||
name := -[][0-9{}\000-\020"'#,.\\ ], -[][{}\000-\020"'#,.\\ ]*
|
||||
SFNumber := [-+]*, ( ('0',[xX],[0-9]+) / ([0-9.]+,([eE],[-+0-9.]+)?))
|
||||
SFBool := 'TRUE'/'FALSE'
|
||||
SFString := '"',(CHARNODBLQUOTE/ESCAPEDCHAR/SIMPLEBACKSLASH)*,'"'
|
||||
CHARNODBLQUOTE := -[\134"]+
|
||||
SIMPLEBACKSLASH := '\134'
|
||||
ESCAPEDCHAR := '\\"'/'\134\134'
|
||||
<ts> := ( [ \011-\015,]+ / ('#',-'\012'*,'\n')+ )*
|
||||
'''
|
||||
|
||||
|
||||
PARSERTABLE = generator.buildParser( PARSERDECLARATION )
|
||||
HEADERPARSER = PARSERTABLE.parserbyname( "header" )
|
||||
ROOTITEMPARSER = PARSERTABLE.parserbyname( "rootItem" )
|
||||
|
833
intern/python/modules/vrml/scenegraph.py
Normal file
833
intern/python/modules/vrml/scenegraph.py
Normal file
@@ -0,0 +1,833 @@
|
||||
# VRML node prototype class (SGbuilder)
|
||||
# Wed Oct 31 16:18:35 CET 2001
|
||||
|
||||
'''Prototype2 -- VRML 97 sceneGraph/Node/Script/ROUTE/IS implementations'''
|
||||
import copy, types # extern
|
||||
import strop as string # builtin
|
||||
from utils import typeclasses, err, namespace # XXX
|
||||
## TODO: namespace must go
|
||||
|
||||
|
||||
class baseProto:
|
||||
def __vrmlStr__( self, **namedargs ):
|
||||
'''Generate a VRML 97-syntax string representing this Prototype
|
||||
**namedargs -- key:value
|
||||
passed arguments for the linearisation object
|
||||
see lineariser4.Lineariser
|
||||
'''
|
||||
import lineariser4
|
||||
lineariser = apply( lineariser4.Lineariser, (), namedargs )
|
||||
return apply( lineariser.linear, ( self, ), namedargs )
|
||||
|
||||
toString = __vrmlStr__
|
||||
# added stuff for linking support for target scenegraph
|
||||
def setTargetnode(self, node):
|
||||
self.__dict__['_targetnode'] = node
|
||||
def getTargetnode(self):
|
||||
try:
|
||||
return self.__dict__['_targetnode']
|
||||
except:
|
||||
return None
|
||||
|
||||
class Prototype(baseProto):
|
||||
''' A VRML 97 Prototype object
|
||||
|
||||
A Prototype is a callable object which produces Node instances
|
||||
the Node uses a pointer to its Prototype to provide much of the
|
||||
Node's standard functionality.
|
||||
|
||||
Prototype's are often stored in a sceneGraph's protoTypes namespace,
|
||||
where you can access them as sceneGraph.protoTypes.nodeGI . They are
|
||||
also commonly found in Nodes' PROTO attributes.
|
||||
|
||||
Attributes:
|
||||
__gi__ -- constant string "PROTO"
|
||||
nodeGI -- string gi
|
||||
The "generic identifier" of the node type, i.e. the name of the node
|
||||
fieldDictionary -- string name: (string name, string dataType, boolean exposed)
|
||||
defaultDictionary -- string name: object defaultValue
|
||||
Will be blank for EXTERNPROTO's and Script prototypes
|
||||
eventDictionary -- string name: (string name, string dataType, boolean eventOut)
|
||||
sceneGraph -- object sceneGraph
|
||||
MFNodeNames -- list of field name strings
|
||||
Allows for easy calculation of "children" nodes
|
||||
SFNodeNames -- list of field name strings
|
||||
Allows for easy calculation of "children" nodes
|
||||
'''
|
||||
__gi__ = "PROTO"
|
||||
def __init__(self, gi, fieldDict=None, defaultDict=None, eventDict=None, sGraph=None):
|
||||
'''
|
||||
gi -- string gi
|
||||
see attribute nodeGI
|
||||
fieldDict -- string name: (string name, string dataType, boolean exposed)
|
||||
see attribute fieldDictionary
|
||||
defaultDict -- string name: object defaultValue
|
||||
see attribute defaultDictionary
|
||||
eventDict -- string name: (string name, string dataType, boolean eventOut)
|
||||
see attribute eventDictionary
|
||||
sceneGraph -- object sceneGraph
|
||||
see attribute sceneGraph
|
||||
'''
|
||||
self.nodeGI = checkName( gi )
|
||||
self.fieldDictionary = {}
|
||||
self.defaultDictionary = {}
|
||||
self.eventDictionary = {}
|
||||
self.SFNodeNames = []
|
||||
self.MFNodeNames = []
|
||||
self.sceneGraph = sGraph
|
||||
|
||||
# setup the fields/events
|
||||
for definition in (fieldDict or {}).values():
|
||||
self.addField( definition, (defaultDict or {}).get( definition[0]))
|
||||
for definition in (eventDict or {}).values():
|
||||
self.addEvent( definition )
|
||||
|
||||
def getSceneGraph( self ):
|
||||
''' Retrieve the sceneGraph object (may be None object)
|
||||
see attribute sceneGraph'''
|
||||
return self.sceneGraph
|
||||
def setSceneGraph( self, sceneGraph ):
|
||||
''' Set the sceneGraph object (may be None object)
|
||||
see attribute sceneGraph'''
|
||||
self.sceneGraph = sceneGraph
|
||||
def getChildren(self, includeSceneGraph=None, includeDefaults=1, *args, **namedargs):
|
||||
''' Calculate the current children of the PROTO and return as a list of nodes
|
||||
if includeDefaults:
|
||||
include those default values which are node values
|
||||
if includeSceneGraph:
|
||||
include the sceneGraph object if it is not None
|
||||
|
||||
see attribute MFNodeNames
|
||||
see attribute SFNodeNames
|
||||
see attribute sceneGraph
|
||||
'''
|
||||
temp = []
|
||||
if includeDefaults:
|
||||
for attrname in self.SFNodeNames:
|
||||
try:
|
||||
temp.append( self.defaultDictionary[attrname] )
|
||||
except KeyError: # sceneGraph object is not copied...
|
||||
pass
|
||||
for attrname in self.MFNodeNames:
|
||||
try:
|
||||
temp[len(temp):] = self.defaultDictionary[attrname]
|
||||
except KeyError:
|
||||
pass
|
||||
if includeSceneGraph and self.sceneGraph:
|
||||
temp.append( self.getSceneGraph() )
|
||||
return temp
|
||||
def addField (self, definition, default = None):
|
||||
''' Add a single field definition to the Prototype
|
||||
definition -- (string name, string dataType, boolean exposed)
|
||||
default -- object defaultValue
|
||||
|
||||
see attribute fieldDictionary
|
||||
see attribute defaultDictionary
|
||||
'''
|
||||
if type (definition) == types.InstanceType:
|
||||
definition = definition.getDefinition()
|
||||
default = definition.getDefault ()
|
||||
self.removeField( definition[0] )
|
||||
self.fieldDictionary[definition [0]] = definition
|
||||
if default is not None:
|
||||
default = fieldcoercian.FieldCoercian()( default, definition[1] )
|
||||
self.defaultDictionary [definition [0]] = default
|
||||
if definition[1] == 'SFNode':
|
||||
self.SFNodeNames.append(definition[0])
|
||||
elif definition[1] == 'MFNode':
|
||||
self.MFNodeNames.append(definition[0])
|
||||
def removeField (self, key):
|
||||
''' Remove a single field from the Prototype
|
||||
key -- string fieldName
|
||||
The name of the field to remove
|
||||
'''
|
||||
if self.fieldDictionary.has_key (key):
|
||||
del self.fieldDictionary [key]
|
||||
if self.defaultDictionary.has_key (key):
|
||||
del self.defaultDictionary [key]
|
||||
for attribute in (self.SFNodeNames, self.MFNodeNames):
|
||||
while key in attribute:
|
||||
attribute.remove(key)
|
||||
def addEvent(self, definition):
|
||||
''' Add a single event definition to the Prototype
|
||||
definition -- (string name, string dataType, boolean eventOut)
|
||||
|
||||
see attribute eventDictionary
|
||||
'''
|
||||
if type (definition) == types.InstanceType:
|
||||
definition = definition.getDefinition()
|
||||
self.eventDictionary[definition [0]] = definition
|
||||
def removeEvent(self, key):
|
||||
''' Remove a single event from the Prototype
|
||||
key -- string eventName
|
||||
The name of the event to remove
|
||||
'''
|
||||
if self.eventDictionary.has_key (key):
|
||||
del self.eventDictionary [key]
|
||||
def getField( self, key ):
|
||||
'''Return a Field or Event object representing a given name
|
||||
key -- string name
|
||||
The name of the field or event to retrieve
|
||||
will attempt to match key, key[4:], and key [:-8]
|
||||
corresponding to key, set_key and key_changed
|
||||
|
||||
see class Field
|
||||
see class Event
|
||||
'''
|
||||
# print self.fieldDictionary, self.eventDictionary
|
||||
for tempkey in (key, key[4:], key[:-8]):
|
||||
if self.fieldDictionary.has_key( tempkey ):
|
||||
return Field( self.fieldDictionary[tempkey], self.defaultDictionary.get(tempkey) )
|
||||
elif self.eventDictionary.has_key( tempkey ):
|
||||
return Event( self.eventDictionary[tempkey] )
|
||||
raise AttributeError, key
|
||||
def getDefault( self, key ):
|
||||
'''Return the default value for the given field
|
||||
key -- string name
|
||||
The name of the field
|
||||
Will attempt to match key, key[4:], and key [:-8]
|
||||
corresponding to key, set_key and key_changed
|
||||
|
||||
see attribute defaultDictionary
|
||||
'''
|
||||
for key in (key, key[4:], key[:-8]):
|
||||
if self.defaultDictionary.has_key( key ):
|
||||
val = self.defaultDictionary[key]
|
||||
if type(val) in typeclasses.MutableTypes:
|
||||
val = copy.deepcopy( val )
|
||||
return val
|
||||
elif self.fieldDictionary.has_key( key ):
|
||||
'''We have the field, but we don't have a default, we are likely an EXTERNPROTO'''
|
||||
return None
|
||||
raise AttributeError, key
|
||||
def setDefault (self, key, value):
|
||||
'''Set the default value for the given field
|
||||
key -- string name
|
||||
The name of the field to set
|
||||
value -- object defaultValue
|
||||
The default value, will be checked for type and coerced if necessary
|
||||
'''
|
||||
field = self.getField (key)
|
||||
self.defaultDictionary [field.name]= field.coerce (value)
|
||||
def clone( self, children = 1, sceneGraph = 1 ):
|
||||
'''Return a copy of this Prototype
|
||||
children -- boolean
|
||||
if true, copy the children of the Prototype, otherwise include them
|
||||
sceneGraph -- boolean
|
||||
if true, copy the sceneGraph of the Prototype
|
||||
'''
|
||||
if sceneGraph:
|
||||
sceneGraph = self.sceneGraph
|
||||
else:
|
||||
sceneGraph = None
|
||||
# defaults should always be copied before modification, but this is still dangerous...
|
||||
defaultDictionary = self.defaultDictionary.copy()
|
||||
if not children:
|
||||
for attrname in self.SFNodeNames+self.MFNodeNames:
|
||||
try:
|
||||
del defaultDictionary[attrname]
|
||||
except KeyError: # sceneGraph object is not copied...
|
||||
pass
|
||||
# now make a copy
|
||||
if self.__gi__ == "PROTO":
|
||||
newNode = self.__class__(
|
||||
self.nodeGI,
|
||||
self.fieldDictionary,
|
||||
defaultDictionary,
|
||||
self.eventDictionary,
|
||||
sceneGraph,
|
||||
)
|
||||
else:
|
||||
newNode = self.__class__(
|
||||
self.nodeGI,
|
||||
self.url,
|
||||
self.fieldDictionary,
|
||||
self.eventDictionary,
|
||||
)
|
||||
return newNode
|
||||
def __call__(self, *args, **namedargs):
|
||||
'''Create a new Node instance associated with this Prototype
|
||||
*args, **namedargs -- passed to the Node.__init__
|
||||
see class Node
|
||||
'''
|
||||
node = apply( Node, (self, )+args, namedargs )
|
||||
return node
|
||||
def __repr__ ( self ):
|
||||
'''Create a simple Python representation'''
|
||||
return '''%s( %s )'''%( self.__class__.__name__, self.nodeGI )
|
||||
|
||||
class ExternalPrototype( Prototype ):
|
||||
'''Sub-class of Prototype
|
||||
|
||||
The ExternalPrototype is a minor sub-classing of the Prototype
|
||||
it does not have any defaults, nor a sceneGraph
|
||||
|
||||
Attributes:
|
||||
__gi__ -- constant string "EXTERNPROTO"
|
||||
url -- string list urls
|
||||
implementation source for the ExternalPrototype
|
||||
'''
|
||||
__gi__ = "EXTERNPROTO"
|
||||
def __init__(self, gi, url=None, fieldDict=None, eventDict=None):
|
||||
'''
|
||||
gi -- string gi
|
||||
see attribute nodeGI
|
||||
url -- string list url
|
||||
MFString-compatible list of url's for EXTERNPROTO
|
||||
fieldDict -- string name: (string name, string dataType, boolean exposed)
|
||||
see attribute fieldDictionary
|
||||
eventDict -- string name: (string name, string dataType, boolean eventOut)
|
||||
see attribute eventDictionary
|
||||
'''
|
||||
if url is None:
|
||||
url = []
|
||||
self.url = url
|
||||
Prototype.__init__( self, gi, fieldDict=fieldDict, eventDict=eventDict)
|
||||
|
||||
|
||||
from vrml import fieldcoercian # XXX
|
||||
class Field:
|
||||
''' Representation of a Prototype Field
|
||||
The Field object is a simple wrapper to provide convenient
|
||||
access to field coercian and meta- information
|
||||
'''
|
||||
def __init__( self, specification, default=None ):
|
||||
self.name, self.type, self.exposure = specification
|
||||
self.default = default
|
||||
def getDefinition (self):
|
||||
return self.name, self.type, self.exposure
|
||||
def getDefault (self):
|
||||
return self.default
|
||||
def coerce( self, value ):
|
||||
''' Coerce value to the appropriate dataType for this Field '''
|
||||
return fieldcoercian.FieldCoercian()( value,self.type, )
|
||||
def __repr__( self ):
|
||||
if hasattr (self, "default"):
|
||||
return '%s( (%s,%s,%s), %s)'%( self.__class__.__name__, self.name, self.type, self.exposure, self.default)
|
||||
else:
|
||||
return '%s( (%s,%s,%s),)'%( self.__class__.__name__, self.name, self.type, self.exposure)
|
||||
def __str__( self ):
|
||||
if self.exposure:
|
||||
exposed = "exposedField"
|
||||
else:
|
||||
exposed = field
|
||||
if hasattr (self, "default"):
|
||||
default = ' ' + str( self.default)
|
||||
else:
|
||||
default = ""
|
||||
return '%s %s %s%s'%(exposed, self.type, self.name, default)
|
||||
|
||||
class Event (Field):
|
||||
def __str__( self ):
|
||||
if self.exposure:
|
||||
exposed = "eventOut"
|
||||
else:
|
||||
exposed = "eventIn"
|
||||
return '%s %s %s'%(exposed, self.type, self.name)
|
||||
|
||||
|
||||
### Translation strings for VRML node names...
|
||||
translationstring = '''][0123456789{}"'#,.\\ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023'''
|
||||
NAMEFIRSTCHARTRANSLATOR = string.maketrans( translationstring, '_'*len(translationstring) )
|
||||
translationstring = '''][{}"'#,.\\ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023'''
|
||||
NAMERESTCHARTRANSLATOR = string.maketrans( translationstring, '_'*len(translationstring) )
|
||||
del translationstring
|
||||
def checkName( name ):
|
||||
'''Convert arbitrary string to a valid VRML id'''
|
||||
if type(name) is types.StringType:
|
||||
if not name:
|
||||
return name
|
||||
return string.translate( name[:1], NAMEFIRSTCHARTRANSLATOR) + string.translate( name[1:], NAMERESTCHARTRANSLATOR)
|
||||
else:
|
||||
raise TypeError, "VRML Node Name must be a string, was a %s: %s"%(type(name), name)
|
||||
|
||||
class Node(baseProto):
|
||||
''' A VRML 97 Node object
|
||||
|
||||
A Node object represents a VRML 97 node. Attributes of the Node
|
||||
can be set/retrieved with standard python setattr/getattr syntax.
|
||||
VRML 97 attributes may be passed to the constructor as named
|
||||
arguments.
|
||||
|
||||
Attributes:
|
||||
__gi__ -- string PROTOname
|
||||
DEF -- string DEFName
|
||||
The DEF name of the node, will be coerced to be a valid
|
||||
identifier (with "" being considered valid)
|
||||
PROTO -- Prototype PROTO
|
||||
The node's Prototype object
|
||||
attributeDictionary -- string name: object value
|
||||
Dictionary in which VRML 97 attributes are stored
|
||||
'''
|
||||
DEF = '' # the default name for all nodes (arbitrary)
|
||||
def __init__(self, PROTO, name='', attrDict=None, *args, **namedargs):
|
||||
'''Normally this method is only called indirectly via the Prototype() interface
|
||||
PROTO -- Prototype PROTO
|
||||
see attribute PROTO
|
||||
name -- string DEFName
|
||||
see attribute DEF
|
||||
attrDict -- string name: object value
|
||||
see attribute attributeDictionary
|
||||
**namedargs -- string name: object value
|
||||
added to attrDict to create attributeDictionary
|
||||
'''
|
||||
self.__dict__["PROTO"] = PROTO
|
||||
self.DEF = name
|
||||
self.__dict__["attributeDictionary"] = {}
|
||||
## print attrDict, namedargs
|
||||
for dict in (attrDict or {}), namedargs:
|
||||
if dict:
|
||||
for key, value in dict.items ():
|
||||
self.__setattr__( key, value, check=1 )
|
||||
|
||||
def __setattr__( self, key, value, check=1, raw=0 ):
|
||||
'''Set attribute on Node
|
||||
key -- string attributeName
|
||||
value -- object attributeValue
|
||||
check -- boolean check
|
||||
if false, put values for unrecognized keys into __dict__
|
||||
otherwise, raise an AttributeError
|
||||
'''
|
||||
if key == "DEF":
|
||||
self.__dict__["DEF"] = checkName( value )
|
||||
return None
|
||||
elif key == "PROTO":
|
||||
self.__dict__["PROTO"] = value
|
||||
try:
|
||||
field = self.PROTO.getField( key )
|
||||
if (hasattr( value, "__gi__") and value.__gi__ == "IS") or raw:
|
||||
self.attributeDictionary[ field.name] = value
|
||||
else:
|
||||
self.attributeDictionary[ field.name] = field.coerce( value )
|
||||
except ValueError, x:
|
||||
raise ValueError( "Could not coerce value %s into value of VRML type %s for %s node %s's field %s"%( value, field.type, self.__gi__, self.DEF, key), x.args)
|
||||
except (AttributeError), x:
|
||||
if check:
|
||||
raise AttributeError("%s is not a known field for node %s"%(key, repr(self)))
|
||||
else:
|
||||
self.__dict__[key] = value
|
||||
def __getattr__( self, key, default = 1 ):
|
||||
''' Retrieve an attribute when standard lookup fails
|
||||
key -- string attributeName
|
||||
default -- boolean default
|
||||
if true, return the default value if the node does not have local value
|
||||
otherwise, raise AttributeError
|
||||
'''
|
||||
if key != "attributeDictionary":
|
||||
if self.__dict__.has_key( key):
|
||||
return self.__dict__[ key ]
|
||||
elif self.attributeDictionary.has_key( key):
|
||||
return self.attributeDictionary[key]
|
||||
if key != "PROTO":
|
||||
if key == "__gi__":
|
||||
return self.PROTO.nodeGI
|
||||
elif default:
|
||||
try:
|
||||
default = self.PROTO.getDefault( key )
|
||||
if type( default ) in typeclasses.MutableTypes:
|
||||
# we need a copy, not the original
|
||||
default = copy.deepcopy( default )
|
||||
self.__setattr__( key, default, check=0, raw=1 )
|
||||
return default
|
||||
except AttributeError:
|
||||
pass
|
||||
raise AttributeError, key
|
||||
def __delattr__( self, key ):
|
||||
''' Delete an attribute from the Node
|
||||
key -- string attributeName
|
||||
'''
|
||||
if key != "attributeDictionary":
|
||||
if self.attributeDictionary.has_key( key):
|
||||
del self.attributeDictionary[key]
|
||||
elif self.__dict__.has_key( key):
|
||||
del self.__dict__[ key ]
|
||||
raise AttributeError, key
|
||||
|
||||
def __repr__(self):
|
||||
''' Create simple python representation '''
|
||||
return '<%s(%s): %s>'%(self.__gi__, `self.DEF`, self.attributeDictionary.keys() )
|
||||
def getChildrenNames( self, current = 1, *args, **namedargs ):
|
||||
''' Get the (current) children of Node
|
||||
returns two lists: MFNode children, SFNode children
|
||||
current -- boolean currentOnly
|
||||
if true, only return current children
|
||||
otherwise, include all potential children
|
||||
'''
|
||||
MFNODES, SFNODES = self.PROTO.MFNodeNames, self.PROTO.SFNodeNames
|
||||
mns, sns = [],[]
|
||||
for key in MFNODES:
|
||||
if current and self.attributeDictionary.has_key(key):
|
||||
mns.append(key)
|
||||
elif not current:
|
||||
mns.append(key)
|
||||
for key in SFNODES:
|
||||
if self.attributeDictionary.has_key(key):
|
||||
sns.append(key)
|
||||
elif not current:
|
||||
sns.append(key)
|
||||
return mns,sns
|
||||
def calculateChildren(self, *args, **namedargs):
|
||||
'''Calculate the current children of the Node as list of Nodes
|
||||
'''
|
||||
MFNODES, SFNODES = self.getChildrenNames( )
|
||||
temp = []
|
||||
for key in MFNODES:
|
||||
try:
|
||||
temp.extend( self.__getattr__( key, default=0 ) )
|
||||
except AttributeError:
|
||||
pass
|
||||
for key in SFNODES:
|
||||
try:
|
||||
temp.append( self.__getattr__(key, default = 0 ) )
|
||||
except AttributeError:
|
||||
pass
|
||||
return temp
|
||||
def clone(self, newclass=None, name=None, children=None, attrDeepCopy=1, *args, **namedargs):
|
||||
'''Return a copy of this Node
|
||||
newclass -- object newClass or None
|
||||
optionally use a different Prototype as base
|
||||
name -- string DEFName or None or 1
|
||||
if 1, copy from current
|
||||
elif None, set to ""
|
||||
else, set to passed value
|
||||
children -- boolean copyChildren
|
||||
if true, copy the children of this node
|
||||
otherwise, skip children
|
||||
attrDeepCopy -- boolean deepCopy
|
||||
if true, use deepcopy
|
||||
otherwise, use copy
|
||||
'''
|
||||
if attrDeepCopy:
|
||||
cpy = copy.deepcopy
|
||||
else:
|
||||
cpy = copy.copy
|
||||
newattrs = self.attributeDictionary.copy()
|
||||
if not children:
|
||||
mnames,snames = self.getChildrenNames( )
|
||||
for key in mnames+snames:
|
||||
try:
|
||||
del(newattrs[key])
|
||||
except KeyError:
|
||||
pass
|
||||
for key, val in newattrs.items():
|
||||
if type(val) in typeclasses.MutableTypes:
|
||||
newattrs[key] = cpy(val)
|
||||
# following is Node specific, won't work for sceneGraphs, scripts, etceteras
|
||||
if name == 1: # asked to copy the name
|
||||
name = self.DEF
|
||||
elif name is None: # asked to clear the name
|
||||
name = ''
|
||||
if not newclass:
|
||||
newclass = self.PROTO
|
||||
return newclass( name, newattrs )
|
||||
def __cmp__( self, other, stop=None ):
|
||||
''' Compare this node to another object/node
|
||||
other -- object otherNode
|
||||
stop -- boolean stopIfFailure
|
||||
if true, failure to find comparison causes match failure (i.e. considered unequal)
|
||||
'''
|
||||
|
||||
if hasattr( other, '__gi__') and other.__gi__ == self.__gi__:
|
||||
try:
|
||||
return cmp( self.DEF, other.DEF) or cmp( self.attributeDictionary, other.attributeDictionary )
|
||||
except:
|
||||
if not stop:
|
||||
try:
|
||||
return other.__cmp__( self , 1) # 1 being stop...
|
||||
except:
|
||||
pass
|
||||
return -1 # could be one, doesn't really matter
|
||||
|
||||
def Script( name="", attrDict=None, fieldDict=None, defaultDict=None, eventDict=None, **namedarguments):
|
||||
''' Create a script node (and associated prototype)
|
||||
name -- string DEFName
|
||||
attrDict -- string name: object value
|
||||
see class Node.attributeDictionary
|
||||
fieldDict -- string name: (string name, string dataType, boolean exposure)
|
||||
see class Prototype.fieldDictionary
|
||||
defaultDict -- string name: object value
|
||||
see class Prototype.defaultDictionary
|
||||
eventDict -- string name: (string name, string dataType, boolean eventOut)
|
||||
'''
|
||||
fieldDictionary = {
|
||||
'directOutput':('directOutput', 'SFBool',0),
|
||||
'url':('url',"MFString",0),
|
||||
'mustEvaluate':('mustEvaluate', 'SFBool',0),
|
||||
}
|
||||
fieldDictionary.update( fieldDict or {})
|
||||
defaultDictionary = {
|
||||
"directOutput":0,
|
||||
"url":[],
|
||||
"mustEvaluate":0,
|
||||
}
|
||||
defaultDictionary.update( defaultDict or {})
|
||||
PROTO = Prototype(
|
||||
"Script",
|
||||
fieldDictionary,
|
||||
defaultDictionary ,
|
||||
eventDict = eventDict,
|
||||
)
|
||||
if attrDict is not None:
|
||||
attrDict.update( namedarguments )
|
||||
else:
|
||||
attrDict = namedarguments
|
||||
return PROTO( name, attrDict )
|
||||
|
||||
|
||||
class NullNode:
|
||||
'''NULL SFNode value
|
||||
There should only be a single NULL instance for
|
||||
any particular system. It should, for all intents and
|
||||
purposes just sit there inertly
|
||||
'''
|
||||
__gi__ = 'NULL'
|
||||
DEF = ''
|
||||
__walker_is_temporary_item__ = 1 # hacky signal to walking engine not to reject this node as already processed
|
||||
def __repr__(self):
|
||||
return '<NULL vrml SFNode>'
|
||||
def __vrmlStr__(self,*args,**namedargs):
|
||||
return ' NULL '
|
||||
toString = __vrmlStr__
|
||||
def __nonzero__(self ):
|
||||
return 0
|
||||
def __call__(self, *args, **namedargs):
|
||||
return self
|
||||
def __cmp__( self, other ):
|
||||
if hasattr( other, '__gi__') and other.__gi__ == self.__gi__:
|
||||
return 0
|
||||
return -1 # could be one, doesn't really matter
|
||||
def clone( self ):
|
||||
return self
|
||||
NULL = NullNode()
|
||||
|
||||
class fieldRef:
|
||||
'''IS Prototype field reference
|
||||
'''
|
||||
__gi__ = 'IS'
|
||||
DEF = ''
|
||||
def __init__(self, declaredName):
|
||||
self.declaredName = declaredName
|
||||
def __repr__(self):
|
||||
return 'IS %s'%self.declaredName
|
||||
def __vrmlStr__(self,*args,**namedargs):
|
||||
return 'IS %s'%self.declaredName
|
||||
toString = __vrmlStr__
|
||||
def __cmp__( self, other ):
|
||||
if hasattr( other, '__gi__') and other.__gi__ == self.__gi__:
|
||||
return cmp( self.declaredName, other.declaredName )
|
||||
return -1 # could be one, doesn't really matter
|
||||
def clone( self ):
|
||||
return self.__class__( self.declaredName )
|
||||
|
||||
IS = fieldRef
|
||||
|
||||
class ROUTE:
|
||||
''' VRML 97 ROUTE object
|
||||
The ROUTE object keeps track of its source and destination nodes and attributes
|
||||
It generally lives in a sceneGraph's "routes" collection
|
||||
'''
|
||||
__gi__ = 'ROUTE'
|
||||
def __init__( self, fromNode, fromField, toNode, toField ):
|
||||
if type(fromNode) is types.StringType:
|
||||
raise TypeError( "String value for ROUTE fromNode",fromNode)
|
||||
if type(toNode) is types.StringType:
|
||||
raise TypeError( "String value for ROUTE toNode",toNode)
|
||||
self.fromNode = fromNode
|
||||
self.fromField = fromField
|
||||
self.toNode = toNode
|
||||
self.toField = toField
|
||||
def __getitem__( self, index ):
|
||||
return (self.fromNode, self.fromField, self.toNode, self.toField)[index]
|
||||
def __setitem__( self, index, value ):
|
||||
attribute = ("fromNode","fromField","toNode", "toField")[index]
|
||||
setattr( self, attribute, value )
|
||||
def __repr__( self ):
|
||||
return 'ROUTE %s.%s TO %s.%s'%( self.fromNode.DEF, self.fromField, self.toNode.DEF, self.toField )
|
||||
def clone( self ):
|
||||
return self.__class__(
|
||||
self.fromNode,
|
||||
self.fromField,
|
||||
self.toNode,
|
||||
self.toField,
|
||||
)
|
||||
|
||||
|
||||
class sceneGraph(baseProto):
|
||||
''' A VRML 97 sceneGraph
|
||||
Attributes:
|
||||
__gi__ -- constant string "sceneGraph"
|
||||
DEF -- constant string ""
|
||||
children -- Node list
|
||||
List of the root children of the sceneGraph, nodes/scripts only
|
||||
routes -- ROUTE list
|
||||
List of the routes within the sceneGraph
|
||||
defNames -- string DEFName: Node node
|
||||
Mapping of DEF names to their respective nodes
|
||||
protoTypes -- Namespace prototypes
|
||||
Namespace (with chaining lookup) collection of prototypes
|
||||
getattr( sceneGraph.protoTypes, 'nodeGI' ) retrieves a prototype
|
||||
'''
|
||||
__gi__ = 'sceneGraph'
|
||||
DEF = ''
|
||||
def __init__(self, root=None, protoTypes=None, routes=None, defNames=None, children=None, *args, **namedargs):
|
||||
'''
|
||||
root -- sceneGraph root or Dictionary root or Module root or None
|
||||
Base object for root of protoType namespace hierarchy
|
||||
protoTypes -- string nodeGI: Prototype PROTO
|
||||
Dictionary of prototype definitions
|
||||
routes -- ROUTE list or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut) list
|
||||
List of route objects or tuples to be added to the sceneGraph
|
||||
see attribute routes
|
||||
defNames -- string DEFName: Node node
|
||||
see attribute defNames
|
||||
children -- Node list
|
||||
see attribute children
|
||||
'''
|
||||
if children is None:
|
||||
self.children = []
|
||||
else:
|
||||
self.children = children
|
||||
if routes is None:
|
||||
self.routes = [] # how will we efficiently handle routes?
|
||||
else:
|
||||
self.routes = routes
|
||||
if defNames == None:
|
||||
self.defNames = {} # maps 'defName':Node
|
||||
else:
|
||||
self.defNames = defNames
|
||||
if protoTypes is None:
|
||||
protoTypes = {}
|
||||
if root is None:
|
||||
from vrml import basenodes # XXX
|
||||
self.protoTypes = namespace.NameSpace(
|
||||
protoTypes,
|
||||
children = [namespace.NameSpace(basenodes)]
|
||||
)
|
||||
else: # there is a root file, so need to use it as the children instead of basenodes...
|
||||
if hasattr( root, "protoTypes"):
|
||||
self.protoTypes = namespace.NameSpace(
|
||||
protoTypes,
|
||||
children = [root.protoTypes]
|
||||
)
|
||||
else:
|
||||
self.protoTypes = namespace.NameSpace(
|
||||
protoTypes,
|
||||
children = [ namespace.NameSpace(root) ]
|
||||
)
|
||||
def __getinitargs__( self ):
|
||||
# we only copy our explicit protos, our routes, our defNames, and our children
|
||||
# inherited protos will be pulled along by their nodes...
|
||||
return None, self.protoTypes._base, self.routes, self.defNames, self.children
|
||||
def __getstate__( self ):
|
||||
return {}
|
||||
def __setstate__( self, dict ):
|
||||
pass
|
||||
def __del__( self, id=id ):
|
||||
'''
|
||||
Need to clean up the namespace's mutual references,
|
||||
this can be done without affecting the cascade by just
|
||||
eliminating the key/value pairs. The namespaces will
|
||||
no longer contain the prototypes, but they will still
|
||||
chain up to the higher-level namespaces, and the nodes
|
||||
will have those prototypes still in use.
|
||||
'''
|
||||
## print 'del sceneGraph', id(self )
|
||||
try:
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
## self.protoTypes.__dict__.clear()
|
||||
self.protoTypes._base.clear()
|
||||
del self.protoTypes.__namespace_cascade__[:]
|
||||
except:
|
||||
print 'unable to free references'
|
||||
|
||||
def addRoute(self, routeTuple, getNewNodes=0):
|
||||
''' Add a single route to the sceneGraph
|
||||
routeTuple -- ROUTE route or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut)
|
||||
getNewNodes -- boolean getNewNodes
|
||||
if true, look up sourcenode and destinationnode within the current defNames to determine source/destination nodes
|
||||
otherwise, just use current if available
|
||||
'''
|
||||
# create and wire together the Routes here,
|
||||
# should just be a matter of pulling the events and passing the nodes...
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
if type( routeTuple) in ( types.TupleType, types.ListType):
|
||||
(fromNode, fromField, toNode, toField ) = routeTuple
|
||||
if type(fromNode) is types.StringType:
|
||||
# get the node instead of the string...
|
||||
if self.defNames.has_key( fromNode ):
|
||||
fromNode = self.defNames[fromNode]
|
||||
else:
|
||||
err.err( "ROUTE from an unknown node %s "%(routeTuple) )
|
||||
return 0
|
||||
if type(toNode) is types.StringType:
|
||||
# get the node instead of the string...
|
||||
if self.defNames.has_key( toNode ):
|
||||
toNode = self.defNames[toNode]
|
||||
else:
|
||||
err.err( "ROUTE to an unknown node %s "%(routeTuple) )
|
||||
return 0
|
||||
routeTuple = ROUTE( fromNode, fromField, toNode, toField)
|
||||
elif getNewNodes:
|
||||
# get the nodes with the same names...
|
||||
if self.defNames.has_key( routeTuple[0].DEF ):
|
||||
routeTuple[0] = self.defNames[routeTuple[0].DEF]
|
||||
else:
|
||||
err.err( "ROUTE from an unknown node %s "%(routeTuple) )
|
||||
return 0
|
||||
if self.defNames.has_key( routeTuple[2].DEF ):
|
||||
routeTuple[2] = self.defNames[routeTuple[2].DEF]
|
||||
else:
|
||||
err.err( "ROUTE to an unknown node %s "%(routeTuple) )
|
||||
return 0
|
||||
# should be a Route node now, append to our ROUTE list...
|
||||
self.routes.append(routeTuple)
|
||||
return 1
|
||||
def regDefName(self, defName, object):
|
||||
''' Register a DEF name for a particular object
|
||||
defName -- string DEFName
|
||||
object -- Node node
|
||||
'''
|
||||
object.DEF = defName
|
||||
self.defNames[defName] = object
|
||||
def addProto(self, proto):
|
||||
'''Register a Prototype for this sceneGraph
|
||||
proto -- Prototype PROTO
|
||||
'''
|
||||
setattr( self.protoTypes, proto.__gi__, proto )
|
||||
#toString = __vrmlStr__
|
||||
#__vrmlStr__ = toString
|
||||
## def __setattr__( self, key, value ):
|
||||
## if key == 'protoTypes' and type( value) is types.ListType:
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
## raise TypeError( "Invalid type for protoTypes attribute of sceneGraph %s"%(`value`) )
|
||||
## else:
|
||||
## self.__dict__[key] = value
|
||||
|
||||
DEFAULTFIELDVALUES ={
|
||||
"SFBool": 0,
|
||||
"SFString": "",
|
||||
"SFFloat": 0,
|
||||
"SFTime": 0,
|
||||
"SFVec3f": (0, 0,0),
|
||||
"SFVec2f": (0,0),
|
||||
"SFRotation": (0, 1,0, 0),
|
||||
"SFInt32": 0,
|
||||
"SFImage": (0,0,0),
|
||||
"SFColor": (0,0, 0),
|
||||
"SFNode": NULL,
|
||||
"MFString": [],
|
||||
"MFFloat": [],
|
||||
"MFTime": [],
|
||||
"MFVec3f": [],
|
||||
"MFVec2f": [],
|
||||
"MFRotation": [],
|
||||
"MFInt32": [],
|
||||
"MFColor": [],
|
||||
"MFNode": [],
|
||||
}
|
||||
|
||||
|
||||
|
1
intern/python/modules/vrml/utils/__init__.py
Normal file
1
intern/python/modules/vrml/utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""utilities"""
|
169
intern/python/modules/vrml/utils/collapse.py
Normal file
169
intern/python/modules/vrml/utils/collapse.py
Normal file
@@ -0,0 +1,169 @@
|
||||
'''
|
||||
Destructive Functions for "collapsing" Sequences into single levels
|
||||
|
||||
>>> from mcf.utils import collapse
|
||||
|
||||
>>> collapse.test([[[1],[2,3]],[[]],[4],5,[6]])
|
||||
|
||||
[1, 2, 3, 4, 5, 6] # note that is the same root list
|
||||
|
||||
>>> collapse.collapse2([[[1],[2,3]],[[]],(4,()),(5,),[6]])
|
||||
|
||||
[1, 2, 3, 4, 5, 6] # note is the same root list
|
||||
'''
|
||||
import copy, types, sys
|
||||
from types import ListType, TupleType # this now only supports the obsolete stuff...
|
||||
|
||||
def hyperCollapse( inlist, allowedmap, type=type, list=list, itype=types.InstanceType, maxint= sys.maxint):
|
||||
'''
|
||||
Destructively flatten a mixed hierarchy to a single level.
|
||||
Non-recursive, many speedups and obfuscations by Tim Peters :)
|
||||
'''
|
||||
try:
|
||||
# for every possible index
|
||||
for ind in xrange( maxint):
|
||||
# while that index currently holds a list
|
||||
expandable = 1
|
||||
while expandable:
|
||||
expandable = 0
|
||||
if allowedmap.has_key( type(inlist[ind]) ):
|
||||
# expand that list into the index (and subsequent indicies)
|
||||
inlist[ind:ind+1] = list( inlist[ind])
|
||||
expandable = 1
|
||||
|
||||
# alternately you could iterate through checking for isinstance on all possible
|
||||
# classes, but that would be very slow
|
||||
elif type( inlist[ind] ) is itype and allowedmap.has_key( inlist[ind].__class__ ):
|
||||
# here figure out some way to generically expand that doesn't risk
|
||||
# infinite loops...
|
||||
templist = []
|
||||
for x in inlist[ind]:
|
||||
templist.append( x)
|
||||
inlist[ind:ind+1] = templist
|
||||
expandable = 1
|
||||
except IndexError:
|
||||
pass
|
||||
return inlist
|
||||
|
||||
|
||||
def collapse(inlist, type=type, ltype=types.ListType, maxint= sys.maxint):
|
||||
'''
|
||||
Destructively flatten a list hierarchy to a single level.
|
||||
Non-recursive, and (as far as I can see, doesn't have any
|
||||
glaring loopholes).
|
||||
Further speedups and obfuscations by Tim Peters :)
|
||||
'''
|
||||
try:
|
||||
# for every possible index
|
||||
for ind in xrange( maxint):
|
||||
# while that index currently holds a list
|
||||
while type(inlist[ind]) is ltype:
|
||||
# expand that list into the index (and subsequent indicies)
|
||||
inlist[ind:ind+1] = inlist[ind]
|
||||
#ind = ind+1
|
||||
except IndexError:
|
||||
pass
|
||||
return inlist
|
||||
|
||||
def collapse_safe(inlist):
|
||||
'''
|
||||
As collapse, but works on a copy of the inlist
|
||||
'''
|
||||
return collapse( inlist[:] )
|
||||
|
||||
def collapse2(inlist, ltype=(types.ListType, types.TupleType), type=type, maxint= sys.maxint ):
|
||||
'''
|
||||
Destructively flatten a list hierarchy to a single level.
|
||||
Will expand tuple children as well, but will fail if the
|
||||
top level element is not a list.
|
||||
Non-recursive, and (as far as I can see, doesn't have any
|
||||
glaring loopholes).
|
||||
'''
|
||||
ind = 0
|
||||
try:
|
||||
while 1:
|
||||
while type(inlist[ind]) in ltype:
|
||||
try:
|
||||
inlist[ind:ind+1] = inlist[ind]
|
||||
except TypeError:
|
||||
inlist[ind:ind+1] = list(inlist[ind])
|
||||
ind = ind+1
|
||||
except IndexError:
|
||||
pass
|
||||
return inlist
|
||||
|
||||
def collapse2_safe(inlist):
|
||||
'''
|
||||
As collapse2, but works on a copy of the inlist
|
||||
'''
|
||||
return collapse( list(inlist) )
|
||||
|
||||
def old_buggy_collapse(inlist):
|
||||
'''Always return a one-level list of all the non-list elements in listin,
|
||||
rewritten to be non-recursive 96-12-28 Note that the new versions work
|
||||
on the original list, not a copy of the original.'''
|
||||
if type(inlist)==TupleType:
|
||||
inlist = list(inlist)
|
||||
elif type(inlist)!=ListType:
|
||||
return [inlist]
|
||||
x = 0
|
||||
while 1:
|
||||
try:
|
||||
y = inlist[x]
|
||||
if type(y) == ListType:
|
||||
ylen = len(y)
|
||||
if ylen == 1:
|
||||
inlist[x] = y[0]
|
||||
if type(inlist[x]) == ListType:
|
||||
x = x - 1 # need to collapse that list...
|
||||
elif ylen == 0:
|
||||
del(inlist[x])
|
||||
x = x-1 # list has been shortened
|
||||
else:
|
||||
inlist[x:x+1]=y
|
||||
x = x+1
|
||||
except IndexError:
|
||||
break
|
||||
return inlist
|
||||
|
||||
|
||||
def old_buggy_collapse2(inlist):
|
||||
'''As collapse, but also collapse tuples, rewritten 96-12-28 to be non-recursive'''
|
||||
if type(inlist)==TupleType:
|
||||
inlist = list(inlist)
|
||||
elif type(inlist)!=ListType:
|
||||
return [inlist]
|
||||
x = 0
|
||||
while 1:
|
||||
try:
|
||||
y = inlist[x]
|
||||
if type(y) in [ListType, TupleType]:
|
||||
ylen = len(y)
|
||||
if ylen == 1:
|
||||
inlist[x] = y[0]
|
||||
if type(inlist[x]) in [ListType,TupleType]:
|
||||
x = x-1 #(to deal with that element)
|
||||
elif ylen == 0:
|
||||
del(inlist[x])
|
||||
x = x-1 # list has been shortened, will raise exception with tuples...
|
||||
else:
|
||||
inlist[x:x+1]=list(y)
|
||||
x = x+1
|
||||
except IndexError:
|
||||
break
|
||||
return inlist
|
||||
|
||||
|
||||
def oldest_buggy_collapse(listin):
|
||||
'Always return a one-level list of all the non-list elements in listin'
|
||||
if type(listin) == ListType:
|
||||
return reduce(lambda x,y: x+y, map(collapse, listin), [])
|
||||
else: return [listin]
|
||||
|
||||
def oldest_buggy_collapse2(seqin):
|
||||
|
||||
if type(seqin) in [ListType, TupleType]:
|
||||
return reduce(lambda x,y: x+y, map(collapse2, seqin), [])
|
||||
else:
|
||||
return [seqin]
|
||||
|
37
intern/python/modules/vrml/utils/err.py
Normal file
37
intern/python/modules/vrml/utils/err.py
Normal file
@@ -0,0 +1,37 @@
|
||||
'''
|
||||
err.py Encapsulated writing to sys.stderr
|
||||
|
||||
The idea of this module is that, for a GUI system (or a more advanced UI),
|
||||
you can just import a different err module (or object) and keep
|
||||
your code the same. (For instance, you often want a status window
|
||||
which flashes warnings and info, and have error messages pop up an
|
||||
alert to get immediate attention.
|
||||
'''
|
||||
|
||||
import sys
|
||||
|
||||
def err(message, Code=0):
|
||||
'''
|
||||
report an error, with an optional error code
|
||||
'''
|
||||
if Code:
|
||||
sys.stderr.write('Error #%i: %s\n'%(Code,message))
|
||||
else:
|
||||
sys.stderr.write('Error: %s\n'%message)
|
||||
def warn(message, Code=0):
|
||||
'''
|
||||
report a warning, with an optional error code
|
||||
'''
|
||||
if Code:
|
||||
sys.stderr.write('Warning #%i: %s\n'%(Code,message))
|
||||
else:
|
||||
sys.stderr.write('Warning: %s\n'%message)
|
||||
def info(message, Code=0):
|
||||
'''
|
||||
report information/status, with an optional error code
|
||||
'''
|
||||
if Code:
|
||||
sys.stderr.write('Info #%i: %s\n'%(Code,message))
|
||||
else:
|
||||
sys.stderr.write('Info: %s\n'%message)
|
||||
|
225
intern/python/modules/vrml/utils/namespace.py
Normal file
225
intern/python/modules/vrml/utils/namespace.py
Normal file
@@ -0,0 +1,225 @@
|
||||
'''
|
||||
NameSpace v0.04:
|
||||
|
||||
A "NameSpace" is an object wrapper around a _base dictionary
|
||||
which allows chaining searches for an 'attribute' within that
|
||||
dictionary, or any other namespace which is defined as part
|
||||
of the search path (depending on the downcascade variable, is
|
||||
either the hier-parents or the hier-children).
|
||||
|
||||
You can assign attributes to the namespace normally, and read
|
||||
them normally. (setattr, getattr, a.this = that, a.this)
|
||||
|
||||
I use namespaces for writing parsing systems, where I want to
|
||||
differentiate between sources (have multiple sources that I can
|
||||
swap into or out of the namespace), but want to be able to get
|
||||
at them through a single interface. There is a test function
|
||||
which gives you an idea how to use the system.
|
||||
|
||||
In general, call NameSpace(someobj), where someobj is a dictionary,
|
||||
a module, or another NameSpace, and it will return a NameSpace which
|
||||
wraps up the keys of someobj. To add a namespace to the NameSpace,
|
||||
just call the append (or hier_addchild) method of the parent namespace
|
||||
with the child as argument.
|
||||
|
||||
### NOTE: if you pass a module (or anything else with a dict attribute),
|
||||
names which start with '__' will be removed. You can avoid this by
|
||||
pre-copying the dict of the object and passing it as the arg to the
|
||||
__init__ method.
|
||||
|
||||
### NOTE: to properly pickle and/or copy module-based namespaces you
|
||||
will likely want to do: from mcf.utils import extpkl, copy_extend
|
||||
|
||||
### Changes:
|
||||
97.05.04 -- Altered to use standard hierobj interface, cleaned up
|
||||
interface by removing the "addparent" function, which is reachable
|
||||
by simply appending to the __parent__ attribute, though normally
|
||||
you would want to use the hier_addchild or append functions, since
|
||||
they let both objects know about the addition (and therefor the
|
||||
relationship will be restored if the objects are stored and unstored)
|
||||
|
||||
97.06.26 -- Altered the getattr function to reduce the number of
|
||||
situations in which infinite lookup loops could be created
|
||||
(unfortunately, the cost is rather high). Made the downcascade
|
||||
variable harden (resolve) at init, instead of checking for every
|
||||
lookup. (see next note)
|
||||
|
||||
97.08.29 -- Discovered some _very_ weird behaviour when storing
|
||||
namespaces in mcf.store dbases. Resolved it by storing the
|
||||
__namespace_cascade__ attribute as a normal attribute instead of
|
||||
using the __unstore__ mechanism... There was really no need to
|
||||
use the __unstore__, but figuring out how a functions saying
|
||||
self.__dict__['__namespace_cascade__'] = something
|
||||
print `self.__dict__['__namespace_cascade__']` can print nothing
|
||||
is a bit beyond me. (without causing an exception, mind you)
|
||||
|
||||
97.11.15 Found yet more errors, decided to make two different
|
||||
classes of namespace. Those based on modules now act similar
|
||||
to dummy objects, that is, they let you modify the original
|
||||
instead of keeping a copy of the original and modifying that.
|
||||
|
||||
98.03.15 -- Eliminated custom pickling methods as they are no longer
|
||||
needed for use with Python 1.5final
|
||||
|
||||
98.03.15 -- Fixed bug in items, values, etceteras with module-type
|
||||
base objects.
|
||||
'''
|
||||
import copy, types, string
|
||||
|
||||
from mcf.utils import hierobj
|
||||
|
||||
class NameSpace(hierobj.Hierobj):
|
||||
'''
|
||||
An hierarchic NameSpace, allows specification of upward or downward
|
||||
chaining search for resolving names
|
||||
'''
|
||||
def __init__(self, val = None, parents=None, downcascade=1,children=[]):
|
||||
'''
|
||||
A NameSpace can be initialised with a dictionary, a dummied
|
||||
dictionary, another namespace, or something which has a __dict__
|
||||
attribute.
|
||||
Note that downcascade is hardened (resolved) at init, not at
|
||||
lookup time.
|
||||
'''
|
||||
hierobj.Hierobj.__init__(self, parents, children)
|
||||
self.__dict__['__downcascade__'] = downcascade # boolean
|
||||
if val is None:
|
||||
self.__dict__['_base'] = {}
|
||||
else:
|
||||
if type( val ) == types.StringType:
|
||||
# this is a reference to a module which has been pickled
|
||||
val = __import__( val, {},{}, string.split( val, '.') )
|
||||
try:
|
||||
# See if val's a dummy-style object which has a _base
|
||||
self.__dict__['_base']=copy.copy(val._base)
|
||||
except (AttributeError,KeyError):
|
||||
# not a dummy-style object... see if it has a dict attribute...
|
||||
try:
|
||||
if type(val) != types.ModuleType:
|
||||
val = copy.copy(val.__dict__)
|
||||
except (AttributeError, KeyError):
|
||||
pass
|
||||
# whatever val is now, it's going to become our _base...
|
||||
self.__dict__['_base']=val
|
||||
# harden (resolve) the reference to downcascade to speed attribute lookups
|
||||
if downcascade: self.__dict__['__namespace_cascade__'] = self.__childlist__
|
||||
else: self.__dict__['__namespace_cascade__'] = self.__parent__
|
||||
def __setattr__(self, var, val):
|
||||
'''
|
||||
An attempt to set an attribute should place the attribute in the _base
|
||||
dictionary through a setitem call.
|
||||
'''
|
||||
# Note that we use standard attribute access to allow ObStore loading if the
|
||||
# ._base isn't yet available.
|
||||
try:
|
||||
self._base[var] = val
|
||||
except TypeError:
|
||||
setattr(self._base, var, val)
|
||||
def __getattr__(self,var):
|
||||
## print '__getattr__', var
|
||||
return self.__safe_getattr__(var, {}) # the {} is a stopdict
|
||||
|
||||
def __safe_getattr__(self, var,stopdict):
|
||||
'''
|
||||
We have a lot to do in this function, if the attribute is an unloaded
|
||||
but stored attribute, we need to load it. If it's not in the stored
|
||||
attributes, then we need to load the _base, then see if it's in the
|
||||
_base.
|
||||
If it's not found by then, then we need to check our resource namespaces
|
||||
and see if it's in them.
|
||||
'''
|
||||
# we don't have a __storedattr__ or it doesn't have this key...
|
||||
if var != '_base':
|
||||
try:
|
||||
return self._base[var]
|
||||
except (KeyError,TypeError), x:
|
||||
try:
|
||||
return getattr(self._base, var)
|
||||
except AttributeError:
|
||||
pass
|
||||
try: # with pickle, it tries to get the __setstate__ before restoration is complete
|
||||
for cas in self.__dict__['__namespace_cascade__']:
|
||||
try:
|
||||
stopdict[id(cas)] # if succeeds, we've already tried this child
|
||||
# no need to do anything, if none of the children succeeds we will
|
||||
# raise an AttributeError
|
||||
except KeyError:
|
||||
stopdict[id(cas)] = None
|
||||
return cas.__safe_getattr__(var,stopdict)
|
||||
except (KeyError,AttributeError):
|
||||
pass
|
||||
raise AttributeError, var
|
||||
def items(self):
|
||||
try:
|
||||
return self._base.items()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
return self._base.__dict__.items()
|
||||
except AttributeError:
|
||||
pass
|
||||
def keys(self):
|
||||
try:
|
||||
return self._base.keys()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
return self._base.__dict__.keys()
|
||||
except AttributeError:
|
||||
pass
|
||||
def has_key( self, key ):
|
||||
try:
|
||||
return self._base.has_key( key)
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
return self._base.__dict__.has_key( key)
|
||||
except AttributeError:
|
||||
pass
|
||||
def values(self):
|
||||
try:
|
||||
return self._base.values()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
return self._base.__dict__.values()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def __getinitargs__(self):
|
||||
if type( self._base ) is types.ModuleType:
|
||||
base = self._base.__name__
|
||||
else:
|
||||
base = self._base
|
||||
return (base, self.__parent__, self.__downcascade__, self.__childlist__)
|
||||
def __getstate__(self):
|
||||
return None
|
||||
def __setstate__(self,*args):
|
||||
pass
|
||||
def __deepcopy__(self, memo=None):
|
||||
d = id(self)
|
||||
if memo is None:
|
||||
memo = {}
|
||||
elif memo.has_key(d):
|
||||
return memo[d]
|
||||
if type(self._base) == types.ModuleType:
|
||||
rest = tuple(map( copy.deepcopy, (self.__parent__, self.__downcascade__, self.__childlist__) ))
|
||||
new = apply(self.__class__, (self._base,)+rest )
|
||||
else:
|
||||
new = tuple(map( copy.deepcopy, (self._base, self.__parent__, self.__downcascade__, self.__childlist__) ))
|
||||
return new
|
||||
## def __del__( self, id=id ):
|
||||
## print 'del namespace', id( self )
|
||||
|
||||
|
||||
def test():
|
||||
import string
|
||||
a = NameSpace(string)
|
||||
del(string)
|
||||
a.append(NameSpace({'a':23,'b':42}))
|
||||
import math
|
||||
a.append(NameSpace(math))
|
||||
print 'The returned object should allow access to the attributes of the string,\nand math modules, and two simple variables "a" and "b" (== 23 and42 respectively)'
|
||||
return a
|
||||
|
||||
|
50
intern/python/modules/vrml/utils/typeclasses.py
Normal file
50
intern/python/modules/vrml/utils/typeclasses.py
Normal file
@@ -0,0 +1,50 @@
|
||||
'''
|
||||
Classes of Types
|
||||
|
||||
Often you want to be able to say:
|
||||
if type(obj) in MutableTypes:
|
||||
yada
|
||||
|
||||
This module is intended to make that easier.
|
||||
Just import and use :)
|
||||
'''
|
||||
import types
|
||||
|
||||
MutableTypes = [ types.ListType, types.DictType, types.InstanceType ]
|
||||
MutableSequenceTypes = [ types.ListType ]
|
||||
SequenceTypes = [ types.ListType, types.StringType, types.TupleType ]
|
||||
NumericTypes = [ types.IntType, types.FloatType, types.LongType, types.ComplexType ]
|
||||
MappingTypes = [ types.DictType ]
|
||||
|
||||
def regarray():
|
||||
if globals().has_key('array'):
|
||||
return 1
|
||||
try:
|
||||
import array
|
||||
SequenceTypes.append( array.ArrayType )
|
||||
MutableTypes.append( array.ArrayType )
|
||||
MutableSequenceTypes.append( array.ArrayType )
|
||||
return 1
|
||||
except ImportError:
|
||||
return 0
|
||||
|
||||
def regnumpy():
|
||||
'''
|
||||
Call if you want to register numpy arrays
|
||||
according to their types.
|
||||
'''
|
||||
if globals().has_key('Numeric'):
|
||||
return 1
|
||||
try:
|
||||
import Numeric
|
||||
SequenceTypes.append( Numeric.ArrayType )
|
||||
MutableTypes.append( Numeric.ArrayType )
|
||||
MutableSequenceTypes.append( Numeric.ArrayType )
|
||||
return 1
|
||||
except ImportError:
|
||||
return 0
|
||||
|
||||
# for now, I'm going to always register these, if the module becomes part of the base distribution
|
||||
# it might be better to leave it out so numpy isn't always getting loaded...
|
||||
regarray()
|
||||
regnumpy()
|
Reference in New Issue
Block a user