Skip to content

Commit 10819fc

Browse files
committed
[WIP] Instanciation of "back end"
Creation of Iteration Nodes for each instance that are not displayed in the graph
1 parent 123ef97 commit 10819fc

File tree

7 files changed

+143
-55
lines changed

7 files changed

+143
-55
lines changed

meshroom/core/graph.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,6 @@ def addEdge(self, srcAttr, dstAttr):
899899
dstAttr.valueChanged.emit()
900900
dstAttr.isLinkChanged.emit()
901901
srcAttr.hasOutputConnectionsChanged.emit()
902-
dstAttr.node.countForLoopChanged.emit()
903902
return edge
904903

905904
def addEdges(self, *edges):
@@ -916,7 +915,6 @@ def removeEdge(self, dstAttr):
916915
dstAttr.valueChanged.emit()
917916
dstAttr.isLinkChanged.emit()
918917
edge.src.hasOutputConnectionsChanged.emit()
919-
dstAttr.node.countForLoopChanged.emit()
920918

921919
def getDepth(self, node, minimal=False):
922920
""" Return node's depth in this Graph.
@@ -1487,7 +1485,6 @@ def markNodesDirty(self, fromNode):
14871485
nodes, edges = self.dfsOnDiscover(startNodes=[fromNode], reverse=True)
14881486
for node in nodes:
14891487
node.dirty = True
1490-
node.countForLoopChanged.emit()
14911488

14921489
def stopExecution(self):
14931490
""" Request graph execution to be stopped by terminating running chunks"""

meshroom/core/node.py

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,55 @@ class ExecMode(Enum):
5858
LOCAL = 1
5959
EXTERN = 2
6060

61+
class ForLoopData(BaseObject):
62+
"""
63+
"""
64+
65+
def __init__(self, parentNode=None, connectedAttribute=None, parent=None):
66+
super(ForLoopData, self).__init__(parent)
67+
self._countForLoop = 0
68+
self._iterations = ListModel(parent=self) # list of nodes for each iteration
69+
self._parentNode = parentNode # parent node
70+
self.connectedAttribute = connectedAttribute # attribute connected to the ForLoop node from parent node
71+
72+
def update(self, currentNode=None):
73+
# set the connectedAttribute
74+
if currentNode is not None:
75+
for attr in currentNode._attributes:
76+
if attr.isInput and attr.isLink:
77+
srcAttr = attr.getLinkParam()
78+
# If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
79+
if isinstance(srcAttr.root, ListAttribute) and srcAttr.type == attr.type:
80+
self.connectedAttribute = srcAttr.root
81+
self._parentNode = srcAttr.root.node
82+
break
83+
84+
# set the countForLoop
85+
if self.connectedAttribute is not None:
86+
self._countForLoop = self._parentNode._forLoopData._countForLoop + 1
87+
if self.connectedAttribute.isInput:
88+
self._countForLoop -= 1 if self._countForLoop > 1 else 1
89+
90+
# 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
91+
for i in range(len(self.connectedAttribute.value)):
92+
iterationNode = IterationNode(currentNode, i)
93+
# check if node already exists
94+
if iterationNode.name not in [n.name for n in self._parentNode.graph.nodes]:
95+
self._parentNode.graph.addNode(iterationNode, iterationNode.name)
96+
self._iterations.append(iterationNode)
97+
98+
self.parentNodeChanged.emit()
99+
self.iterationsChanged.emit()
100+
self.countForLoopChanged.emit()
101+
102+
countForLoopChanged = Signal()
103+
countForLoop = Property(int, lambda self: self._countForLoop, notify=countForLoopChanged)
104+
iterationsChanged = Signal()
105+
iterations = Property(Variant, lambda self: self._iterations, notify=iterationsChanged)
106+
parentNodeChanged = Signal()
107+
parentNode = Property(Variant, lambda self: self._parentNode, notify=parentNodeChanged)
108+
109+
61110

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

517567
self.globalStatusChanged.connect(self.updateDuplicatesStatusAndLocked)
518568

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

9681018
# Update chunks splitting
9691019
self._updateChunks()
1020+
1021+
# try to update for loopdata as node is created
1022+
self._forLoopData.update(self)
1023+
9701024
# Retrieve current internal folder (if possible)
9711025
try:
9721026
folder = self.internalFolder
@@ -1321,23 +1375,11 @@ def has3DOutputAttribute(self):
13211375
return True
13221376
return False
13231377

1324-
def _countForLoop(self):
1378+
def getForLoopData(self):
13251379
"""
1326-
Return in how many ForLoop nodes this node is.
1380+
Return the ForLoopData of the node.
13271381
"""
1328-
count = 0
1329-
# Access to the input attributes of the node
1330-
for attr in self._attributes:
1331-
if attr.isInput and attr.isLink:
1332-
# Access to the attribute connected to the input attribute
1333-
srcAttr = attr.getLinkParam()
1334-
# If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
1335-
if isinstance(srcAttr.root, ListAttribute) and srcAttr.type == attr.type:
1336-
# Access the countForLoop of the node of the ListAttribute
1337-
count = srcAttr.root.node.countForLoop + 1
1338-
if srcAttr.root.isInput:
1339-
count = count - 1 if count > 1 else 1
1340-
return count
1382+
return self._forLoopData
13411383

13421384

13431385

@@ -1392,8 +1434,8 @@ def _countForLoop(self):
13921434
hasSequenceOutput = Property(bool, hasSequenceOutputAttribute, notify=outputAttrEnabledChanged)
13931435
has3DOutput = Property(bool, has3DOutputAttribute, notify=outputAttrEnabledChanged)
13941436

1395-
countForLoopChanged = Signal()
1396-
countForLoop = Property(int, _countForLoop, notify=countForLoopChanged)
1437+
forLoopDataChanged = Signal()
1438+
forLoopData = Property(Variant, getForLoopData, notify=forLoopDataChanged)
13971439

13981440
class Node(BaseNode):
13991441
"""
@@ -1553,6 +1595,22 @@ def _updateChunks(self):
15531595
self._chunks[0].range = desc.Range()
15541596

15551597

1598+
class IterationNode(BaseNode):
1599+
"""
1600+
A node that is not added to the graph but used to process a specific iteration of a ForLoop node.
1601+
"""
1602+
def __init__(self, node, iteration):
1603+
super(IterationNode, self).__init__(node.nodeType, parent=node.graph, uids=node._uids)
1604+
self._name = f"{node.name}_{iteration}"
1605+
1606+
self._chunks.setObjectList([NodeChunk(self, desc.Range(iteration, iteration))])
1607+
1608+
# if iteration is 3 set status to success
1609+
if iteration == 3 or iteration == 12:
1610+
self._chunks.at(0).status.status = Status.SUCCESS
1611+
1612+
# print(self._attributes.at(0))
1613+
15561614
class CompatibilityIssue(Enum):
15571615
"""
15581616
Enum describing compatibility issues when deserializing a Node.

meshroom/ui/graph.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from meshroom.core.taskManager import TaskManager
1919

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

781780
# Last, replace the edge with the first element of the list
782781
return self.replaceEdge(currentEdge, listAttribute.at(0), dst)
@@ -1120,12 +1119,26 @@ def pasteNodes(self, clipboardContent, position=None, centerPosition=False):
11201119
positions.append(finalPosition)
11211120

11221121
return self.push(commands.PasteNodesCommand(self.graph, d, position=positions))
1122+
1123+
def getNodes(self):
1124+
"""
1125+
Return all the nodes that are not Iteration nodes.
1126+
"""
1127+
nodes = self._graph.nodes
1128+
toRemove = []
1129+
for node in nodes.values():
1130+
if isinstance(node, IterationNode):
1131+
toRemove.append(node)
1132+
for node in toRemove:
1133+
nodes.pop(node.name)
1134+
return nodes
1135+
11231136

11241137
undoStack = Property(QObject, lambda self: self._undoStack, constant=True)
11251138
graphChanged = Signal()
11261139
graph = Property(Graph, lambda self: self._graph, notify=graphChanged)
11271140
taskManager = Property(TaskManager, lambda self: self._taskManager, constant=True)
1128-
nodes = Property(QObject, lambda self: self._graph.nodes, notify=graphChanged)
1141+
nodes = Property(QObject, getNodes, notify=graphChanged)
11291142
layout = Property(GraphLayout, lambda self: self._layout, constant=True)
11301143

11311144
computeStatusChanged = Signal()

meshroom/ui/qml/GraphEditor/GraphEditor.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ Item {
10851085
Repeater {
10861086
id: filteredNodes
10871087
model: SortFilterDelegateModel {
1088-
model: root.graph ? root.graph.nodes : undefined
1088+
model: root.uigraph ? root.uigraph.nodes : undefined
10891089
sortRole: "label"
10901090
filters: [{role: "label", value: graphSearchBar.text}]
10911091
delegate: Item {

meshroom/ui/qml/GraphEditor/Node.qml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,12 @@ Item {
278278

279279
// Is in for loop indicator
280280
MaterialLabel {
281-
visible: node.countForLoop > 0
281+
visible: node.forLoopData.countForLoop > 0
282282
text: MaterialIcons.loop
283283
padding: 2
284284
font.pointSize: 7
285285
palette.text: Colors.sysPalette.text
286-
ToolTip.text: "Is in " + node.countForLoop + " for loop(s)"
286+
ToolTip.text: "Is in " + node.forLoopData.countForLoop + " for loop(s)"
287287
}
288288

289289
// Submitted externally indicator
@@ -386,14 +386,15 @@ Item {
386386
// so if the count is 0 we display only one iteration
387387
// else we display the number of iterations
388388
model: {
389-
if (node.countForLoop === 0)
390-
return 1
391-
392-
for (let i = 0; i < node.attributes.count; ++i) {
393-
if (node.attributes.at(i).isLink) {
394-
var srcAttr = node.attributes.at(i).linkParam
395-
return srcAttr.root.value.count
389+
if (node.forLoopData.countForLoop === 0) {
390+
return node
391+
} else {
392+
// convert the iterations to a list
393+
let list = []
394+
for (let i = 0; i < node.forLoopData.iterations.count; ++i) {
395+
list.push(node.forLoopData.iterations.at(i))
396396
}
397+
return list
397398
}
398399
}
399400

@@ -402,7 +403,9 @@ Item {
402403
defaultColor: Colors.sysPalette.mid
403404
height: 3
404405
width: parent.width
405-
model: node ? node.chunks : undefined
406+
model: {
407+
return modelData.chunks
408+
}
406409

407410
Rectangle {
408411
anchors.fill: parent

meshroom/ui/qml/GraphEditor/NodeEditor.qml

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -258,29 +258,40 @@ Panel {
258258
anchors.fill: parent
259259

260260
// The list of iterations
261-
NodeEditorElementsListView {
262-
id: iterationsLV
263-
visible: root.node.countForLoop > 0
264-
elements: {
265-
if (root.node.countForLoop == 0)
266-
return []
267-
var elements = []
268-
for (let i = 0; i < node.attributes.count; ++i) {
269-
if (node.attributes.at(i).isLink) {
270-
var srcAttr = node.attributes.at(i).linkParam
271-
for (let j = 0; j < srcAttr.root.value.count; ++j) {
272-
elements.push(j)
273-
}
274-
return elements
275-
}
261+
262+
Repeater {
263+
id: iterationsRepeater
264+
visible: root.node.forLoopData.countForLoop > 0
265+
266+
model: {
267+
let currentNode = root.node
268+
let count = root.node.forLoopData.countForLoop
269+
let list = []
270+
for (let i = 0; i < count; i++) {
271+
let parent = currentNode.forLoopData.parentNode
272+
list.push(currentNode.forLoopData.iterations)
273+
currentNode = parent
276274
}
275+
276+
// reverse the list
277+
list.reverse()
278+
return list
277279
}
278280

279-
// TODO to remove when the elements would be correct
280-
currentElement: elements[0]
281-
282-
isChunk: false
283-
title: "Iterations"
281+
NodeEditorElementsListView {
282+
id: iterationsLV
283+
elements: {
284+
if (root.node.forLoopData.countForLoop == 0)
285+
return []
286+
return modelData
287+
}
288+
289+
// TODO to remove when the elements would be correct
290+
// currentElement: elements[0]
291+
292+
isChunk: false
293+
title: "Iterations"
294+
}
284295
}
285296

286297
// The list of chunks

meshroom/ui/qml/GraphEditor/NodeEditorElementsListView.qml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,13 @@ ColumnLayout {
9292
Rectangle {
9393
width: 4
9494
height: parent.height
95-
color: isChunk ? Common.getChunkColor(parent.element) : palette.mid
95+
color: {
96+
if (isChunk) {
97+
return Common.getChunkColor(parent.element)
98+
} else {
99+
return Common.getChunkColor(parent.element.chunks.at(0))
100+
}
101+
}
96102
}
97103
}
98104
}

0 commit comments

Comments
 (0)