As a developer, it's very often inconvenient that objects are returned as instances of either APIv1 or APIv2 classes.
Both are often, but not always compatible to each other.
I've created several convenience extension methods for these that I have to inject (e.g. through a VRED Script Plugin) before I can use them in several scripts.
Wishlist:
Let me know what you think about this idea 🙂
Following code has been tested with VRED 2023.2, I don't have access to newer versions of VRED yet.
"""
Provides additional functions for the following classes:
vrKernelServices.vrKernelServices.vrdNode
- asVrNodePtr (also available as property vrNodePtr)
- getChild
- addChild
vrNodePtr.vrNodePtr
- asVrdNode (also available as property vrdNode)
vrOSGTypes.Pnt3f
- getitem
vrOSGTypes.Vec3f
- getitem
PySide2.QtGui.QVector3D
- getitem
"""
import vrNodePtr
import vrKernelServices
from PySide2.QtGui import QVector3D
import vrOSGTypes
def getitem(self, key:int) -> float:
"""
Extension method to support unpacking of QVector3D objects
returns:
float value of the x, y or z coordinate depending on the key
"""
if key == 0:
return self.x()
elif key == 1:
return self.y()
elif key == 2:
return self.z()
else:
# IndexError marks the end of an iteration
raise IndexError(f"__getitem__ of {type(self).__name__} only supports keys in [0,1,2]")
# same method for QVector3D, Pnt3f and Vec3f, because their API is similar
QVector3D.__getitem__ = getitem
vrOSGTypes.Pnt3f.__getitem__ = getitem
vrOSGTypes.Vec3f.__getitem__ = getitem
def asVrdNode(self:vrNodePtr.vrNodePtr) -> vrKernelServices.vrdNode:
"""
Extension method for vrNodePtr.vrNodePtr that provides access to corresponding VRED API v2 vrKernelServices.vrdNode
"""
return vrNodeService.getNodeFromId(self.getID())
vrNodePtr.vrNodePtr.asVrdNode = asVrdNode
@property
def vrdNodeProperty(self:vrNodePtr.vrNodePtr) -> vrKernelServices.vrdNode:
"""
property for vrNodePtr.vrNodePtr that provides access to corresponding VRED API v2 vrKernelServices.vrdNode
"""
if isinstance(self, vrKernelServices.vrdNode):
return self
elif isinstance(self, vrNodePtr.vrNodePtr):
return self.asVrdNode()
else:
raise TypeError(f"Property vrdNode not applicable to objects of type {type(self)}")
vrNodePtr.vrNodePtr.vrdNode = vrdNodeProperty
# it might not seem to be neccessary to provide a 'vrdNode' property to a 'vrKernelServices.vrdNode',
# but it's convenient to have code that's compatible to both types at the same time
vrKernelServices.vrdNode.vrdNode = vrdNodeProperty
def asVrNodePtr(self:vrKernelServices.vrdNode) -> vrNodePtr.vrNodePtr:
"""
Extension method for vrKernelServices.vrdNode that provides access to corresponding VRED API v1 vrNodePtr.vrNodePtr
"""
return vrNodePtr.toNode(self.getObjectId())
vrKernelServices.vrdNode.asVrNodePtr = asVrNodePtr
@property
def vrNodePtrProperty(self:vrKernelServices.vrdNode) -> vrNodePtr.vrNodePtr:
"""
Extension method for vrKernelServices.vrdNode that provides access to corresponding VRED API v1 vrNodePtr.vrNodePtr
"""
if isinstance(self, vrKernelServices.vrdNode):
return self.asVrNodePtr()
elif isinstance(self, vrNodePtr.vrNodePtr):
return self
else:
raise TypeError(f"Property vrNodePtr not applicable to objects of type {type(self)}")
vrKernelServices.vrdNode.vrNodePtr = vrNodePtrProperty
# it might not seem to be neccessary to provide a 'vrNodePtr' property to a 'vrNodePtr.vrNodePtr',
# but it's convenient to have code that's compatible to both types at the same time
vrNodePtr.vrNodePtr.vrNodePtr = vrNodePtrProperty
def getChild(self:vrKernelServices.vrdNode, nameOrIndex) -> vrKernelServices.vrdNode:
"""
Extension method for vrKernelServices.vrdNode that enables getChild search by name VRED API v1 vrNodePtr.vrNodePtr
"""
# getChild of API v1 can distinguish between int or str input and can do the job
return self.asVrNodePtr().getChild(nameOrIndex).asVrdNode()
vrKernelServices.vrdNode.getChild = getChild
def addChild(self:vrKernelServices.vrdNode, node) -> None:
"""
Extension method for vrKernelServices.vrdNode as wrapper of vrNodePtr.vrNodePtr.addChild from VRED API v1
"""
if isinstance(node, vrKernelServices.vrdNode):
self.asVrNodePtr().addChild(node.asVrNodePtr())
elif isinstance(node, vrNodePtr.vrNodePtr):
self.asVrNodePtr().addChild(node)
else:
raise TypeError(f"Extension method 'addChild' doesn't support type '{type(node).__name__}' of node '{node}'")
vrKernelServices.vrdNode.addChild = addChild
def getVrNodePtrItem(self:vrNodePtr.vrNodePtr, childIndex:int) -> vrNodePtr.vrNodePtr:
"""
Extension method to support unpacking of vrNodePtr objects
returns:
vrNodePtr
"""
# prevent 'vrNodePtr::getChild : Index out of range!' message in vred terminal
if not childIndex < self.getNChildren():
raise IndexError(f"vrNodePtr::getChild : Index {childIndex} out of range [0, {self.getNChildren()}]")
childVrNodePtr = self.getChild(childIndex)
if not childVrNodePtr.isValid():
raise IndexError(f"vrNodePtr::getChild : Child node with index {childIndex} doesn't exist")
return childVrNodePtr
vrNodePtr.vrNodePtr.__getitem__ = getVrNodePtrItem
def getVrdNodeItem(self:vrKernelServices.vrdNode, childIndex:int) -> vrKernelServices.vrdNode:
"""
Extension method to support unpacking of vrKernelServices.vrdNode objects
returns:
vrKernelServices.vrdNode
"""
if not childIndex < self.getChildCount():
raise IndexError(f"vrNodePtr::getChild : Index {childIndex} out of range [0, {self.getChildCount()}]")
childVrdNode = self.getChild(childIndex)
if not childVrdNode.isValid():
raise IndexError(f"vrKernelServices.vrdNode::getChild : Child node with index {childIndex} doesn't exist")
return childVrdNode
vrKernelServices.vrdNode.__getitem__ = getVrdNodeItem
if __name__ == '__main__':
# API v1
root_v1 = getRootNode()
print(f"type(root_v1) = {type(root_v1)}")
assert isinstance(root_v1, vrNodePtr.vrNodePtr)
print(f"type(root_v1.vrdNode) = {type(root_v1.vrdNode)}")
assert isinstance(root_v1.vrdNode, vrKernelServices.vrdNode)
print(f"type(root_v1.asVrdNode()) = {type(root_v1.asVrdNode())}")
assert isinstance(root_v1.asVrdNode(), vrKernelServices.vrdNode)
print(f"[childNode.getName() for childNode in root_v1] = {[childNode.getName() for childNode in root_v1]}")
assert "Perspective" in [childNode.getName() for childNode in root_v1]
# API v2
root_v2 = vrNodeService.getRootNode()
print(f"type(root_v2) = {type(root_v2)}")
assert isinstance(root_v2, vrKernelServices.vrdNode)
print(f"type(root_v2.vrNodePtr) = {type(root_v2.vrNodePtr)}")
assert isinstance(root_v2.vrNodePtr, vrNodePtr.vrNodePtr)
print(f"type(root_v2.asVrNodePtr()) = {type(root_v2.asVrNodePtr())}")
assert isinstance(root_v2.asVrNodePtr(), vrNodePtr.vrNodePtr)
print(f"type(root_v2.getChild('Perspective')) = {type(root_v2.getChild('Perspective'))}")
assert isinstance(root_v2.getChild('Perspective'), vrKernelServices.vrdNode)
print(f"[childNode.getName() for childNode in root_v2] = {[childNode.getName() for childNode in root_v2]}")
assert "Perspective" in [childNode.getName() for childNode in root_v2]
# Qt / Pnt3f / Vec3f
q = QVector3D(1, 2, 3)
p = Pnt3f(1, 2, 3)
v = Vec3f(1, 2, 3)
for obj in [q,p,v]:
print(f"{type(obj)} values: {[value for value in obj]}")
Usage is shown in the '__main__' section. Script can be imported to inject methods to existing classes.
Output in the VRED terminal:
type(root_v1) = <class 'vrNodePtr.vrNodePtr'>
type(root_v1.vrdNode) = <class 'vrKernelServices.vrdNode'>
type(root_v1.asVrdNode()) = <class 'vrKernelServices.vrdNode'>
[childNode.getName() for childNode in root_v1] = ['VREDMaterialPool', 'Perspective', 'Front', 'Side', 'Top', 'Environments']
type(root_v2) = <class 'vrKernelServices.vrdNode'>
type(root_v2.vrNodePtr) = <class 'vrNodePtr.vrNodePtr'>
type(root_v2.asVrNodePtr()) = <class 'vrNodePtr.vrNodePtr'>
type(root_v2.getChild('Perspective')) = <class 'vrKernelServices.vrdCameraNode'>
[childNode.getName() for childNode in root_v2] = ['VREDMaterialPool', 'Perspective', 'Front', 'Side', 'Top', 'Environments']
<class 'PySide2.QtGui.QVector3D'> values [1.0, 2.0, 3.0]
<class 'vrOSGTypes.Pnt3f'> values [1.0, 2.0, 3.0]
<class 'vrOSGTypes.Vec3f'> values [1.0, 2.0, 3.0]
Can't find what you're looking for? Ask the community or share your knowledge.