Python:Spoonfed - (2-10) 激励选择脚本(搬砖)

https://www.patreon.com/posts/python-spoonfed-31572219

2019年11月15日

利用上一课的选择函数,我们现在可以拼凑出一些脚本(有一些事情我们还没有解释,但应该很容易理解)。以下代码将允许您选择当前所选对象的父对象、顶级对象、同级对象、表兄弟对象或子对象。这些功能的一部分过去已包含在 Cineversity 中,但在这里您可以获取它们,包括源代码。

我们先从Parent的选择开始。PS_SelectObject_Parent.py

import c4d

def SetActiveObjects(objlist):
    cleared = False
    for obj in objlist:
        if not cleared:
            doc.SetActiveObject(obj, c4d.SELECTION_NEW)
            cleared = True
        else:
            doc.SetActiveObject(obj, c4d.SELECTION_ADD)
            

def main():
    if doc == None: return

    activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    if not activeObjectList: return
    
    newSelection = []
    for obj in activeObjectList:
        if obj.GetUp() != None:
            newSelection += [obj.GetUp()]
        else:
            newSelection += [obj]

    SetActiveObjects(newSelection)
    c4d.EventAdd()


if __name__=='__main__':
    main()

在这里,我们将函数 SetActiveObjects() 添加到 API 中的选择设置函数数量中。由于给定的函数 只能选择一个BaseObject 一次 ,因此我们在这里封装SetActiveObject() 并允许传递整个列表。

唯一的技巧是,我们必须使用标志 SELECTION_NEW 设置第一个对象以清除 以前的 设置其他每个对象 选择,但必须使用SELECTION_ADD 。为此,我们使用一个布尔变量 清除 开始 ,它从False 设置为 True ,并在第一次有机会时 保持True )。 (此后一直

在函数 main() 循环中迭代当前选择 中,我们在for ,获取每个对象的直接父对象并将其添加到新选择中。如果没有父对象,则将添加对象本身(本质上保持选中状态)。

newSelection 是一个列表对象。 文字初始化为空列表 它由[ ] 。要添加对象,我们首先通过再次将对象括在方括号中来创建一个列表,其中包含该对象中的一项。 将此迷你列表附加到现有列表 可以使用扩展赋值+=

第二个脚本基本相同,但它不是寻找直接父代,而是寻找最顶层的祖先。这是在 while 循环中完成的: PS_SelectObject_Top.py

import c4d

def SetActiveObjects(objlist):
    cleared = False
    for obj in objlist:
        if not cleared:
            doc.SetActiveObject(obj, c4d.SELECTION_NEW)
            cleared = True
        else:
            doc.SetActiveObject(obj, c4d.SELECTION_ADD)


def main():
    if doc == None: return

    activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    if not activeObjectList: return

    newSelection = []
    for obj in activeObjectList:
        while obj.GetUp() != None:
            obj = obj.GetUp()
        newSelection += [obj]

    SetActiveObjects(newSelection)
    c4d.EventAdd()


if __name__=='__main__':
    main()

我们不需要额外的情况来包含 obj 请注意,如果没有祖先, 循环 本身。在这种情况下,while 结束 本身在obj 处

如果我们在最初的选择中有两个兄弟姐妹会怎样?难道我们不会为两者获得相同的父级或祖先,并且有一个包含重复元素的列表可供选择吗? -- 确实如此,但没关系:将对象设置为活动 两次 不会产生不良影响,因此我们不需要经历整理重复项的麻烦。PS_SelectObject_Siblings.py

import c4d

def SetActiveObjects(objlist):
    cleared = False
    for obj in objlist:
        if not cleared:
            doc.SetActiveObject(obj, c4d.SELECTION_NEW)
            cleared = True
        else:
            doc.SetActiveObject(obj, c4d.SELECTION_ADD)


def SelectSiblings(startobj):
    global newSelection
    if startobj == None: return

    newSelection += [startobj]
    obj = startobj
    while obj.GetPred() != None:
        newSelection += [obj.GetPred()]
        obj = obj.GetPred()
    obj = startobj
    while obj.GetNext() != None:
        newSelection += [obj.GetNext()]
        obj = obj.GetNext()


def main():
    global newSelection
    if doc == None: return

    activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    if not activeObjectList: return

    newSelection = []
    for obj in activeObjectList:
        SelectSiblings(obj)

    SetActiveObjects(newSelection)
    c4d.EventAdd()


if __name__=='__main__':
    main()

在第三个脚本(选择最初选定对象的所有同级)中,我们引入了一个新函数 SelectSiblings() 。这将获取一个 BaseObject ,并将该对象本身及其所有同级添加到共享全局列表 newSelection 中 。 它通过从参数对象走到列表的前面,然后再次从参数对象走到列表的后面来实现这一点。

我们只调用 SelectSiblings 一次,因此我们可能直接保留该代码而不是函数调用(这种做法也称为 内联代码 )。 函数 但是,分离出SetActiveObjects SelectSiblings 使代码更清晰、更易于阅读 - 而且,我们可以为最后两个脚本重用相同的结构。PS_SelectObject_Cousins.py

import c4d

def SetActiveObjects(objlist):
    cleared = False
    for obj in objlist:
        if not cleared:
            doc.SetActiveObject(obj, c4d.SELECTION_NEW)
            cleared = True
        else:
            doc.SetActiveObject(obj, c4d.SELECTION_ADD)


def SelectSiblings(startobj):
    global newSelection
    if startobj == None: return

    newSelection += [startobj]
    obj = startobj
    while obj.GetPred() != None:
        newSelection += [obj.GetPred()]
        obj = obj.GetPred()
    obj = startobj
    while obj.GetNext() != None:
        newSelection += [obj.GetNext()]
        obj = obj.GetNext()


def main():
    global newSelection
    if doc == None: return

    activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    if not activeObjectList: return

    newSelection = []
    for obj in activeObjectList:
        if obj.GetUp() == None:
            SelectSiblings(obj)
        else:
            parent = obj.GetUp()
            while parent.GetPred() != None:
                parent = parent.GetPred()
            while parent != None:
                SelectSiblings(parent.GetDown())
                parent = parent.GetNext()

    SetActiveObjects(newSelection)
    c4d.EventAdd()


if __name__=='__main__':
    main()

第四个脚本不仅选择兄弟姐妹,还选择最初选择的对象的“表兄弟”。在这种情况下,“表兄弟”是父母的兄弟姐妹的子对象。为了找到这些,代码首先上一层,然后从头到尾遍历这一层,将所有节点的所有子节点添加到选择中。如果没有父母,代码只会添加兄弟姐妹。

第五个也是最后一个选择器脚本选择最初选定对象的子对象:PS_SelectObject_Children

import c4d

def SetActiveObjects(objlist):
    cleared = False
    for obj in objlist:
        if not cleared:
            doc.SetActiveObject(obj, c4d.SELECTION_NEW)
            cleared = True
        else:
            doc.SetActiveObject(obj, c4d.SELECTION_ADD)
            

def main():
    if doc == None: return

    activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
    if not activeObjectList: return
    
    newSelection = []
    for obj in activeObjectList:
        if obj.GetUp() != None:
            newSelection += [obj.GetUp()]
        else:
            newSelection += [obj]

    SetActiveObjects(newSelection)
    c4d.EventAdd()


if __name__=='__main__':
    main()

这与 Cinema 4D 的内置功能“选择子项”不同,因为该功能会选择所有依赖子树直至最低级别。相反,脚本仅限于 直接 子对象(如果没有子对象,甚至是原始对象)。

我没有包含像 C4D 的“选择子项”(无论如何应该命名为“选择子树”)这样的功能,因为该功能已经可用。

一点作业:如果所需的目标对象(父对象、顶级对象、兄弟姐妹、子对象、表兄弟)不可用,则所有五个脚本都会保留最初选择的对象。您可能想要更改该行为,以便不再选择最初选择的对象。在什么情况下这才有意义?这容易实现吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值