From 8de29161b7bf48c58b5f9937cb142b21319ed3d0 Mon Sep 17 00:00:00 2001 From: Abdelrahman AL MAROUK Date: Wed, 28 Jun 2023 15:23:33 +0200 Subject: [PATCH 1/4] [BoundingBox] add visualization for automatically computed bounding box --- meshroom/core/node.py | 20 +++- meshroom/nodes/aliceVision/Meshing.py | 103 ++++++++++++++++++ meshroom/ui/qml/Viewer3D/EntityWithGizmo.qml | 1 + meshroom/ui/qml/Viewer3D/MediaLibrary.qml | 6 +- .../ui/qml/Viewer3D/MeshingBoundingBox.qml | 1 + 5 files changed, 128 insertions(+), 3 deletions(-) diff --git a/meshroom/core/node.py b/meshroom/core/node.py index 247ba3c6fb..eb52ec60f7 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -20,6 +20,7 @@ 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.nodes.aliceVision.Meshing import boundingBoxMonitor def getWritingFilepath(filepath): @@ -1323,6 +1324,19 @@ def _updateChunks(self): else: self._chunks[0].range = desc.Range() +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) + + def checkBBox(self): + """Load automatic bounding box if needed.""" + if self.useBoundingBox.value: + return + self.automaticBBoxValid.value = False + with boundingBoxMonitor(self, checkOnce=True) as thread: + pass class CompatibilityIssue(Enum): """ @@ -1564,7 +1578,8 @@ def upgrade(self): # store internal attributes that could be used during node upgrade commonInternalAttributes.append(attrName) - node = Node(self.nodeType, position=self.position) + cl = MeshingNode if self.nodeType=="Meshing" else Node + node = cl(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()} @@ -1685,7 +1700,8 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): break if compatibilityIssue is None: - node = Node(nodeType, position, **inputs) + cl = MeshingNode if nodeType=="Meshing" else Node + node = cl(nodeType, position, **inputs) node.setInternalAttributeValues(internalInputs) else: logging.warning("Compatibility issue detected for node '{}': {}".format(name, compatibilityIssue.name)) diff --git a/meshroom/nodes/aliceVision/Meshing.py b/meshroom/nodes/aliceVision/Meshing.py index 306ad1d7e1..01ab899a45 100644 --- a/meshroom/nodes/aliceVision/Meshing.py +++ b/meshroom/nodes/aliceVision/Meshing.py @@ -2,6 +2,11 @@ from meshroom.core import desc from meshroom.core.utils import VERBOSE_LEVEL +import os +import threading +import psutil +import time +from contextlib import contextmanager class Meshing(desc.AVCommandLineNode): @@ -536,4 +541,102 @@ class Meshing(desc.AVCommandLineNode): value="{cache}/{nodeType}/{uid0}/densePointCloud.abc", uid=[], ), + desc.BoolParam( + name="automaticBBoxValid", + label="", + description="Indicates if the Bounding Box has been " + "automatically computed and loaded.\n" + "Note that this param is always not enabled (not exposed in the UI) and " + "only used to indicate if the automatic bounding box should be displayed.", + value=False, + enabled=False, + uid=[], + ), ] + + def processChunk(self, chunk): + with boundingBoxMonitor(chunk.node): + super(Meshing, self).processChunk(chunk) + +@contextmanager +def boundingBoxMonitor(node, checkOnce=False): + """ + Context manager to load the automatic bounding box. + + Inputs + ------ + node: MeshingNode + The considered meshing node + + checkOnce: bool + If `True`, the bounding box file will be checked continuously + till created; if already exists, it will be ignored. + Otherwise, the file is checked only once and it will not be + ignored if already created. + + Returns + ------- + BoundingBoxThread + """ + bboxThread = None + try: + if not node.useBoundingBox.value: + bboxThread = BoundingBoxThread(node, checkOnce) + bboxThread.start() + yield bboxThread + finally: + if bboxThread is not None: + bboxThread.stopRequest() + bboxThread.join() + +class BoundingBoxThread(threading.Thread): + """Thread that loads the bounding box.""" + def __init__(self, node, checkOnce): + threading.Thread.__init__(self) + self.node = node + self.checkOnce = checkOnce + self.parentProc = psutil.Process() # by default current process pid + self._stopFlag = threading.Event() + self.interval = 5 # wait duration before rechecking for bounding box file + + def run(self): + self.startTime = time.time() if not self.checkOnce else -1 + try: + while True: + updated = self.updateBoundingBox() + if updated or self.checkOnce: + return + if self._stopFlag.wait(self.interval): + # stopFlag has been set + # try to update boundingBox one last time and exit main loop + if self.parentProc.is_running(): + self.updateBoundingBox() + return + except (KeyboardInterrupt, SystemError, GeneratorExit, psutil.NoSuchProcess): + pass + + def updateBoundingBox(self) -> bool: + """Tries to load the bounding box. + + Returns + ------- + bool: indicates if loading was successful + """ + file = os.path.join(os.path.dirname(self.node.outputMesh.value), "boundingBox.txt") + if not os.path.exists(file) or os.path.getmtime(file) < self.startTime: + return False + with open(file, 'r') as stream: + # file contains (in order, one value per line): + # translation: x, y, z ; rotation: x, y, z ; scale: x, y, z + data = list(map(float, stream.read().strip().splitlines())) + i = 0 + for vec in self.node.boundingBox.value: + for x in vec.value: + x.value = data[i] + i += 1 + self.node.automaticBBoxValid.value = True + return True + + def stopRequest(self): + """ Request the thread to exit as soon as possible. """ + self._stopFlag.set() diff --git a/meshroom/ui/qml/Viewer3D/EntityWithGizmo.qml b/meshroom/ui/qml/Viewer3D/EntityWithGizmo.qml index fe485d19b4..bbb3d2962b 100644 --- a/meshroom/ui/qml/Viewer3D/EntityWithGizmo.qml +++ b/meshroom/ui/qml/Viewer3D/EntityWithGizmo.qml @@ -18,6 +18,7 @@ Entity { property Layer frontLayerComponent property var window property alias uniformScale: transformGizmo.uniformScale // By default, if not set, the value is: false + property alias gizmoEnabled : transformGizmo.enabled property TransformGizmo transformGizmo: TransformGizmo { id: transformGizmo camera: root.camera diff --git a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml index aa60488d08..674235cb62 100644 --- a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml +++ b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml @@ -167,8 +167,12 @@ Entity { // Specific properties to the MESHING node (declared and initialized for every Entity anyway) property bool hasBoundingBox: { - if (nodeType === "Meshing" && currentNode.attribute("useBoundingBox")) // Can have a BoundingBox + if(nodeType === "Meshing" && currentNode.attribute("useBoundingBox")) // Can have a BoundingBox + { + if(currentNode.attribute("automaticBBoxValid")) + return currentNode.attribute("useBoundingBox").value || currentNode.attribute("automaticBBoxValid").value return currentNode.attribute("useBoundingBox").value + } return false } onHasBoundingBoxChanged: model.hasBoundingBox = hasBoundingBox diff --git a/meshroom/ui/qml/Viewer3D/MeshingBoundingBox.qml b/meshroom/ui/qml/Viewer3D/MeshingBoundingBox.qml index 3f9e0b7a3a..f5cc138f42 100644 --- a/meshroom/ui/qml/Viewer3D/MeshingBoundingBox.qml +++ b/meshroom/ui/qml/Viewer3D/MeshingBoundingBox.qml @@ -18,6 +18,7 @@ Entity { EntityWithGizmo { id: boundingBoxEntity + gizmoEnabled: root.currentMeshingNode ? root.currentMeshingNode.attribute("useBoundingBox").value : true sceneCameraController: root.sceneCameraController frontLayerComponent: root.frontLayerComponent window: root.window From 400a82e7858673629711ed03c153af5dc051d53a Mon Sep 17 00:00:00 2001 From: Abdelrahman AL MAROUK Date: Mon, 3 Jul 2023 16:55:35 +0200 Subject: [PATCH 2/4] [BoundingBox] fix automatic bounding box - fix circular dependacy issue in import - fix dirty hack for reading python variable "automaticBBoxValid" in qml --- meshroom/core/node.py | 25 ++++--------------- meshroom/core/nodes/MeshingNode.py | 30 +++++++++++++++++++++++ meshroom/core/nodes/__init__.py | 23 +++++++++++++++++ meshroom/nodes/aliceVision/Meshing.py | 13 +--------- meshroom/ui/qml/Viewer3D/MediaLibrary.qml | 4 +-- 5 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 meshroom/core/nodes/MeshingNode.py create mode 100644 meshroom/core/nodes/__init__.py diff --git a/meshroom/core/node.py b/meshroom/core/node.py index eb52ec60f7..70b196d5cf 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -20,8 +20,7 @@ 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.nodes.aliceVision.Meshing import boundingBoxMonitor - +from meshroom.core.nodes import getNodeClass def getWritingFilepath(filepath): return filepath + '.writing.' + str(uuid.uuid4()) @@ -1324,20 +1323,6 @@ def _updateChunks(self): else: self._chunks[0].range = desc.Range() -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) - - def checkBBox(self): - """Load automatic bounding box if needed.""" - if self.useBoundingBox.value: - return - self.automaticBBoxValid.value = False - with boundingBoxMonitor(self, checkOnce=True) as thread: - pass - class CompatibilityIssue(Enum): """ Enum describing compatibility issues when deserializing a Node. @@ -1578,8 +1563,8 @@ def upgrade(self): # store internal attributes that could be used during node upgrade commonInternalAttributes.append(attrName) - cl = MeshingNode if self.nodeType=="Meshing" else Node - node = cl(self.nodeType, position=self.position) + cls = getNodeClass(self.nodeType) + node = cls(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()} @@ -1700,8 +1685,8 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): break if compatibilityIssue is None: - cl = MeshingNode if nodeType=="Meshing" else Node - node = cl(nodeType, position, **inputs) + cls = getNodeClass(nodeType) + node = cls(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 new file mode 100644 index 0000000000..2c135102e9 --- /dev/null +++ b/meshroom/core/nodes/MeshingNode.py @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000000..e2050f262d --- /dev/null +++ b/meshroom/core/nodes/__init__.py @@ -0,0 +1,23 @@ +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/Meshing.py b/meshroom/nodes/aliceVision/Meshing.py index 01ab899a45..fa3ed6d70b 100644 --- a/meshroom/nodes/aliceVision/Meshing.py +++ b/meshroom/nodes/aliceVision/Meshing.py @@ -541,17 +541,6 @@ class Meshing(desc.AVCommandLineNode): value="{cache}/{nodeType}/{uid0}/densePointCloud.abc", uid=[], ), - desc.BoolParam( - name="automaticBBoxValid", - label="", - description="Indicates if the Bounding Box has been " - "automatically computed and loaded.\n" - "Note that this param is always not enabled (not exposed in the UI) and " - "only used to indicate if the automatic bounding box should be displayed.", - value=False, - enabled=False, - uid=[], - ), ] def processChunk(self, chunk): @@ -634,7 +623,7 @@ def updateBoundingBox(self) -> bool: for x in vec.value: x.value = data[i] i += 1 - self.node.automaticBBoxValid.value = True + self.node.automaticBBoxValid = True return True def stopRequest(self): diff --git a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml index 674235cb62..bcb6504a64 100644 --- a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml +++ b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml @@ -169,8 +169,8 @@ Entity { property bool hasBoundingBox: { if(nodeType === "Meshing" && currentNode.attribute("useBoundingBox")) // Can have a BoundingBox { - if(currentNode.attribute("automaticBBoxValid")) - return currentNode.attribute("useBoundingBox").value || currentNode.attribute("automaticBBoxValid").value + if(currentNode.automaticBBoxValid !== undefined) + return currentNode.attribute("useBoundingBox").value || currentNode.automaticBBoxValid return currentNode.attribute("useBoundingBox").value } return false From 742011d33d9a24e073be17e5a9c564fb551f999b Mon Sep 17 00:00:00 2001 From: Abdelrahman AL MAROUK Date: Mon, 28 Aug 2023 17:22:45 +0200 Subject: [PATCH 3/4] [BoundingBox] refactor automatic bounding box - remove hardcoded nodes information from the code engine - add "runtime attributes" for more flexibility --- meshroom/core/desc.py | 11 ++++++--- meshroom/core/node.py | 20 ++++++++------- meshroom/core/nodes/MeshingNode.py | 30 ----------------------- meshroom/core/nodes/__init__.py | 23 ----------------- meshroom/nodes/aliceVision/CameraInit.py | 4 +-- meshroom/nodes/aliceVision/Meshing.py | 27 +++++++++++++++++++- meshroom/ui/qml/Viewer3D/MediaLibrary.qml | 4 +-- 7 files changed, 49 insertions(+), 70 deletions(-) delete mode 100644 meshroom/core/nodes/MeshingNode.py delete mode 100644 meshroom/core/nodes/__init__.py diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 6d8cc2fa85..e862814b41 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 70b196d5cf..417ddb4967 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()) @@ -487,10 +486,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 = "" @@ -504,12 +499,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._runtimeAttributes = 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): @@ -613,6 +613,10 @@ def internalAttribute(self, name): # The internal attribute itself can be returned directly return self._internalAttributes.get(name) + @Slot(str, result=Attribute) + def runtimeAttribute(self, name): + return self._runtimeAttributes.get(name) + def setInternalAttributeValues(self, values): # initialize internal attribute values for k, v in values.items(): @@ -1563,8 +1567,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()} @@ -1685,8 +1688,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 2c135102e9..0000000000 --- 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 e2050f262d..0000000000 --- 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 b891884e89..d6121c451a 100644 --- a/meshroom/nodes/aliceVision/CameraInit.py +++ b/meshroom/nodes/aliceVision/CameraInit.py @@ -506,8 +506,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 fa3ed6d70b..4988735ebe 100644 --- a/meshroom/nodes/aliceVision/Meshing.py +++ b/meshroom/nodes/aliceVision/Meshing.py @@ -2,6 +2,8 @@ from meshroom.core import desc from meshroom.core.utils import VERBOSE_LEVEL +from meshroom.common import Slot +from meshroom.core.attribute import attributeFactory import os import threading import psutil @@ -543,10 +545,33 @@ 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._runtimeAttributes.add(attributeFactory(attrDesc, None, False, self.coreNode)) + 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.runtimeAttribute('automaticBBoxValid').value = False + with boundingBoxMonitor(self.coreNode, checkOnce=True) as thread: + pass + @contextmanager def boundingBoxMonitor(node, checkOnce=False): """ @@ -623,7 +648,7 @@ def updateBoundingBox(self) -> bool: for x in vec.value: x.value = data[i] i += 1 - self.node.automaticBBoxValid = True + self.node.runtimeAttribute('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 bcb6504a64..6ee942e300 100644 --- a/meshroom/ui/qml/Viewer3D/MediaLibrary.qml +++ b/meshroom/ui/qml/Viewer3D/MediaLibrary.qml @@ -169,8 +169,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.runtimeAttribute("automaticBBoxValid") !== undefined) + return currentNode.attribute("useBoundingBox").value || currentNode.runtimeAttribute("automaticBBoxValid").value return currentNode.attribute("useBoundingBox").value } return false From 44a2a676ee6356745fb6e73a3d5f0c1960ea1871 Mon Sep 17 00:00:00 2001 From: Abdelrahman AL MAROUK Date: Tue, 12 Mar 2024 17:07:14 +0100 Subject: [PATCH 4/4] [BoundingBox] Fix MaterialIcon name for bounding box --- meshroom/ui/qml/Viewer3D/Inspector3D.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshroom/ui/qml/Viewer3D/Inspector3D.qml b/meshroom/ui/qml/Viewer3D/Inspector3D.qml index 6674946f35..19086e6205 100644 --- a/meshroom/ui/qml/Viewer3D/Inspector3D.qml +++ b/meshroom/ui/qml/Viewer3D/Inspector3D.qml @@ -470,7 +470,7 @@ FloatingPane { enabled: model.visible Layout.alignment: Qt.AlignTop Layout.fillHeight: true - text: MaterialIcons.transform + text: MaterialIcons.transform_ font.pointSize: 10 ToolTip.text: model.displayBoundingBox ? "Hide BBox" : "Show BBox" flat: true