[ui] Add a "Clear All Images" action and update "Clear Images"'s behaviour

"Clear Images" used to clear the intrinsics and viewpoints for all the
existing CameraInit nodes in the graph. There was no-user friendly way
to clear the images of a specific CameraInit node.

This commit modifies the behaviour of "Clear Images" so that it only
deletes the intrinsics and viewpoints of the current CameraInit. A new menu
action, "Clear All Images", is added in the "Advanced" sub-menu, and
deletes all the intrinsics and viewpoints for all the CameraInit nodes.

The way images are cleared is also modified: instead of removing the
intrinsics and viewpoints attributes, they are reset. To be undone
properly, a corresponding "ClearImagesCommand" has been added. This offers
a great performance increase (clearing 1000 images now takes 1s).

Tooltips have been added to make the distinction clearer for users.
This commit is contained in:
Candice Bentéjac 2023-02-22 13:24:32 +01:00
parent 2987bf0617
commit 43f439be88
4 changed files with 66 additions and 26 deletions

View file

@ -350,6 +350,31 @@ class ListAttributeRemoveCommand(GraphCommand):
listAttribute.insert(self.index, self.value) listAttribute.insert(self.index, self.value)
class ClearImagesCommand(GraphCommand):
def __init__(self, graph, cameraInitNodes, parent=None):
super(ClearImagesCommand, self).__init__(graph, parent)
self.cameraInits = cameraInitNodes
self.viewpoints = { cameraInit.name: cameraInit.attribute("viewpoints").getExportValue() for cameraInit in self.cameraInits }
self.intrinsics = { cameraInit.name: cameraInit.attribute("intrinsics").getExportValue() for cameraInit in self.cameraInits }
self.title = "Clear{}Images".format(" " if len(self.cameraInits) == 1 else " All ")
self.setText(self.title)
def redoImpl(self):
for i in range(len(self.cameraInits)):
# Reset viewpoints
self.cameraInits[i].viewpoints.resetValue()
self.cameraInits[i].viewpoints.valueChanged.emit()
# Reset intrinsics
self.cameraInits[i].intrinsics.resetValue()
self.cameraInits[i].intrinsics.valueChanged.emit()
def undoImpl(self):
for cameraInit in self.viewpoints:
with GraphModification(self.graph):
self.graph.node(cameraInit).viewpoints.value = self.viewpoints[cameraInit]
self.graph.node(cameraInit).intrinsics.value = self.intrinsics[cameraInit]
class MoveNodeCommand(GraphCommand): class MoveNodeCommand(GraphCommand):
""" Move a node to a given position. """ """ Move a node to a given position. """
def __init__(self, graph, node, position, parent=None): def __init__(self, graph, node, position, parent=None):

View file

@ -733,6 +733,16 @@ class UIGraph(QObject):
def removeAttribute(self, attribute): def removeAttribute(self, attribute):
self.push(commands.ListAttributeRemoveCommand(self._graph, attribute)) self.push(commands.ListAttributeRemoveCommand(self._graph, attribute))
@Slot()
def clearImages(self):
with self.groupedGraphModification("Clear Images"):
self.push(commands.ClearImagesCommand(self._graph, [self.cameraInit]))
@Slot()
def clearAllImages(self):
with self.groupedGraphModification("Clear All Images"):
self.push(commands.ClearImagesCommand(self._graph, list(self.cameraInits)))
@Slot(Node) @Slot(Node)
def appendSelection(self, node): def appendSelection(self, node):
""" Append 'node' to the selection if it is not already part of the selection. """ """ Append 'node' to the selection if it is not already part of the selection. """

View file

@ -427,6 +427,26 @@ ApplicationWindow {
uigraph: _reconstruction uigraph: _reconstruction
} }
Action {
id: clearImagesAction
property string tooltip: "Clear images for the current CameraInit group"
text: "Clear Images"
onTriggered: {
_reconstruction.clearImages()
_reconstruction.selectedViewId = "-1"
}
}
Action {
id: clearAllImagesAction
property string tooltip: "Clear all the images for all the CameraInit groups"
text: "Clear All Images"
onTriggered: {
_reconstruction.clearAllImages()
_reconstruction.selectedViewId = "-1"
}
}
Action { Action {
id: undoAction id: undoAction
@ -638,13 +658,12 @@ ApplicationWindow {
} }
} }
Action { MenuItem {
id: clearImagesAction action: clearImagesAction
text: "Clear Images" ToolTip.visible: hovered
onTriggered: { ToolTip.text: clearImagesAction.tooltip
_reconstruction.clearImages()
}
} }
MenuSeparator { } MenuSeparator { }
Menu { Menu {
id: advancedMenu id: advancedMenu
@ -677,6 +696,12 @@ ApplicationWindow {
importProjectDialog.open(); importProjectDialog.open();
} }
} }
MenuItem {
action: clearAllImagesAction
ToolTip.visible: hovered
ToolTip.text: clearAllImagesAction.tooltip
}
} }
MenuSeparator { } MenuSeparator { }
Action { Action {

View file

@ -694,26 +694,6 @@ class Reconstruction(UIGraph):
""" Get all view Ids involved in the reconstruction. """ """ Get all view Ids involved in the reconstruction. """
return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value] return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value]
@Slot()
def clearImages(self):
""" Clear the list of viewpoints and intrinsics for all the CameraInit nodes. """
with self.groupedGraphModification("Clear Images"):
for cameraInit in self._cameraInits:
# Delete all viewpoints
viewpoints = cameraInit.attribute("viewpoints")
y = len(viewpoints.value) - 1
while y >= 0:
self.removeAttribute(viewpoints.value[y])
y = y - 1
# Delete all intrinsics
intrinsics = cameraInit.attribute("intrinsics")
z = len(intrinsics.value) - 1
while z >= 0:
self.removeAttribute(intrinsics.value[z])
z = z - 1
@Slot(QObject, Node) @Slot(QObject, Node)
def handleFilesDrop(self, drop, cameraInit): def handleFilesDrop(self, drop, cameraInit):
""" Handle drop events aiming to add images to the Reconstruction. """ Handle drop events aiming to add images to the Reconstruction.