Initial revision

This commit is contained in:
Hans Lambermont
2002-10-12 11:37:38 +00:00
commit 12315f4d0e
1699 changed files with 444708 additions and 0 deletions

View File

@@ -0,0 +1 @@
"""The VRML import module"""

View 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':[],
},
{
},
)

View 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 ()

View 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)

View 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" )

View 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": [],
}

View File

@@ -0,0 +1 @@
"""utilities"""

View 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]

View 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)

View 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

View 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()