Skip to content

Commit

Permalink
[WIP] Instanciation of "back end"
Browse files Browse the repository at this point in the history
Creation of Iteration Nodes for each instance that are not displayed in the graph
  • Loading branch information
Just-Kiel committed Sep 5, 2024
1 parent 97b6bc1 commit b21db99
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 55 deletions.
3 changes: 0 additions & 3 deletions meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,6 @@ def addEdge(self, srcAttr, dstAttr):
dstAttr.valueChanged.emit()
dstAttr.isLinkChanged.emit()
srcAttr.hasOutputConnectionsChanged.emit()
dstAttr.node.countForLoopChanged.emit()
return edge

def addEdges(self, *edges):
Expand All @@ -915,7 +914,6 @@ def removeEdge(self, dstAttr):
dstAttr.valueChanged.emit()
dstAttr.isLinkChanged.emit()
edge.src.hasOutputConnectionsChanged.emit()
dstAttr.node.countForLoopChanged.emit()

def getDepth(self, node, minimal=False):
""" Return node's depth in this Graph.
Expand Down Expand Up @@ -1486,7 +1484,6 @@ def markNodesDirty(self, fromNode):
nodes, edges = self.dfsOnDiscover(startNodes=[fromNode], reverse=True)
for node in nodes:
node.dirty = True
node.countForLoopChanged.emit()

def stopExecution(self):
""" Request graph execution to be stopped by terminating running chunks"""
Expand Down
92 changes: 75 additions & 17 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,55 @@ class ExecMode(Enum):
LOCAL = 1
EXTERN = 2

class ForLoopData(BaseObject):
"""
"""

def __init__(self, parentNode=None, connectedAttribute=None, parent=None):
super(ForLoopData, self).__init__(parent)
self._countForLoop = 0
self._iterations = ListModel(parent=self) # list of nodes for each iteration
self._parentNode = parentNode # parent node
self.connectedAttribute = connectedAttribute # attribute connected to the ForLoop node from parent node

def update(self, currentNode=None):
# set the connectedAttribute
if currentNode is not None:
for attr in currentNode._attributes:
if attr.isInput and attr.isLink:
srcAttr = attr.getLinkParam()
# If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
if isinstance(srcAttr.root, ListAttribute) and srcAttr.type == attr.type:
self.connectedAttribute = srcAttr.root
self._parentNode = srcAttr.root.node
break

# set the countForLoop
if self.connectedAttribute is not None:
self._countForLoop = self._parentNode._forLoopData._countForLoop + 1
if self.connectedAttribute.isInput:
self._countForLoop -= 1 if self._countForLoop > 1 else 1

# set the iterations by creating iteration nodes for each connected attribute value and will add them to the core graph and not the ui one
for i in range(len(self.connectedAttribute.value)):
iterationNode = IterationNode(currentNode, i)
# check if node already exists
if iterationNode.name not in [n.name for n in self._parentNode.graph.nodes]:
self._parentNode.graph.addNode(iterationNode, iterationNode.name)
self._iterations.append(iterationNode)

self.parentNodeChanged.emit()
self.iterationsChanged.emit()
self.countForLoopChanged.emit()

countForLoopChanged = Signal()
countForLoop = Property(int, lambda self: self._countForLoop, notify=countForLoopChanged)
iterationsChanged = Signal()
iterations = Property(Variant, lambda self: self._iterations, notify=iterationsChanged)
parentNodeChanged = Signal()
parentNode = Property(Variant, lambda self: self._parentNode, notify=parentNodeChanged)



class StatusData(BaseObject):
"""
Expand Down Expand Up @@ -513,6 +562,7 @@ def __init__(self, nodeType, position=None, parent=None, uids=None, **kwargs):
self._locked = False
self._duplicates = ListModel(parent=self) # list of nodes with the same uid
self._hasDuplicates = False
self._forLoopData = ForLoopData()

self.globalStatusChanged.connect(self.updateDuplicatesStatusAndLocked)

Expand Down Expand Up @@ -967,6 +1017,10 @@ def updateInternals(self, cacheDir=None):

# Update chunks splitting
self._updateChunks()

# try to update for loopdata as node is created
self._forLoopData.update(self)

# Retrieve current internal folder (if possible)
try:
folder = self.internalFolder
Expand Down Expand Up @@ -1321,23 +1375,11 @@ def has3DOutputAttribute(self):
return True
return False

def _countForLoop(self):
def getForLoopData(self):
"""
Return in how many ForLoop nodes this node is.
Return the ForLoopData of the node.
"""
count = 0
# Access to the input attributes of the node
for attr in self._attributes:
if attr.isInput and attr.isLink:
# Access to the attribute connected to the input attribute
srcAttr = attr.getLinkParam()
# If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
if isinstance(srcAttr.root, ListAttribute) and srcAttr.type == attr.type:
# Access the countForLoop of the node of the ListAttribute
count = srcAttr.root.node.countForLoop + 1
if srcAttr.root.isInput:
count = count - 1 if count > 1 else 1
return count
return self._forLoopData



Expand Down Expand Up @@ -1392,8 +1434,8 @@ def _countForLoop(self):
hasSequenceOutput = Property(bool, hasSequenceOutputAttribute, notify=outputAttrEnabledChanged)
has3DOutput = Property(bool, has3DOutputAttribute, notify=outputAttrEnabledChanged)

countForLoopChanged = Signal()
countForLoop = Property(int, _countForLoop, notify=countForLoopChanged)
forLoopDataChanged = Signal()
forLoopData = Property(Variant, getForLoopData, notify=forLoopDataChanged)

class Node(BaseNode):
"""
Expand Down Expand Up @@ -1535,6 +1577,22 @@ def _updateChunks(self):
self._chunks[0].range = desc.Range()


class IterationNode(BaseNode):
"""
A node that is not added to the graph but used to process a specific iteration of a ForLoop node.
"""
def __init__(self, node, iteration):
super(IterationNode, self).__init__(node.nodeType, parent=node.graph, uids=node._uids)
self._name = f"{node.name}_{iteration}"

self._chunks.setObjectList([NodeChunk(self, desc.Range(iteration, iteration))])

# if iteration is 3 set status to success
if iteration == 3 or iteration == 12:
self._chunks.at(0).status.status = Status.SUCCESS

# print(self._attributes.at(0))

class CompatibilityIssue(Enum):
"""
Enum describing compatibility issues when deserializing a Node.
Expand Down
19 changes: 16 additions & 3 deletions meshroom/ui/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from meshroom.core.taskManager import TaskManager

from meshroom.core.node import NodeChunk, Node, Status, ExecMode, CompatibilityNode, Position
from meshroom.core.node import NodeChunk, Node, Status, ExecMode, CompatibilityNode, Position, IterationNode
from meshroom.core import submitters
from meshroom.ui import commands
from meshroom.ui.utils import makeProperty
Expand Down Expand Up @@ -776,7 +776,6 @@ def expandForLoop(self, currentEdge):
newNode = duplicates[0]
previousEdge = self.graph.edge(newNode.attribute(dst.name))
self.replaceEdge(previousEdge, listAttribute.at(i), previousEdge.dst)
newNode.countForLoopChanged.emit()

@Slot(Edge)
def collapseForLoop(self, currentEdge):
Expand Down Expand Up @@ -1119,12 +1118,26 @@ def pasteNodes(self, clipboardContent, position=None, centerPosition=False):
positions.append(finalPosition)

return self.push(commands.PasteNodesCommand(self.graph, d, position=positions))

def getNodes(self):
"""
Return all the nodes that are not Iteration nodes.
"""
nodes = self._graph.nodes
toRemove = []
for node in nodes.values():
if isinstance(node, IterationNode):
toRemove.append(node)
for node in toRemove:
nodes.pop(node.name)
return nodes


undoStack = Property(QObject, lambda self: self._undoStack, constant=True)
graphChanged = Signal()
graph = Property(Graph, lambda self: self._graph, notify=graphChanged)
taskManager = Property(TaskManager, lambda self: self._taskManager, constant=True)
nodes = Property(QObject, lambda self: self._graph.nodes, notify=graphChanged)
nodes = Property(QObject, getNodes, notify=graphChanged)
layout = Property(GraphLayout, lambda self: self._layout, constant=True)

computeStatusChanged = Signal()
Expand Down
2 changes: 1 addition & 1 deletion meshroom/ui/qml/GraphEditor/GraphEditor.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,7 @@ Item {
Repeater {
id: filteredNodes
model: SortFilterDelegateModel {
model: root.graph ? root.graph.nodes : undefined
model: root.uigraph ? root.uigraph.nodes : undefined
sortRole: "label"
filters: [{role: "label", value: graphSearchBar.text}]
delegate: Item {
Expand Down
23 changes: 13 additions & 10 deletions meshroom/ui/qml/GraphEditor/Node.qml
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,12 @@ Item {

// Is in for loop indicator
MaterialLabel {
visible: node.countForLoop > 0
visible: node.forLoopData.countForLoop > 0
text: MaterialIcons.loop
padding: 2
font.pointSize: 7
palette.text: Colors.sysPalette.text
ToolTip.text: "Is in " + node.countForLoop + " for loop(s)"
ToolTip.text: "Is in " + node.forLoopData.countForLoop + " for loop(s)"
}

// Submitted externally indicator
Expand Down Expand Up @@ -386,14 +386,15 @@ Item {
// so if the count is 0 we display only one iteration
// else we display the number of iterations
model: {
if (node.countForLoop === 0)
return 1

for (let i = 0; i < node.attributes.count; ++i) {
if (node.attributes.at(i).isLink) {
var srcAttr = node.attributes.at(i).linkParam
return srcAttr.root.value.count
if (node.forLoopData.countForLoop === 0) {
return node
} else {
// convert the iterations to a list
let list = []
for (let i = 0; i < node.forLoopData.iterations.count; ++i) {
list.push(node.forLoopData.iterations.at(i))
}
return list
}
}

Expand All @@ -402,7 +403,9 @@ Item {
defaultColor: Colors.sysPalette.mid
height: 3
width: parent.width
model: node ? node.chunks : undefined
model: {
return modelData.chunks
}

Rectangle {
anchors.fill: parent
Expand Down
51 changes: 31 additions & 20 deletions meshroom/ui/qml/GraphEditor/NodeEditor.qml
Original file line number Diff line number Diff line change
Expand Up @@ -258,29 +258,40 @@ Panel {
anchors.fill: parent

// The list of iterations
NodeEditorElementsListView {
id: iterationsLV
visible: root.node.countForLoop > 0
elements: {
if (root.node.countForLoop == 0)
return []
var elements = []
for (let i = 0; i < node.attributes.count; ++i) {
if (node.attributes.at(i).isLink) {
var srcAttr = node.attributes.at(i).linkParam
for (let j = 0; j < srcAttr.root.value.count; ++j) {
elements.push(j)
}
return elements
}

Repeater {
id: iterationsRepeater
visible: root.node.forLoopData.countForLoop > 0

model: {
let currentNode = root.node
let count = root.node.forLoopData.countForLoop
let list = []
for (let i = 0; i < count; i++) {
let parent = currentNode.forLoopData.parentNode
list.push(currentNode.forLoopData.iterations)
currentNode = parent
}

// reverse the list
list.reverse()
return list
}

// TODO to remove when the elements would be correct
currentElement: elements[0]

isChunk: false
title: "Iterations"
NodeEditorElementsListView {
id: iterationsLV
elements: {
if (root.node.forLoopData.countForLoop == 0)
return []
return modelData
}

// TODO to remove when the elements would be correct
// currentElement: elements[0]

isChunk: false
title: "Iterations"
}
}

// The list of chunks
Expand Down
8 changes: 7 additions & 1 deletion meshroom/ui/qml/GraphEditor/NodeEditorElementsListView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ ColumnLayout {
Rectangle {
width: 4
height: parent.height
color: isChunk ? Common.getChunkColor(parent.element) : palette.mid
color: {
if (isChunk) {
return Common.getChunkColor(parent.element)
} else {
return Common.getChunkColor(parent.element.chunks.at(0))
}
}
}
}
}
Expand Down

0 comments on commit b21db99

Please sign in to comment.