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
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Scenegraph node-like "prototype" for VRML97"""
|
|
2
|
+
from vrml import node, protofunctions, protonamespace, fieldtypes, route
|
|
3
|
+
from vrml import copier as copiermodule
|
|
4
|
+
from vrml.vrml97 import nodetypes
|
|
5
|
+
import weakref
|
|
6
|
+
from .._bytes import unicode
|
|
7
|
+
|
|
8
|
+
class SceneGraph( nodetypes.Traversable, node.Node ):
|
|
9
|
+
''' A VRML 97 sceneGraph
|
|
10
|
+
Attributes:
|
|
11
|
+
__gi__ -- constant string "sceneGraph"
|
|
12
|
+
DEF -- constant string ""
|
|
13
|
+
children -- Node list
|
|
14
|
+
List of the root children of the sceneGraph, nodes/scripts only
|
|
15
|
+
routes -- ROUTE list
|
|
16
|
+
List of the routes within the sceneGraph
|
|
17
|
+
defNames -- string DEFName: Node node
|
|
18
|
+
Mapping of DEF names to their respective nodes
|
|
19
|
+
protoTypes -- Namespace prototypes
|
|
20
|
+
Namespace (with chaining lookup) collection of prototypes
|
|
21
|
+
getattr( sceneGraph.protoTypes, 'nodeGI' ) retrieves a prototype
|
|
22
|
+
'''
|
|
23
|
+
PROTO = "sceneGraph"
|
|
24
|
+
children = node.MFNode( 'children',)
|
|
25
|
+
routes = route.MFRoute(
|
|
26
|
+
'routes',
|
|
27
|
+
)
|
|
28
|
+
baseURI = fieldtypes.SFString(
|
|
29
|
+
'baseURI',
|
|
30
|
+
1,
|
|
31
|
+
"",
|
|
32
|
+
)
|
|
33
|
+
def __init__(
|
|
34
|
+
self, root=None, protoTypes=None,
|
|
35
|
+
routes=None, defNames=None,
|
|
36
|
+
children=None,
|
|
37
|
+
*args, **namedargs
|
|
38
|
+
):
|
|
39
|
+
'''
|
|
40
|
+
root -- sceneGraph root or Dictionary root or Module root or None
|
|
41
|
+
Base object for root of protoType namespace hierarchy
|
|
42
|
+
protoTypes -- string nodeGI: Prototype PROTO
|
|
43
|
+
Dictionary of prototype definitions
|
|
44
|
+
routes -- ROUTE list or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut) list
|
|
45
|
+
List of route objects or tuples to be added to the sceneGraph
|
|
46
|
+
see attribute routes
|
|
47
|
+
defNames -- string DEFName: Node node
|
|
48
|
+
see attribute defNames
|
|
49
|
+
children -- Node list
|
|
50
|
+
see attribute children
|
|
51
|
+
'''
|
|
52
|
+
if root is not None:
|
|
53
|
+
self.root = weakref.ref( root )
|
|
54
|
+
else:
|
|
55
|
+
self.root = None
|
|
56
|
+
if protoTypes is None:
|
|
57
|
+
protoTypes = protonamespace.ProtoNamespace()
|
|
58
|
+
self.protoTypes = protoTypes
|
|
59
|
+
if defNames is None:
|
|
60
|
+
defNames = {}
|
|
61
|
+
self.defNames = defNames
|
|
62
|
+
namedargs['children'] = children
|
|
63
|
+
super( SceneGraph, self ).__init__(
|
|
64
|
+
*args,
|
|
65
|
+
**namedargs
|
|
66
|
+
)
|
|
67
|
+
node.Node.rootSceneGraph.fset( self, self )
|
|
68
|
+
if routes:
|
|
69
|
+
for route in routes:
|
|
70
|
+
self.addRoute( route )
|
|
71
|
+
def getProto( self, name ):
|
|
72
|
+
"""Get a prototype by name
|
|
73
|
+
|
|
74
|
+
go up the scenegraph chain to try to resolve
|
|
75
|
+
"""
|
|
76
|
+
current = self.protoTypes.get( name )
|
|
77
|
+
if current is not None:
|
|
78
|
+
return current
|
|
79
|
+
elif hasattr( self, 'root'):
|
|
80
|
+
root = self.root
|
|
81
|
+
if root:
|
|
82
|
+
root = root()
|
|
83
|
+
if root:
|
|
84
|
+
return root.getProto( name )
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
def getDEF( self, name ):
|
|
88
|
+
"""Get a node by DEF name"""
|
|
89
|
+
return self.defNames.get(name)
|
|
90
|
+
|
|
91
|
+
def regDefName(self, defName, object):
|
|
92
|
+
''' Register a DEF name for a particular object
|
|
93
|
+
|
|
94
|
+
defName -- string DEFName
|
|
95
|
+
object -- Node node
|
|
96
|
+
|
|
97
|
+
Eliminates previous references to the object by
|
|
98
|
+
its current DEFName and sets the object's new
|
|
99
|
+
DEFName.
|
|
100
|
+
'''
|
|
101
|
+
current = protofunctions.defName( object )
|
|
102
|
+
if self.defNames.get(current) is object:
|
|
103
|
+
del self.defNames[current]
|
|
104
|
+
protofunctions.defName( object, defName )
|
|
105
|
+
self.defNames[defName] = object
|
|
106
|
+
def addProto(self, proto):
|
|
107
|
+
'''Register a Prototype for this sceneGraph
|
|
108
|
+
proto -- Prototype PROTO
|
|
109
|
+
'''
|
|
110
|
+
self.protoTypes[protofunctions.name( proto ) ] = proto
|
|
111
|
+
def addRoute(self, route, *args):
|
|
112
|
+
'''Add a route to the scenegraph
|
|
113
|
+
|
|
114
|
+
route,args -- Possible forms:
|
|
115
|
+
|
|
116
|
+
ROUTE object -- added to routes
|
|
117
|
+
((source)node,field,(destination)node,field) -- ROUTE
|
|
118
|
+
created, nodes may be strings, in which case
|
|
119
|
+
getDEF( node ) is called for each
|
|
120
|
+
((source)node,field,target( signal, sender, value )) --
|
|
121
|
+
field.watch( target ) is called for the source
|
|
122
|
+
node (which can be a DEF name).
|
|
123
|
+
'''
|
|
124
|
+
if args:
|
|
125
|
+
route = (route,) + args
|
|
126
|
+
if isinstance( route, (tuple,list)):
|
|
127
|
+
if len(route) == 4:
|
|
128
|
+
# 4-element route definition, e.g. from strings...
|
|
129
|
+
from vrml.route import ROUTE
|
|
130
|
+
source,sourceField,destination,destinationField = route
|
|
131
|
+
if isinstance( source, (str,unicode)):
|
|
132
|
+
source = self.getDEF( source )
|
|
133
|
+
if isinstance( destination, (str,unicode)):
|
|
134
|
+
destination = self.getDEF( destination )
|
|
135
|
+
route = ROUTE(
|
|
136
|
+
source = source,
|
|
137
|
+
sourceField = sourceField,
|
|
138
|
+
destination = destination,
|
|
139
|
+
destinationField = destinationField,
|
|
140
|
+
)
|
|
141
|
+
elif len(route) == 3:
|
|
142
|
+
# 2-element source plus a function to receive...
|
|
143
|
+
source,sourceField,target = route
|
|
144
|
+
if not callable( target ):
|
|
145
|
+
raise TypeError(
|
|
146
|
+
"""Need a callable target object!"""
|
|
147
|
+
)
|
|
148
|
+
if isinstance( source, (str,unicode)):
|
|
149
|
+
source = self.getDEF( source )
|
|
150
|
+
field = protofunctions.getField( source, sourceField )
|
|
151
|
+
field.watch( source, target, ('set',field) )
|
|
152
|
+
field.watch( source, target, ('del',field) )
|
|
153
|
+
self.routes.append( route )
|
|
154
|
+
return route
|
|
155
|
+
## def addIsMap( self, name, node, field ):
|
|
156
|
+
## """Add an isMap for the given name to the given node+field"""
|
|
157
|
+
## self.isMaps.setdefault( name, []).append( (node,field) )
|
|
158
|
+
|
|
159
|
+
def copy( self, copier=None ):
|
|
160
|
+
"""Copy this node for copier"""
|
|
161
|
+
if copier is None:
|
|
162
|
+
copier = copiermodule.Copier()
|
|
163
|
+
# order for creation is going to be important to make sure
|
|
164
|
+
# that prototypes are available to nodes getting re-built
|
|
165
|
+
# if we aren't sharing protos...
|
|
166
|
+
if not copier.shareProtos:
|
|
167
|
+
newPrototypes = protonamespace.ProtoNamespace()
|
|
168
|
+
for key,value in self.protoTypes.items():
|
|
169
|
+
newPrototypes[key] = protofunctions.copyProto( value, copier )
|
|
170
|
+
else:
|
|
171
|
+
newPrototypes = self.protoTypes.copy()
|
|
172
|
+
newDefs = {}
|
|
173
|
+
for key,value in self.defNames.items():
|
|
174
|
+
if (not key) or value is None:
|
|
175
|
+
continue
|
|
176
|
+
newDefs[key] = value.copy( copier )
|
|
177
|
+
node = super( SceneGraph, self).copy( copier )
|
|
178
|
+
node.protoTypes = newPrototypes
|
|
179
|
+
node.defNames = newDefs
|
|
180
|
+
return node
|
|
181
|
+
|
vrml/vrml97/script.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""VRML97 Script-node stub"""
|
|
2
|
+
from vrml import node, fieldtypes
|
|
3
|
+
from vrml.vrml97 import nodetypes
|
|
4
|
+
|
|
5
|
+
class _Script( nodetypes.Children, node.Node ):
|
|
6
|
+
"""A sub-type of node with scripting/pseudo-proto support
|
|
7
|
+
|
|
8
|
+
The class here just handles basic node-like functionality,
|
|
9
|
+
a special constructor factory takes care of the PROTO-like
|
|
10
|
+
functionality.
|
|
11
|
+
"""
|
|
12
|
+
url = fieldtypes.MFString(
|
|
13
|
+
'url', 1,
|
|
14
|
+
)
|
|
15
|
+
directOutput = fieldtypes.SFBool(
|
|
16
|
+
'directOutput', default = 0,
|
|
17
|
+
)
|
|
18
|
+
mustEvaluate = fieldtypes.SFBool(
|
|
19
|
+
'mustEvaluate', default = 0,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def Script( fields, **namedarguments ):
|
|
23
|
+
"""Create a new script prototype and an instance of that prototype"""
|
|
24
|
+
proto = node.prototype( 'Script', fields, baseClasses = (_Script,) )
|
|
25
|
+
return proto( **namedarguments )
|
vrml/vrml97/shaders.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Node definitions for a non-standard Programable Shaders extension
|
|
2
|
+
"""
|
|
3
|
+
from vrml.vrml97 import nodetypes
|
|
4
|
+
from vrml import field, node, fieldtypes
|
|
5
|
+
|
|
6
|
+
class ShaderGeometry( nodetypes.Children, nodetypes.Rendering, node.Node ):
|
|
7
|
+
"""Generic geometry definition for a shader-based renderer
|
|
8
|
+
|
|
9
|
+
attributes -- define the attribute pointers which feed the
|
|
10
|
+
shader, the individual attributes may share a buffer or
|
|
11
|
+
define one per attribute
|
|
12
|
+
indices -- if present, node defining index array to be used
|
|
13
|
+
to index into buffers, will be uploaded to an element
|
|
14
|
+
buffer
|
|
15
|
+
uniforms -- Uniform nodes which are bound/updated on the
|
|
16
|
+
shader before rendering this geometry, binds to the
|
|
17
|
+
shader's location == to the uniform's name.
|
|
18
|
+
slices -- slices of the array to render, if not specified
|
|
19
|
+
then we'll render the whole data-set
|
|
20
|
+
"""
|
|
21
|
+
PROTO = "ShaderGeometry"
|
|
22
|
+
indices = field.newField( 'indices', 'MFInt32', 1, list )
|
|
23
|
+
attributes = field.newField( 'attributes','MFNode',1,list )
|
|
24
|
+
slices = field.newField( 'slices', 'MFNode',1,list )
|
|
25
|
+
uniforms = field.newField( 'uniforms','MFNode',1,list )
|
|
26
|
+
appearance = field.newField( 'appearance', 'SFNode',1,list )
|
|
27
|
+
|
|
28
|
+
class ShaderSlice( node.Node ):
|
|
29
|
+
"""Segment of a shader geometry element to render"""
|
|
30
|
+
offset = field.newField( 'offset', 'SFUInt32',1, -1 )
|
|
31
|
+
count = field.newField( 'count', 'SFUInt32',1, -1 )
|
|
32
|
+
uniforms = field.newField( 'uniforms','MFNode',1,list)
|
|
33
|
+
|
|
34
|
+
class ShaderAttribute( node.Node ):
|
|
35
|
+
"""Attribute (variable) binding for a shader
|
|
36
|
+
"""
|
|
37
|
+
name = field.newField( 'name', 'SFString', 1, '' )
|
|
38
|
+
offset = field.newField( 'offset','SFUInt32',1, 0 )
|
|
39
|
+
stride = field.newField( 'stride', 'SFUInt32',1, 0 ) # default to buffer natural stride
|
|
40
|
+
size = field.newField( 'size','SFUInt32',1,3 ) # default num of elements
|
|
41
|
+
dataType = field.newField( 'dataType','SFString', 1, 'FLOAT' )
|
|
42
|
+
# the buffer into which we index...
|
|
43
|
+
buffer = field.newField( 'buffer','SFNode',1,node.NULL )
|
|
44
|
+
isCoord = field.newField( 'isCoord','SFBool',1,False)
|
|
45
|
+
bufferKey = field.newField( 'bufferKey', 'SFString', 1,'')
|
|
46
|
+
|
|
47
|
+
class ShaderBuffer( node.Node ):
|
|
48
|
+
"""Buffer of data into which pointers can be generated"""
|
|
49
|
+
type = field.newField( 'type','SFString', 1, 'ARRAY' )
|
|
50
|
+
usage = field.newField( 'usage','SFString', 1, 'DYNAMIC_DRAW' )
|
|
51
|
+
buffer = field.newField( 'buffer','SFArray32', 1, list )
|
|
52
|
+
class ShaderIndexBuffer( ShaderBuffer ):
|
|
53
|
+
"""Buffer of data from which indices are generated"""
|
|
54
|
+
type = field.newField( 'type','SFString', 1, 'ELEMENT' )
|
|
55
|
+
usage = field.newField( 'usage','SFString', 1, 'DYNAMIC_DRAW' )
|
|
56
|
+
buffer = field.newField( 'buffer','MFUInt32', 1, list )
|
|
57
|
+
|
|
58
|
+
class FloatUniform( node.Node ):
|
|
59
|
+
"""Uniform (variable) binding for a shader
|
|
60
|
+
|
|
61
|
+
The FloatUniform is the base class for FloatUniforms,
|
|
62
|
+
that is, there are FloatUniform1f, FloatUniform2f,
|
|
63
|
+
FloatUniformm3x2, etceteras Node-types, but not a
|
|
64
|
+
FloatUniform node-type.
|
|
65
|
+
"""
|
|
66
|
+
name = field.newField( 'name', 'SFString', 1, '' )
|
|
67
|
+
# type values, 1f, 2f, 3f, 4f, m2, m3, m4, m2x3,m3x2,m2x4,m4x2,m3x4,m4x3
|
|
68
|
+
value = field.newField( 'value', 'SFArray32', 1, list )
|
|
69
|
+
|
|
70
|
+
class IntUniform( node.Node ):
|
|
71
|
+
"""Uniform (variable) binding for a shader (integer form)
|
|
72
|
+
"""
|
|
73
|
+
PROTO = "IntUniform"
|
|
74
|
+
name = field.newField( 'name', 'SFString', 1, '' )
|
|
75
|
+
# type values, 1i,2i,3i,4i
|
|
76
|
+
value = field.newField( 'value', 'MFInt32', 1, list )
|
|
77
|
+
|
|
78
|
+
class TextureUniform( node.Node ):
|
|
79
|
+
"""Uniform which specifies a texture sampler"""
|
|
80
|
+
PROTO = 'TextureUniform'
|
|
81
|
+
name = field.newField( 'name','SFString', 1, '' )
|
|
82
|
+
value = field.newField( 'value', 'SFNode', 1, node.NULL )
|
|
83
|
+
class TextureBufferUniform( node.Node ):
|
|
84
|
+
"""Uniform which specifies a texture across vbo data"""
|
|
85
|
+
PROTO = 'TextureBufferUniform'
|
|
86
|
+
name = field.newField( 'name','SFString', 1, '' )
|
|
87
|
+
value = field.newField( 'value', 'SFNode', 1, node.NULL )
|
|
88
|
+
format = field.newField( 'format', 'SFString',1,'RGBA32F' )
|
|
89
|
+
|
|
90
|
+
class GLSLShader( node.Node ):
|
|
91
|
+
"""GLSL-based shader node"""
|
|
92
|
+
PROTO = "GLSLShader"
|
|
93
|
+
url = field.newField( 'url', 'MFString', 1, list)
|
|
94
|
+
source = field.newField( 'source','MFString',1, list)
|
|
95
|
+
imports = field.newField( 'imports', 'MFNode', 1, list )
|
|
96
|
+
# type values, VERTEX or FRAGMENT
|
|
97
|
+
type = field.newField( 'type', 'SFString', 1, 'VERTEX' )
|
|
98
|
+
|
|
99
|
+
class GLSLImport( node.Node ):
|
|
100
|
+
"""GLSL-base shader source-code import"""
|
|
101
|
+
PROTO = "GLSLImport"
|
|
102
|
+
url = field.newField( 'url', 'MFString', 1, list)
|
|
103
|
+
source = field.newField( 'source','MFString',1, list)
|
|
104
|
+
|
|
105
|
+
class GLSLObject( node.Node ):
|
|
106
|
+
"""GLSL-based shader object (compiled set of shaders)"""
|
|
107
|
+
PROTO = "GLSLObject"
|
|
108
|
+
# role values, VISIBLE, DEPTH, SELECT
|
|
109
|
+
role = field.newField( 'role', 'SFString', 1, 'VISIBLE' )
|
|
110
|
+
uniforms = field.newField( 'uniforms', 'MFNode', 1, list )
|
|
111
|
+
shaders = field.newField( 'shaders', 'MFNode', 1, list )
|
|
112
|
+
# textures is a set of texture uniforms...
|
|
113
|
+
textures = field.newField( 'textures', 'MFNode', 1, list )
|
|
114
|
+
|
|
115
|
+
class Shader( node.Node ):
|
|
116
|
+
"""Shader is a programmable substitute for an Appearance node"""
|
|
117
|
+
PROTO = 'Shader'
|
|
118
|
+
#Fields
|
|
119
|
+
material = field.newField( 'material', 'SFNode', 1, node.NULL)
|
|
120
|
+
objects = field.newField( 'objects', 'MFNode', 1, list )
|
|
121
|
+
|
|
122
|
+
implementation = field.newField( 'implementation','SFNode',1,node.NULL)
|
|
123
|
+
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Utility module for creating transformation matrices
|
|
2
|
+
|
|
3
|
+
Basically this gives you the ability to construct
|
|
4
|
+
transformation matrices without needing OpenGL
|
|
5
|
+
or similar run-time engines. The result is that
|
|
6
|
+
design-time utilities can process files without
|
|
7
|
+
trading dependencies on a particular run-time.
|
|
8
|
+
|
|
9
|
+
This code is originally from the mcf.vrml processing
|
|
10
|
+
engine, and has only been cosmetically altered to
|
|
11
|
+
fit the new organizational pattern.
|
|
12
|
+
|
|
13
|
+
Note: to apply these matrices to a particular coordinate,
|
|
14
|
+
you would do the following:
|
|
15
|
+
|
|
16
|
+
p = ones( 4 )
|
|
17
|
+
p[:3] = coordinate
|
|
18
|
+
return dot( p, matrix)
|
|
19
|
+
|
|
20
|
+
That is, you use the homogenous coordinate, and
|
|
21
|
+
make it the first item in the dot'ing.
|
|
22
|
+
"""
|
|
23
|
+
from math import *
|
|
24
|
+
from vrml.arrays import *
|
|
25
|
+
try:
|
|
26
|
+
from vrml.vrml97._transformmatrix_accel import (
|
|
27
|
+
rotMatrix,
|
|
28
|
+
scaleMatrix,
|
|
29
|
+
transMatrix,
|
|
30
|
+
perspectiveMatrix,
|
|
31
|
+
orthoMatrix,
|
|
32
|
+
)
|
|
33
|
+
except ImportError:
|
|
34
|
+
from vrml.vrml97._transformmatrix import (
|
|
35
|
+
rotMatrix,
|
|
36
|
+
scaleMatrix,
|
|
37
|
+
transMatrix,
|
|
38
|
+
perspectiveMatrix,
|
|
39
|
+
orthoMatrix,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
assert perspectiveMatrix
|
|
43
|
+
assert orthoMatrix
|
|
44
|
+
|
|
45
|
+
# used to determine whether angles are non-null
|
|
46
|
+
TWOPI = pi * 2.0
|
|
47
|
+
RADTODEG = 360./TWOPI
|
|
48
|
+
DEGTORAD = TWOPI/360.
|
|
49
|
+
# used to determine the center point of a transform
|
|
50
|
+
ORIGINPOINT = array([0,0,0,1],'f')
|
|
51
|
+
VERY_SMALL = 1e-300
|
|
52
|
+
|
|
53
|
+
def transformMatrix(
|
|
54
|
+
translation = (0,0,0),
|
|
55
|
+
center = (0,0,0),
|
|
56
|
+
rotation = (0,1,0,0),
|
|
57
|
+
scale = (1,1,1),
|
|
58
|
+
scaleOrientation = (0,1,0,0),
|
|
59
|
+
parentMatrix = None,
|
|
60
|
+
):
|
|
61
|
+
"""Convert VRML transform values to an overall matrix
|
|
62
|
+
|
|
63
|
+
Returns 4x4 transformation matrix
|
|
64
|
+
Note that this uses VRML standard for rotations
|
|
65
|
+
(angle last, and in radians).
|
|
66
|
+
|
|
67
|
+
This should return matrices which, when applied to
|
|
68
|
+
local-space coordinates, give you parent-space
|
|
69
|
+
coordinates.
|
|
70
|
+
|
|
71
|
+
parentMatrix if provided, should be the parent's
|
|
72
|
+
transformation matrix, a 4x4 matrix of such as
|
|
73
|
+
returned by this function.
|
|
74
|
+
"""
|
|
75
|
+
T,T1 = transMatrix( translation )
|
|
76
|
+
C,C1 = transMatrix( center )
|
|
77
|
+
R,R1 = rotMatrix( rotation )
|
|
78
|
+
SO,SO1 = rotMatrix( scaleOrientation )
|
|
79
|
+
S,S1 = scaleMatrix( scale )
|
|
80
|
+
return compressMatrices( parentMatrix, T,C,R,SO,S,SO1,C1 )
|
|
81
|
+
|
|
82
|
+
def itransformMatrix(
|
|
83
|
+
translation = (0,0,0),
|
|
84
|
+
center = (0,0,0),
|
|
85
|
+
rotation = (0,1,0,0),
|
|
86
|
+
scale = (1,1,1),
|
|
87
|
+
scaleOrientation = (0,1,0,0),
|
|
88
|
+
parentMatrix = None,
|
|
89
|
+
):
|
|
90
|
+
"""Convert VRML transform values to an inverse transform matrix
|
|
91
|
+
|
|
92
|
+
Returns 4x4 transformation matrix
|
|
93
|
+
Note that this uses VRML standard for rotations
|
|
94
|
+
(angle last, and in radians).
|
|
95
|
+
|
|
96
|
+
This should return matrices which, when applied to
|
|
97
|
+
parent-space coordinates, give you local-space
|
|
98
|
+
coordinates for the corresponding transform.
|
|
99
|
+
|
|
100
|
+
Note: this is a substantially un-tested algorithm
|
|
101
|
+
though it seems to be properly constructed as far
|
|
102
|
+
as I can see. Whether to use dot(x, parentMatrix)
|
|
103
|
+
or the reverse is not immediately clear to me.
|
|
104
|
+
|
|
105
|
+
parentMatrix if provided, should be the child's
|
|
106
|
+
transformation matrix, a 4x4 matrix of such as
|
|
107
|
+
returned by this function.
|
|
108
|
+
"""
|
|
109
|
+
T,T1 = transMatrix( translation )
|
|
110
|
+
C,C1 = transMatrix( center )
|
|
111
|
+
R,R1 = rotMatrix( rotation )
|
|
112
|
+
SO,SO1 = rotMatrix( scaleOrientation )
|
|
113
|
+
S,S1 = scaleMatrix( scale )
|
|
114
|
+
return compressMatrices( parentMatrix, C,SO, S1, SO1, R1, C1, T1)
|
|
115
|
+
|
|
116
|
+
def transformMatrices(
|
|
117
|
+
translation = (0,0,0),
|
|
118
|
+
center = (0,0,0),
|
|
119
|
+
rotation = (0,1,0,0),
|
|
120
|
+
scale = (1,1,1),
|
|
121
|
+
scaleOrientation = (0,1,0,0),
|
|
122
|
+
parentMatrix = None,
|
|
123
|
+
):
|
|
124
|
+
"""Calculate both forward and backward matrices for these parameters"""
|
|
125
|
+
T,T1 = transMatrix( translation )
|
|
126
|
+
C,C1 = transMatrix( center )
|
|
127
|
+
R,R1 = rotMatrix( rotation )
|
|
128
|
+
SO,SO1 = rotMatrix( scaleOrientation )
|
|
129
|
+
S,S1 = scaleMatrix( scale )
|
|
130
|
+
return (
|
|
131
|
+
compressMatrices( parentMatrix, T,C,R,SO,S,SO1,C1 ),
|
|
132
|
+
compressMatrices( parentMatrix, C,SO, S1, SO1, R1, C1, T1)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def localMatrices(
|
|
136
|
+
translation = (0,0,0),
|
|
137
|
+
center = (0,0,0),
|
|
138
|
+
rotation = (0,1,0,0),
|
|
139
|
+
scale = (1,1,1),
|
|
140
|
+
scaleOrientation = (0,1,0,0),
|
|
141
|
+
parentMatrix = None,
|
|
142
|
+
):
|
|
143
|
+
"""Calculate (forward,inverse) matrices for this transform element"""
|
|
144
|
+
T,T1 = transMatrix( translation )
|
|
145
|
+
C,C1 = transMatrix( center )
|
|
146
|
+
R,R1 = rotMatrix( rotation )
|
|
147
|
+
SO,SO1 = rotMatrix( scaleOrientation )
|
|
148
|
+
S,S1 = scaleMatrix( scale )
|
|
149
|
+
return (
|
|
150
|
+
compressMatrices( T,C,R,SO,S,SO1,C1 ),
|
|
151
|
+
compressMatrices( C,SO, S1, SO1, R1, C1, T1)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def compressMatrices( *matrices ):
|
|
155
|
+
"""Compress a set of matrices
|
|
156
|
+
|
|
157
|
+
Any (or all) of the matrices may be None,
|
|
158
|
+
if *all* are None, then the result will be None,
|
|
159
|
+
otherwise will be the dot product of all of the
|
|
160
|
+
matrices...
|
|
161
|
+
"""
|
|
162
|
+
if not matrices:
|
|
163
|
+
return None
|
|
164
|
+
else:
|
|
165
|
+
first = matrices[0]
|
|
166
|
+
matrices = matrices[1:]
|
|
167
|
+
for item in matrices:
|
|
168
|
+
if item is not None:
|
|
169
|
+
if first is None:
|
|
170
|
+
first = item
|
|
171
|
+
else:
|
|
172
|
+
first = dot( item, first )
|
|
173
|
+
return first
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def center(
|
|
177
|
+
translation = (0,0,0),
|
|
178
|
+
center = (0,0,0),
|
|
179
|
+
parentMatrix = None,
|
|
180
|
+
):
|
|
181
|
+
"""Determine the center of rotation for a transform node
|
|
182
|
+
|
|
183
|
+
Returns the parent-space coordinate of the
|
|
184
|
+
node's center of rotation.
|
|
185
|
+
"""
|
|
186
|
+
if parentMatrix is None:
|
|
187
|
+
parentMatrix = identity(4)
|
|
188
|
+
T,T1 = transMatrix( translation )
|
|
189
|
+
C,C1 = transMatrix( center )
|
|
190
|
+
for x in (T,C):
|
|
191
|
+
if x:
|
|
192
|
+
parentMatrix = dot( x, parentMatrix)
|
|
193
|
+
return dot( ORIGINPOINT, parentMatrix )
|
vrml/weakkeydictfix.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Module providing patched weakkeydictionary operation"""
|
|
2
|
+
import weakref
|
|
3
|
+
ref = weakref.ref
|
|
4
|
+
|
|
5
|
+
class WeakKeyDictionary( weakref.WeakKeyDictionary ):
|
|
6
|
+
"""Sub-class to work around error in WeakKeyDictionary implementation
|
|
7
|
+
|
|
8
|
+
Python 2.2.2 and 2.2.3c1 both have an annoying
|
|
9
|
+
problem in their __delitem__ for the
|
|
10
|
+
WeakKeyDictionary class. This class provides
|
|
11
|
+
a work-around for it.
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self, dict=None):
|
|
14
|
+
"""Initialize the WeakKeyDictionary
|
|
15
|
+
|
|
16
|
+
dict -- previously-existing weak key records or
|
|
17
|
+
None to create a new dictionary
|
|
18
|
+
"""
|
|
19
|
+
self.data = {}
|
|
20
|
+
def remove(k, selfref=ref(self)):
|
|
21
|
+
self = selfref()
|
|
22
|
+
if self is not None and self.data:
|
|
23
|
+
try:
|
|
24
|
+
v = self.data.get( k )
|
|
25
|
+
del self.data[k]
|
|
26
|
+
except (KeyError,RuntimeError):
|
|
27
|
+
pass
|
|
28
|
+
# now v goes out of scope and is deleted...
|
|
29
|
+
self._remove = remove
|
|
30
|
+
if dict is not None: self.update(dict)
|
|
31
|
+
def __delitem__(self, key):
|
|
32
|
+
"""Overridden delitem to avoid scanning"""
|
|
33
|
+
try:
|
|
34
|
+
del self.data[weakref.ref(key)]
|
|
35
|
+
except KeyError:
|
|
36
|
+
raise KeyError( """Item %r does not appear as a key"""%( key,))
|