Connecting Nodes
================

.. currentmodule:: NodegraphAPI


Adding and Removing Ports
-------------------------

Katana recipes are created by adding and connecting nodes in the
:kat:ui:`Node Graph`. Nodes are connected through their input and output ports.
Some node types have a fixed number of ports, while others allow for an
arbitrary number. The :kat:node:`Merge` nodes, for example, takes any number of
inputs and combines them into a single output. To create a :kat:node:`Merge`
node and add two input ports enter the following::

    rootNode = NodegraphAPI.GetRootNode()
    mergeNode = NodegraphAPI.CreateNode('Merge', rootNode)
    firstPort = mergeNode.addInputPort("First")
    secondPort = mergeNode.addInputPort("Second")

Ports can be added by index as well as by name, which allows direct control of
their ordering. For example, to add an input port to the merge node created
above, add the following::

    newPort = mergeNode.addInputPortAtIndex("BetweenFirstAndSecond", 1)

.. automethod:: Node.addInputPort
.. automethod:: Node.addOutputPort

.. automethod:: Node.addInputPortAtIndex
.. automethod:: Node.addOutputPortAtIndex

.. automethod:: Node.removeInputPort
.. automethod:: Node.removeOutputPort


Retrieving Ports
----------------

.. automethod:: Node.getNumInputPorts
.. automethod:: Node.getNumOutputPorts

.. automethod:: Node.getInputPort
.. automethod:: Node.getOutputPort

.. automethod:: Node.getInputPortByIndex
.. automethod:: Node.getOutputPortByIndex

.. automethod:: Node.getInputPorts
.. automethod:: Node.getOutputPorts

.. automethod:: Node.getSourcePort
.. automethod:: Node.getInputSource
.. automethod:: Node.getInputPortAndGraphState


Renaming Ports
--------------

The :meth:`~Node.renameInputPort` and :meth:`~Node.renameOutputPort`
methods rename ports. For example, to rename the input port named "i0" and the
output port named "out" on the :kat:node:`Merge` node from earlier, enter the
following::

    mergeNode.renameInputPort("i0", "input")
    mergeNode.renameOutputPort("out", "output")

.. automethod:: Node.renameInputPort
.. automethod:: Node.renameOutputPort


Connecting and Disconnecting Ports
----------------------------------

.. currentmodule:: NodegraphAPI

The :meth:`~Port.connect` method links ports. For example, to take an output
port on a :kat:node:`PrimitiveCreate` node and connect it to an input port on a
:kat:node:`Merge` node enter the following::

    primOutPort = primNode.getOutputPort("out")
    mergeInPort = mergeNode.getInputPort("i0")
    primOutPort.connect(mergeInPort)
    # or...
    mergeInPort.connect(primOutPort)

The :meth:`~Port.disconnect` method unlinks two ports. For example, to unlink
the two ports connected above enter the following::

    mergeInPort.disconnect(primOutPort)
    # or...
    primOutPort.disconnect(mergeInPort)

.. automethod:: Port.isConnected
.. automethod:: Port.getNumConnectedPorts
.. automethod:: Port.getConnectedPort
.. automethod:: Port.getConnectedPorts

.. automethod:: Port.connect
.. automethod:: Port.disconnect


Port Information
----------------

.. automethod:: Port.getIndex
.. automethod:: Port.getName
.. automethod:: Port.getDisplayName
.. automethod:: Port.getType
.. automethod:: Port.getNode


Physical Source
---------------

A physical connection is determined by which output ports any given input port is directly connected. The physical
connections are those you see represented by connection arrows in the Node Graph.

To find the physical source from a given port, use :meth:`~Port.getConnectedPorts`. For example, create a 
:kat:node:`PrimitiveCreate` node and a :kat:node:`Merge` node, connect the output of the PrimitiveCreate node to an 
input on the Merge node, then get the source of the connection into the Merge node::

    # Get the root node
    rootNode = NodegraphAPI.GetRootNode()

    # Create a PrimitiveCreate node at root level
    primNode = NodegraphAPI.CreateNode('PrimitiveCreate', rootNode)

    # Create a Merge node at root level
    mergeNode = NodegraphAPI.CreateNode('Merge', rootNode)

    # Add an output port to the PrimitiveCreate node
    primOutPort = primNode.addOutputPort("newOutputPort")

    # Add an input to the Merge node
    mergeInPort = mergeNode.addInputPort("fromPrim")

    # Connect PrimitiveCreate to Merge
    primOutPort.connect(mergeInPort)

    # Use getConnectedPorts to find connections on mergeInPort
    mergeInConnectedPorts = mergeInPort.getConnectedPorts()

    # Print the connected port
    print(mergeInConnectedPorts)


Logical Source
--------------

Logical connections are those used to traverse up the node graph at render time. Conditional logic, parameter values
and time are used to determine the next relevant source of data, and this is represented by a logical connection
between the current node and the next.

The diagram below shows an example of physical and logical connections in the :kat:ui:`Node Graph` tab. Nodes A and B
have physical connections to inputs on the :kat:node:`Switch` node, and node C has a physical connection to the output
of the Switch.

The logical connection from node A or B to node C, depends on the setting of the switch. When the Switch node's in
parameter is set to 0, there is a logical connection from node A, to node C, passing through the Switch. When the
Switch's :kat:param:`in` parameter is set to :kat:ui:`1`, there is a logical connection from node B to node C, passing
through the Switch.

.. image:: LogicalConnection.png

To find the logical source of an input node use :meth:`~Port.getLogicalSource`, which takes the name of the port and a
time as arguments, and returns a tuple containing the source port and the time. If no port is found, it returns None.

For example, recreate the scene shown above then find the input source at the output::

    root = NodegraphAPI.GetRootNode()
    
    # Create TheInputSourceNode at root level
    primANode = NodegraphAPI.CreateNode('PrimitiveCreate', root)
    primBNode = NodegraphAPI.CreateNode('PrimitiveCreate', root)
    primANode.setName("A")
    primBNode.setName("B")
    primAOutPort = primANode.getOutputPort("out")
    primBOutPort = primBNode.getOutputPort("out")
     
    # Create the Switch node at root level
    switchNode = NodegraphAPI.CreateNode('Switch', root)
    switchInPort1 = switchNode.addInputPort("input1")
    switchInPort2 = switchNode.addInputPort("input2")
    switchOutPort = switchNode.getOutputPort("output")
     
    # Create a Render node at root level
    renderNode = NodegraphAPI.CreateNode('Render', root)
    renderInPort = renderNode.getInputPort("input")
     
    # Connect the primitive to the switch, and switch to render
    primAOutPort.connect(switchInPort1)
    primBOutPort.connect(switchInPort2)
    switchOutPort.connect(renderInPort)
     
    # Get the logical input of the render.input port
    inputPort, inputTime = renderNode.getInputSource("input", TIME)
     
    # Get hold of the source node so that we can print its name.
    inputNode = inputPort.getNode()
    inputNodeName = inputNode.getName()
     
    # Print the name of the source node
    print(inputNodeName)