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.
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyVRML97
3
+ Version: 2.3.4b3
4
+ Summary: VRML97 Scenegraph model for Python
5
+ Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
6
+ License: BSD-style, see license.txt for details
7
+ Project-URL: Homepage, http://pyopengl.sourceforge.net/context/
8
+ Keywords: VRML,VRML97,scenegraph
9
+ Classifier: License :: OSI Approved :: BSD License
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: C
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
14
+ Classifier: Intended Audience :: Developers
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/x-rst
17
+ Requires-Dist: numpy
18
+ Requires-Dist: PyDispatcher
19
+ Requires-Dist: simpleparse
20
+
21
+ PyVRML97 Scenegraph Model
22
+ ==========================
23
+
24
+ PyVRML97 is the scenegraph model from `OpenGLContext`_ but can be used separately
25
+ in VRML97 processing tools. It relies on `SimpleParse`_, `PyDispatcher`_ and `Numpy`_
26
+ to provide the basic modelling functionality.
27
+
28
+ Properties (fields) in PyVRML97 follow the "Observer" pattern, and PyVRML97
29
+ provides a cache mechanism that allows you to do cache invalidation when
30
+ setting properties (fields). OpenGLContext uses that extensively to
31
+ optimize the rendering process.
32
+
33
+ .. _`OpenGLContext`: https://pypi.python.org/pypi/OpenGLContext
34
+ .. _`SimpleParse`: https://pypi.python.org/pypi/SimpleParse
35
+ .. _`PyDispatcher`: https://pypi.python.org/pypi/PyDispatcher
36
+ .. _`Numpy`: https://pypi.python.org/pypi/numpy
37
+
38
+ Installation
39
+ -------------
40
+
41
+ It isn't common to directly install PyVRML97 itself (normally you want to
42
+ install it as part of installing OpenGLContext), but should you wish to, you
43
+ can install via::
44
+
45
+ $ pip install PyVRML97 PyVRML97_accelerate
46
+
47
+ The PyVRML97_accelerate module requires that you have a working compiler
48
+ (or, if you are on Windows, prebuilt wheels likely are available).
49
+
50
+ .. image:: https://ci.appveyor.com/api/projects/status/MikeCFletcher/pyvrml97/branch/master
51
+ :target: https://ci.appveyor.com/project/MikeCFletcher/pyvrml97
52
+ :alt: Appveyor Build
53
+
54
+ .. image:: https://img.shields.io/pypi/v/pyvrml97.svg
55
+ :target: https://pypi.python.org/pypi/pyvrml97
56
+ :alt: Latest PyPI Version
57
+
58
+ .. image:: https://img.shields.io/pypi/dm/pyvrml97.svg
59
+ :target: https://pypi.python.org/pypi/pyvrml97
60
+ :alt: Monthly download counter
61
+
62
+ Build/Release Process
63
+ ----------------------
64
+
65
+ * Push an annotated tag with `version` prefix (github workflow `build_and_publish.yml`)
@@ -0,0 +1,39 @@
1
+ vrml/__init__.py,sha256=MaK51RM3d-jCwGlHh5Emvb_QVwejMvHdhViz5DgWGRc,827
2
+ vrml/_bytes.py,sha256=Xug9wGWIn91Y9HeTDuZwxhsSxgUYAmNFH9U409JvShY,2404
3
+ vrml/arrays.py,sha256=b8MvRaTJ8dJRTk3oQ_WhHlEMU7urbO4D0vqftb8lEZo,2511
4
+ vrml/cache.py,sha256=netNmLNUVSutC2beD0Z89I_wOv7stIUGbzSS0PUyzVU,8062
5
+ vrml/copier.py,sha256=1tP1xbHe5UOulpnzO_ccywHfm0HoQTSb-l-o17FgPqE,1077
6
+ vrml/csscolors.py,sha256=d76-sTGbLcMZs9Wh65cmLrdf2VcKsQrwHYOiqat2ztA,6978
7
+ vrml/event.py,sha256=6u_Je6Qad8nauBc2vCyOvEBJzv-4ZseuXn1yOse5Dtg,845
8
+ vrml/field.py,sha256=9c5aC_ixOTSkkaowpHPocf93ukZ60maZXtXg_LZQDT4,14380
9
+ vrml/fieldtypes.py,sha256=sTchoCoi8elYOXPNlka9i1oEfQnjqjUfBPgYfz3ZkYo,37090
10
+ vrml/node.py,sha256=JfE8xg14ptkFBgq3WkuEf6IRpEsDbxTuxLiTNh4IxRM,18364
11
+ vrml/nodepath.py,sha256=ojvV5Wg3ktZ0s82HGwJatuvhFOWDPmlZfpk36qEXxOQ,2388
12
+ vrml/olist.py,sha256=asZ3Z_AE_5wiAi0yQJX-RCaentaqffUp1IcuqR_hMIs,4774
13
+ vrml/protofunctions.py,sha256=Any0tervT96fWFPt9q9fELbus5yoqX1LW2Iq95QIznM,6685
14
+ vrml/protonamespace.py,sha256=WkWoZykw09OIxi7DjGiwXdSYFExDBNLLAeyk_lX1ocY,567
15
+ vrml/route.py,sha256=KSx9vYtYRW63_hjS6wrxus4e5BZf6CDM5PDGFpbk5lM,6139
16
+ vrml/weakkeydictfix.py,sha256=O-svMXnT2I7333EKtJOp59Kxj_QLaoAHzJGwfh2APmQ,1278
17
+ vrml/weaklist.py,sha256=36WRCeWWyPsMbfoSjEBUxlQIQxSNjP2EqVbMMXVuQTs,5759
18
+ vrml/weaktuple.py,sha256=bxIA6QZxIiWa1PEy1TNEDlRsGbSwL9gp7UJcgOKZ2BE,4733
19
+ vrml/vrml200x/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ vrml/vrml200x/parser.py,sha256=deDLgwLdXCBWudmhuFxU2eY_yyYhEOv_gg4ECwIis_k,3842
21
+ vrml/vrml97/__init__.py,sha256=QZ1php9-9TKWFblZ8L6LctbKTFJSKOVQtqM1JQHScqs,119
22
+ vrml/vrml97/_transformmatrix.py,sha256=rBG6B7mi32cGA3BzilzFfUoJklmUVU4-IXucOrPE2tg,3986
23
+ vrml/vrml97/_transformmatrix_accel.py,sha256=AMh9R0lMrXdEtsa3r9iaHDgtcyP0n4mq7mRAUtgmYlM,1922
24
+ vrml/vrml97/basenamespaces.py,sha256=BRk0qAG7kAWBvXLEVOEz0eSgWoq50JMYNLOb9AvM1-8,740
25
+ vrml/vrml97/basenodes.py,sha256=IXNxZq7EuoXRLA_DhZ9XLRt2e_0gAgmQtQabdydsZzY,28273
26
+ vrml/vrml97/linearise.py,sha256=p9a9vo05RmTgZnJSQKml42tnPxPHRrfLca5Olngy7vs,21946
27
+ vrml/vrml97/nodepath.py,sha256=dPtrTpYGrRKdjc0rQy1CIRW1rKYYs6-8LP78ne5OtcI,4948
28
+ vrml/vrml97/nodetypes.py,sha256=V00a3zA5ucNGn-csVNQL6f-hfSjUG6DVbREaiQzYYRQ,2275
29
+ vrml/vrml97/nurbs.py,sha256=JTRZBSEWOwvfL34tmgbk2THLErVpKlLZuH4-Su6dqUQ,3500
30
+ vrml/vrml97/parseprocessor.py,sha256=ZeTIhPqbxmpNy_mWfEIHud3cGom1blNoIPH2yITVHyU,16070
31
+ vrml/vrml97/parser.py,sha256=3jsCmpiYpO846QuQJJikUlGJeKAo-OxBxCmqjVYh5AA,3350
32
+ vrml/vrml97/scenegraph.py,sha256=8ebIqPWsiwVBAQrncuOfh1VbLGbIvWVAsnoCiBeVmLc,6955
33
+ vrml/vrml97/script.py,sha256=cxXRJp9xbYJTlO-hLqXSR_-UBmc8BWHSJE0_4Hor3_U,809
34
+ vrml/vrml97/shaders.py,sha256=Igc8A1td7n9pNl5-QINA1X-ZEKPYVcec-djleJhDYg4,5421
35
+ vrml/vrml97/transformmatrix.py,sha256=-7Em6LRpNxErUKqGOFoTPLma04oCrbdel2eJdDYeGjo,5673
36
+ pyvrml97-2.3.4b3.dist-info/METADATA,sha256=Ue-K5TWkQR5onszMzFXx8_Ezclo7-GsYlqeThvKLfIs,2491
37
+ pyvrml97-2.3.4b3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
38
+ pyvrml97-2.3.4b3.dist-info/top_level.txt,sha256=HNkQ-TkhfmnJgOd_zwLjqNi-T86T_CSpBac8zWIFGBc,5
39
+ pyvrml97-2.3.4b3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ vrml
vrml/__init__.py ADDED
@@ -0,0 +1,22 @@
1
+ """VRML Directed Acyclic Graph library and VRML97 tools
2
+
3
+ This package is a partial representation of VRML97
4
+ node and prototype semantics based loosely on the
5
+ original mcf.vrml processing engine by the author.
6
+ It is strongly dependent on the Python 2.2.2 property
7
+ class, and as such will not likely be portable to
8
+ earlier python versions.
9
+
10
+ The package includes a full VRML97 parser and
11
+ lineariser based on the SimpleParse 2.0 parsing engine
12
+ (also by the author).
13
+
14
+ The vrml.vrml97 sub-package contains classes and
15
+ functions specifically relating to the VRML97 ISO
16
+ standard. For instance, the vrml.vrml97.basenodes
17
+ file contains the "prototypes" for most of the
18
+ built-in nodes in the official specification.
19
+ """
20
+ __version__ = "2.3.4b3"
21
+ __author__ = "Michael Colin Fletcher"
22
+ __license__ = "BSD-style, see license.txt for details"
vrml/_bytes.py ADDED
@@ -0,0 +1,85 @@
1
+ """8-bit string definitions for Python 2/3 compatibility
2
+
3
+ Defines the following which allow for dealing with Python 3 breakages:
4
+
5
+ STR_IS_BYTES
6
+ STR_IS_UNICODE
7
+
8
+ Easily checked booleans for type identities
9
+
10
+ _NULL_8_BYTE
11
+
12
+ An 8-bit byte with NULL (0) value
13
+
14
+ as_8_bit( x, encoding='utf-8')
15
+
16
+ Returns the value as the 8-bit version
17
+
18
+ unicode -- always pointing to the unicode type
19
+ bytes -- always pointing to the 8-bit bytes type
20
+ """
21
+ import sys
22
+
23
+ _NULL_8_BYTE = b'\000'
24
+ try:
25
+ STR_IS_BYTES = True
26
+ STR_IS_UNICODE = False
27
+ unicode
28
+ bytes = str
29
+ unicode = unicode
30
+ long = long
31
+ integer_types = int,long
32
+ def as_8_bit( x, encoding='utf-8' ):
33
+ if isinstance( x, unicode ):
34
+ return x.encode( encoding )
35
+ return bytes( x )
36
+ def as_str( x, encoding='utf-8'):
37
+ """Produce a native string (i.e. different on python 2 and 3)"""
38
+ if isinstance(x,bytes):
39
+ return x
40
+ elif isinstance(x,unicode):
41
+ return x.encode(encoding)
42
+ else:
43
+ return str(x)
44
+ except NameError:
45
+ STR_IS_BYTES = False
46
+ STR_IS_UNICODE = True
47
+ unicode = str
48
+ bytes = bytes
49
+ long = int
50
+ integer_types = int,
51
+ def as_8_bit( x, encoding='utf-8' ):
52
+ if isinstance( x,unicode ):
53
+ return x.encode(encoding)
54
+ elif isinstance( x, bytes ):
55
+ # Note: this can create an 8-bit string that is *not* in encoding,
56
+ # but that is potentially exactly what we wanted, as these can
57
+ # be arbitrary byte-streams being passed to C functions
58
+ return x
59
+ return str(x).encode( encoding )
60
+ def as_str( x, encoding='utf-8'):
61
+ """Produce a native string (i.e. different on python 2 and 3)"""
62
+ if isinstance(x,unicode):
63
+ return x
64
+ elif isinstance(x,bytes):
65
+ return x.decode(encoding)
66
+ else:
67
+ return str(x)
68
+
69
+ if hasattr( sys, 'maxsize' ):
70
+ maxsize = sys.maxsize
71
+ else:
72
+ maxsize = sys.maxint
73
+
74
+ def as_unicode(x,encoding='utf-8'):
75
+ """Ensure is a unicode object given default encoding"""
76
+ if isinstance(x,unicode):
77
+ return x
78
+ elif isinstance(x,bytes):
79
+ try:
80
+ return x.decode(encoding)
81
+ except UnicodeDecodeError as err:
82
+ return x.decode('latin-1')
83
+ else:
84
+ return unicode(x)
85
+
vrml/arrays.py ADDED
@@ -0,0 +1,86 @@
1
+ """Abstraction point allowing use with numpy or Numeric
2
+
3
+ Chooses numpy if available because when it's installed
4
+ Numeric tends to be a bit flaky...
5
+ """
6
+
7
+ from numpy import *
8
+
9
+ try:
10
+ # TODO: don't import this here, as it's not
11
+ # actually *used* in pyvrml97, it's just used
12
+ # in OpenGLContext...
13
+ from vrml_accelerate import frustcullaccel
14
+ except ImportError as err:
15
+ frustcullaccel = None
16
+ # why did this get taken out? Is divide now safe?
17
+ amin = amin
18
+ amax = amax
19
+ divide_safe = divide
20
+ # Now deal with differing numpy APIs...
21
+ a = array([1, 2, 3], 'i')
22
+ ArrayType = ndarray # alias removed in later versions
23
+ # Take's API changed from Numeric, we've updated to
24
+ # always provide axis now...
25
+ if hasattr(a, '__array_typestr__'):
26
+
27
+ def typeCode(a):
28
+ """Retrieve the typecode for the given array
29
+
30
+ Depending on whether you access the classic or new API
31
+ you have different access methods, so we have to use
32
+ the typecode() method if __array_typestr__ isn't there.
33
+ """
34
+ try:
35
+ return a.__array_typestr__
36
+ except AttributeError:
37
+ return a.typecode()
38
+
39
+ else:
40
+
41
+ def typeCode(a):
42
+ """Retrieve the typecode for the given array
43
+
44
+ Depending on whether you access the classic or new API
45
+ you have different access methods, so we have to use
46
+ the typecode() method if .dtype.char isn't there.
47
+ """
48
+ try:
49
+ return a.dtype.char
50
+ except AttributeError:
51
+ return a.typecode()
52
+
53
+
54
+ del a
55
+ implementation_name = 'numpy'
56
+ try:
57
+ # PyVRML97 is from before numpy printed errors, we explicitly do not care
58
+ # about the divide-by-zero, which commonly happens in mesh data processing
59
+ # TODO: likely should rework the mesh processing to check manually and remove
60
+ # this sledge-hammer approach
61
+ seterr(all='ignore')
62
+ except Exception as err:
63
+ pass
64
+
65
+
66
+ def safeCompare(first, second):
67
+ """Watch out for pointless numpy truth-value checks"""
68
+ if first is None:
69
+ if second is None:
70
+ return True
71
+ else:
72
+ return False
73
+ elif second is None:
74
+ return False
75
+ if isinstance(first, (int, float, str)):
76
+ return first == second
77
+ if isinstance(first, ArrayType) and isinstance(second, ArrayType):
78
+ return bool(any(first == second))
79
+ elif type(first) != type(second):
80
+ return False
81
+ return bool(first == second)
82
+
83
+
84
+ def contiguous(a):
85
+ """Force to a contiguous array"""
86
+ return array(a, typeCode(a))
vrml/cache.py ADDED
@@ -0,0 +1,250 @@
1
+ """Caching mechanism for scene graph
2
+
3
+ Basically, the scenegraph Cache allows you to associate
4
+ data with particular nodes in the scene graph without
5
+ actually attaching the information to the particular
6
+ node being annotated.
7
+
8
+ This allows us to store cached information such as:
9
+ display list objects
10
+ texture objects
11
+ compiled array geometry
12
+
13
+ The cache uses weak reference key dictionaries to clear
14
+ the cache of data associated with deleted nodes within
15
+ the scene graph. similarly, cache is cleared when node
16
+ fields which are dependencies of the cache are changed.
17
+
18
+ The cache is based on the vrml.field and dispatch.dispatcher
19
+ modules. All field objects by default provide dispatcher
20
+ notifications on set and delete, and can provide
21
+ notification on get as well. The cache watches for these
22
+ notifications for dependent nodes where the dispatcher
23
+ messages are (type, fieldObject) for type in ("set","del").
24
+
25
+ There is a per-context cache, and a global cache, display-
26
+ lists, textures, etceteras should be stored in the per-
27
+ context cache, while data with dependencies only on the
28
+ node can be stored in the global cache.
29
+
30
+ Note:
31
+ The cache makes extensive use of weak references, and
32
+ was the failure case which exposed a number of problems
33
+ with the Python 2.2.2 weakref and weakkeydictionary
34
+ mechanisms.
35
+ """
36
+ from vrml import protofunctions
37
+ import weakref
38
+ #from vrml.weakkeydictfix import WeakKeyDictionary
39
+ from pydispatch import dispatcher
40
+ import traceback
41
+
42
+ import sys
43
+ if sys.version_info[0] == 2:
44
+ bytes = str
45
+ else:
46
+ unicode = str
47
+
48
+ class Cache (dict):
49
+ """Trivial sub-class of a dict which has some convenience methods
50
+
51
+ Maps id(client): {
52
+ key="": CacheHolder()
53
+ }
54
+
55
+ That is, for each client node, a dictionary
56
+ holds opaque key(normally strings) to CacheHolder
57
+ instances. The CacheHolder is responsible for
58
+ most of the implementation of the cache.
59
+ """
60
+ def getHolder( self, client, key = ""):
61
+ """Return the cache holder for the given client and key"""
62
+ current = self.get(id(client))
63
+ if current is not None:
64
+ return current.get( key)
65
+ return None
66
+ def getData( self, client, key="", default=None):
67
+ """Return the data for given client and key, default otherwise"""
68
+ current = self.get( id(client) )
69
+ if current is not None:
70
+ current = current.get( key )
71
+ if current is not None:
72
+ return current.data
73
+ return default
74
+ def holder(
75
+ self,
76
+ client,
77
+ data,
78
+ key="",
79
+ ):
80
+ """Create a new CacheHolder in this cache"""
81
+ return CacheHolder(
82
+ client,
83
+ data,
84
+ key,
85
+ self,
86
+ )
87
+
88
+ CACHE = Cache()
89
+ getData = CACHE.getData
90
+
91
+ def cleaner( cache, id ):
92
+ """Return callback function that cleans the given id from cache"""
93
+ def clean_id( weak ):
94
+ try:
95
+ del cache[id]
96
+ except Exception:
97
+ pass
98
+ return clean_id
99
+
100
+
101
+ class CacheHolder( object ):
102
+ """Holder for data values within a cache
103
+
104
+ The CacheHolder provides the bulk of the cache
105
+ implementation. It associates an opaque data value
106
+ with a client node and an opaque key. The key
107
+ value allows multiple dimensions of storage, to
108
+ allow, for instance storing compiled shadow
109
+ information separate from compiled geometry
110
+ information.
111
+
112
+ The depend method uses the dispatcher module
113
+ to invalidate this CacheHolder when the given
114
+ fields for the given nodes are changed.
115
+
116
+ Attributes:
117
+ client -- weak reference to the client node
118
+ key -- strong reference to the opaque key value
119
+ data -- strong reference to the opaque data value
120
+ cache -- weak reference to the cache in which
121
+ we are storing ourselves
122
+ """
123
+ #__slots__ = ('client','data','key','cache','nodeDependencies','__weakref__','notifier')
124
+ def __init__(
125
+ self,
126
+ client, data,
127
+ key="",
128
+ cache = CACHE,
129
+ ):
130
+ """Initialise the cache-deletion callable
131
+
132
+ client -- the node doing the caching, if gc'd,
133
+ then the entire cache for the node is deleted
134
+ key -- opaque key into the cache's per-node storage
135
+ cache -- the particular cache in which to store
136
+ ourselves.
137
+ """
138
+ client_id = id(client)
139
+ self.client = weakref.ref(client, cleaner( cache,client_id) )
140
+ self.key = key
141
+ self.data = data
142
+ self.cache = weakref.ref( cache )
143
+ self.nodeDependencies = []
144
+
145
+ # get the cached values for this client node
146
+ set = cache.get(client_id, None)
147
+ if set is None:
148
+ cache[ client_id ] = set = {}
149
+ set[key] = self
150
+ def set( self, data ):
151
+ """Set data after instantiation"""
152
+ self.data = data
153
+
154
+ def depend( self, node, field=None ):
155
+ """Add a dependency on given node's field value
156
+
157
+ source -- the node being watched
158
+ field -- the field on the node being watched
159
+
160
+ Dependency on the node means that this cache
161
+ holder will be invalidated if the field value
162
+ changes. This does not create a dependency
163
+ on the existence of node, so you should set
164
+ the dependency for the field holding any
165
+ nodes which should invalidate this CacheHolder
166
+
167
+ Note:
168
+ This does not affect any other CacheHolder
169
+ for our client node.
170
+ """
171
+ if field is not None:
172
+ if isinstance( field, (bytes,unicode)):
173
+ field = protofunctions.getField(node, field)
174
+ self.depend_signal(
175
+ ('set', field),#signal
176
+ node, # sender
177
+ )
178
+ self.depend_signal(
179
+ ('del', field),#signal
180
+ node, # sender
181
+ )
182
+ self.depend_signal(
183
+ ('route', field),#signal
184
+ node, # sender
185
+ )
186
+ else:
187
+ # dependency on the mere existence of the node
188
+ self.depend_object( node )
189
+ def depend_signal( self, signal, sender=dispatcher.Any ):
190
+ """Depend on signal from sender"""
191
+ dispatcher.connect(
192
+ self.clear,#receiver
193
+ signal,
194
+ sender,
195
+ )
196
+ def depend_object( self, node ):
197
+ """Depend on node's existence"""
198
+ self.nodeDependencies.append(
199
+ weakref.ref(
200
+ node,
201
+ self,
202
+ )
203
+ )
204
+ def clear( self, signal=None, sender=None ):
205
+ """Clear this object's held value (only)"""
206
+ if not self.client():
207
+ self( signal=signal, sender=sender )
208
+ else:
209
+ self.data = None
210
+ def __call__( self, signal=None, sender=None ):
211
+ """Delete the cached value (this object)
212
+
213
+ This de-registers ourselves from our cache object,
214
+ with suitable checks for whether our cache is still
215
+ alive itself, and whether it still has an entry
216
+ for our client and our key.
217
+
218
+ If this is the last registered cache object
219
+ for our client, deletes the overall cache dictionary
220
+ for the client.
221
+ """
222
+ try:
223
+ cache = self.cache()
224
+ if cache is None:
225
+ return 0
226
+ client = self.client()
227
+ if client is None:
228
+ return 0
229
+ client_id = id(client)
230
+ current = cache.get( client_id )
231
+ self.data = None
232
+ if current is None:
233
+ return 0
234
+ try:
235
+ del current[ self.key ]
236
+ if not current:
237
+ try:
238
+ del cache[ client_id ]
239
+ except KeyError:
240
+ pass
241
+ try:
242
+ del self.nodeDependencies[:]
243
+ except:
244
+ pass
245
+ return 1
246
+ except KeyError:
247
+ return 0
248
+ except RuntimeError:
249
+ traceback.print_exc()
250
+
vrml/copier.py ADDED
@@ -0,0 +1,27 @@
1
+ """Object representing node-copying pass"""
2
+
3
+ class Copier( object ):
4
+ """An object representing a node-copying pass"""
5
+ def __init__(
6
+ self,
7
+ shareProtos = 1,
8
+ instantiation=0,
9
+ ):
10
+ """Instantiate the copier object
11
+
12
+ # share prototypes, we don't currently support not doing this!
13
+ shareProtos -- whether to try to share prototypes between source
14
+ and copied nodes
15
+ instantiation -- whether this is a prototype-instantiation copy
16
+ baseNode -- baseNode for prototype instantiations, this is the
17
+ node whose sub-scenegraph is being built by the copier
18
+ """
19
+ self.shareProtos, self.instantiation = shareProtos, instantiation
20
+ def use( self, clientNode, newNode=None ):
21
+ """See whether (or register that) we have a USE for this (source) clientNode"""
22
+ if not hasattr( self, 'useNodes'):
23
+ self.useNodes = {}
24
+ if newNode is not None:
25
+ self.useNodes[ clientNode ] = newNode
26
+ else:
27
+ return self.useNodes.get( clientNode )