测试一个对象是否依赖于另一个对象
Testing if an object is dependent to another object
有没有办法通过父子关系、约束或与另一个对象的连接来检查一个对象是否依赖?我想在为对象创建父对象之前进行此检查,看看它是否会导致依赖循环。
我记得 3DsMax 有一个命令可以准确地执行此操作。我检查了 OpenMaya
但找不到任何东西。有cmds.cycleCheck
,但是这个只有在当前有循环的情况下才有效,我用起来就来不及了
棘手的是这 2 个对象可能位于场景层次结构中的任何位置,因此它们可能有也可能没有直接的父关系。
编辑
检查层次结构是否会导致任何问题相对容易:
children = cmds.listRelatives(obj1, ad = True, f = True)
if obj2 in children:
print "Can't parent to its own children!"
检查约束或连接是另一回事。
根据您要查找的内容,cmds.listHistory
或 cmds.listConnections
会告诉您给定节点的内容。 listHistory
仅限于驱动形状节点更改的可能连接的子集,因此如果您对约束感兴趣,则需要遍历节点的 listConnections
并查看上游的内容。该列表可以任意大,因为它可能包含许多您可能不想关心的隐藏节点,例如单元翻译、组部分等。
下面是控制节点的传入连接并获取传入连接树的简单方法:
def input_tree(root_node):
visited = set() # so we don't get into loops
# recursively extract input connections
def upstream(node, depth = 0):
if node not in visited:
visited.add(node)
children = cmds.listConnections(node, s=True, d=False)
if children:
grandparents = ()
for history_node in children:
grandparents += (tuple(d for d in upstream(history_node, depth + 1)))
yield node, tuple((g for g in grandparents if len(g)))
# unfold the recursive generation of the tree
tree_iter = tuple((i for i in upstream(root_node)))
# return the grandparent array of the first node
return tree_iter[0][-1]
这应该会生成一个嵌套的输入连接列表,例如
((u'pCube1_parentConstraint1',
((u'pSphere1',
((u'pSphere1_orientConstraint1', ()),
(u'pSphere1_scaleConstraint1', ()))),)),
(u'pCube1_scaleConstraint1', ()))
其中每个级别都包含一个输入列表。然后您可以浏览它以查看您提议的更改是否包括该项目。
这 不会 告诉您连接是否会导致真正的循环,但是:这取决于不同节点内的数据流。一旦你确定了可能的循环,你就可以回过头来看看这个循环是真实的(例如,两个项目相互影响翻译)还是无害的(我影响你的轮换,你影响我的翻译)。
这不是最优雅的方法,但它是一种快速而肮脏的方法,到目前为止似乎工作正常。这个想法是,如果发生循环,则只需撤消操作并停止脚本的其余部分。用钻机测试,不管连接有多复杂,它都会捕捉到它。
# Class to use to undo operations
class UndoStack():
def __init__(self, inputName = ''):
self.name = inputName
def __enter__(self):
cmds.undoInfo(openChunk = True, chunkName = self.name, length = 300)
def __exit__(self, type, value, traceback):
cmds.undoInfo(closeChunk = True)
# Create a sphere and a box
mySphere = cmds.polySphere()[0]
myBox = cmds.polyCube()[0]
# Parent box to the sphere
myBox = cmds.parent(myBox, mySphere)[0]
# Set constraint from sphere to box (will cause cycle)
with UndoStack("Parent box"):
cmds.parentConstraint(myBox, mySphere)
# If there's a cycle, undo it
hasCycle = cmds.cycleCheck([mySphere, myBox])
if hasCycle:
cmds.undo()
cmds.warning("Can't do this operation, a dependency cycle has occurred!")
有没有办法通过父子关系、约束或与另一个对象的连接来检查一个对象是否依赖?我想在为对象创建父对象之前进行此检查,看看它是否会导致依赖循环。
我记得 3DsMax 有一个命令可以准确地执行此操作。我检查了 OpenMaya
但找不到任何东西。有cmds.cycleCheck
,但是这个只有在当前有循环的情况下才有效,我用起来就来不及了
棘手的是这 2 个对象可能位于场景层次结构中的任何位置,因此它们可能有也可能没有直接的父关系。
编辑
检查层次结构是否会导致任何问题相对容易:
children = cmds.listRelatives(obj1, ad = True, f = True)
if obj2 in children:
print "Can't parent to its own children!"
检查约束或连接是另一回事。
根据您要查找的内容,cmds.listHistory
或 cmds.listConnections
会告诉您给定节点的内容。 listHistory
仅限于驱动形状节点更改的可能连接的子集,因此如果您对约束感兴趣,则需要遍历节点的 listConnections
并查看上游的内容。该列表可以任意大,因为它可能包含许多您可能不想关心的隐藏节点,例如单元翻译、组部分等。
下面是控制节点的传入连接并获取传入连接树的简单方法:
def input_tree(root_node):
visited = set() # so we don't get into loops
# recursively extract input connections
def upstream(node, depth = 0):
if node not in visited:
visited.add(node)
children = cmds.listConnections(node, s=True, d=False)
if children:
grandparents = ()
for history_node in children:
grandparents += (tuple(d for d in upstream(history_node, depth + 1)))
yield node, tuple((g for g in grandparents if len(g)))
# unfold the recursive generation of the tree
tree_iter = tuple((i for i in upstream(root_node)))
# return the grandparent array of the first node
return tree_iter[0][-1]
这应该会生成一个嵌套的输入连接列表,例如
((u'pCube1_parentConstraint1',
((u'pSphere1',
((u'pSphere1_orientConstraint1', ()),
(u'pSphere1_scaleConstraint1', ()))),)),
(u'pCube1_scaleConstraint1', ()))
其中每个级别都包含一个输入列表。然后您可以浏览它以查看您提议的更改是否包括该项目。
这 不会 告诉您连接是否会导致真正的循环,但是:这取决于不同节点内的数据流。一旦你确定了可能的循环,你就可以回过头来看看这个循环是真实的(例如,两个项目相互影响翻译)还是无害的(我影响你的轮换,你影响我的翻译)。
这不是最优雅的方法,但它是一种快速而肮脏的方法,到目前为止似乎工作正常。这个想法是,如果发生循环,则只需撤消操作并停止脚本的其余部分。用钻机测试,不管连接有多复杂,它都会捕捉到它。
# Class to use to undo operations
class UndoStack():
def __init__(self, inputName = ''):
self.name = inputName
def __enter__(self):
cmds.undoInfo(openChunk = True, chunkName = self.name, length = 300)
def __exit__(self, type, value, traceback):
cmds.undoInfo(closeChunk = True)
# Create a sphere and a box
mySphere = cmds.polySphere()[0]
myBox = cmds.polyCube()[0]
# Parent box to the sphere
myBox = cmds.parent(myBox, mySphere)[0]
# Set constraint from sphere to box (will cause cycle)
with UndoStack("Parent box"):
cmds.parentConstraint(myBox, mySphere)
# If there's a cycle, undo it
hasCycle = cmds.cycleCheck([mySphere, myBox])
if hasCycle:
cmds.undo()
cmds.warning("Can't do this operation, a dependency cycle has occurred!")