PyVRML97 2.3.4b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyvrml97-2.3.4b3.dist-info/METADATA +65 -0
- pyvrml97-2.3.4b3.dist-info/RECORD +39 -0
- pyvrml97-2.3.4b3.dist-info/WHEEL +5 -0
- pyvrml97-2.3.4b3.dist-info/top_level.txt +1 -0
- vrml/__init__.py +22 -0
- vrml/_bytes.py +85 -0
- vrml/arrays.py +86 -0
- vrml/cache.py +250 -0
- vrml/copier.py +27 -0
- vrml/csscolors.py +177 -0
- vrml/event.py +24 -0
- vrml/field.py +476 -0
- vrml/fieldtypes.py +1491 -0
- vrml/node.py +569 -0
- vrml/nodepath.py +70 -0
- vrml/olist.py +126 -0
- vrml/protofunctions.py +233 -0
- vrml/protonamespace.py +13 -0
- vrml/route.py +167 -0
- vrml/vrml200x/__init__.py +0 -0
- vrml/vrml200x/parser.py +87 -0
- vrml/vrml97/__init__.py +6 -0
- vrml/vrml97/_transformmatrix.py +133 -0
- vrml/vrml97/_transformmatrix_accel.py +63 -0
- vrml/vrml97/basenamespaces.py +28 -0
- vrml/vrml97/basenodes.py +648 -0
- vrml/vrml97/linearise.py +579 -0
- vrml/vrml97/nodepath.py +135 -0
- vrml/vrml97/nodetypes.py +95 -0
- vrml/vrml97/nurbs.py +79 -0
- vrml/vrml97/parseprocessor.py +452 -0
- vrml/vrml97/parser.py +72 -0
- vrml/vrml97/scenegraph.py +181 -0
- vrml/vrml97/script.py +25 -0
- vrml/vrml97/shaders.py +123 -0
- vrml/vrml97/transformmatrix.py +193 -0
- vrml/weakkeydictfix.py +36 -0
- vrml/weaklist.py +163 -0
- vrml/weaktuple.py +138 -0
vrml/olist.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Observable list class"""
|
|
2
|
+
from pydispatch.dispatcher import send
|
|
3
|
+
import weakref, types
|
|
4
|
+
try:
|
|
5
|
+
set
|
|
6
|
+
except NameError as err:
|
|
7
|
+
from sets import Set as set
|
|
8
|
+
|
|
9
|
+
class OList( list ):
|
|
10
|
+
"""List sub-class which generates pydispatch events on changes
|
|
11
|
+
|
|
12
|
+
Generates 4 types of events:
|
|
13
|
+
|
|
14
|
+
* NEW_CHILD_EVT, from self, with value=child, for each added child
|
|
15
|
+
* NEW_PARENT_EVT, from child, with parent=self, for each added child
|
|
16
|
+
* DEL_CHILD_EVT, from self, with value=child, for each removed child
|
|
17
|
+
* DEL_PARENT_EVT, from child, with parent=self, for each removed child
|
|
18
|
+
|
|
19
|
+
Note that the OList semantics are a little loose currently, as
|
|
20
|
+
it sometimes acts as though adding a new duplicate child is not
|
|
21
|
+
an event and sometimes acts as though it is. This doesn't cause
|
|
22
|
+
problems for the OpenGLContext scenegraph.
|
|
23
|
+
|
|
24
|
+
The OList is intended for situations where slow-write-fast-read
|
|
25
|
+
is the primary requirement, it allows you to hook writing events
|
|
26
|
+
in order to recalculate/cache values.
|
|
27
|
+
"""
|
|
28
|
+
NEW_CHILD_EVT = 'new'
|
|
29
|
+
NEW_PARENT_EVT = 'added'
|
|
30
|
+
DEL_CHILD_EVT = 'del'
|
|
31
|
+
DEL_PARENT_EVT = 'removed'
|
|
32
|
+
sender = None
|
|
33
|
+
extraArgs = None
|
|
34
|
+
def setSender( self, sender, **named ):
|
|
35
|
+
"""Set the (node) from which messages should be sent"""
|
|
36
|
+
if sender is not None:
|
|
37
|
+
sender = weakref.ref(sender)
|
|
38
|
+
self.sender = sender
|
|
39
|
+
self.extraArgs = named
|
|
40
|
+
def _sender( self ):
|
|
41
|
+
sender = self
|
|
42
|
+
if self.sender is not None:
|
|
43
|
+
sender = self.sender()
|
|
44
|
+
if sender is None:
|
|
45
|
+
sender = self
|
|
46
|
+
return sender
|
|
47
|
+
def _sendAdded( self, value ):
|
|
48
|
+
"""Send events for adding value to self"""
|
|
49
|
+
sender = self._sender()
|
|
50
|
+
send( self.NEW_CHILD_EVT, sender, value=value, **(self.extraArgs or {}))
|
|
51
|
+
send( self.NEW_PARENT_EVT, value, parent=sender,**(self.extraArgs or {}))
|
|
52
|
+
def _sendRemoved( self, value ):
|
|
53
|
+
"""Send events for removing value from self"""
|
|
54
|
+
sender = self._sender()
|
|
55
|
+
send( self.DEL_CHILD_EVT, sender, value=value,**(self.extraArgs or {}))
|
|
56
|
+
send( self.DEL_PARENT_EVT, value, parent=sender,**(self.extraArgs or {}))
|
|
57
|
+
|
|
58
|
+
def append( self, value ):
|
|
59
|
+
"""Append a value and send a message"""
|
|
60
|
+
super( OList,self ).append( value )
|
|
61
|
+
self._sendAdded( value )
|
|
62
|
+
return value
|
|
63
|
+
def insert( self, index, value ):
|
|
64
|
+
"""Insert a new item at index"""
|
|
65
|
+
super( OList,self ).insert( index, value )
|
|
66
|
+
self._sendAdded( value )
|
|
67
|
+
return value
|
|
68
|
+
def pop( self, index=None ):
|
|
69
|
+
"""Pop a single item out of the list"""
|
|
70
|
+
if index is None:
|
|
71
|
+
index = len(self)-1
|
|
72
|
+
value = super( OList,self ).pop( index )
|
|
73
|
+
self._sendRemoved( value )
|
|
74
|
+
return value
|
|
75
|
+
def remove( self, item ):
|
|
76
|
+
"""Remove this instance from the list"""
|
|
77
|
+
super(OList,self).remove( item )
|
|
78
|
+
self._sendRemoved( item )
|
|
79
|
+
return item
|
|
80
|
+
def __delitem__( self, index ):
|
|
81
|
+
"""Delete a single item"""
|
|
82
|
+
if isinstance( index, slice ):
|
|
83
|
+
current = self.__getitem__( index )
|
|
84
|
+
for value in current:
|
|
85
|
+
self._sendRemoved( value )
|
|
86
|
+
super( OList,self ).__delitem__( index )
|
|
87
|
+
return current
|
|
88
|
+
else:
|
|
89
|
+
value = self[index]
|
|
90
|
+
self._sendRemoved( value )
|
|
91
|
+
return value
|
|
92
|
+
def __delslice__( self, i,j):
|
|
93
|
+
return self.__delitem__( slice(i,j))
|
|
94
|
+
def __setitem__( self, index, value ):
|
|
95
|
+
"""Set a value and send a message"""
|
|
96
|
+
if isinstance( index, slice ):
|
|
97
|
+
values = list(value)
|
|
98
|
+
previous = self.__getitem__( index )
|
|
99
|
+
currents = set( previous )
|
|
100
|
+
super(OList,self).__setitem__( index, values )
|
|
101
|
+
for value in values:
|
|
102
|
+
if value not in currents:
|
|
103
|
+
self._sendAdded( value )
|
|
104
|
+
else:
|
|
105
|
+
try:
|
|
106
|
+
previous.remove( value )
|
|
107
|
+
except ValueError as err:
|
|
108
|
+
pass
|
|
109
|
+
for current in previous:
|
|
110
|
+
self._sendRemoved( current )
|
|
111
|
+
return values
|
|
112
|
+
else:
|
|
113
|
+
current = self[index]
|
|
114
|
+
if current is not value:
|
|
115
|
+
self._sendRemoved( current )
|
|
116
|
+
super( OList,self ).__setitem__( index, value )
|
|
117
|
+
if current is not value:
|
|
118
|
+
self._sendAdded( value )
|
|
119
|
+
return value
|
|
120
|
+
def __setslice__( self, i,j, iterable ):
|
|
121
|
+
return self.__setitem__( slice(i,j), iterable)
|
|
122
|
+
def __iadd__( self, iterable ):
|
|
123
|
+
"""Do an in-place add"""
|
|
124
|
+
return self.__setitem__( slice(len(self),len(self)), iterable )
|
|
125
|
+
extend = __iadd__
|
|
126
|
+
|
vrml/protofunctions.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Functions for manipulating prototypes (node classes)
|
|
2
|
+
|
|
3
|
+
Prototypes are implemented as classes, and so are
|
|
4
|
+
available from every instance node, but we often
|
|
5
|
+
want to be able to manipulate the classes themselves
|
|
6
|
+
without needing lots of class-methods
|
|
7
|
+
|
|
8
|
+
The protofunctions module allows us to abstract the
|
|
9
|
+
actual implementation of the prototype away. If we
|
|
10
|
+
at some point want to create a real "prototype" class,
|
|
11
|
+
we could do so with most changes confined to this
|
|
12
|
+
module.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import unicode_literals
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _getcls(cls):
|
|
19
|
+
"""Utility function returns class when passed instance or class"""
|
|
20
|
+
if type(cls) == type:
|
|
21
|
+
return cls
|
|
22
|
+
else:
|
|
23
|
+
return cls.__class__
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def getPrototype(cls):
|
|
27
|
+
"""Return the prototype for the node or class
|
|
28
|
+
returns either the argument (if it is a proto)
|
|
29
|
+
or the prototype of the argument
|
|
30
|
+
"""
|
|
31
|
+
return _getcls(cls)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def protoName(obj, value=None, *args, **named):
|
|
35
|
+
"""Get/set the prototype name for the object"""
|
|
36
|
+
obj = _getcls(obj)
|
|
37
|
+
if value is not None:
|
|
38
|
+
return setattr(obj, "PROTO", value)
|
|
39
|
+
elif issubclass(obj, list):
|
|
40
|
+
return '__MFNode__'
|
|
41
|
+
else:
|
|
42
|
+
possible = getattr(obj, "PROTO")
|
|
43
|
+
if not possible:
|
|
44
|
+
return obj.__name__.split(".")[-1]
|
|
45
|
+
return possible
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def defName(obj, value=None, *args, **named):
|
|
49
|
+
"""Get/set the VRML97 defName for the object"""
|
|
50
|
+
from vrml import node
|
|
51
|
+
|
|
52
|
+
if value is not None:
|
|
53
|
+
return node.Node.DEF.fset(obj, value, *args, **named)
|
|
54
|
+
else:
|
|
55
|
+
return node.Node.DEF.fget(obj, *args, **named)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def name(obj, value=None, *args, **named):
|
|
59
|
+
"""Get/set prototype name for prototypes, DEF name for nodes"""
|
|
60
|
+
if type(obj) == type:
|
|
61
|
+
return protoName(obj, value, *args, **named)
|
|
62
|
+
else:
|
|
63
|
+
return defName(obj, value, *args, **named)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def root(obj, value=None, *args, **named):
|
|
67
|
+
"""Get/set root-node reference for nodes/protos"""
|
|
68
|
+
from vrml import node
|
|
69
|
+
|
|
70
|
+
if value is not None:
|
|
71
|
+
return node.Node.rootSceneGraph.fset(obj, value, *args, **named)
|
|
72
|
+
else:
|
|
73
|
+
return node.Node.rootSceneGraph.fget(obj, *args, **named)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def builtin(cls):
|
|
77
|
+
"""Return whether the class is "built-in" to the system"""
|
|
78
|
+
from vrml import node
|
|
79
|
+
|
|
80
|
+
return not issubclass(_getcls(cls), node.PrototypedNode)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def addField(cls, field):
|
|
84
|
+
"""Add a particular field/event to the class/prototype definition
|
|
85
|
+
|
|
86
|
+
At present this just calls setattr(cls,field.name,field)
|
|
87
|
+
"""
|
|
88
|
+
setattr(_getcls(cls), field.name, field)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def removeField(cls, field):
|
|
92
|
+
"""Remove a particular field/event to the class/prototype definition
|
|
93
|
+
|
|
94
|
+
If field is a string, calls delattr(cls,field) for the class
|
|
95
|
+
otherwise calls delattr( cls, field.name )
|
|
96
|
+
"""
|
|
97
|
+
if isinstance(field, str):
|
|
98
|
+
delattr(_getcls(cls), field)
|
|
99
|
+
else:
|
|
100
|
+
delattr(_getcls(cls), field.name)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def getField(cls, field):
|
|
104
|
+
"""Get a field/event object for the given name
|
|
105
|
+
|
|
106
|
+
field -- a field-name specifier, which may be any of
|
|
107
|
+
the following, (with the various options checked in
|
|
108
|
+
order, so that earlier options will take
|
|
109
|
+
precedence over later options):
|
|
110
|
+
|
|
111
|
+
* the exact name of the field/demand as specified
|
|
112
|
+
in the class's namespace (fastest and first
|
|
113
|
+
checked)
|
|
114
|
+
* the "storage" name of a field, that is, the "name"
|
|
115
|
+
attribute of a field where that name does not
|
|
116
|
+
match the previous definition (commonly seen in
|
|
117
|
+
non-standard fields on VRML97 standard nodes)
|
|
118
|
+
* the "storage" name of an event
|
|
119
|
+
* a pseudo-event with the prefix "set_" or the
|
|
120
|
+
suffix "_changed", which will return the
|
|
121
|
+
associated field/event as if the suffix were
|
|
122
|
+
not present (does a recursive call with the
|
|
123
|
+
truncated name)
|
|
124
|
+
"""
|
|
125
|
+
cls = _getcls(cls)
|
|
126
|
+
try:
|
|
127
|
+
return getattr(cls, field)
|
|
128
|
+
except (AttributeError, KeyError):
|
|
129
|
+
# OK, may be a space-prefixed name...
|
|
130
|
+
for fieldObject in getFields(cls):
|
|
131
|
+
if fieldObject.name == field:
|
|
132
|
+
return field
|
|
133
|
+
# OK, may be an event with space-prefixed name
|
|
134
|
+
for fieldObject in getFields(cls, 1):
|
|
135
|
+
if fieldObject.name == field:
|
|
136
|
+
return field
|
|
137
|
+
# OK, may be one of the "component" events
|
|
138
|
+
# of a field...
|
|
139
|
+
if field.startswith("set_"):
|
|
140
|
+
return getField(cls, field[4:])
|
|
141
|
+
elif field.endswith("_changed"):
|
|
142
|
+
return getField(cls, field[:-8])
|
|
143
|
+
raise AttributeError(
|
|
144
|
+
"""The prototype %s does not define a field named %s"""
|
|
145
|
+
% (protoName(cls), field)
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def getFields(cls, events=0):
|
|
150
|
+
"""Get all fields of the definition/prototype
|
|
151
|
+
|
|
152
|
+
if events is true, then return events
|
|
153
|
+
instead of fields.
|
|
154
|
+
"""
|
|
155
|
+
cls = _getcls(cls)
|
|
156
|
+
from vrml import field
|
|
157
|
+
|
|
158
|
+
if events:
|
|
159
|
+
wanted = field.Event
|
|
160
|
+
else:
|
|
161
|
+
wanted = field.Field
|
|
162
|
+
items = {}
|
|
163
|
+
mro = cls.__mro__[:]
|
|
164
|
+
while mro:
|
|
165
|
+
items.update(
|
|
166
|
+
dict(
|
|
167
|
+
[
|
|
168
|
+
(key, value)
|
|
169
|
+
for key, value in mro[-1].__dict__.items()
|
|
170
|
+
if isinstance(value, wanted)
|
|
171
|
+
]
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
mro = mro[:-1]
|
|
175
|
+
return list(items.values())
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
##def clonePROTO( cls ):
|
|
179
|
+
## """Clone the prototype/class
|
|
180
|
+
##
|
|
181
|
+
## This allows you to create a new prototype from the
|
|
182
|
+
## current prototype. The entire prototype is cloned,
|
|
183
|
+
## including all fields, and the scene graph.
|
|
184
|
+
## """
|
|
185
|
+
## cls = _getcls(cls)
|
|
186
|
+
## fields = [ item.clone() for item in cls.__dict__.values() if isinstance(item, field.Field)]
|
|
187
|
+
## return prototype(
|
|
188
|
+
## cls.PROTO,
|
|
189
|
+
## fields,
|
|
190
|
+
## cls.sceneGraph.clone(),
|
|
191
|
+
## )
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def setSceneGraph(cls, sg):
|
|
195
|
+
"""Set the scenegraph associated with a prototype"""
|
|
196
|
+
from vrml import node
|
|
197
|
+
|
|
198
|
+
return node.PrototypedNode.scenegraph.fset(cls, sg)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def getSceneGraph(cls):
|
|
202
|
+
"""Get the scenegraph associated with a prototype (or None)"""
|
|
203
|
+
from vrml import node
|
|
204
|
+
|
|
205
|
+
return node.PrototypedNode.scenegraph.fget(cls)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def delSceneGraph(cls):
|
|
209
|
+
"""Delete the scenegraph associated with a prototype"""
|
|
210
|
+
from vrml import node
|
|
211
|
+
|
|
212
|
+
return node.PrototypedNode.scenegraph.fdel(cls)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def setExternalURL(cls, url):
|
|
216
|
+
"""Set the externproto URL associated with a prototype"""
|
|
217
|
+
from vrml import node
|
|
218
|
+
|
|
219
|
+
return node.Node.externalURL.fset(cls, url)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def getExternalURL(cls):
|
|
223
|
+
"""Get the externproto URL associated with a prototype (or [])"""
|
|
224
|
+
from vrml import node
|
|
225
|
+
|
|
226
|
+
return node.Node.externalURL.fget(cls)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def delExternalURL(cls):
|
|
230
|
+
"""Delete the externproto URL associated with a prototype"""
|
|
231
|
+
from vrml import node
|
|
232
|
+
|
|
233
|
+
return node.Node.externalURL.fdel(cls)
|
vrml/protonamespace.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Trivial dict sub-class to hold prototype definitions"""
|
|
2
|
+
class ProtoNamespace( dict ):
|
|
3
|
+
"""Simple namespace for holding prototypes"""
|
|
4
|
+
def __getattr__( self, key ):
|
|
5
|
+
"""Map attribute access to key access"""
|
|
6
|
+
if key != '__contains__':
|
|
7
|
+
if key in self:
|
|
8
|
+
return self[ key ]
|
|
9
|
+
raise AttributeError( '%r object has no %r attribute'%( self.__class__.__name__, key))
|
|
10
|
+
def __copy__( self ):
|
|
11
|
+
"""Produce a ProtoNamespace copy of self"""
|
|
12
|
+
return self.__class__( super(ProtoNamespace,self).__copy__())
|
|
13
|
+
|
vrml/route.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""ROUTE and ISRoute Implementations (event-processing)"""
|
|
2
|
+
import traceback
|
|
3
|
+
from vrml import field, fieldtypes, protofunctions, node
|
|
4
|
+
from pydispatch import dispatcher
|
|
5
|
+
|
|
6
|
+
class ROUTE( node.Node ):
|
|
7
|
+
"""Representation and implementation of a VRML97 ROUTE
|
|
8
|
+
|
|
9
|
+
This implementation uses the dispatcher module to create
|
|
10
|
+
an approximation of the VRML97 event model. It allows nodes
|
|
11
|
+
to forward events via the ROUTE objects, and watches for
|
|
12
|
+
event cycles.
|
|
13
|
+
"""
|
|
14
|
+
PROTO = "ROUTE"
|
|
15
|
+
source = node.SFNode('source',)
|
|
16
|
+
sourceField = fieldtypes.SFString('sourceField',)
|
|
17
|
+
destination = node.SFNode('destination',)
|
|
18
|
+
destinationField = fieldtypes.SFString( 'destinationField',)
|
|
19
|
+
def __init__( self, *arguments, **named ):
|
|
20
|
+
"""Initialize the route object
|
|
21
|
+
|
|
22
|
+
Calls self.bind() after normal node.Node
|
|
23
|
+
argument processing.
|
|
24
|
+
"""
|
|
25
|
+
if arguments:
|
|
26
|
+
if len(arguments) == 4:
|
|
27
|
+
named['source'] = arguments[0]
|
|
28
|
+
named['sourceField'] = arguments[1]
|
|
29
|
+
named['destination'] = arguments[2]
|
|
30
|
+
named['destinationField'] = arguments[3]
|
|
31
|
+
arguments = ()
|
|
32
|
+
super( ROUTE, self ).__init__( *arguments, **named )
|
|
33
|
+
self.bind()
|
|
34
|
+
def bind( self ):
|
|
35
|
+
"""Bind this ROUTE node's source to destination
|
|
36
|
+
|
|
37
|
+
Should also setup notification for changes to our
|
|
38
|
+
values to cause changes to the ROUTING table in
|
|
39
|
+
dispatcher.
|
|
40
|
+
"""
|
|
41
|
+
return self._bind( self.source, self.sourceField )
|
|
42
|
+
def _bind( self, source, field ):
|
|
43
|
+
"""Low-level binding of the source,field key
|
|
44
|
+
|
|
45
|
+
This method allows sub-classes to do multiple
|
|
46
|
+
bindings when bind() is called.
|
|
47
|
+
"""
|
|
48
|
+
if source and field:
|
|
49
|
+
try:
|
|
50
|
+
sf = protofunctions.getField( source, field )
|
|
51
|
+
except (AttributeError, KeyError):
|
|
52
|
+
print("""%s: field %s doesn't exist on %s"""%(protofunctions.protoName(self), field, source))
|
|
53
|
+
else:
|
|
54
|
+
for message in ('set','del','route'):
|
|
55
|
+
dispatcher.connect(
|
|
56
|
+
receiver = self.forward,
|
|
57
|
+
sender = source,
|
|
58
|
+
signal = (message,sf),
|
|
59
|
+
)
|
|
60
|
+
else:
|
|
61
|
+
print("""NULL ROUTE bound""", self)
|
|
62
|
+
def forward(
|
|
63
|
+
self, signal, sender, event=None, value=None, **arguments
|
|
64
|
+
):
|
|
65
|
+
"""Forward a value update to our destination
|
|
66
|
+
"""
|
|
67
|
+
return self._forward(
|
|
68
|
+
sender, signal,
|
|
69
|
+
self.destination, self.destinationField,
|
|
70
|
+
event, value, **arguments
|
|
71
|
+
)
|
|
72
|
+
def _forward(
|
|
73
|
+
self,
|
|
74
|
+
sender, signal,
|
|
75
|
+
destination, destinationField,
|
|
76
|
+
event=None, value=None, **arguments
|
|
77
|
+
):
|
|
78
|
+
"""Do the low-level forwarding of the value to a target field"""
|
|
79
|
+
if event is None:
|
|
80
|
+
from vrml import event as eventmodule
|
|
81
|
+
event = eventmodule.Event()
|
|
82
|
+
signal, sourceField = signal
|
|
83
|
+
if signal == 'del':
|
|
84
|
+
value = sourceField.fget( sender )
|
|
85
|
+
if destination and destinationField:
|
|
86
|
+
destinationField = protofunctions.getField( destination, destinationField )
|
|
87
|
+
if event and hasattr(event, "visited"):
|
|
88
|
+
if event.visited((destination, destinationField),):
|
|
89
|
+
### Short-circuit before a cycle is created...
|
|
90
|
+
return
|
|
91
|
+
event.visited( (destination,destinationField), 1)
|
|
92
|
+
if isinstance( destinationField, field.Field ):
|
|
93
|
+
try:
|
|
94
|
+
value = destinationField.fset( destination, value, notify = 0 )
|
|
95
|
+
except (ValueError, TypeError):
|
|
96
|
+
traceback.print_exc()
|
|
97
|
+
else:
|
|
98
|
+
try:
|
|
99
|
+
value = destinationField.__set__( destination, value )
|
|
100
|
+
except (ValueError, TypeError):
|
|
101
|
+
traceback.print_exc()
|
|
102
|
+
dispatcher.send(
|
|
103
|
+
signal = ('route',destinationField),
|
|
104
|
+
sender = destination,
|
|
105
|
+
value = value,
|
|
106
|
+
event = event,
|
|
107
|
+
)
|
|
108
|
+
def copy( self, copier ):
|
|
109
|
+
"""Copy the route for the copier object"""
|
|
110
|
+
source = self.source.copy(copier)
|
|
111
|
+
destination = self.destination.copy( copier )
|
|
112
|
+
return self.__class__(
|
|
113
|
+
source = source,
|
|
114
|
+
destination = destination,
|
|
115
|
+
sourceField = self.sourceField,
|
|
116
|
+
destinationField = self.destinationField,
|
|
117
|
+
)
|
|
118
|
+
def __str__( self ):
|
|
119
|
+
"""Get a friendly representation of the Node"""
|
|
120
|
+
return """%s %r.%s TO %r.%s"""%(
|
|
121
|
+
self.__class__.__name__,
|
|
122
|
+
self.source,
|
|
123
|
+
self.sourceField,
|
|
124
|
+
self.destination,
|
|
125
|
+
self.destinationField,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### Field-type for multi-field route objects...
|
|
130
|
+
class SFRoute( node.SFNode ):
|
|
131
|
+
"""Single-field ROUTE value"""
|
|
132
|
+
requiredTypes = (ROUTE,)
|
|
133
|
+
|
|
134
|
+
class MFRoute( node.MFNode ):
|
|
135
|
+
"""Multiple-value-field ROUTEs"""
|
|
136
|
+
baseSFNode = SFRoute( "GeneralSFRoute" )
|
|
137
|
+
|
|
138
|
+
class IS( ROUTE ):
|
|
139
|
+
"""An is-mapping for a field/event
|
|
140
|
+
|
|
141
|
+
Functionally, an instantiated IS is just a
|
|
142
|
+
multi-directional ROUTE (that is, it's a route
|
|
143
|
+
to and from a given field on the base node to
|
|
144
|
+
the sub-nodes.
|
|
145
|
+
"""
|
|
146
|
+
PROTO = "IS"
|
|
147
|
+
def bind( self ):
|
|
148
|
+
"""Bind the in and out routes for the IS mapping
|
|
149
|
+
"""
|
|
150
|
+
self._bind( self.source, self.sourceField )
|
|
151
|
+
self._bind( self.destination, self.destinationField )
|
|
152
|
+
def forward( self, signal, sender, event=None, value=None, **arguments ):
|
|
153
|
+
"""Forward a value update to our destination (or source)
|
|
154
|
+
"""
|
|
155
|
+
if sender is self.source:
|
|
156
|
+
return self._forward(
|
|
157
|
+
sender, signal,
|
|
158
|
+
self.destination, self.destinationField,
|
|
159
|
+
event, value, **arguments
|
|
160
|
+
)
|
|
161
|
+
elif sender is self.destination:
|
|
162
|
+
return self._forward(
|
|
163
|
+
sender, signal,
|
|
164
|
+
self.source, self.sourceField,
|
|
165
|
+
event, value, **arguments
|
|
166
|
+
)
|
|
167
|
+
|
|
File without changes
|
vrml/vrml200x/parser.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""VRML200X SimpleParse 2 Parser
|
|
2
|
+
|
|
3
|
+
VRML200x is a fairly minor modification to the VRML97 grammar,
|
|
4
|
+
with almost all of the changes being the more involved header,
|
|
5
|
+
and a few new field-types that are already accepted by the
|
|
6
|
+
VRML97 grammar.
|
|
7
|
+
"""
|
|
8
|
+
from simpleparse.parser import Parser
|
|
9
|
+
from simpleparse.common import chartypes
|
|
10
|
+
|
|
11
|
+
#print file
|
|
12
|
+
grammar = r'''
|
|
13
|
+
header := headerStatement,profileStatement,componentStatement*,metaStatement*
|
|
14
|
+
headerStatement := ('#X3D',ts,SFNumber,ts,'utf8',ts,headerComment?,newLine)/('#',headerComment?,newLine)
|
|
15
|
+
headerComment := -newLine+
|
|
16
|
+
profileStatement := 'PROFILE', ts, profileName,newLine
|
|
17
|
+
profileName := name
|
|
18
|
+
<newLine> := ('\r\n'/'\r'/'\n')
|
|
19
|
+
|
|
20
|
+
componentStatement := 'COMPONENT',ts, componentNameId, ts,':', ts, componentSupportLevel
|
|
21
|
+
componentNameId := name
|
|
22
|
+
componentSupportLevel := SFNumber
|
|
23
|
+
|
|
24
|
+
metaStatement := 'META',ts, metakey,ts,metavalue
|
|
25
|
+
metakey := SFString
|
|
26
|
+
metavalue := SFString
|
|
27
|
+
|
|
28
|
+
# not in the grammar, but apparently part of the VRML200x encoding
|
|
29
|
+
importStatement := 'IMPORT',ts,name,ts,'.',ts,name,(ts,asClause)?,ts
|
|
30
|
+
exportStatement := 'EXPORT',ts,name,(ts,asClause)?,ts
|
|
31
|
+
asClause := 'AS',ts,name
|
|
32
|
+
|
|
33
|
+
vrmlFile := header, vrmlScene, !, EOF
|
|
34
|
+
vrmlScene := rootItem*
|
|
35
|
+
rootItem := ts,(Proto/ExternProto/ROUTE/('USE',ts,USE,ts)/Script/Node),ts
|
|
36
|
+
|
|
37
|
+
Proto := 'PROTO',ts,!, nodegi,ts,'[',ts,(fieldDecl/eventDecl)*,']', ts, '{', ts, vrmlScene,ts, '}', ts
|
|
38
|
+
fieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,Field,ts
|
|
39
|
+
|
|
40
|
+
# inputOutput/initializeOnly not in the grammar
|
|
41
|
+
fieldExposure := 'inputOutput'/'initializeOnly'/'field'/'exposedField'
|
|
42
|
+
dataType := ('SF'/'MF')?,name
|
|
43
|
+
eventDecl := eventDirection, ts, !,dataType, ts, name, ts
|
|
44
|
+
|
|
45
|
+
# inputOnly/outputOnly not in the grammar
|
|
46
|
+
eventDirection := 'inputOnly'/'outputOnly'/'eventIn'/'eventOut'
|
|
47
|
+
ExternProto := 'EXTERNPROTO',ts,!,nodegi,ts,'[',ts,(extFieldDecl/eventDecl)*,']', ts, ExtProtoURL
|
|
48
|
+
extFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts
|
|
49
|
+
ExtProtoURL := '['?,(ts,SFString)*, ts, ']'?, ts # just an MFString by another name :)
|
|
50
|
+
|
|
51
|
+
ROUTE := 'ROUTE',ts, !,name,'.',name, ts, 'TO', ts, name,'.',name, ts
|
|
52
|
+
|
|
53
|
+
Node := ('DEF',ts,!,name,ts)?,nodegi,ts,'{',ts,(Proto/ExternProto/ROUTE/Attr)*,ts,!,'}', ts
|
|
54
|
+
|
|
55
|
+
Script := ('DEF',ts,!,name,ts)?,'Script',ts,!,'{',ts,(ScriptFieldDecl/ScriptEventDecl/Proto/ExternProto/ROUTE/Attr)*,ts,'}', ts
|
|
56
|
+
ScriptEventDecl := eventDirection, ts, !,dataType, ts, name, ts, ('IS', ts,!, IS,ts)?
|
|
57
|
+
ScriptFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,(('IS', ts,!,IS,ts)/Field),ts
|
|
58
|
+
|
|
59
|
+
SFNull := 'NULL', ts
|
|
60
|
+
|
|
61
|
+
# should really have an optimised way of declaring a different reporting name for the same production...
|
|
62
|
+
USE := name
|
|
63
|
+
IS := name
|
|
64
|
+
nodegi := name
|
|
65
|
+
Attr := name, ts, (('IS', ts,IS,ts)/Field), ts
|
|
66
|
+
Field := ( '[',ts,((SFNumber/SFBool/SFString/('USE',ts,USE,ts)/Script/Node),ts)*, ']'!, ts )/((SFNumber/SFBool/SFNull/SFString/('USE',ts,USE,ts)/Script/Node),ts)+
|
|
67
|
+
|
|
68
|
+
name := -[][0-9{}\000-\020"'#,.\\ ], -[][{}\000-\020"'#,.\\ ]*
|
|
69
|
+
SFNumber := [-+]*, ( ('0',[xX],[0-9A-Fa-f]+) / ([0-9.]+,([eE],[-+0-9.]+)?))
|
|
70
|
+
SFBool := 'TRUE'/'FALSE'
|
|
71
|
+
SFString := '"',(CHARNODBLQUOTE/ESCAPEDCHAR/SIMPLEBACKSLASH)*,'"'!
|
|
72
|
+
CHARNODBLQUOTE := -[\134"]+
|
|
73
|
+
SIMPLEBACKSLASH := '\134'
|
|
74
|
+
ESCAPEDCHAR := '\\"'/'\134\134'
|
|
75
|
+
<ts> := ( [ \011-\015,]+ / ('#',-'\012'*,'\n')+ )*
|
|
76
|
+
'''
|
|
77
|
+
|
|
78
|
+
class VRMLParser( Parser ):
|
|
79
|
+
"""Simple subclassing of Parser to create proper ParseProcessor"""
|
|
80
|
+
def buildProcessor( self ):
|
|
81
|
+
"""Build and return a vrml.vrml97.parseprocessor.ParseProcessor"""
|
|
82
|
+
from vrml.vrml97 import parseprocessor
|
|
83
|
+
return parseprocessor.ParseProcessor()
|
|
84
|
+
|
|
85
|
+
def buildParser( declaration = grammar ):
|
|
86
|
+
"""Build a new VRMLParser object"""
|
|
87
|
+
return VRMLParser( declaration, "vrmlFile" )
|