diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 6d8cc2fa857..e862814b41d 100644 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -556,9 +556,10 @@ class Node(object): parallelization = None documentation = '' category = 'Other' + coreNode = None - def __init__(self): - pass + def __init__(self, coreNode = None): + self.coreNode = coreNode def upgradeAttributeValues(self, attrValues, fromVersion): return attrValues @@ -599,6 +600,9 @@ class CommandLineNode(Node): parallelization = None commandLineRange = '' + def __init__(self, coreNode = None): + super().__init__(coreNode) + def buildCommandLine(self, chunk): cmdPrefix = '' @@ -665,7 +669,8 @@ class AVCommandLineNode(CommandLineNode): cmdMem = '' cmdCore = '' - def __init__(self): + def __init__(self, coreNode = None): + super().__init__(coreNode) if AVCommandLineNode.cgroupParsed is False: diff --git a/meshroom/core/node.py b/meshroom/core/node.py index 9b95b47b5b1..5de271fe583 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -20,7 +20,6 @@ from meshroom.core import desc, stats, hashValue, nodeVersion, Version from meshroom.core.attribute import attributeFactory, ListAttribute, GroupAttribute, Attribute from meshroom.core.exception import NodeUpgradeError, UnknownNodeTypeError -from meshroom.core.nodes import getNodeClass def getWritingFilepath(filepath): return filepath + '.writing.' + str(uuid.uuid4()) @@ -483,10 +482,6 @@ def __init__(self, nodeType, position=None, parent=None, **kwargs): self._nodeType = nodeType self.nodeDesc = None - # instantiate node description if nodeType is valid - if nodeType in meshroom.core.nodesDesc: - self.nodeDesc = meshroom.core.nodesDesc[nodeType]() - self.packageName = self.packageVersion = "" self._internalFolder = "" @@ -500,12 +495,17 @@ def __init__(self, nodeType, position=None, parent=None, **kwargs): self._position = position or Position() self._attributes = DictModel(keyAttrName='name', parent=self) self._internalAttributes = DictModel(keyAttrName='name', parent=self) + self._instanceAttributes = DictModel(keyAttrName='name', parent=self) self.attributesPerUid = defaultdict(set) self._alive = True # for QML side to know if the node can be used or is going to be deleted self._locked = False self._duplicates = ListModel(parent=self) # list of nodes with the same uid self._hasDuplicates = False + # instantiate node description if nodeType is valid + if nodeType in meshroom.core.nodesDesc: + self.nodeDesc = meshroom.core.nodesDesc[nodeType](coreNode=self) + self.globalStatusChanged.connect(self.updateDuplicatesStatusAndLocked) def __getattr__(self, k): @@ -609,6 +609,10 @@ def internalAttribute(self, name): # The internal attribute itself can be returned directly return self._internalAttributes.get(name) + @Slot(str, result=Attribute) + def instanceAttribute(self, name): + return self._instanceAttributes.get(name) + def setInternalAttributeValues(self, values): # initialize internal attribute values for k, v in values.items(): @@ -1554,8 +1558,7 @@ def upgrade(self): # store internal attributes that could be used during node upgrade commonInternalAttributes.append(attrName) - cls = getNodeClass(self.nodeType) - node = cls(self.nodeType, position=self.position) + node = Node(self.nodeType, position=self.position) # convert attributes from a list of tuples into a dict attrValues = {key: value for (key, value) in self.inputs.items()} intAttrValues = {key: value for (key, value) in self.internalInputs.items()} @@ -1676,8 +1679,7 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): break if compatibilityIssue is None: - cls = getNodeClass(nodeType) - node = cls(nodeType, position, **inputs) + node = Node(nodeType, position, **inputs) node.setInternalAttributeValues(internalInputs) else: logging.warning("Compatibility issue detected for node '{}': {}".format(name, compatibilityIssue.name)) diff --git a/meshroom/core/nodes/MeshingNode.py b/meshroom/core/nodes/MeshingNode.py deleted file mode 100644 index 2c135102e97..00000000000 --- a/meshroom/core/nodes/MeshingNode.py +++ /dev/null @@ -1,30 +0,0 @@ -from meshroom.nodes.aliceVision.Meshing import boundingBoxMonitor -from meshroom.core.node import Node -from meshroom.common import Property, Signal - -class MeshingNode(Node): - def __init__(self, nodeType, position=None, parent=None, **kwargs): - super().__init__(nodeType, position, parent, **kwargs) - self.internalFolderChanged.connect(self.checkBBox) - self.globalStatusChanged.connect(self.checkBBox) - self._automaticBBoxValid = False - - @property - def automaticBBoxValid(self): - return self._automaticBBoxValid - - @automaticBBoxValid.setter - def automaticBBoxValid(self, value): - self._automaticBBoxValid = value - self.automaticBBoxValidChanged.emit() - - automaticBBoxValidChanged = Signal() - automaticBBoxValid = Property(bool, automaticBBoxValid.fget, automaticBBoxValid.fset, notify=automaticBBoxValidChanged) - - def checkBBox(self): - """Load automatic bounding box if needed.""" - if self.useBoundingBox.value: - return - self.automaticBBoxValid = False - with boundingBoxMonitor(self, checkOnce=True) as thread: - pass diff --git a/meshroom/core/nodes/__init__.py b/meshroom/core/nodes/__init__.py deleted file mode 100644 index e2050f262dc..00000000000 --- a/meshroom/core/nodes/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import TYPE_CHECKING - -def getNodeClass(nodeType: str): - """ - Returns the appropriate subclass of `meshroom.core.node.Node` based on `nodeType`. - - Inputs - ------ - nodeType: str - the name of the node type - - Returns - ------- - type[Node] - the corresponding type class - """ - if nodeType=="Meshing": - from meshroom.core.nodes.MeshingNode import MeshingNode - cls = MeshingNode - else: - from meshroom.core.node import Node - cls = Node - return cls \ No newline at end of file diff --git a/meshroom/nodes/aliceVision/CameraInit.py b/meshroom/nodes/aliceVision/CameraInit.py index be0dab26d44..ee50060d5f7 100644 --- a/meshroom/nodes/aliceVision/CameraInit.py +++ b/meshroom/nodes/aliceVision/CameraInit.py @@ -328,8 +328,8 @@ class CameraInit(desc.AVCommandLineNode, desc.InitNode): ), ] - def __init__(self): - super(CameraInit, self).__init__() + def __init__(self, coreNode = None): + super(CameraInit, self).__init__(coreNode) def initialize(self, node, inputs, recursiveInputs): # Reset graph inputs diff --git a/meshroom/nodes/aliceVision/Meshing.py b/meshroom/nodes/aliceVision/Meshing.py index d661ce3f88d..a9203f0265a 100644 --- a/meshroom/nodes/aliceVision/Meshing.py +++ b/meshroom/nodes/aliceVision/Meshing.py @@ -1,6 +1,8 @@ __version__ = "7.0" from meshroom.core import desc +from meshroom.common import Slot +from meshroom.core.attribute import attributeFactory import os import threading import psutil @@ -533,10 +535,34 @@ class Meshing(desc.AVCommandLineNode): ), ] + def __init__(self, coreNode=None): + super().__init__(coreNode) + + attrDesc = desc.BoolParam( + name="automaticBBoxValid", + label="", + description="", + value=False, + uid=[], + group="" + ) + self.coreNode._instanceAttributes.add(attributeFactory(attrDesc, None, False, self.coreNode)) + coreNode.internalFolderChanged.connect(self.checkBBox) + coreNode.globalStatusChanged.connect(self.checkBBox) + def processChunk(self, chunk): with boundingBoxMonitor(chunk.node): super(Meshing, self).processChunk(chunk) + @Slot() + def checkBBox(self): + """Load automatic bounding box if needed.""" + if self.coreNode.useBoundingBox.value: + return + self.coreNode.instanceAttribute('automaticBBoxValid').value = False + with boundingBoxMonitor(self.coreNode, checkOnce=True) as thread: + pass + @contextmanager def boundingBoxMonitor(node, checkOnce=False): """ @@ -613,7 +639,7 @@ def updateBoundingBox(self) -> bool: for x in vec.value: x.value = data[i] i += 1 - self.node.automaticBBoxValid = True + self.node.instanceAttribute('automaticBBoxValid').value = True return True def stopRequest(self): diff --git a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml index 6edac0465f8..0842bb699d3 100644 --- a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml +++ b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml @@ -167,8 +167,8 @@ Entity { property bool hasBoundingBox: { if(nodeType === "Meshing" && currentNode.attribute("useBoundingBox")) // Can have a BoundingBox { - if(currentNode.automaticBBoxValid !== undefined) - return currentNode.attribute("useBoundingBox").value || currentNode.automaticBBoxValid + if(currentNode.instanceAttribute("automaticBBoxValid") !== undefined) + return currentNode.attribute("useBoundingBox").value || currentNode.instanceAttribute("automaticBBoxValid").value return currentNode.attribute("useBoundingBox").value } return false