Inheritence |
|
Each DOP network builds a tree of data, and then Houdini examines and updates this tree when it runs the simulation. DOP data elements can be DOP objects, geometry, volumes, forces, solvers, etc. The data is arranged in a tree structure, where child nodes are called subdata and are said to be attached to their parent nodes. Under the root of the tree are usually the DOP objects and data describing their relationships.
Note that the same piece of data can appear in the tree in multiple locations, with different names. DopData objects thus do not store their name, and the name of a piece of data in the tree is instead stored with its parent data(s).
By default, DopData objects store the path within the tree to the data. As a consequence, if the time changes and the solvers within the simulation change the contents of the tree of data, the Python DopData object will update to refer to the simulation’s new state. If the data path no longer refers to valid data, Houdini raises hou.ObjectWasDeleted when you try to access the DopData object from Python.
If you do not want the DopData to update with changes to the simulation, you can call hou.DopData.freeze(). freeze returns another DopData object that refers the simulation’s state at the current time, and will not change when the simulation time changes.
Each piece of data can contain records, and each record stores a list of name and value pairs called fields. Each record has a name, but it’s possible for multiple records with the same name to exist in the same piece of data. In this case, the record also has an index, and you can think of the records as rows of a spreadsheet.
Methods
subData()
→ dict of str
to hou.DopData
Return a dictionary mapping names to DOP data instances for the subdata attached to this data.
# The following code assumes you have created a box from the shelf and used # Rigid Bodies > RBD Object on the shelf to make it a rigid body. >>> obj = hou.node("/obj/AutoDopNetwork").simulation().objects()[0] >>> obj <hou.DopObject box_object1 id 0> >>> obj.recordTypes() ('Basic', 'Options', 'RelInGroup', 'RelInAffectors') >>> record = obj.record("Options") >>> record.fieldNames() ('name', 'groups', 'affectors', 'affectorids', 'objid') >>> record.field("name") 'box_object1' >>> obj.subData().keys() ['PhysicalParms', 'ODE_Body', 'Solver', 'Geometry', 'SolverParms', 'ODE_Geometry', 'Forces', 'Position', 'Colliders'] >>> obj.findSubData("Forces/Gravity_gravity1") <hou.DopData of type SIM_ForceGravity> >>> obj.findSubData("Forces/Gravity_gravity1").options().field("force") <hou.Vector3 [0, -9.80665, 0]>
findSubData(data_spec)
→ hou.DopData or None
Return the DOP data with the given name that is attached to this DOP data,
or None
if no such data exists. Note that the name may also be a
slash-separated path to nested subdata.
See hou.DopData.subData() for an example.
This method can be approximately implemented as follows:
def findSubData(self, data_spec): data = self for name in data_spec.split("/"): if name not in data.subData(): return None data = data.subData()[name] return data
findAllSubData(data_spec, recurse=False)
→ dict of str
to hou.DopData
Given a pattern, return a dictionary mapping subdata paths to DOP data
instances for all the subdatas whose name matches the pattern. If
recurse
is True
, all grandchildren subdata will be added to the result.
# The following code assumes you have created a box from the shelf and used # Rigid Bodies > RBD Object on the shelf to make it a rigid body. >>> obj = hou.node("/obj/AutoDopNetwork").simulation().objects()[0] >>> obj.findAllSubData("S*").keys() ['SolverParms', 'Solver'] >>> obj.findAllSubData("S*", recurse=True).keys() ['SolverParms', 'Solver/Random', 'SolverParms/ActiveValue', 'Solver'] >>> obj.findAllSubData("S*/*", recurse=True).keys() ['SolverParms/ActiveValue', 'Solver/Random']
freeze()
→ hou.DopData
Return a frozen version of this DopData. Frozen versions of the data will not update when the simulation updates. Instead, they will refer to the state of the simulation at the time they were frozen.
It is ok to call this method on a DopData object that is already frozen.
isFrozen()
→ bool
Return whether or not this data is frozen.
See hou.DopData.freeze() for more information.
path()
→ str
Return the path to this object within the tree of DOP data. This path includes the DOP object or relationship as the first part of the path.
Note that the same piece of DOP data can exist in multiple places of the tree. The path returned is the path stored inside this Python DopData object, since the Python object uses the path to look up the underlying data each time you call a method on it.
Note that the path is only available for unfrozen objects. If you call this method on a frozen DopData object it raises hou.OperationFailed.
selectionPath()
→ str
For DopData objects returned from a hou.SceneViewer.selectDynamics()
function call, this will return the a string that contains both the path
to the DOP Network that created the data, and the path within the DOP
data tree which uniquely identifies this DopData. This string is
specifically intended to be passed in the prior_selection_paths
argument of the hou.SceneViewer selection methods.
dataType()
→ str
Return a string describing the type of data this object contains.
>>> obj = hou.node("/obj/AutoDopNetwork").simulation().objects()[0] >>> obj.dataType() 'SIM_Object'
See also hou.DopData.dataTypeObject.
dataTypeObject()
→ hou.DopDataType or None
recordTypes()
→ tuple
of str
Return a tuple of strings containing the record types stored inside this DOP data. Each DOP data contains records named "Basic" and "Options", and some types of DOP data contain additional records.
record(record_type, record_index=0)
→ hou.DopRecord
Given a record type name return that record, or None
if no record exists
with that name. If this DOP data contains multiple records with this
record type name you can think of each record as a row in a spreadsheet,
and record_index
determines which one is returned. Use
len(self.records(record_type))
to determine how many records of this type
are in this DOP data.
Use hou.DopData.recordTypes() to get a tuple of record types in a DOP data. See also hou.DopData.records() for an example, and see hou.DopData.options() for a way to easily access the "Options" record.
records(record_type)
→ tuple
of hou.DopRecord
Return a tuple of all the records of this record type. See also hou.DopData.record().
This example lists the input affectors for a rigid body box that collides with a ground plane:
>>> obj = hou.node("/obj/AutoDopNetwork").simulation().objects()[-1] >>> obj.records("RelInAffectors") (<hou.DopRecord of type RelInAffectors index 0>, <hou.DopRecord of type RelInAffectors index 1>) >>> [record.field("relname") for record in obj.records("RelInAffectors")] ['merge1', 'staticsolver1_staticsolver1'] >>> obj.record("RelInAffectors", 1).field("relname") 'staticsolver1_staticsolver1'
options()
→ hou.DopRecord
Return the Options record. This method is a shortcut for
self.record("Options")
.
dopNetNode()
→ hou.Node
Return the DOP network node containing this DOP data.
simulation()
→ hou.DopSimulation
Return the DOP simulation containing this DOP data. This method is a
shortcut for self.dopNetNode().simulation()
.
creator()
→ hou.DopNode
Return the DOP node that created this DOP data inside the DOP network.
id()
→ str
Return the globally unique identifier (GUID) for this DOP data. This
method is a shortcut for self.record("Basic").field("uniqueid")
.
If you want an object’s index, hou.DopObject.objid().
>>> obj = hou.node("/obj/AutoDopNetwork").simulation().objects()[0] >>> obj.id() '0xD011E41C-0x000034AE-0x494C12E4-0x000018B9' >>> obj.objid() 0
save(file_path)
createSubData(data_name, data_type="SIM_EmptyData", avoid_name_collisions=False)
→ hou.DopData
Create subdata under this data with the specified name and type. You would call this method from a script solver DOP.
data_name
The name of the new data. Note that this name may contain slashes to create subdata on existing data.
data_type
Either the name of the data type to create or a hou.DopDataType instance. If you simply want something containing an empty options record, use "SIM_EmptyData".
avoid_name_collisions
If True and data with the specified name exists, Houdini will create a unique name that does not conflict with any existing data.
Raises hou.OperationFailed if data with this name already exists. If you want to replace existing data it is up to you to first call hou.DopData.removeData.
Raises hou.PermissionError if called from outside a script solver DOP.
Use hou.DopData.attachSubData() to create a reference to existing data. See hou.DopData.copyContentsFrom() for an example of how to create a copy of existing data.
attachSubData(data, new_data_name, avoid_name_collisions=False)
Make existing data become subdata of this data. Houdini does not create a duplicate of the data. Instead, the data’s parent(s) and this data will both refer to the same instance of subdata. You would call this method from a script solver DOP.
data
The DopData that will become subdata of this data.
new_data_name
The name of the new subdata.
avoid_name_collisions
If True and data with the specified name exists, Houdini will create a unique name that does not conflict with any existing data.
Raises hou.OperationFailed if data with this name already exists. If you want to replace existing data it is up to you to first call hou.DopData.removeData.
Raises hou.PermissionError if called from outside a script solver DOP.
See hou.DopData.copyContentsFrom() for an example of how to create a copy of existing data.
removeSubData(data_spec)
Remove subdata with the given name. Raises hou.PermissionError if called from outside a script solver DOP.
Raises hou.OperationFailed if data with that name already exists.
copyContentsFrom(data)
Copy the contents of the given DopData into this one, adapting the data if it is of a different type. You would call this method from a script solver DOP.
Raises hou.PermissionError if called from outside a script solver DOP.
Use this method along with hou.DopData.createSubData() to copy existing subdata:
def copySubData(new_parent_data, data_to_copy, new_data_name, avoid_name_collisions=False): '''Create a copy of data and attach it to other data.''' new_data = new_parent_data.createSubData(new_data_name, data_to_copy.dataType(), avoid_name_collisions) new_data.copyContentsFrom(data_to_copy) return new_data