-- Script to move nodes into the node pin -- -- @description Moves the selected nodes inside the node pins -- @author Roeland Schoukens -- @version 0.1 ------------------------------- -- wraps a function so calls with the same argument are cached only once local FMapMT = { __call = function(self, x) local v = self._r[x] if v then return v end v = self.f(x) self._r[x] = v return v end } function FMap(f) local M = { _r = {}, f = f } setmetatable(M, FMapMT) return M end ------------------------------- -- find an item in a list local function find(list, v) for i, v0 in ipairs(list) do if v0 == v then return i end end return nil end ------------------------------- -- enumerate source items for an item local function sources(n) -- enumerate all input pins local pins = {} if n.isNode then for i = 1, n:getPinCount() do table.insert(pins, {node=n, pinIx=i}) end else local inputs = n:getInputNodes() for _, n in pairs(inputs) do table.insert(pins, {node=n, pinIx=1}) end end -- enumerate all input nodes local sourceList = {} for _, p in ipairs(pins) do local si = p.node:getConnectedNodeIx(p.pinIx) -- select parent graph for output linkers if si and si.isOutputLinker then si = si.graphOwner end if si then table.insert(sourceList, si) end end return sourceList end -- destination of item. Returns the destination item in the graph and the pin -- if a node has multiple destinations, return nil local function destination(n) -- for node graphs, get the destination of the output linker instead if n.isGraph then local ol = n:getOutputNodes() if #ol ~= 1 then return nil end n = ol[1] end -- select destination local d = n:getDestinationNodes() if #d ~= 1 then return nil end n = d[1].node local pin = d[1] -- if we go to an input linker, select the parent graph if n.isInputLinker then n = n.graphOwner end return n, pin end -- filter out any node without destination or with multiple destinations -- and any input linker nodes too local selection = octane.project.getSelection() local nodes = {} for _, n in pairs(selection) do if not n.isInputLinker and destination(n) then table.insert(nodes, n) end end -- order the nodes so destination nodes appear after source nodes local function leafOrder(n) if not find(nodes, n) then return 0 end local d = destination(n) return leafOrder(d) + 1 end -- wrap to avoid repeated evauations for the same node leafOrder = FMap(leafOrder) -- reverse sort by leaf order table.sort(nodes, function(a, b) return leafOrder(a) > leafOrder(b) end) -- filter out any nodes with a source node which is not selected. -- Do this in leaf order, so previously filtered nodes are not -- considered anymore for i, n in ipairs(nodes) do local ss = sources(n) for _, s in ipairs(ss) do if not s.pinOwned and not find(nodes, s) then nodes[i] = false end end end -- and move: for _, n in ipairs(nodes) do if n then local _, pin = destination(n) pin.node:copyFrom(pin.pin, n) n:destroy() end end