2015-10-29 3 views
3

Есть ли способ проверить, зависит ли объект от родительского контроля, ограничений или соединений с другим объектом? Я хотел бы сделать эту проверку до родительского объекта, чтобы узнать, вызовет ли он циклы зависимостей или нет.Тестирование, если объект зависит от другого объекта

Я помню, что у 3DsMax была команда, чтобы сделать это точно. Я проверил OpenMaya, но ничего не нашел. Существует cmds.cycleCheck, но это работает только тогда, когда в настоящее время существует цикл, который будет слишком поздно для меня использовать.

Сложно то, что эти 2 объекта могут находиться где угодно в иерархии сцены, поэтому они могут иметь или не иметь прямых отношений с родителями.


EDIT

Это относительно легко проверить, если иерархия будет вызывать вопросы:

children = cmds.listRelatives(obj1, ad = True, f = True) 
if obj2 in children: 
    print "Can't parent to its own children!" 

Проверка ограничений или связей другая история, хотя.

+0

Вы проверили cmds.listConections()? – Achayan

+0

Да, но если у него нет прямого соединения, это не удастся. –

ответ

2

в зависимости от того, что вы ищете, 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',())) 

, в котором каждый уровень содержит список входов. Затем вы можете пройти через это, чтобы узнать, включает ли предлагаемое изменение этот элемент.

Это не будет, сообщите вам, если соединение вызовет реальный цикл, однако: это зависит от потока данных в разных узлах. Как только вы определите возможный цикл, вы можете вернуться назад, чтобы увидеть, действительно ли этот цикл (например, два предмета, влияющие на перевод друг друга) или безвредный (я влияю на ваш поворот, и вы влияете на мой перевод).

+0

Я попытался сделать ту же идею вчера с функцией рекурсии, но с буровой установкой, которая имеет сложные соединения, она не все ломает (проверка твист-сустава руки против его векторного управления локтевым полюсом не работает). Спасибо за ответ, хотя! –

+0

yah, это не то, что Майя делает легко.'cycleCheck' склонен к ложным срабатываниям (например, my-translate, your-rotate case выше), которые не являются логически проблематичными, но, тем не менее, присылают вам сообщения об ошибках. – theodox

+0

Да, это не кажется слишком прямым решением. Вы дали очень солидный ответ, хотя я все же дал вам преимущество. :) –

1

Это не самый изящный подход, но это быстрый и грязный способ, который, кажется, работает нормально. Идея состоит в том, что если цикл происходит, просто отмените операцию и остановите оставшуюся часть скрипта. Тестирование с помощью буровой установки не имеет значения, насколько сложны соединения, и это поймает.

# 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!") 
Смежные вопросы