From 31b04092a02029f8026459d91bbc2ff27d94b65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 8 Mar 2023 08:45:19 +0100 Subject: [PATCH 1/5] [ui] update QML properties after changes in qtAV --- .../ui/qml/Viewer/FeaturesInfoOverlay.qml | 14 +++++----- meshroom/ui/qml/Viewer/FeaturesViewer.qml | 26 ++++++++++++++++++- meshroom/ui/qml/Viewer/Viewer2D.qml | 7 ++--- meshroom/ui/reconstruction.py | 1 + 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml index d62ebd3bfa..9b2c5b4f5d 100644 --- a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml +++ b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml @@ -157,7 +157,7 @@ FloatingPane { Layout.alignment: Qt.AlignRight from: -1 to: 50 - value: root.mfeatures.timeWindow + value: root.featuresViewer.timeWindow stepSize: 1 editable: true @@ -174,7 +174,7 @@ FloatingPane { } onValueChanged: { - root.mfeatures.timeWindow = timeWindowSB.value; + root.featuresViewer.timeWindow = timeWindowSB.value; } } } @@ -224,7 +224,7 @@ FloatingPane { ToolTip.text: "Display Tracks" onClicked: { featureType.viewer.displayTracks = tracksVisibilityButton.checked; - root.mfeatures.enableTimeWindow = tracksVisibilityButton.checked; + root.featuresViewer.enableTimeWindow = tracksVisibilityButton.checked; } font.pointSize: 10 } @@ -232,7 +232,7 @@ FloatingPane { MaterialToolButton { id: matchesVisibilityButton checkable: true - checked: true + checked: false text: MaterialIcons.sync ToolTip.text: "Display Matches" onClicked: { @@ -244,7 +244,7 @@ FloatingPane { MaterialToolButton { id: landmarksVisibilityButton checkable: true - checked: true + checked: false text: MaterialIcons.fiber_manual_record ToolTip.text: "Display Landmarks" onClicked: { @@ -267,9 +267,7 @@ FloatingPane { if(featureType.viewer.loadingFeatures) return featureType.viewer.describerType; return featureType.viewer.describerType + ": " + - ((featureExtractionNode && featureExtractionNode.isComputed) ? root.mfeatures.featuresInfo[featureType.viewer.describerType][root.mfeatures.currentViewId]['nbFeatures'] : " - ") + " / " + - (root.mfeatures.haveValidTracks ? root.mfeatures.featuresInfo[featureType.viewer.describerType][root.mfeatures.currentViewId]['nbTracks'] : " - ") + " / " + - (root.mfeatures.haveValidLandmarks ? root.mfeatures.featuresInfo[featureType.viewer.describerType][root.mfeatures.currentViewId]['nbLandmarks'] : " - "); + ((featureExtractionNode && featureExtractionNode.isComputed) ? root.mfeatures.featuresInfo[featureType.viewer.describerType][root.featuresViewer.currentViewId]['nbFeatures'] : " - "); } } // Feature loading status diff --git a/meshroom/ui/qml/Viewer/FeaturesViewer.qml b/meshroom/ui/qml/Viewer/FeaturesViewer.qml index 63e8becdd9..c33538bc93 100644 --- a/meshroom/ui/qml/Viewer/FeaturesViewer.qml +++ b/meshroom/ui/qml/Viewer/FeaturesViewer.qml @@ -10,34 +10,53 @@ import Utils 1.0 Repeater { id: root - /// Features to display + /// Features property var features + /// Tracks + property var tracks + /// SfMData + property var sfmData /// The list of describer types to load property alias describerTypes: root.model + /// List of available feature display modes readonly property var featureDisplayModes: ['Points', 'Squares', 'Oriented Squares'] /// Current feature display mode index property int featureDisplayMode: 2 + /// List of available track display modes readonly property var trackDisplayModes: ['Lines Only', 'Current Matches', 'All Matches'] /// Current track display mode index property int trackDisplayMode: 1 + // Minimum feature scale score to display property real featureMinScaleFilter: 0 // Maximum feature scale score to display property real featureMaxScaleFilter: 1 + /// Display 3d tracks property bool display3dTracks: false + /// Display only contiguous tracks property bool trackContiguousFilter: true + /// Display only tracks with at least one inlier property bool trackInliersFilter: false + /// Display track endpoints property bool displayTrackEndpoints: true + /// The list of colors used for displaying several describers property var colors: [Colors.blue, Colors.green, Colors.yellow, Colors.cyan, Colors.pink, Colors.lime] //, Colors.orange, Colors.red + /// Current view ID + property var currentViewId + + /// Time window + property bool enableTimeWindow: false + property int timeWindow: 1 + model: root.describerTypes // instantiate one FeaturesViewer by describer type @@ -56,6 +75,11 @@ Repeater { matchColor: Colors.orange landmarkColor: Colors.red describerType: modelData + currentViewId: root.currentViewId + enableTimeWindow: root.enableTimeWindow + timeWindow: root.timeWindow mfeatures: root.features + mtracks: root.tracks + msfmData: root.sfmData } } diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index 2f3fe778f8..b91739888d 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -548,7 +548,10 @@ FocusScope { // instantiate and initialize a FeaturesViewer component dynamically using Loader.setSource setSource("FeaturesViewer.qml", { 'model': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : ""; }), + 'currentViewId': Qt.binding(function() { return _reconstruction.selectedViewId; }), 'features': Qt.binding(function() { return mfeaturesLoader.status === Loader.Ready ? mfeaturesLoader.item : null; }), + 'tracks': Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null; }), + 'sfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null; }), }) } else { // Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14 @@ -725,11 +728,9 @@ FocusScope { // instantiate and initialize a MFeatures component dynamically using Loader.setSource // so it can fail safely if the c++ plugin is not available setSource("MFeatures.qml", { - 'currentViewId': Qt.binding(function() { return _reconstruction.selectedViewId; }), 'describerTypes': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : {}; }), 'featureFolder': Qt.binding(function() { return activeNode ? Filepath.stringToUrl(activeNode.attribute("output").value) : ""; }), - 'mtracks': Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null; }), - 'msfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null; }), + 'viewIds': Qt.binding(function() { return _reconstruction ? _reconstruction.allViewIds() : {}; }), }) } else { diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index aecf85d9c1..bfdebb2e61 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -692,6 +692,7 @@ def allImagePaths(self): """ Get all image paths in the reconstruction. """ return [vp.path.value for node in self._cameraInits for vp in node.viewpoints.value] + @Slot(result="QVariantList") def allViewIds(self): """ Get all view Ids involved in the reconstruction. """ return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value] From 634fb96aa9d3bec3f181e779e4818997d9b60cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 22 Mar 2023 09:58:00 +0100 Subject: [PATCH 2/5] [ui] use new q_invokables for displaying nb features, matches and landmarks --- .../ui/qml/Viewer/FeaturesInfoOverlay.qml | 21 +++++++------------ meshroom/ui/qml/Viewer/Viewer2D.qml | 21 ++++++------------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml index 9b2c5b4f5d..269b30f30a 100644 --- a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml +++ b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml @@ -16,16 +16,12 @@ FloatingPane { property int pluginStatus: Loader.Null property Item featuresViewer: null property var mfeatures: null - property var featureExtractionNode: null + property var mtracks: null + property var msfmdata: null ColumnLayout { // Header RowLayout { - // FeatureExtraction node name - Label { - text: featureExtractionNode ? featureExtractionNode.label : "" - Layout.fillWidth: true - } // Settings menu Loader { active: root.pluginStatus === Loader.Ready @@ -232,7 +228,7 @@ FloatingPane { MaterialToolButton { id: matchesVisibilityButton checkable: true - checked: false + checked: true text: MaterialIcons.sync ToolTip.text: "Display Matches" onClicked: { @@ -244,7 +240,7 @@ FloatingPane { MaterialToolButton { id: landmarksVisibilityButton checkable: true - checked: false + checked: true text: MaterialIcons.fiber_manual_record ToolTip.text: "Display Landmarks" onClicked: { @@ -263,12 +259,9 @@ FloatingPane { } // Feature type name Label { - text: { - if(featureType.viewer.loadingFeatures) - return featureType.viewer.describerType; - return featureType.viewer.describerType + ": " + - ((featureExtractionNode && featureExtractionNode.isComputed) ? root.mfeatures.featuresInfo[featureType.viewer.describerType][root.featuresViewer.currentViewId]['nbFeatures'] : " - "); - } + property string descType: featureType.viewer.describerType + property int viewId: root.featuresViewer.currentViewId + text: descType + ": " + ((root.mfeatures.status === MFeatures.Ready) ? root.mfeatures.nbFeatures(descType, viewId) : " - ") + " / " + ((root.mtracks.status === MTracks.Ready) ? root.mtracks.nbMatches(descType, viewId) : " - ") + " / " + ((root.msfmdata.status === MSfMData.Ready) ? root.msfmdata.nbLandmarks(descType, viewId) : " - ") } // Feature loading status Loader { diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index b91739888d..73fed243ac 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -68,33 +68,23 @@ FocusScope { return ""; var res = ""; if(imgContainer.image.status === Image.Loading) - res += " Image"; - if(featuresViewerLoader.status === Loader.Ready && featuresViewerLoader.item) { - for (var i = 0; i < featuresViewerLoader.item.count; ++i) { - if(featuresViewerLoader.item.itemAt(i).loadingFeatures) - { - res += " Features"; - break; - } - } + res += " Image"; } if(mfeaturesLoader.status === Loader.Ready) { - if(mfeaturesLoader.item.status === MFeatures.Loading) + if(mfeaturesLoader.item && mfeaturesLoader.item.status === MFeatures.Loading) res += " Features"; } if(mtracksLoader.status === Loader.Ready) { - if(mtracksLoader.item.status === MTracks.Loading) + if(mtracksLoader.item && mtracksLoader.item.status === MTracks.Loading) res += " Tracks"; } if(msfmDataLoader.status === Loader.Ready) { - if(msfmDataLoader.item != null && msfmDataLoader.item.status === MSfMData.Loading) - { + if(msfmDataLoader.item && msfmDataLoader.item.status === MSfMData.Loading) res += " SfMData"; - } } return res; } @@ -919,10 +909,11 @@ FocusScope { active: root.aliceVisionPluginAvailable && displayFeatures.checked && featuresViewerLoader.status === Loader.Ready sourceComponent: FeaturesInfoOverlay { - featureExtractionNode: _reconstruction.activeNodes.get('FeatureExtraction').node pluginStatus: featuresViewerLoader.status featuresViewer: featuresViewerLoader.item mfeatures: mfeaturesLoader.item + mtracks: mtracksLoader.item + msfmdata: msfmDataLoader.item } } From 8d68f1741075154897d904ff32d01b2598cd3861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 22 Mar 2023 15:43:54 +0100 Subject: [PATCH 3/5] [ui] MFeatures: use viewId from active cameraInit only (not all cameraInits) --- meshroom/ui/qml/Viewer/Viewer2D.qml | 12 +++++++++++- meshroom/ui/reconstruction.py | 1 - 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index 73fed243ac..9bdd9f710c 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -720,7 +720,17 @@ FocusScope { setSource("MFeatures.qml", { 'describerTypes': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : {}; }), 'featureFolder': Qt.binding(function() { return activeNode ? Filepath.stringToUrl(activeNode.attribute("output").value) : ""; }), - 'viewIds': Qt.binding(function() { return _reconstruction ? _reconstruction.allViewIds() : {}; }), + 'viewIds': Qt.binding(function() { + if (_reconstruction) { + let result = []; + for (let i = 0; i < _reconstruction.viewpoints.count; i++) { + let vp = _reconstruction.viewpoints.at(i); + result.push(vp.childAttribute("viewId").value); + } + return result; + } + return {}; + }), }) } else { diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index bfdebb2e61..aecf85d9c1 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -692,7 +692,6 @@ def allImagePaths(self): """ Get all image paths in the reconstruction. """ return [vp.path.value for node in self._cameraInits for vp in node.viewpoints.value] - @Slot(result="QVariantList") def allViewIds(self): """ Get all view Ids involved in the reconstruction. """ return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value] From 2bf1a5f809b7d9f6caf8b837a60ab725333b9b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 10 May 2023 17:17:58 +0200 Subject: [PATCH 4/5] [ui] Viewer2D: notion of feature/match provider nodes for features viewer --- .../ui/qml/Viewer/FeaturesInfoOverlay.qml | 5 ++ meshroom/ui/qml/Viewer/Viewer2D.qml | 90 +++++++++++++------ meshroom/ui/reconstruction.py | 4 + 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml index 269b30f30a..93786af8c1 100644 --- a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml +++ b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml @@ -22,6 +22,11 @@ FloatingPane { ColumnLayout { // Header RowLayout { + // Node used to read features + Label { + text: _reconstruction ? _reconstruction.activeNodes.get("featureProvider").node.label : "" + Layout.fillWidth: true + } // Settings menu Loader { active: root.pluginStatus === Loader.Ready diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index 9bdd9f710c..ef5b3c29b1 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -699,7 +699,12 @@ FocusScope { id: mfeaturesLoader property bool isUsed: displayFeatures.checked - property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get("FeatureExtraction").node : null + property var activeNode: { + if (!root.aliceVisionPluginAvailable) { + return null; + } + return _reconstruction ? _reconstruction.activeNodes.get("featureProvider").node : null; + } property bool isComputed: activeNode && activeNode.isComputed active: false @@ -718,8 +723,23 @@ FocusScope { // instantiate and initialize a MFeatures component dynamically using Loader.setSource // so it can fail safely if the c++ plugin is not available setSource("MFeatures.qml", { - 'describerTypes': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : {}; }), - 'featureFolder': Qt.binding(function() { return activeNode ? Filepath.stringToUrl(activeNode.attribute("output").value) : ""; }), + 'describerTypes': Qt.binding(function() { + return activeNode ? activeNode.attribute("describerTypes").value : {}; + }), + 'featureFolders': Qt.binding(function() { + let result = []; + if (activeNode) { + if (activeNode.nodeType == "FeatureExtraction" && isComputed) { + result.push(activeNode.attribute("output").value); + } else { + for (let i = 0; i < activeNode.attribute("featuresFolders").value.count; i++) { + let attr = activeNode.attribute("featuresFolders").value.at(i); + result.push(attr.value); + } + } + } + return result; + }), 'viewIds': Qt.binding(function() { if (_reconstruction) { let result = []; @@ -742,39 +762,33 @@ FocusScope { Loader { id: msfmDataLoader - property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked - || displayPanoramaViewer.checked || displayLensDistortionViewer.checked + property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked || displayPanoramaViewer.checked || displayLensDistortionViewer.checked property var activeNode: { - if(! root.aliceVisionPluginAvailable){ - return null + if(!root.aliceVisionPluginAvailable){ + return null; } - // For lens distortion viewer: use all nodes creating a sfmData file - var nodeType = displayLensDistortionViewer.checked ? 'sfmData' : 'sfm' - var sfmNode = _reconstruction ? _reconstruction.activeNodes.get(nodeType).node : null + var nodeType = "sfm"; + if (displayLensDistortionViewer.checked) { + nodeType = "sfmData"; + } + var sfmNode = _reconstruction ? _reconstruction.activeNodes.get(nodeType).node : null; if(sfmNode === null){ - return null + return null; } if(displayPanoramaViewer.checked){ - sfmNode = _reconstruction.activeNodes.get('SfMTransform').node - var previousNode = sfmNode.attribute("input").rootLinkParam.node - return previousNode - } - else{ - return sfmNode + sfmNode = _reconstruction.activeNodes.get('SfMTransform').node; + var previousNode = sfmNode.attribute("input").rootLinkParam.node; + return previousNode; } + return sfmNode; } property bool isComputed: activeNode && activeNode.isComputed property string filepath: { - var sfmValue = "" - if(!isComputed){ - return Filepath.stringToUrl(sfmValue) - } - else{ - if(activeNode.hasAttribute("output")){ - sfmValue = activeNode.attribute("output").value - } - return Filepath.stringToUrl(sfmValue) + var sfmValue = ""; + if (isComputed && activeNode.hasAttribute("output")) { + sfmValue = activeNode.attribute("output").value; } + return Filepath.stringToUrl(sfmValue); } active: false @@ -828,11 +842,16 @@ FocusScope { id: mtracksLoader property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked || displayPanoramaViewer.checked - property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get('FeatureMatching').node : null + property var activeNode: { + if (!root.aliceVisionPluginAvailable) { + return null; + } + return _reconstruction ? _reconstruction.activeNodes.get("matchProvider").node : null; + } property bool isComputed: activeNode && activeNode.isComputed active: false - // It takes time to load tracks, so keep them looaded, if we may use it again. + // It takes time to load tracks, so keep them loaded, if we may use it again. // If we load another node, we can trash them (to eventually load the new node data). onIsUsedChanged: { if(!active && isUsed && isComputed) { @@ -864,7 +883,20 @@ FocusScope { // instantiate and initialize a SfmStatsView component dynamically using Loader.setSource // so it can fail safely if the c++ plugin is not available setSource("MTracks.qml", { - 'matchingFolder': Qt.binding(function() { return Filepath.stringToUrl(isComputed ? activeNode.attribute("output").value : ""); }), + 'matchingFolders': Qt.binding(function() { + let result = []; + if (activeNode) { + if (activeNode.nodeType == "FeatureMatching" && isComputed) { + result.push(activeNode.attribute("output").value); + } else { + for (let i = 0; i < activeNode.attribute("matchesFolders").value.count; i++) { + let attr = activeNode.attribute("matchesFolders").value.at(i); + result.push(attr.value); + } + } + } + return result; + }), }) } else { // Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14 diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index aecf85d9c1..266305f159 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -408,6 +408,10 @@ class Reconstruction(UIGraph): "SfMAlignment"], # All nodes generating depth map files "allDepthMap": ["DepthMap", "DepthMapFilter"], + # Nodes that can be used to provide features folders to the UI + "featureProvider": ["FeatureExtraction", "FeatureMatching", "StructureFromMotion"], + # Nodes that can be used to provide matches folders to the UI + "matchProvider": ["FeatureMatching", "StructureFromMotion"] } def __init__(self, undoStack, taskManager, defaultPipeline='', parent=None): From 5b9d37c836039cc2128bbb1759e968b0eb40caab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Thu, 11 May 2023 16:02:08 +0200 Subject: [PATCH 5/5] [ui] bug fix in features viewer --- .../ui/qml/Viewer/FeaturesInfoOverlay.qml | 4 +- meshroom/ui/qml/Viewer/Viewer2D.qml | 80 ++----------------- 2 files changed, 8 insertions(+), 76 deletions(-) diff --git a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml index 93786af8c1..fb28140a9f 100644 --- a/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml +++ b/meshroom/ui/qml/Viewer/FeaturesInfoOverlay.qml @@ -266,11 +266,11 @@ FloatingPane { Label { property string descType: featureType.viewer.describerType property int viewId: root.featuresViewer.currentViewId - text: descType + ": " + ((root.mfeatures.status === MFeatures.Ready) ? root.mfeatures.nbFeatures(descType, viewId) : " - ") + " / " + ((root.mtracks.status === MTracks.Ready) ? root.mtracks.nbMatches(descType, viewId) : " - ") + " / " + ((root.msfmdata.status === MSfMData.Ready) ? root.msfmdata.nbLandmarks(descType, viewId) : " - ") + text: descType + ": " + ((root.mfeatures && root.mfeatures.status === MFeatures.Ready) ? root.mfeatures.nbFeatures(descType, viewId) : " - ") + " / " + ((root.mtracks && root.mtracks.status === MTracks.Ready) ? root.mtracks.nbMatches(descType, viewId) : " - ") + " / " + ((root.msfmdata && root.msfmdata.status === MSfMData.Ready) ? root.msfmdata.nbLandmarks(descType, viewId) : " - ") } // Feature loading status Loader { - active: (root.mfeatures.status === MFeatures.Loading) + active: (root.mfeatures && root.mfeatures.status === MFeatures.Loading) sourceComponent: BusyIndicator { padding: 0 implicitWidth: 12 diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index ef5b3c29b1..f40926f7be 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -524,7 +524,7 @@ FocusScope { ExifOrientedViewer { id: featuresViewerLoader active: displayFeatures.checked - property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("FeatureExtraction").node : null + property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("featureProvider").node : null width: imgContainer.width height: imgContainer.height anchors.centerIn: parent @@ -706,17 +706,7 @@ FocusScope { return _reconstruction ? _reconstruction.activeNodes.get("featureProvider").node : null; } property bool isComputed: activeNode && activeNode.isComputed - active: false - - onIsUsedChanged: { - active = (!active && isUsed && isComputed); - } - onIsComputedChanged: { - active = (!active && isUsed && isComputed); - } - onActiveNodeChanged: { - active = (!active && isUsed && isComputed); - } + active: isUsed && isComputed onActiveChanged: { if(active) { @@ -731,7 +721,7 @@ FocusScope { if (activeNode) { if (activeNode.nodeType == "FeatureExtraction" && isComputed) { result.push(activeNode.attribute("output").value); - } else { + } else if (activeNode.hasAttribute("featuresFolders")) { for (let i = 0; i < activeNode.attribute("featuresFolders").value.count; i++) { let attr = activeNode.attribute("featuresFolders").value.at(i); result.push(attr.value); @@ -791,39 +781,7 @@ FocusScope { return Filepath.stringToUrl(sfmValue); } - active: false - // It takes time to load tracks, so keep them looaded, if we may use it again. - // If we load another node, we can trash them (to eventually load the new node data). - onIsUsedChanged: { - if(!active && isUsed && isComputed) - { - active = true; - } - } - onIsComputedChanged: { - if(!isComputed) - { - active = false; - } - else if(!active && isUsed) - { - active = true; - } - } - onActiveNodeChanged: { - if(!isUsed) - { - active = false; - } - else if(!isComputed) - { - active = false; - } - else - { - active = true; - } - } + active: isUsed && isComputed onActiveChanged: { if(active) { @@ -850,33 +808,7 @@ FocusScope { } property bool isComputed: activeNode && activeNode.isComputed - active: false - // It takes time to load tracks, so keep them loaded, if we may use it again. - // If we load another node, we can trash them (to eventually load the new node data). - onIsUsedChanged: { - if(!active && isUsed && isComputed) { - active = true; - } - } - onIsComputedChanged: { - if(!isComputed) { - active = false; - } - else if(!active && isUsed) { - active = true; - } - } - onActiveNodeChanged: { - if(!isUsed) { - active = false; - } - else if(!isComputed) { - active = false; - } - else { - active = true; - } - } + active: isUsed && isComputed onActiveChanged: { if(active) { @@ -888,7 +820,7 @@ FocusScope { if (activeNode) { if (activeNode.nodeType == "FeatureMatching" && isComputed) { result.push(activeNode.attribute("output").value); - } else { + } else if (activeNode.hasAttribute("matchesFolders")) { for (let i = 0; i < activeNode.attribute("matchesFolders").value.count; i++) { let attr = activeNode.attribute("matchesFolders").value.at(i); result.push(attr.value);