diff --git a/mapclientplugins/scaffoldcreator/model/scaffoldcreatormodel.py b/mapclientplugins/scaffoldcreator/model/scaffoldcreatormodel.py index bf7ab46..fa742e5 100644 --- a/mapclientplugins/scaffoldcreator/model/scaffoldcreatormodel.py +++ b/mapclientplugins/scaffoldcreator/model/scaffoldcreatormodel.py @@ -8,7 +8,7 @@ from cmlibs.utils.zinc.general import ChangeManager, HierarchicalChangeManager from cmlibs.utils.zinc.group import group_add_group_elements, group_get_highest_dimension, \ identifier_ranges_fix, identifier_ranges_from_string, identifier_ranges_to_string, mesh_group_to_identifier_ranges -from cmlibs.utils.zinc.region import determine_appropriate_glyph_size +from cmlibs.utils.zinc.region import determine_appropriate_glyph_size, copy_fitting_data from cmlibs.utils.zinc.scene import ( scene_create_selection_group, scene_get_selection_group, scene_create_node_derivative_graphics) from cmlibs.zinc.field import Field, FieldGroup @@ -18,8 +18,11 @@ from scaffoldmaker.annotation.annotationgroup import findAnnotationGroupByName, getAnnotationMarkerGroup, \ getAnnotationMarkerLocationField, getAnnotationMarkerNameField from scaffoldmaker.scaffolds import Scaffolds +from scaffoldmaker.utils.zinc_utils import find_or_create_field_zero_fibres from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils.exportvtk import ExportVtk +from scaffoldfitter.fitter import Fitter as GeometryFitter +from scaffoldfitter.fitterstepalign import FitterStepAlign import copy import math @@ -734,6 +737,65 @@ def applyTransformation(self, editCoordinatesField): self._checkCustomParameterSet() self._setGraphicsTransformation() + def initializeAutoAlignTransformation(self): + """ + Initialize the fitter for the automatic align process + """ + scaffold_region = self._region + # Load data into the current region (copied from load_vagus_data in 3d_nerve1) + # This way of loading data is probably not completely right? Need to consult for a better way + data_region = self._parentRegion.findChildByName('data') + data_fieldmodule = data_region.getFieldmodule() + with ChangeManager(data_fieldmodule): + copy_fitting_data(scaffold_region, data_region) + del data_region, data_fieldmodule + # Setup fitting routine + fieldmodule = scaffold_region.getFieldmodule() + self.fitter = GeometryFitter(region=scaffold_region) + self.fitter.getInitialFitterStepConfig() + # Load the _loadModel routines + self.fitter._discoverModelCoordinatesField() + self.fitter._discoverModelFitGroup() + zero_fibres = find_or_create_field_zero_fibres(fieldmodule) + self.fitter.setFibreField(zero_fibres) + del zero_fibres + self.fitter._discoverFlattenGroup() + self.fitter.defineCommonMeshFields() + # Load the _loadData routines + self.fitter._discoverDataCoordinatesField() + self.fitter._discoverMarkerGroup() + self.fitter.defineDataProjectionFields() + # Start fit + self.fitter.initializeFit() + fit1 = FitterStepAlign() + self.fitter.addFitterStep(fit1) + return fit1.canAutoAlign() + + def runAutoAlignTransformation(self): + """ + Run the align step and update visual settings + """ + scaffoldPackage = self._scaffoldPackages[-1] + fit1 = self.fitter.getFitterSteps()[-1] + # Add markers/groups to align step if possible + if fit1.canAlignMarkers(): + fit1.setAlignMarkers(True) + if fit1.canAlignGroups(): + fit1.setAlignGroups(True) + # Run align step + fit1._doAutoAlign() + # Store align rotation settings + rotation = [rad * 180.0 / math.pi for rad in fit1._rotation] + scale = [fit1._scale for i in range(3)] + translation = fit1._translation + del fit1 + # If any visual settings changes, update graphics settings + update_rotation = scaffoldPackage.setRotation(rotation) + update_scale = scaffoldPackage.setScale(scale) + update_translation = scaffoldPackage.setTranslation(translation) + if update_rotation or update_scale or update_translation: + self._setGraphicsTransformation() + def getRotationText(self): return ', '.join(STRING_FLOAT_FORMAT.format(value) for value in self._scaffoldPackages[-1].getRotation()) diff --git a/mapclientplugins/scaffoldcreator/qt/scaffoldsettingswidget.ui b/mapclientplugins/scaffoldcreator/qt/scaffoldsettingswidget.ui index e1f1dae..50657af 100644 --- a/mapclientplugins/scaffoldcreator/qt/scaffoldsettingswidget.ui +++ b/mapclientplugins/scaffoldcreator/qt/scaffoldsettingswidget.ui @@ -6,7 +6,7 @@ 0 0 - 556 + 554 773 @@ -41,7 +41,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame @@ -56,7 +56,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -82,7 +82,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -100,7 +100,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame @@ -135,7 +135,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame @@ -150,13 +150,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::NoFrame + QFrame::Shape::NoFrame @@ -189,7 +189,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -209,7 +209,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -256,7 +256,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -276,7 +276,44 @@ - Qt::Horizontal + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Auto align + + + + + + + Qt::Orientation::Horizontal @@ -294,7 +331,7 @@ - Qt::Vertical + Qt::Orientation::Vertical diff --git a/mapclientplugins/scaffoldcreator/view/scaffoldcreatorwidget.py b/mapclientplugins/scaffoldcreator/view/scaffoldcreatorwidget.py index 5d52ab8..cf640c9 100644 --- a/mapclientplugins/scaffoldcreator/view/scaffoldcreatorwidget.py +++ b/mapclientplugins/scaffoldcreator/view/scaffoldcreatorwidget.py @@ -166,6 +166,7 @@ def _makeConnections(self): self._scaffold_settings_ui.scale_lineEdit.editingFinished.connect(self._scaleLineEditChanged) self._scaffold_settings_ui.translation_lineEdit.editingFinished.connect(self._translationLineEditChanged) self._scaffold_settings_ui.applyTransformation_pushButton.clicked.connect(self._applyTransformationButtonPressed) + self._scaffold_settings_ui.autoAlignTransformation_pushButton.clicked.connect(self._autoAlignTransformationButtonPressed) self._display_settings_ui.displayDataGroup_fieldChooser.setNullObjectName('-') self._display_settings_ui.displayDataGroup_fieldChooser.setRegion(self._segmentation_data_model.getRegion()) self._display_settings_ui.displayDataGroup_fieldChooser.setConditional(field_is_managed_group) @@ -700,6 +701,55 @@ def _applyTransformationButtonPressed(self): self._scaffold_model.applyTransformation(self._display_settings_ui.displayModelCoordinates_fieldChooser.getField()) self._transformationChanged() + def _autoAlignTransformationButtonPressed(self): + # Create dialog + reply = QtWidgets.QDialog(self) + reply.setWindowTitle('Confirm action') + layout = QtWidgets.QVBoxLayout(reply) + hasData = self._segmentation_data_model.hasData() + if not hasData: + # Add text + textLabel = QtWidgets.QLabel('No data file supplied') + textLabel.setWordWrap(True) + layout.addWidget(textLabel) + layout.addSpacing(10) + # add Ok Button + buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok) + buttons.accepted.connect(reply.reject) + layout.addWidget(buttons) + else: + # Initilize fitter + canAutoAlign = self._scaffold_model.initializeAutoAlignTransformation() + if canAutoAlign: + # Add text + textLabel = QtWidgets.QLabel('Automatically align scaffold to data?') + textLabel.setWordWrap(True) + layout.addWidget(textLabel) + layout.addSpacing(10) + # Add buttons + buttons = QtWidgets.QDialogButtonBox( + QtWidgets.QDialogButtonBox.StandardButton.Yes | + QtWidgets.QDialogButtonBox.StandardButton.No + ) + layout.addWidget(buttons) + buttons.accepted.connect(reply.accept) + buttons.rejected.connect(reply.reject) + else: + # Add text + textLabel = QtWidgets.QLabel('Not enough markers and/or groups' \ + ' to perform automatic alignment to data') + textLabel.setWordWrap(True) + layout.addWidget(textLabel) + layout.addSpacing(10) + # add Ok Button + buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok) + layout.addWidget(buttons) + buttons.accepted.connect(reply.reject) + # Execute dialog + if reply.exec() == QtWidgets.QDialog.Accepted: + self._scaffold_model.runAutoAlignTransformation() + self._transformationChanged() + def _displayDataGroupChanged(self, index): """ Callback for change in model coordinates field chooser widget. diff --git a/mapclientplugins/scaffoldcreator/view/ui_scaffoldsettingswidget.py b/mapclientplugins/scaffoldcreator/view/ui_scaffoldsettingswidget.py index eb762f0..f1b66e3 100644 --- a/mapclientplugins/scaffoldcreator/view/ui_scaffoldsettingswidget.py +++ b/mapclientplugins/scaffoldcreator/view/ui_scaffoldsettingswidget.py @@ -3,7 +3,7 @@ ################################################################################ ## Form generated from reading UI file 'scaffoldsettingswidget.ui' ## -## Created by: Qt User Interface Compiler version 6.8.1 +## Created by: Qt User Interface Compiler version 6.9.1 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ @@ -23,7 +23,7 @@ class Ui_ScaffoldSettings(object): def setupUi(self, ScaffoldSettings): if not ScaffoldSettings.objectName(): ScaffoldSettings.setObjectName(u"ScaffoldSettings") - ScaffoldSettings.resize(556, 773) + ScaffoldSettings.resize(554, 773) self.verticalLayout_2 = QVBoxLayout(ScaffoldSettings) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) @@ -35,7 +35,7 @@ def setupUi(self, ScaffoldSettings): sizePolicy.setHeightForWidth(self.subscaffold_frame.sizePolicy().hasHeightForWidth()) self.subscaffold_frame.setSizePolicy(sizePolicy) self.subscaffold_frame.setMinimumSize(QSize(0, 0)) - self.subscaffold_frame.setFrameShape(QFrame.NoFrame) + self.subscaffold_frame.setFrameShape(QFrame.Shape.NoFrame) self.verticalLayout_5 = QVBoxLayout(self.subscaffold_frame) self.verticalLayout_5.setObjectName(u"verticalLayout_5") self.subscaffold_label = QLabel(self.subscaffold_frame) @@ -71,36 +71,36 @@ def setupUi(self, ScaffoldSettings): self.meshType_frame = QFrame(ScaffoldSettings) self.meshType_frame.setObjectName(u"meshType_frame") - self.meshType_frame.setFrameShape(QFrame.NoFrame) + self.meshType_frame.setFrameShape(QFrame.Shape.NoFrame) self.formLayout = QFormLayout(self.meshType_frame) self.formLayout.setObjectName(u"formLayout") self.formLayout.setContentsMargins(0, -1, 0, -1) self.meshType_label = QLabel(self.meshType_frame) self.meshType_label.setObjectName(u"meshType_label") - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.meshType_label) + self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.meshType_label) self.meshType_comboBox = QComboBox(self.meshType_frame) self.meshType_comboBox.setObjectName(u"meshType_comboBox") - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.meshType_comboBox) + self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.meshType_comboBox) self.parameterSet_label = QLabel(self.meshType_frame) self.parameterSet_label.setObjectName(u"parameterSet_label") - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.parameterSet_label) + self.formLayout.setWidget(1, QFormLayout.ItemRole.LabelRole, self.parameterSet_label) self.parameterSet_comboBox = QComboBox(self.meshType_frame) self.parameterSet_comboBox.setObjectName(u"parameterSet_comboBox") - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.parameterSet_comboBox) + self.formLayout.setWidget(1, QFormLayout.ItemRole.FieldRole, self.parameterSet_comboBox) self.verticalLayout_2.addWidget(self.meshType_frame) self.meshTypeOptions_frame = QFrame(ScaffoldSettings) self.meshTypeOptions_frame.setObjectName(u"meshTypeOptions_frame") - self.meshTypeOptions_frame.setFrameShape(QFrame.NoFrame) + self.meshTypeOptions_frame.setFrameShape(QFrame.Shape.NoFrame) self.verticalLayout_9 = QVBoxLayout(self.meshTypeOptions_frame) self.verticalLayout_9.setObjectName(u"verticalLayout_9") self.verticalLayout_9.setContentsMargins(0, -1, 0, -1) @@ -109,12 +109,12 @@ def setupUi(self, ScaffoldSettings): self.modifyOptions_frame = QFrame(ScaffoldSettings) self.modifyOptions_frame.setObjectName(u"modifyOptions_frame") - self.modifyOptions_frame.setFrameShape(QFrame.NoFrame) + self.modifyOptions_frame.setFrameShape(QFrame.Shape.NoFrame) self.verticalLayout = QVBoxLayout(self.modifyOptions_frame) self.verticalLayout.setObjectName(u"verticalLayout") self.deleteElementsRanges_frame = QFrame(self.modifyOptions_frame) self.deleteElementsRanges_frame.setObjectName(u"deleteElementsRanges_frame") - self.deleteElementsRanges_frame.setFrameShape(QFrame.NoFrame) + self.deleteElementsRanges_frame.setFrameShape(QFrame.Shape.NoFrame) self.verticalLayout_10 = QVBoxLayout(self.deleteElementsRanges_frame) self.verticalLayout_10.setObjectName(u"verticalLayout_10") self.verticalLayout_10.setContentsMargins(0, 0, 0, 0) @@ -197,6 +197,24 @@ def setupUi(self, ScaffoldSettings): self.verticalLayout.addLayout(self.horizontalLayout_12) + self.horizontalLayout_5 = QHBoxLayout() + self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_5.addItem(self.horizontalSpacer_2) + + self.autoAlignTransformation_pushButton = QPushButton(self.modifyOptions_frame) + self.autoAlignTransformation_pushButton.setObjectName(u"autoAlignTransformation_pushButton") + + self.horizontalLayout_5.addWidget(self.autoAlignTransformation_pushButton) + + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.horizontalLayout_5.addItem(self.horizontalSpacer) + + + self.verticalLayout.addLayout(self.horizontalLayout_5) + self.verticalLayout_2.addWidget(self.modifyOptions_frame) @@ -222,5 +240,6 @@ def retranslateUi(self, ScaffoldSettings): self.scale_label.setText(QCoreApplication.translate("ScaffoldSettings", u"Scale x, y, z:", None)) self.translation_label.setText(QCoreApplication.translate("ScaffoldSettings", u"Translation x, y, z", None)) self.applyTransformation_pushButton.setText(QCoreApplication.translate("ScaffoldSettings", u"Apply transformation", None)) + self.autoAlignTransformation_pushButton.setText(QCoreApplication.translate("ScaffoldSettings", u"Auto align", None)) # retranslateUi