OpenGLContext.scenegraph.boundingvolume
index
p:\openglcontext\scenegraph\boundingvolume.py

Bounding volume implementation
 
Based on code from:
        http://www.markmorley.com/opengl/frustumculling.html
 
Notes regarding general implementation:
 
        BoundingVolume objects are generally created by Grouping
        and/or Shape nodes (or rather, the geometry nodes of Shape
        nodes).  Grouping nodes are able to create union
        BoundingVolume objects from their children's bounding
        volumes.
 
        The RenderPass object (for visiting rendering passes)
        defines a children method which will use the bounding
        volumes to filter out those children which are not visible.
 
        The first attempt to do that filtering will recursively
        generate and cache the bounding volumes.
 
        Setting the module-global value DEBUG_RENDER_VOLUMES while
        not running in Python's -O (optimised) mode will draw all
        Axis-aligned bounding boxes (the normal/default volumes)
        as red line-sets.

 
Modules
            
Numeric
OpenGLContext.scenegraph.cache
copy
copy_reg
OpenGLContext.doinchildmatrix
exceptions
vrml.field
OpenGLContext.frustum
math
multiarray
vrml.node
vrml.vrml97.nodetypes
pickle
vrml.protofunctions
string
types
OpenGLContext.utilities
 
Classes
            
Node(object)
BoundingVolume
BoundingBox
AABoundingBox
BoundingSphere
UnboundedVolume
ValueError(StandardError)
UnboundedObject
 
class AABoundingBox(BoundingBox)
      Representation of an axis-aligned bounding box
 
The axis-aligned bounding box defines the entire
bounding box with two pieces of data, a center position
and a size vector.  Other than this, it is just a
point-based bounding box implementation.
 
  
Method resolution order:
AABoundingBox
BoundingBox
BoundingVolume
Node
object

Methods defined here:
_occlusionRender(self)
Do the low-level rendering of the occlusion volume
debugRender(self)
Render this bounding box for debugging mode
 
Draws the bounding box as a set of lines in the
current OpenGL matrix (in OpenGLContext's visiting
pattern, this is the matrix of the parent of the
node which is determining whether to cull the node
to which this bounding box is attached)
getPoints(self)
Return set of points to test against the frustum
 
If self.points field is not set, will calculate the
points from the center and size fields.
occlusionVisible(self, mode=None)
Render this bounding volume for an occlusion test
 
This requires that the GL_HP_occlusion_test
extension be available.
 
Note:
        We will someday want to avoid doing this test
        if the time required to do the occlusion test
        is > the time to render our children.  We don't
        yet have the instrumentation in the rendering
        engine to support that :( .
visible(self, frust, matrix=None, occlusion=0, mode=None)
Allow for occlusion-checking as well as frustum culling

Properties defined here:
center
field SFVec3f center (0, 0, 0)
center getter = fget(self, client) from SFVec3f
Get the client's value for this property
 
if notify is true send a notification event.
center setter = fset(self, client, value, notify=1) from SFVec3f
Set the client's value for this property
 
if notify is true send a notification event.
center deleter = fdel(self, client, notify=1) from SFVec3f
Delete the client's value for this property
 
if notify is true send a notification event.
size
field SFVec3f size (0, 0, 0)
size getter = fget(self, client) from SFVec3f
Get the client's value for this property
 
if notify is true send a notification event.
size setter = fset(self, client, value, notify=1) from SFVec3f
Set the client's value for this property
 
if notify is true send a notification event.
size deleter = fdel(self, client, notify=1) from SFVec3f
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions defined here:
__doc__ = 'Representation of an axis-aligned bounding box\n\n...ust a\n\tpoint-based bounding box implementation.\n\t'
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Static methods inherited from BoundingBox:
union(boxes, matrix=None)
Create BoundingBox union for the given bounding boxes
 
This uses the getPoints method of the given
bounding boxes to retrieve the extrema points
which must be present in the union.  It then
calculates an Axis-Aligned bounding box shape
taking into account the matrix given.
 
It would seem somewhat more efficient here to
use the points array directly, but that would
have the effect of geometrically increasing the
number of checks for each succeeding parent,
while creating the axis-aligned bounding box
trades more work here to keep the constant-time
operation for the "visible" check.
 
Group nodes pass a None as the matrix, while
Transform nodes should pass their individual
transformation matrix (not the cumulative matrix).
 
boxes -- list of AABoundingBox instances
matrix -- if specified, the matrix to be applied
        to the box coordinates before calculating the
        resulting axis-aligned bounding box.

Properties inherited from BoundingBox:
points
field MFVec4f points []
points getter = fget(self, client) from MFVec4f
Get the client's value for this property
 
if notify is true send a notification event.
points setter = fset(self, client, value, notify=1) from MFVec4f
Set the client's value for this property
 
if notify is true send a notification event.
points deleter = fdel(self, client, notify=1) from MFVec4f
Delete the client's value for this property
 
if notify is true send a notification event.

Methods inherited from Node:
__init__(self, **namedarguments)
Initialise the node with appropriate named args
 
All properties/attributes must be specified with
named arguments, and the property/attribute must
exist within the Node's class/prototype.
 
This will raise AttributeError/ValueError/TypeError
if the values or the property names are inappropriate.
 
Note that all Node objects have the attribute/property
        exposedField SFString DEF ""
defined.  You may therefore specify a DEF name by
passing it as a named argument.
__repr__(self)
Get a code-like representation of the Node
 
Basically every attribute except for sub-nodes values
are returned as a full representation.
__str__(self)
Get a friendly representation of the Node
copy(self, copier=None)
Copy this node for copier
toString(self, **namedargs)
Generate a VRML 97-syntax string representing this Prototype
**namedargs -- key:value
        passed arguments for the linearisation object
see lineariser4.Lineariser

Properties inherited from Node:
DEF
exposedField SFString  DEF 
DEF getter = fget(self, client) from SFString
Get the client's value for this property
 
if notify is true send a notification event.
DEF setter = fset(self, client, value, notify=1) from SFString
Set the client's value for this property
 
if notify is true send a notification event.
DEF deleter = fdel(self, client, notify=1) from SFString
Delete the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph
exposedField WeakSFNode  root NULL
rootSceneGraph getter = fget(self, client) from WeakSFNode
Get the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph setter = fset(self, client, value, notify=1) from WeakSFNode
Set the client's value for this property
 
notify -- if true send a notification event
 
The SFNode tries to update the value's root
attribute to point to the root of the client
*iff* the value doesn't currently point at
a valid root.  (That is, it only updates root
if there is no current root).  This is done
without sending notify events.
rootSceneGraph deleter = fdel(self, client, notify=1) from WeakSFNode
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions inherited from Node:
PROTO = ''
__dict__ = <dict-proxy object at 0x076900A8>
__weakref__ = <member '__weakref__' of 'Node' objects>
externalURL = ()

Methods inherited from object:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__hash__(...)
x.__hash__() <==> hash(x)
__reduce__(...)
helper for pickle
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and non-method functions inherited from object:
__class__ = <type 'type'>
__new__ = <built-in method __new__ of type object at 0x1E0BD978>
T.__new__(S, ...) -> a new object with type S, a subtype of T
 
class BoundingBox(BoundingVolume)
      Generic representation of a bounding box
 
A bounding box is a bounding volume which is implemented
as a set of points which can be tested against a frustum.
Although at the moment we don't use the distinction between
BoundingBox and AABoundingBox, the BoundingBox may
eventually be used to provide specialized support for
bitmap Text nodes (which should only need four points
to determine their visibility, rather than eight).
 
  
Method resolution order:
BoundingBox
BoundingVolume
Node
object

Methods defined here:
debugRender(self)
Render this bounding box for debugging mode
 
XXX Should really use points for rendering GL_POINTS
        geometry for the base class when it gets used.
getPoints(self)
Return set of points to test against the frustum
visible(self, frust, matrix=None, occlusion=0, mode=None)
Determine whether this bounding-box is visible in frustum
 
frustum -- Frustum object holding the clipping planes
        for the view
matrix -- a matrix which transforms the local
        coordinates to the (world-space) coordinate
        system in which the frustum is defined.
 
This version of the method uses a pure-python loop
to do the actual culling once the points are
multiplied by the matrix. (i.e. it does not use the
frustcullaccel C extension module)

Static methods defined here:
union(boxes, matrix=None)
Create BoundingBox union for the given bounding boxes
 
This uses the getPoints method of the given
bounding boxes to retrieve the extrema points
which must be present in the union.  It then
calculates an Axis-Aligned bounding box shape
taking into account the matrix given.
 
It would seem somewhat more efficient here to
use the points array directly, but that would
have the effect of geometrically increasing the
number of checks for each succeeding parent,
while creating the axis-aligned bounding box
trades more work here to keep the constant-time
operation for the "visible" check.
 
Group nodes pass a None as the matrix, while
Transform nodes should pass their individual
transformation matrix (not the cumulative matrix).
 
boxes -- list of AABoundingBox instances
matrix -- if specified, the matrix to be applied
        to the box coordinates before calculating the
        resulting axis-aligned bounding box.

Properties defined here:
points
field MFVec4f points []
points getter = fget(self, client) from MFVec4f
Get the client's value for this property
 
if notify is true send a notification event.
points setter = fset(self, client, value, notify=1) from MFVec4f
Set the client's value for this property
 
if notify is true send a notification event.
points deleter = fdel(self, client, notify=1) from MFVec4f
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions defined here:
__doc__ = 'Generic representation of a bounding box\n\n\tA bou...determine their visibility, rather than eight).\n\t'
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Methods inherited from Node:
__init__(self, **namedarguments)
Initialise the node with appropriate named args
 
All properties/attributes must be specified with
named arguments, and the property/attribute must
exist within the Node's class/prototype.
 
This will raise AttributeError/ValueError/TypeError
if the values or the property names are inappropriate.
 
Note that all Node objects have the attribute/property
        exposedField SFString DEF ""
defined.  You may therefore specify a DEF name by
passing it as a named argument.
__repr__(self)
Get a code-like representation of the Node
 
Basically every attribute except for sub-nodes values
are returned as a full representation.
__str__(self)
Get a friendly representation of the Node
copy(self, copier=None)
Copy this node for copier
toString(self, **namedargs)
Generate a VRML 97-syntax string representing this Prototype
**namedargs -- key:value
        passed arguments for the linearisation object
see lineariser4.Lineariser

Properties inherited from Node:
DEF
exposedField SFString  DEF 
DEF getter = fget(self, client) from SFString
Get the client's value for this property
 
if notify is true send a notification event.
DEF setter = fset(self, client, value, notify=1) from SFString
Set the client's value for this property
 
if notify is true send a notification event.
DEF deleter = fdel(self, client, notify=1) from SFString
Delete the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph
exposedField WeakSFNode  root NULL
rootSceneGraph getter = fget(self, client) from WeakSFNode
Get the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph setter = fset(self, client, value, notify=1) from WeakSFNode
Set the client's value for this property
 
notify -- if true send a notification event
 
The SFNode tries to update the value's root
attribute to point to the root of the client
*iff* the value doesn't currently point at
a valid root.  (That is, it only updates root
if there is no current root).  This is done
without sending notify events.
rootSceneGraph deleter = fdel(self, client, notify=1) from WeakSFNode
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions inherited from Node:
PROTO = ''
__dict__ = <dict-proxy object at 0x0775FBC0>
__weakref__ = <member '__weakref__' of 'Node' objects>
externalURL = ()

Methods inherited from object:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__hash__(...)
x.__hash__() <==> hash(x)
__reduce__(...)
helper for pickle
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and non-method functions inherited from object:
__class__ = <type 'type'>
__new__ = <built-in method __new__ of type object at 0x1E0BD978>
T.__new__(S, ...) -> a new object with type S, a subtype of T
 
class BoundingSphere(BoundingVolume)
      Representation of a geometry bounding-sphere (unfinished)
 
XXX Note: this implementation is not used, and will
        either need to be removed or finished. That shouldn't
        be a particularly difficult project, as the
        frustcullaccel module was written to support bounding
        sphere calculations, it's just that the benefits
        don't really promise to be worth the effort.
 
  
Method resolution order:
BoundingSphere
BoundingVolume
Node
object

Methods defined here:
visible(self, frust, matrix=None, occlusion=0, mode=None)
Determine whether this bounding-sphere is visible in frustum

Static methods defined here:
union(boxes, matrix=None)
Create BoundingBox union for the given bounding boxes

Properties defined here:
center
field SFVec3f center (0, 0, 0)
center getter = fget(self, client) from SFVec3f
Get the client's value for this property
 
if notify is true send a notification event.
center setter = fset(self, client, value, notify=1) from SFVec3f
Set the client's value for this property
 
if notify is true send a notification event.
center deleter = fdel(self, client, notify=1) from SFVec3f
Delete the client's value for this property
 
if notify is true send a notification event.
radius
field SFFloat radius 0.0
radius getter = fget(self, client) from SFFloat
Get the client's value for this property
 
if notify is true send a notification event.
radius setter = fset(self, client, value, notify=1) from SFFloat
Set the client's value for this property
 
if notify is true send a notification event.
radius deleter = fdel(self, client, notify=1) from SFFloat
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions defined here:
__doc__ = "Representation of a geometry bounding-sphere (un...\n\t\tdon't really promise to be worth the effort.\n\t"
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Methods inherited from BoundingVolume:
getPoints(self)
Get the points which comprise the volume

Methods inherited from Node:
__init__(self, **namedarguments)
Initialise the node with appropriate named args
 
All properties/attributes must be specified with
named arguments, and the property/attribute must
exist within the Node's class/prototype.
 
This will raise AttributeError/ValueError/TypeError
if the values or the property names are inappropriate.
 
Note that all Node objects have the attribute/property
        exposedField SFString DEF ""
defined.  You may therefore specify a DEF name by
passing it as a named argument.
__repr__(self)
Get a code-like representation of the Node
 
Basically every attribute except for sub-nodes values
are returned as a full representation.
__str__(self)
Get a friendly representation of the Node
copy(self, copier=None)
Copy this node for copier
toString(self, **namedargs)
Generate a VRML 97-syntax string representing this Prototype
**namedargs -- key:value
        passed arguments for the linearisation object
see lineariser4.Lineariser

Properties inherited from Node:
DEF
exposedField SFString  DEF 
DEF getter = fget(self, client) from SFString
Get the client's value for this property
 
if notify is true send a notification event.
DEF setter = fset(self, client, value, notify=1) from SFString
Set the client's value for this property
 
if notify is true send a notification event.
DEF deleter = fdel(self, client, notify=1) from SFString
Delete the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph
exposedField WeakSFNode  root NULL
rootSceneGraph getter = fget(self, client) from WeakSFNode
Get the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph setter = fset(self, client, value, notify=1) from WeakSFNode
Set the client's value for this property
 
notify -- if true send a notification event
 
The SFNode tries to update the value's root
attribute to point to the root of the client
*iff* the value doesn't currently point at
a valid root.  (That is, it only updates root
if there is no current root).  This is done
without sending notify events.
rootSceneGraph deleter = fdel(self, client, notify=1) from WeakSFNode
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions inherited from Node:
PROTO = ''
__dict__ = <dict-proxy object at 0x076932C0>
__weakref__ = <member '__weakref__' of 'Node' objects>
externalURL = ()

Methods inherited from object:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__hash__(...)
x.__hash__() <==> hash(x)
__reduce__(...)
helper for pickle
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and non-method functions inherited from object:
__class__ = <type 'type'>
__new__ = <built-in method __new__ of type object at 0x1E0BD978>
T.__new__(S, ...) -> a new object with type S, a subtype of T
 
class BoundingVolume(Node)
      Base class for all bounding volumes
 
BoundingVolume is both a base class and a functional
bounding volume which is always considered visible.
Geometry which wishes to never be visible can return
BoundingVolume as their boundingVolume.
 
  
Method resolution order:
BoundingVolume
Node
object

Methods defined here:
getPoints(self)
Get the points which comprise the volume
visible(self, frustum, matrix=None, occlusion=0, mode=None)
Test whether volume is within given frustum

Data and non-method functions defined here:
__doc__ = 'Base class for all bounding volumes\n\n\tBoundingVo...turn\n\ta BoundingVolume as their boundingVolume.\n\t'
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Methods inherited from Node:
__init__(self, **namedarguments)
Initialise the node with appropriate named args
 
All properties/attributes must be specified with
named arguments, and the property/attribute must
exist within the Node's class/prototype.
 
This will raise AttributeError/ValueError/TypeError
if the values or the property names are inappropriate.
 
Note that all Node objects have the attribute/property
        exposedField SFString DEF ""
defined.  You may therefore specify a DEF name by
passing it as a named argument.
__repr__(self)
Get a code-like representation of the Node
 
Basically every attribute except for sub-nodes values
are returned as a full representation.
__str__(self)
Get a friendly representation of the Node
copy(self, copier=None)
Copy this node for copier
toString(self, **namedargs)
Generate a VRML 97-syntax string representing this Prototype
**namedargs -- key:value
        passed arguments for the linearisation object
see lineariser4.Lineariser

Properties inherited from Node:
DEF
exposedField SFString  DEF 
DEF getter = fget(self, client) from SFString
Get the client's value for this property
 
if notify is true send a notification event.
DEF setter = fset(self, client, value, notify=1) from SFString
Set the client's value for this property
 
if notify is true send a notification event.
DEF deleter = fdel(self, client, notify=1) from SFString
Delete the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph
exposedField WeakSFNode  root NULL
rootSceneGraph getter = fget(self, client) from WeakSFNode
Get the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph setter = fset(self, client, value, notify=1) from WeakSFNode
Set the client's value for this property
 
notify -- if true send a notification event
 
The SFNode tries to update the value's root
attribute to point to the root of the client
*iff* the value doesn't currently point at
a valid root.  (That is, it only updates root
if there is no current root).  This is done
without sending notify events.
rootSceneGraph deleter = fdel(self, client, notify=1) from WeakSFNode
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions inherited from Node:
PROTO = ''
__dict__ = <dict-proxy object at 0x0732ACD8>
__weakref__ = <member '__weakref__' of 'Node' objects>
externalURL = ()

Methods inherited from object:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__hash__(...)
x.__hash__() <==> hash(x)
__reduce__(...)
helper for pickle
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and non-method functions inherited from object:
__class__ = <type 'type'>
__new__ = <built-in method __new__ of type object at 0x1E0BD978>
T.__new__(S, ...) -> a new object with type S, a subtype of T
 
class UnboundedObject(ValueError)
      Error raised when an object does not support bounding volumes
 
  
Method resolution order:
UnboundedObject
ValueError
StandardError
Exception

Data and non-method functions defined here:
__doc__ = 'Error raised when an object does not support bounding volumes'
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Methods inherited from Exception:
__getitem__(...)
__init__(...)
__str__(...)
 
class UnboundedVolume(BoundingVolume)
      A bounding volume which is always visible
 
Opposite of a BoundingVolume, geometry can return
an UnboundedVolume if they always wish to be visible.
 
  
Method resolution order:
UnboundedVolume
BoundingVolume
Node
object

Methods defined here:
getPoints(self)
Signal to parents that we require unbounded operation
visible(self, frustum, matrix=None, occlusion=0, mode=None)
Test whether volume is within given frustum
 
We don't actually do anything here, just return true

Data and non-method functions defined here:
__doc__ = 'A bounding volume which is always visible\n\n\tOppo...oundedVolume if they always wish to be visible.\n\t'
__module__ = 'OpenGLContext.scenegraph.boundingvolume'

Methods inherited from Node:
__init__(self, **namedarguments)
Initialise the node with appropriate named args
 
All properties/attributes must be specified with
named arguments, and the property/attribute must
exist within the Node's class/prototype.
 
This will raise AttributeError/ValueError/TypeError
if the values or the property names are inappropriate.
 
Note that all Node objects have the attribute/property
        exposedField SFString DEF ""
defined.  You may therefore specify a DEF name by
passing it as a named argument.
__repr__(self)
Get a code-like representation of the Node
 
Basically every attribute except for sub-nodes values
are returned as a full representation.
__str__(self)
Get a friendly representation of the Node
copy(self, copier=None)
Copy this node for copier
toString(self, **namedargs)
Generate a VRML 97-syntax string representing this Prototype
**namedargs -- key:value
        passed arguments for the linearisation object
see lineariser4.Lineariser

Properties inherited from Node:
DEF
exposedField SFString  DEF 
DEF getter = fget(self, client) from SFString
Get the client's value for this property
 
if notify is true send a notification event.
DEF setter = fset(self, client, value, notify=1) from SFString
Set the client's value for this property
 
if notify is true send a notification event.
DEF deleter = fdel(self, client, notify=1) from SFString
Delete the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph
exposedField WeakSFNode  root NULL
rootSceneGraph getter = fget(self, client) from WeakSFNode
Get the client's value for this property
 
if notify is true send a notification event.
rootSceneGraph setter = fset(self, client, value, notify=1) from WeakSFNode
Set the client's value for this property
 
notify -- if true send a notification event
 
The SFNode tries to update the value's root
attribute to point to the root of the client
*iff* the value doesn't currently point at
a valid root.  (That is, it only updates root
if there is no current root).  This is done
without sending notify events.
rootSceneGraph deleter = fdel(self, client, notify=1) from WeakSFNode
Delete the client's value for this property
 
if notify is true send a notification event.

Data and non-method functions inherited from Node:
PROTO = ''
__dict__ = <dict-proxy object at 0x0681C248>
__weakref__ = <member '__weakref__' of 'Node' objects>
externalURL = ()

Methods inherited from object:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__hash__(...)
x.__hash__() <==> hash(x)
__reduce__(...)
helper for pickle
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and non-method functions inherited from object:
__class__ = <type 'type'>
__new__ = <built-in method __new__ of type object at 0x1E0BD978>
T.__new__(S, ...) -> a new object with type S, a subtype of T
 
Functions
            
cacheVolume(node, volume, nodeFieldPairs=())
Cache bounding volume for the given node
 
node -- the node associated with the volume
volume -- the BoundingVolume object to be cached
nodeFieldPairs -- set of (node,fieldName) tuples giving
        the dependencies for the volume.  Should normally
        include the node itself. If fieldName is None
        a dependency is created on the node itself.
getCachedVolume(node)
Get currently-cached bounding volume for the node or None
volumeFromCoordinate(node)
Calculate a bounding volume for a coordinate node
 
This should work for all of:
        IndexedFaceSet
        IndexedLineSet
        PointSet
        IndexedPolygons
 
This just takes advantage of the common features of the
coordinate-based geometry types, ignoring the fact
that individual pieces of geometry may not actually use
all of the points within a volume.
 
Note:
        this method is cache aware, it will return a cached
        bounding box if possible, or calculate and cache the
        bounding box before returning it.
 
XXX There is a pathological case which may be encountered
        due to an optimization seen in certain VRML97
        generators. Namely, these generators will create
        an entire file with a single coordinate node with each
        individual piece of geometry indexing into that
        universal coordinate node. This would, in many designs
        provide an optimization because the coordinate node
        would never be swapped out, allowing the geometry to
        remain within the GL as the current vertex/color
        matrices.  In this case, OpenGLContext will have no
        bounding volume optimization at all, as it will take
        rebounding volume of each piece of geometry to be the
        bounding volume of the entire world.
 
Data
             DEBUG_RENDER_VOLUMES = 0
frustcullaccel = None