mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-07 13:21:56 +02:00
Merge pull request #2449 from alicevision/dev/accessCurrentFrame
Provide access to the path of the currently displayed frame
This commit is contained in:
commit
ccf76ab3b5
6 changed files with 72 additions and 47 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
# [Viewer] Clean-up: Harmonize syntax for the Viewer2D
|
||||||
|
9af65092b9e881c828430f54a73fb4522bc1e370
|
||||||
# [nodes] Harmonize the use of trailing commas across all the nodes
|
# [nodes] Harmonize the use of trailing commas across all the nodes
|
||||||
61a8dcd4e2878f80b2f320f2b1c3c9b41e999b82
|
61a8dcd4e2878f80b2f320f2b1c3c9b41e999b82
|
||||||
# [nodes] Clean-up: Harmonize nodes' descriptions
|
# [nodes] Clean-up: Harmonize nodes' descriptions
|
||||||
|
|
|
@ -226,8 +226,6 @@ class Graph(BaseObject):
|
||||||
self._fileDateVersion = 0
|
self._fileDateVersion = 0
|
||||||
self.header = {}
|
self.header = {}
|
||||||
|
|
||||||
self._selectedViewpoint = None
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.header.clear()
|
self.header.clear()
|
||||||
self._compatibilityNodes.clear()
|
self._compatibilityNodes.clear()
|
||||||
|
@ -1566,12 +1564,6 @@ class Graph(BaseObject):
|
||||||
self.updateStatusFromCache(force=True)
|
self.updateStatusFromCache(force=True)
|
||||||
self.cacheDirChanged.emit()
|
self.cacheDirChanged.emit()
|
||||||
|
|
||||||
@property
|
|
||||||
def selectedViewpoint(self):
|
|
||||||
""" Return the attribute describing the viewpoint that is
|
|
||||||
currently set as the 'selected viewpoint'. """
|
|
||||||
return self._selectedViewpoint
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fileDateVersion(self):
|
def fileDateVersion(self):
|
||||||
return self._fileDateVersion
|
return self._fileDateVersion
|
||||||
|
|
|
@ -6,6 +6,8 @@ from meshroom.common import Backend
|
||||||
meshroom.setupEnvironment(backend=Backend.PYSIDE)
|
meshroom.setupEnvironment(backend=Backend.PYSIDE)
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
from meshroom.ui.app import MeshroomApp
|
import meshroom.ui
|
||||||
app = MeshroomApp(sys.argv)
|
import meshroom.ui.app
|
||||||
app.exec_()
|
|
||||||
|
meshroom.ui.uiInstance = meshroom.ui.app.MeshroomApp(sys.argv)
|
||||||
|
meshroom.ui.uiInstance.exec_()
|
||||||
|
|
|
@ -4,13 +4,14 @@ import re
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from PySide2 import QtCore
|
from PySide2 import QtCore
|
||||||
from PySide2.QtCore import Qt, QUrl, Slot, QJsonValue, Property, Signal, qInstallMessageHandler, QtMsgType, QSettings
|
from PySide2.QtCore import Qt, QUrl, QJsonValue, qInstallMessageHandler, QtMsgType, QSettings
|
||||||
from PySide2.QtGui import QIcon
|
from PySide2.QtGui import QIcon
|
||||||
from PySide2.QtWidgets import QApplication
|
from PySide2.QtWidgets import QApplication
|
||||||
|
|
||||||
import meshroom
|
import meshroom
|
||||||
from meshroom.core import nodesDesc
|
from meshroom.core import nodesDesc
|
||||||
from meshroom.core.taskManager import TaskManager
|
from meshroom.core.taskManager import TaskManager
|
||||||
|
from meshroom.common import Property, Variant, Signal, Slot
|
||||||
|
|
||||||
from meshroom.ui import components
|
from meshroom.ui import components
|
||||||
from meshroom.ui.components.clipboard import ClipboardHelper
|
from meshroom.ui.components.clipboard import ClipboardHelper
|
||||||
|
@ -143,9 +144,9 @@ class MeshroomApp(QApplication):
|
||||||
# instantiate Reconstruction object
|
# instantiate Reconstruction object
|
||||||
self._undoStack = commands.UndoStack(self)
|
self._undoStack = commands.UndoStack(self)
|
||||||
self._taskManager = TaskManager(self)
|
self._taskManager = TaskManager(self)
|
||||||
r = Reconstruction(undoStack=self._undoStack, taskManager=self._taskManager, defaultPipeline=args.pipeline, parent=self)
|
self._activeProject = Reconstruction(undoStack=self._undoStack, taskManager=self._taskManager, defaultPipeline=args.pipeline, parent=self)
|
||||||
r.setSubmitLabel(args.submitLabel)
|
self._activeProject.setSubmitLabel(args.submitLabel)
|
||||||
self.engine.rootContext().setContextProperty("_reconstruction", r)
|
self.engine.rootContext().setContextProperty("_reconstruction", self._activeProject)
|
||||||
|
|
||||||
# those helpers should be available from QML Utils module as singletons, but:
|
# those helpers should be available from QML Utils module as singletons, but:
|
||||||
# - qmlRegisterUncreatableType is not yet available in PySide2
|
# - qmlRegisterUncreatableType is not yet available in PySide2
|
||||||
|
@ -162,7 +163,7 @@ class MeshroomApp(QApplication):
|
||||||
self.engine.rootContext().setContextProperty("MeshroomApp", self)
|
self.engine.rootContext().setContextProperty("MeshroomApp", self)
|
||||||
|
|
||||||
# request any potential computation to stop on exit
|
# request any potential computation to stop on exit
|
||||||
self.aboutToQuit.connect(r.stopChildThreads)
|
self.aboutToQuit.connect(self._activeProject.stopChildThreads)
|
||||||
|
|
||||||
if args.project and not os.path.isfile(args.project):
|
if args.project and not os.path.isfile(args.project):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
|
@ -171,17 +172,17 @@ class MeshroomApp(QApplication):
|
||||||
|
|
||||||
if args.project:
|
if args.project:
|
||||||
args.project = os.path.abspath(args.project)
|
args.project = os.path.abspath(args.project)
|
||||||
r.load(args.project)
|
self._activeProject.load(args.project)
|
||||||
self.addRecentProjectFile(args.project)
|
self.addRecentProjectFile(args.project)
|
||||||
else:
|
else:
|
||||||
r.new()
|
self._activeProject.new()
|
||||||
|
|
||||||
# import is a python keyword, so we have to access the attribute by a string
|
# import is a python keyword, so we have to access the attribute by a string
|
||||||
if getattr(args, "import", None):
|
if getattr(args, "import", None):
|
||||||
r.importImagesFromFolder(getattr(args, "import"), recursive=False)
|
self._activeProject.importImagesFromFolder(getattr(args, "import"), recursive=False)
|
||||||
|
|
||||||
if args.importRecursive:
|
if args.importRecursive:
|
||||||
r.importImagesFromFolder(args.importRecursive, recursive=True)
|
self._activeProject.importImagesFromFolder(args.importRecursive, recursive=True)
|
||||||
|
|
||||||
if args.save:
|
if args.save:
|
||||||
if os.path.isfile(args.save):
|
if os.path.isfile(args.save):
|
||||||
|
@ -195,7 +196,7 @@ class MeshroomApp(QApplication):
|
||||||
"Meshroom Command Line Error: Cannot save the new Meshroom project file (.mg) as the parent of the folder does not exists.\n"
|
"Meshroom Command Line Error: Cannot save the new Meshroom project file (.mg) as the parent of the folder does not exists.\n"
|
||||||
"Invalid value: '{}'".format(args.save))
|
"Invalid value: '{}'".format(args.save))
|
||||||
os.mkdir(projectFolder)
|
os.mkdir(projectFolder)
|
||||||
r.saveAs(args.save)
|
self._activeProject.saveAs(args.save)
|
||||||
self.addRecentProjectFile(args.save)
|
self.addRecentProjectFile(args.save)
|
||||||
|
|
||||||
self.engine.load(os.path.normpath(url))
|
self.engine.load(os.path.normpath(url))
|
||||||
|
@ -459,7 +460,8 @@ class MeshroomApp(QApplication):
|
||||||
def _default8bitViewerEnabled(self):
|
def _default8bitViewerEnabled(self):
|
||||||
return bool(os.environ.get("MESHROOM_USE_8BIT_VIEWER", False))
|
return bool(os.environ.get("MESHROOM_USE_8BIT_VIEWER", False))
|
||||||
|
|
||||||
|
activeProjectChanged = Signal()
|
||||||
|
activeProject = Property(Variant, lambda self: self._activeProject, notify=activeProjectChanged)
|
||||||
changelogModel = Property("QVariantList", _changelogModel, constant=True)
|
changelogModel = Property("QVariantList", _changelogModel, constant=True)
|
||||||
licensesModel = Property("QVariantList", _licensesModel, constant=True)
|
licensesModel = Property("QVariantList", _licensesModel, constant=True)
|
||||||
pipelineTemplateFilesChanged = Signal()
|
pipelineTemplateFilesChanged = Signal()
|
||||||
|
|
|
@ -137,8 +137,8 @@ FocusScope {
|
||||||
if (Math.min(imgContainer.width, imgContainer.image.height) * imgContainer.scale * zoomFactor < 10)
|
if (Math.min(imgContainer.width, imgContainer.image.height) * imgContainer.scale * zoomFactor < 10)
|
||||||
return
|
return
|
||||||
var point = mapToItem(imgContainer, wheel.x, wheel.y)
|
var point = mapToItem(imgContainer, wheel.x, wheel.y)
|
||||||
imgContainer.x += (1-zoomFactor) * point.x * imgContainer.scale
|
imgContainer.x += (1 - zoomFactor) * point.x * imgContainer.scale
|
||||||
imgContainer.y += (1-zoomFactor) * point.y * imgContainer.scale
|
imgContainer.y += (1 - zoomFactor) * point.y * imgContainer.scale
|
||||||
imgContainer.scale *= zoomFactor
|
imgContainer.scale *= zoomFactor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,12 +224,15 @@ FocusScope {
|
||||||
// Entry point for getting the image file from the gallery
|
// Entry point for getting the image file from the gallery
|
||||||
let vp = getViewpoint(_reconstruction.pickedViewId)
|
let vp = getViewpoint(_reconstruction.pickedViewId)
|
||||||
let path = vp ? vp.childAttribute("path").value : ""
|
let path = vp ? vp.childAttribute("path").value : ""
|
||||||
|
_reconstruction.currentViewPath = path
|
||||||
return Filepath.stringToUrl(path)
|
return Filepath.stringToUrl(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_reconstruction && displayedNode && displayedNode.hasSequenceOutput && displayedAttr && (displayedAttr.desc.semantic === "imageList" || displayedAttr.desc.semantic === "sequence")) {
|
if (_reconstruction && displayedNode && displayedNode.hasSequenceOutput && displayedAttr &&
|
||||||
|
(displayedAttr.desc.semantic === "imageList" || displayedAttr.desc.semantic === "sequence")) {
|
||||||
// Entry point for getting the image file from a sequence defined by an output attribute
|
// Entry point for getting the image file from a sequence defined by an output attribute
|
||||||
var path = sequence[currentFrame-frameRange.min]
|
var path = sequence[currentFrame - frameRange.min]
|
||||||
|
_reconstruction.currentViewPath = path
|
||||||
return Filepath.stringToUrl(path)
|
return Filepath.stringToUrl(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,20 +241,22 @@ FocusScope {
|
||||||
let vp = getViewpoint(_reconstruction.pickedViewId)
|
let vp = getViewpoint(_reconstruction.pickedViewId)
|
||||||
let path = displayedAttr ? displayedAttr.value : ""
|
let path = displayedAttr ? displayedAttr.value : ""
|
||||||
let resolved = vp ? Filepath.resolve(path, vp) : path
|
let resolved = vp ? Filepath.resolve(path, vp) : path
|
||||||
|
_reconstruction.currentViewPath = resolved
|
||||||
return Filepath.stringToUrl(resolved)
|
return Filepath.stringToUrl(resolved)
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOrderedSequence(path_template) {
|
function buildOrderedSequence(pathTemplate) {
|
||||||
// Resolve the path template on the sequence of viewpoints
|
// Resolve the path template on the sequence of viewpoints
|
||||||
// ordered by path
|
// ordered by path
|
||||||
|
|
||||||
let objs = []
|
let objs = []
|
||||||
|
|
||||||
if (displayedNode && displayedNode.hasSequenceOutput && displayedAttr && (displayedAttr.desc.semantic === "imageList" || displayedAttr.desc.semantic === "sequence")) {
|
if (displayedNode && displayedNode.hasSequenceOutput && displayedAttr &&
|
||||||
let sequence = Filepath.resolveSequence(path_template)
|
(displayedAttr.desc.semantic === "imageList" || displayedAttr.desc.semantic === "sequence")) {
|
||||||
|
let sequence = Filepath.resolveSequence(pathTemplate)
|
||||||
let ids = sequence[0]
|
let ids = sequence[0]
|
||||||
let resolved = sequence[1]
|
let resolved = sequence[1]
|
||||||
|
|
||||||
|
@ -260,7 +265,7 @@ FocusScope {
|
||||||
// concat in one array all sequences in resolved
|
// concat in one array all sequences in resolved
|
||||||
resolved = [].concat.apply([], resolved)
|
resolved = [].concat.apply([], resolved)
|
||||||
frameRange.min = 0
|
frameRange.min = 0
|
||||||
frameRange.max = resolved.length-1
|
frameRange.max = resolved.length - 1
|
||||||
currentFrame = 0
|
currentFrame = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +275,7 @@ FocusScope {
|
||||||
resolved = resolved[0]
|
resolved = resolved[0]
|
||||||
ids = ids[0]
|
ids = ids[0]
|
||||||
frameRange.min = ids[0]
|
frameRange.min = ids[0]
|
||||||
frameRange.max = ids[ids.length-1]
|
frameRange.max = ids[ids.length - 1]
|
||||||
currentFrame = frameRange.min
|
currentFrame = frameRange.min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +287,11 @@ FocusScope {
|
||||||
objs.sort((a, b) => { return a.childAttribute("path").value < b.childAttribute("path").value ? -1 : 1; })
|
objs.sort((a, b) => { return a.childAttribute("path").value < b.childAttribute("path").value ? -1 : 1; })
|
||||||
let seq = [];
|
let seq = [];
|
||||||
for (let i = 0; i < objs.length; i++) {
|
for (let i = 0; i < objs.length; i++) {
|
||||||
seq.push(Filepath.resolve(path_template, objs[i]))
|
seq.push(Filepath.resolve(pathTemplate, objs[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
frameRange.min = 0
|
frameRange.min = 0
|
||||||
frameRange.max = seq.length-1
|
frameRange.max = seq.length - 1
|
||||||
currentFrame = 0
|
currentFrame = 0
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
@ -322,13 +327,15 @@ FocusScope {
|
||||||
// store attr name for output attributes that represent images
|
// store attr name for output attributes that represent images
|
||||||
for (var i = 0; i < displayedNode.attributes.count; i++) {
|
for (var i = 0; i < displayedNode.attributes.count; i++) {
|
||||||
var attr = displayedNode.attributes.at(i)
|
var attr = displayedNode.attributes.at(i)
|
||||||
if (attr.isOutput && (attr.desc.semantic === "image" || attr.desc.semantic === "sequence" || attr.desc.semantic === "imageList") && attr.enabled) {
|
if (attr.isOutput && (attr.desc.semantic === "image" || attr.desc.semantic === "sequence" ||
|
||||||
|
attr.desc.semantic === "imageList") && attr.enabled) {
|
||||||
names.push(attr.name)
|
names.push(attr.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!displayedNode || displayedNode.isComputable) names.push("gallery")
|
if (!displayedNode || displayedNode.isComputable)
|
||||||
|
names.push("gallery")
|
||||||
|
|
||||||
outputAttribute.names = names
|
outputAttribute.names = names
|
||||||
}
|
}
|
||||||
|
@ -399,7 +406,8 @@ FocusScope {
|
||||||
if (floatImageViewerLoader.item.containsMouse === false) {
|
if (floatImageViewerLoader.item.containsMouse === false) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
var pix = floatImageViewerLoader.item.pixelValueAt(Math.floor(floatImageViewerLoader.item.mouseX), Math.floor(floatImageViewerLoader.item.mouseY))
|
var pix = floatImageViewerLoader.item.pixelValueAt(Math.floor(floatImageViewerLoader.item.mouseX),
|
||||||
|
Math.floor(floatImageViewerLoader.item.mouseY))
|
||||||
return pix
|
return pix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,7 +452,8 @@ FocusScope {
|
||||||
// qtAliceVision Image Viewer
|
// qtAliceVision Image Viewer
|
||||||
ExifOrientedViewer {
|
ExifOrientedViewer {
|
||||||
id: floatImageViewerLoader
|
id: floatImageViewerLoader
|
||||||
active: root.aliceVisionPluginAvailable && (root.useFloatImageViewer || root.useLensDistortionViewer) && !panoramaViewerLoader.active
|
active: root.aliceVisionPluginAvailable &&
|
||||||
|
(root.useFloatImageViewer || root.useLensDistortionViewer) && !panoramaViewerLoader.active
|
||||||
visible: (floatImageViewerLoader.status === Loader.Ready) && active
|
visible: (floatImageViewerLoader.status === Loader.Ready) && active
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
orientationTag: imgContainer.orientationTag
|
orientationTag: imgContainer.orientationTag
|
||||||
|
@ -467,7 +476,8 @@ FocusScope {
|
||||||
* opened, for example, and the images have a different size), then another auto-fit needs to be
|
* opened, for example, and the images have a different size), then another auto-fit needs to be
|
||||||
* performed */
|
* performed */
|
||||||
if ((!fittedOnce && imgContainer.image && imgContainer.image.height > 0) ||
|
if ((!fittedOnce && imgContainer.image && imgContainer.image.height > 0) ||
|
||||||
(fittedOnce && ((width > 1 && previousWidth != width) || (height > 1 && previousHeight != height)))) {
|
(fittedOnce && ((width > 1 && previousWidth != width) ||
|
||||||
|
(height > 1 && previousHeight != height)))) {
|
||||||
fit()
|
fit()
|
||||||
fittedOnce = true
|
fittedOnce = true
|
||||||
previousWidth = width
|
previousWidth = width
|
||||||
|
@ -515,7 +525,8 @@ FocusScope {
|
||||||
// qtAliceVision Panorama Viewer
|
// qtAliceVision Panorama Viewer
|
||||||
Loader {
|
Loader {
|
||||||
id: panoramaViewerLoader
|
id: panoramaViewerLoader
|
||||||
active: root.aliceVisionPluginAvailable && root.usePanoramaViewer && _reconstruction.activeNodes.get('sfm').node
|
active: root.aliceVisionPluginAvailable && root.usePanoramaViewer &&
|
||||||
|
_reconstruction.activeNodes.get('sfm').node
|
||||||
visible: (panoramaViewerLoader.status === Loader.Ready) && active
|
visible: (panoramaViewerLoader.status === Loader.Ready) && active
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
@ -689,7 +700,7 @@ FocusScope {
|
||||||
|
|
||||||
onJsonFolderChanged: {
|
onJsonFolderChanged: {
|
||||||
json = null
|
json = null
|
||||||
if(activeNode.attribute("autoDetect").value) {
|
if (activeNode.attribute("autoDetect").value) {
|
||||||
// auto detection enabled
|
// auto detection enabled
|
||||||
var jsonPath = activeNode.attribute("output").value + "/detection.json"
|
var jsonPath = activeNode.attribute("output").value + "/detection.json"
|
||||||
Request.get(Filepath.stringToUrl(jsonPath), function(xhr) {
|
Request.get(Filepath.stringToUrl(jsonPath), function(xhr) {
|
||||||
|
@ -711,12 +722,12 @@ FocusScope {
|
||||||
onNodeCircleRadiusChanged : { updateGizmo() }
|
onNodeCircleRadiusChanged : { updateGizmo() }
|
||||||
|
|
||||||
function updateGizmo() {
|
function updateGizmo() {
|
||||||
if(activeNode.attribute("autoDetect").value) {
|
if (activeNode.attribute("autoDetect").value) {
|
||||||
// update gizmo from auto detection json file
|
// update gizmo from auto detection json file
|
||||||
if(json) {
|
if (json) {
|
||||||
// json file found
|
// json file found
|
||||||
var data = json[currentViewId]
|
var data = json[currentViewId]
|
||||||
if(data && data[0]) {
|
if (data && data[0]) {
|
||||||
// current view id found
|
// current view id found
|
||||||
circleX = data[0].x
|
circleX = data[0].x
|
||||||
circleY= data[0].y
|
circleY= data[0].y
|
||||||
|
@ -738,11 +749,13 @@ FocusScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoved: {
|
onMoved: {
|
||||||
_reconstruction.setAttribute(activeNode.attribute("sphereCenter"), JSON.stringify([xoffset, yoffset]))
|
_reconstruction.setAttribute(activeNode.attribute("sphereCenter"),
|
||||||
|
JSON.stringify([xoffset, yoffset]))
|
||||||
}
|
}
|
||||||
|
|
||||||
onIncrementRadius: {
|
onIncrementRadius: {
|
||||||
_reconstruction.setAttribute(activeNode.attribute("sphereRadius"), activeNode.attribute("sphereRadius").value + radiusOffset)
|
_reconstruction.setAttribute(activeNode.attribute("sphereRadius"),
|
||||||
|
activeNode.attribute("sphereRadius").value + radiusOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1087,7 +1100,8 @@ FocusScope {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
margins: 2
|
margins: 2
|
||||||
}
|
}
|
||||||
active: root.aliceVisionPluginAvailable && displayFeatures.checked && featuresViewerLoader.status === Loader.Ready
|
active: root.aliceVisionPluginAvailable && displayFeatures.checked &&
|
||||||
|
featuresViewerLoader.status === Loader.Ready
|
||||||
|
|
||||||
sourceComponent: FeaturesInfoOverlay {
|
sourceComponent: FeaturesInfoOverlay {
|
||||||
pluginStatus: featuresViewerLoader.status
|
pluginStatus: featuresViewerLoader.status
|
||||||
|
|
|
@ -464,6 +464,8 @@ class Reconstruction(UIGraph):
|
||||||
self._pickedViewId = None
|
self._pickedViewId = None
|
||||||
self._liveSfmManager = LiveSfmManager(self)
|
self._liveSfmManager = LiveSfmManager(self)
|
||||||
|
|
||||||
|
self._currentViewPath = ""
|
||||||
|
|
||||||
self._workerThreads = ThreadPool(processes=1)
|
self._workerThreads = ThreadPool(processes=1)
|
||||||
|
|
||||||
# react to internal graph changes to update those variables
|
# react to internal graph changes to update those variables
|
||||||
|
@ -1158,7 +1160,6 @@ class Reconstruction(UIGraph):
|
||||||
# Reconstruction has ownership of Viewpoint object - destroy it when not needed anymore
|
# Reconstruction has ownership of Viewpoint object - destroy it when not needed anymore
|
||||||
self._selectedViewpoint.deleteLater()
|
self._selectedViewpoint.deleteLater()
|
||||||
self._selectedViewpoint = ViewpointWrapper(viewpointAttribute, self) if viewpointAttribute else None
|
self._selectedViewpoint = ViewpointWrapper(viewpointAttribute, self) if viewpointAttribute else None
|
||||||
self._graph._selectedViewpoint = self._selectedViewpoint.attribute if viewpointAttribute else None
|
|
||||||
self.selectedViewpointChanged.emit()
|
self.selectedViewpointChanged.emit()
|
||||||
|
|
||||||
def setPickedViewId(self, viewId):
|
def setPickedViewId(self, viewId):
|
||||||
|
@ -1217,6 +1218,12 @@ class Reconstruction(UIGraph):
|
||||||
|
|
||||||
return R, T
|
return R, T
|
||||||
|
|
||||||
|
def setCurrentViewPath(self, path):
|
||||||
|
if self._currentViewPath == path:
|
||||||
|
return
|
||||||
|
self._currentViewPath = path
|
||||||
|
self.currentViewPathChanged.emit()
|
||||||
|
|
||||||
selectedViewIdChanged = Signal()
|
selectedViewIdChanged = Signal()
|
||||||
selectedViewId = Property(str, lambda self: self._selectedViewId, setSelectedViewId, notify=selectedViewIdChanged)
|
selectedViewId = Property(str, lambda self: self._selectedViewId, setSelectedViewId, notify=selectedViewIdChanged)
|
||||||
selectedViewpointChanged = Signal()
|
selectedViewpointChanged = Signal()
|
||||||
|
@ -1234,6 +1241,12 @@ class Reconstruction(UIGraph):
|
||||||
|
|
||||||
nbCameras = Property(int, reconstructedCamerasCount, notify=sfmReportChanged)
|
nbCameras = Property(int, reconstructedCamerasCount, notify=sfmReportChanged)
|
||||||
|
|
||||||
|
# Provides the path of the image that is currently displayed
|
||||||
|
# This is an alternative to "selectedViewpoint.attribute.path.value" for images that are displayed
|
||||||
|
# but not part of the list of viewpoints of a CameraInit node (i.e. "sequence" node outputs)
|
||||||
|
currentViewPathChanged = Signal()
|
||||||
|
currentViewPath = Property(str, lambda self: self._currentViewPath, setCurrentViewPath, notify=currentViewPathChanged)
|
||||||
|
|
||||||
# Signals to propagate high-level messages
|
# Signals to propagate high-level messages
|
||||||
error = Signal(Message)
|
error = Signal(Message)
|
||||||
warning = Signal(Message)
|
warning = Signal(Message)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue