概述
Compound 节点是一种创建自定义节点的方式,可以使用 Python 脚本封装现有节点的功能,并用一个新的自定义节点界面显示他们的控制。例如,此功能可以用来结合现有的 Auto Track 和 Camera Solver 节点到一个新的单个的 Track & Solve 节点中,或为新用户简化一个节点的控制。
在 PFTrack 应用安装的 “nodes” 子目录下的 ”simpleSolve.py”,提供了一个 compound 节点脚本示例,实现了上述例子。
用户编写的 Compound 节点脚本可以放置在用户的 $HOME/.pftrack/nodes 目录下,如果它们只适用于一个用户;或者放在 PFTrack 应用安装的 “nodes” 子目录下,如果它们适用于所有用户。应用启动时会扫描这些目录。
在节点管理器中,每个 Compound 节点会在 “Compound Nodes” 的下拉菜单中显示为一个新的选项(除非 pfNodeTopLevelButton 函数返回 1,这种情况下,节点作为单独的节点按钮显示)。
Defining basic functionality
脚本从以下行开始导入复合节点功能:
import pfpy
必须用一个 “pfNodeName” 函数定义 compound 节点显示在应用中的名字:
def pfNodeName():
return ‘Simple solve’
还必须有一个 “pfCreateNode” 函数定义 compound 节点的内容。此函数的单参数是 class PyCompoundNode 的一个 Python 对象。定义 compound 节点基本操作时,用到 PyCompoundNode 的以下两种方法:
addNode(string name, string type)
connectNodes(string from, string to)
这两个函数构造 compound 节点中的内部网络节点。例如:
def pfCreateNode(cnode):
cnode.addNode(‘track’, ‘Auto Track’) # Add an Auto Track node called ‘track’
cnode.addNode(‘solve’, ‘Camera Solver’) # Add a Camera Solver node called ‘solve’
cnode.connectNodes(‘input’, ‘track’) # The input of the compound node is wired to the input of the track node
cnode.connectNodes(‘track’, ‘solve’) # The output of the track node is connected to the input of the solve node
cnode.connectNodes(‘solve’, ‘output’) # The output of the solve node forms the output of the compound node
注意“input”和“output”是保留名称,表示复合节点的单输入和单输出。
compound 节点创建之后,您可以定义函数 “pfInitNode” 来初始化它。此函数的单参数是 class PyCompoundNode 中表示复合节点的一个 Python 对象。在 “pfInitNode” 函数中,PyCompoundNode 方法 “getNode” 可以使用。此方法返回一个特定名称的节点作为相关节点类的 Python 对象。此返回的对象可用于调用特定于该节点类型的方法。例如:
def pfInitNode(cnode):
cnode.getNode(‘track’).setFailureThreshold(0.5) # Set failure threshold of Auto Track node
注意,复合节点的创建和初始化是两个不同的操作。
Defining a GUI
复合节点的脚本可以定义简单的GUI界面,即节点界面/编辑器,它预置在应用中。注意,只有少数几个控件类型支持创建复合节点的GUI,如按钮,滑块等。
GUI 是由 “pfCreateGUI”, “pfUpdateGUI” 和 ”pfGUIActivated” 函数定义的。第一个函数定义 GUI 的内容;第二个函数更新 GUI 的状态(当 GUI 发生更改时);第三个函数定义各种 GUI 控件被激活时需要采取的操作。
“pfCreateGUI” 有2个参数,第一个是类 PyCompoundNode 中显示复合节点的 Python 对象;第二个是类 PyCompoundNodeEditor 的 Python 对象。当定义 GUI 内容时,以下7个 PyCompoundNodeEditor 可用:
addButton(string name, string text)
addInput(string name)
addLabel(string name, string text)
addSlider(string name, float min, float max)
addCheckbox(string name, int checked)
addCombo(string name)
newRow()
这些函数分别添加按钮、文本框、文本标签、滑块、复选框、下拉选框,和为布局 GUI 控件创建新的行(控件是从左到右水平排列的)。例如:
def pfCreateGUI(cnode, gui):
gui.addButton(‘trackButton’, ‘Track’) # Add a button labelled ‘Track’ called ‘trackButton’
gui.addButton(‘solveButton’, ‘Solve’) # Add a button labelled ‘Solve’ called ‘solveButton’
gui.addButton(‘bothButton’, ‘Track+Solve’) # Add a button labelled ‘Track+Solve’ called ‘bothButton’
通过定义函数来更新GUI的状态:
def pfUpdateGUI(cnode, gui):
gui.setEnabled(‘trackButton’, 0) # Disable the ‘Track’ button
以下 PyCompoundNodeEditor 方法可以设置各种控件的状态:
setButtonText(string name, string text)
setLabelText(string name, string text)
setSliderValue(string name, float value)
setInputText(string name, string text)
setCheckboxChecked(string name, int checked)
setComboEntry(string name, string entry)
setComboCurrentEntry(string name, string entry)
clearCombo(string name)
setWidth(string name, int width)
setEnabled(string name, int enabled)
setHidden(string name, int hidden)
当控件被激活并指定采取的动作时,同源函数 “pfGUIActivated” 被调用。例如:
def pfGUIActivated(cnode, gui, widget, value):
if widget == ‘trackButton’: # When the ‘Track’ button is pressed, call the autoTrack() method of the track node
track= cnode.getNode(‘track’)
track.autoTrack()
elif widget == ‘solveButton’: # When the ‘Solve’ button is pressed, call the solveAll() method of the solve node
solve= cnode.getNode(‘solve’)
solve.solveAll()
elif widget == ‘bothButton’: # When the ‘Track+Solve’ button is pressed, call both methods above
track= cnode.getNode(‘track’)
track.autoTrack()
solve= cnode.getNode(‘solve’)
solve.solveAll()
第一个参数是一个显示复合节点的 PyCompoundNode 对象;第二个是显示 GUI 的 PyCompoundNodeEditor 对象;第三个是一个包含激活的控件名称的字符串;第四个参数是为激活的控件指定新的值的字符串。
在 “pfGUIActivated” 函数中,下面的 PyCompoundNodeEditor 方法可用:
fileBrowser(string text, string initialDirectory, string filter, string loadOrSave)
messageBox(string title, string text, string button1Text, [string button2Text], [string button3Text])
writeToLog(string text)
这些函数产生一个文件浏览器,带一个消息框,并向应用日志写一个接口。”fileBrowser” 函数返回选择的文件的名称为一个字符串,同样的,”messageBox” 函数返回一个对应按钮的字符串。
Expanding a compound node
Compound 节点与跟踪树中的其他节点有轻微不同,它们是红色的:
这表明复合节点是可以扩展的,按住Shift双击它,进入它的组成部分:
在扩展状态中,组成复合节点的组成部分被一个红色的边界框包围。组成部分可以像任何其他节点一样使用。在许多情况下,扩展复合节点是有用的:
准确地查看复合节点的内部在做什么
访问内部节点,定义mask或者访问它的节点编辑器
将外部节点连接到复合节点内部网络中的一个点上
在任意一个组成部分上按住 Shift 双击,会使复合节点恢复到原来的状态。如果你对复合节点的内部网络进行更改,例如改变或删除一部分,会被给予警告,此操作将破坏复合节点。如果继续执行,复合节点本身将不复存在,它的组成部分会变成独立节点。
另一种访问复合节点内部组件的方式是通过节点编辑器。复合节点的节点编辑器默认显示节点为它自身定义的 GUI。然而,在编辑器的右下角有一个 “More” 按钮。按此按钮可在每个复合节点组成部分定义的 GUI 和编辑器之间切换。当编辑器扩展后,”More” 按钮变成 “Less” 按钮,当按下 “Less” 时显示复合节点定义的 GUI。
复合节点的作者可以通过调用 “pfCreateNode” 函数中的 PyCompoundNode 方式 “setExpandAllowed”, 控制扩展节点的功能并在跟踪树中显示。此函数需要一个结合以下条件的整型值:
1 – 可以使用 More/Less 按钮扩展
2 – 在节点树中显示为红色
4 – 可通过 Shift + 双击扩展