Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 8c0413db authored by Emmanuel Promayon's avatar Emmanuel Promayon
Browse files

Merge branch 'fix/various-small-bugs' into 'develop'

Fix/various small bugs + Slice simplification

See merge request !137
parents b5f9f671 42343ce0
......@@ -57,7 +57,16 @@ QWidget* QuitAction::getWidget() {
// --------------- apply -------------------
Action::ApplyStatus QuitAction::apply() {
Application::getMainWindow()->close();
// close all components (and therefore ask the user to savet the modified ones)
ApplyStatus closeAllStatus = Application::getAction("Close All")->apply();
if (closeAllStatus == SUCCESS) {
// Quit the app (will call Application::quitting() and therefore unload all action extensions and delete all actions)
Application::quit();
return SUCCESS;
}
else {
// or abort the operation
return ABORTED;
}
}
......@@ -25,14 +25,8 @@
#include "SaveAllAction.h"
#include <Application.h>
#include <ImageComponent.h>
#include <ImageComponentExtension.h>
#include <MeshComponent.h>
#include <MeshComponentExtension.h>
#include <Log.h>
#include <QFileDialog>
using namespace camitk;
......
......@@ -36,11 +36,11 @@ using namespace camitk;
// --------------- constructor -------------------
ImageLutAction::ImageLutAction(ActionExtension* extension) : Action(extension) {
setName("Lut");
setName("Image Look Up Table");
setDescription("Modify the LUT of an image components");
setComponent("ImageComponent");
setFamily("ImageLut");
addTag("Lut");
setFamily("Image LUT");
addTag("LUT");
}
// --------------- getWidget -------------------
......
......@@ -47,7 +47,7 @@ using namespace camitk;
// ---------------------- Constructor ----------------------------
ImageLutWidget::ImageLutWidget(QWidget* parent) : QWidget(parent) {
myComponent = NULL;
myComponent = nullptr;
lutMin = 0;
lutMax = 255;
......@@ -92,7 +92,7 @@ void ImageLutWidget::updateComponent(ImageComponent* comp) {
myComponent = comp;
// if there is no lookup table, just don't display this widget!
if (myComponent->getLut() == NULL) {
if (myComponent->getLut() == nullptr) {
setEnabled(false);
return;
}
......
......@@ -51,10 +51,8 @@ public:
/// Default Destructor
virtual ~VolumeRenderingAction() = default;
void createVolumeRendering(camitk::ImageComponent* comp);
public slots:
/** this method is automatically called when the action is triggered.
* Call getTargets() method to get the list of components to use.
......
......@@ -189,7 +189,7 @@ Action::ApplyStatus WarpOut::apply() {
for (vtkIdType i = 0; i < connectivityFilter->GetOutput()->GetNumberOfPoints(); i++) {
// get the id of the point in the original point set
#if VTK_MAJOR_VERSION == 8
#if VTK_MAJOR_VERSION >= 7
pointId->GetTypedTuple(i, &id);
#else
pointId->GetTupleValue(i, &id);
......
......@@ -488,14 +488,14 @@ void ImpMainWindow::updateViewMenu() {
});
Viewer* cViewer = (*it);
// viewerAction is own by viewMenu, viewMenu->clear() will delete it
QAction *viewerAction = viewMenu->addAction(cViewer->objectName());
QAction* viewerAction = viewMenu->addAction(cViewer->objectName());
viewerAction->setCheckable(true);
viewerAction->setChecked(cViewer == centralViewer);
QString tipString = "Hide/show the " + cViewer->objectName() + " central viewer";
viewerAction->setStatusTip(tr(tipString.toStdString().c_str()));
viewerAction->setWhatsThis(tr(tipString.toStdString().c_str()));
// add the toggle action slot using C++11 lambda so that everything is contained inside viewMenu
connect(viewerAction, &QAction::toggled, [=](bool) {
connect(viewerAction, &QAction::toggled, [ = ](bool) {
setCentralViewer(cViewer);
});
}
......@@ -600,60 +600,62 @@ void ImpMainWindow::saveHistoryAsSCXML() {
// ------------------------- openDataDirectoryMenuBuilder ---------------------------
void ImpMainWindow::openDataDirectoryMenuBuilder() {
QStringList dirExt = ExtensionManager::getDataDirectoryExtNames();
QString dirExtName;
if (dirExt.size() > 1) {
if (fileOpenDataDirectoryMenu == nullptr){
if (fileOpenDataDirectoryMenu == nullptr) {
fileOpenDataDirectoryMenu = new QMenu("Open Data Directory");
fileMenu->addMenu(fileOpenDataDirectoryMenu);
} else {
disconnect(fileOpenDataDirectoryMenu,0,0,0);
}
else {
disconnect(fileOpenDataDirectoryMenu, 0, 0, 0);
fileOpenDataDirectoryMenu->clear();
}
fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));
foreach (dirExtName, dirExt) {
for (QString dirExtName : dirExt) {
QAction* openDirectory = new QAction(dirExtName, this);
openDirectory->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
openDirectory->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
connect(openDirectory, &QAction::triggered, this, [=]() {this->openDataDirectory(dirExtName);});
connect(openDirectory, &QAction::triggered, this, [ = ]() {
this->openDataDirectory(dirExtName);
});
fileOpenDataDirectoryMenu->addAction(openDirectory);
}
} else if (dirExt.size() == 1) {
QAction* openDirectoryAct;
dirExtName = dirExt.at(0);
int indexAction = 0;
}
else
if (dirExt.size() == 1) {
// if it exists, remove the default directory extension menu (that has only one submenu)
// from the file "open" action list
bool updateAction = false;
bool IDidntFindWhatImLookingFor = true;
QList<QAction *> actions = fileMenu->actions();
int size = actions.size();
while (IDidntFindWhatImLookingFor && indexAction < actions.size() ) {
if (actions.at(indexAction)->text().contains(" Directory")) {
actions.at(indexAction)->destroyed();
QList<QAction*> menuActions = fileMenu->actions();
int indexAction = 0;
while (indexAction < menuActions.size() && !updateAction) {
if (menuActions.at(indexAction)->text().contains(" Directory")) {
menuActions.at(indexAction)->destroyed();
updateAction = true;
IDidntFindWhatImLookingFor = false;
}
indexAction++;
};
}
// create the single open directory action
QString dirExtName = dirExt.at(0);
QAction* openDirectoryAction = new QAction("Open " + dirExtName + " Directory", this);
if (!updateAction) {
openDirectoryAct = new QAction("Open " + dirExtName + " Directory", this);
fileMenu->addAction(openDirectoryAct);
} else {
openDirectoryAct = new QAction("Open " + dirExtName + " Directory", this);
// there was no specific menu, just add the single "open directory" action in the file menu
fileMenu->addAction(openDirectoryAction);
}
openDirectoryAct->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
openDirectoryAct->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
openDirectoryAction->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
openDirectoryAction->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
connect(openDirectoryAct, &QAction::triggered, this, [=]() {this->openDataDirectory(dirExtName);});
connect(openDirectoryAction, &QAction::triggered, this, [ = ]() {
this->openDataDirectory(dirExtName);
});
openDirectoryAct->setIcon(QPixmap(":/fileOpen"));
} else {
openDirectoryAction->setIcon(QPixmap(":/fileOpen"));
}
else {
fileOpenDataDirectoryMenu = new QMenu("No plugins loaded to Open Data Directory");
fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));
fileOpenDataDirectoryMenu->setEnabled(false);
......
......@@ -572,7 +572,7 @@ private:
}
// -------------------- declare the interface for QPluginLoader --------------------
Q_DECLARE_INTERFACE(camitk::Action, "TIMC-IMAG.Action/2.1") //TODO use svn version?
Q_DECLARE_INTERFACE(camitk::Action, "TIMC-IMAG.Action/2.1")
#endif // ACTION_H
......
......@@ -58,6 +58,7 @@ void ActionExtension::initResources() {
// -------------------- destructor --------------------
ActionExtension::~ActionExtension() {
// delete all actions one by one
while (!actions.empty()) {
Action* toDelete = actions.takeFirst();
// do not delete the "Quit" action: it is the action that triggers this delete!
......@@ -66,7 +67,7 @@ ActionExtension::~ActionExtension() {
}
}
//delete internationalization instance
// delete internationalization instance
if (translator) {
delete translator;
}
......
......@@ -108,7 +108,7 @@ private:
}
// -------------------- declare the interface for QPluginLoader --------------------
Q_DECLARE_INTERFACE(camitk::ActionExtension, "TIMC-IMAG. Action Extension/2.1") //TODO use variable from CMake?
Q_DECLARE_INTERFACE(camitk::ActionExtension, "TIMC-IMAG. Action Extension/2.1")
#endif //ACTION_EXTENSION_H
......@@ -204,7 +204,7 @@ QString Application::getName() {
// ----------------- quitting --------------------
void Application::quitting() {
// this is connect to the aboutToQuit signal from QApplication
// this is connected to the aboutToQuit signal from QApplication
// it should contain all the code that frees the resources
// delete all actions (they are instantiated when the extension is loaded)
......
......@@ -186,6 +186,27 @@ public:
*/
vtkSmartPointer<vtkActor> getActor(const RenderingModes) override;
/** Set a texture to this object. */
void setTexture(vtkSmartPointer<vtkTexture> texture) override;
/// a vtkPoint of the structured was picked (to be reimplemented in a Component inherited class if needed)
void pointPicked(vtkIdType, bool) {};
/// a vtkCell of the structured was picked (to be reimplemented in a Component inherited class if needed)
void cellPicked(vtkIdType, bool) {};
///@}
/// @name manage extra prop associated with a Geometry
/// @{
/// TODO
/// - put all this management into a dedicated interface
/// - remove it from InterfaceBitMap and InterfaceGeometry
/// - remove it from Slice and Geometry helper classes
/// - create a new associated helper class
/// - update Component class and all other code using it (if needed)
/// Note : beware that Geometry requires this to manage to at least "label" and "glyph" extra actors
/// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
vtkSmartPointer<vtkProp> getProp(const QString&) override;
......@@ -204,17 +225,7 @@ public:
* @return true if effictively done
*/
bool removeProp(const QString&) override;
/** Set a texture to this object. */
void setTexture(vtkSmartPointer<vtkTexture> texture) override;
/// a vtkPoint of the structured was picked (to be reimplemented in a Component inherited class if needed)
void pointPicked(vtkIdType, bool) {};
/// a vtkCell of the structured was picked (to be reimplemented in a Component inherited class if needed)
void cellPicked(vtkIdType, bool) {};
///@}
/// @}
/// @name InterfaceGeometry Helpers inherited methods
/// @{
......@@ -308,9 +319,6 @@ private:
/// the VTK mapper
vtkSmartPointer<vtkDataSetMapper> mapper;
/// The additional map for prop (include at least "label" and "glyph"
QMap<QString, vtkSmartPointer<vtkProp> > extraProp;
/// the mapper to create the text
vtkSmartPointer<vtkTextMapper> labelActorMapper;
......@@ -386,8 +394,15 @@ private:
double oldAlphaPoints;
double oldPointsColor[4];
///@}
protected:
vtkSmartPointer< vtkPointSet > New();
/// @name manage extra prop associated with a Geometry
/// @{
/// TODO see extra prop management method section
/// The additional map for prop (include at least "label" and "glyph")
QMap<QString, vtkSmartPointer<vtkProp> > extraProp;
///@}
};
......
......@@ -85,15 +85,12 @@ public:
/** Return the vtkActor used to pick pixels in the slices. */
virtual vtkSmartPointer<vtkActor> getPixelActor() = 0;
/** Return 2D Axes at the proper slice origin */
// virtual vtkSmartPointer<vtkAxesActor> get2DAxesActor() = 0;
/** This method is called when the associated plane has been picked in the InteractiveViewer,
* the given coordinates is position where the plane was picked.
*/
virtual void pixelPicked(double, double, double) = 0;
/// update the position of the plane surrounding the currently selected slice
virtual void updatePickPlane() = 0;
/** Return the number of slices in the image data set. */
......@@ -122,9 +119,17 @@ public:
/** Returns the encapsultaed data structure: the image as a vtkImageData. */
virtual vtkSmartPointer<vtkImageData> getImageData() const = 0;
// TODO : put all of this into a dedicated interface
/// The additional map for prop (include at least "label" and "glyph"
QMap<QString, vtkSmartPointer<vtkProp> > extraProp;
/// @name manage extra prop associated with an InterfaceBitMap
/// @{
/// TODO
/// - put all this management into a dedicated interface
/// - remove it from InterfaceBitMap and InterfaceGeometry
/// - remove it from Slice and Geometry helper classes
/// - create a new associated helper class
/// - update Component class and all other code using it (if needed)
/// Note : beware that Geometry requires this to manage to at least "label" and "glyph" extra actors
/// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
virtual vtkSmartPointer<vtkProp> getProp(const QString&) = 0;
......@@ -144,7 +149,7 @@ public:
* @return true if effictively done
*/
virtual bool removeProp(const QString&) = 0;
// END TODO
/// @}
};
......
......@@ -153,28 +153,6 @@ public:
*/
virtual void setDataConnection(vtkSmartPointer<vtkAlgorithmOutput>) = 0;
/// Return the actor for the representation mode, NULL if the actor doesn't exist.
virtual vtkSmartPointer<vtkActor> getActor(const RenderingModes) = 0;
/// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
virtual vtkSmartPointer<vtkProp> getProp(const QString&) = 0;
/// return the number of additional prop
virtual unsigned int getNumberOfProp() const = 0;
/// return an additional prop by its index
virtual vtkSmartPointer<vtkProp> getProp(unsigned int) = 0;
/** remove a given additional prop.
* @return true if effictively done
*/
virtual bool removeProp(const QString&) = 0;
/** insert an additional prop, defining it by its name (default visibility = false).
* @return true if the additional prop was added (i.e. another additional prop of the same name does not exist)
*/
virtual bool addProp(const QString&, vtkSmartPointer<vtkProp>) = 0;
/// Set a texture to this object.
virtual void setTexture(vtkSmartPointer<vtkTexture>) = 0;
......@@ -204,6 +182,40 @@ public:
* @see InteractiveViewer
*/
virtual void cellPicked(vtkIdType cellId, bool pickingIsSelecting) = 0;
/// Return the actor for the representation mode, NULL if the actor doesn't exist.
virtual vtkSmartPointer<vtkActor> getActor(const RenderingModes) = 0;
///@}
/// @name manage extra prop associated with an InterfaceGeometry
/// @{
/// TODO
/// - put all this management into a dedicated interface
/// - remove it from InterfaceBitMap and InterfaceGeometry
/// - remove it from Slice and Geometry helper classes
/// - create a new associated helper class
/// - update Component class and all other code using it (if needed)
/// Note : beware that Geometry requires this to manage to at least "label" and "glyph" extra actors
/// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
virtual vtkSmartPointer<vtkProp> getProp(const QString&) = 0;
/// return the number of additional prop
virtual unsigned int getNumberOfProp() const = 0;
/// return an additional prop by its index
virtual vtkSmartPointer<vtkProp> getProp(unsigned int) = 0;
/** remove a given additional prop.
* @return true if effictively done
*/
virtual bool removeProp(const QString&) = 0;
/** insert an additional prop, defining it by its name (default visibility = false).
* @return true if the additional prop was added (i.e. another additional prop of the same name does not exist)
*/
virtual bool addProp(const QString&, vtkSmartPointer<vtkProp>) = 0;
///@}
/// @name Helpers methods
......
This diff is collapsed.
......@@ -31,36 +31,48 @@
#include "InterfaceBitMap.h"
// -- vtk stuff
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkWindowLevelLookupTable.h>
#include <vtkImageMapToColors.h>
#include <vtkTransform.h>
#include <vtkActor.h>
#include <vtkImageActor.h>
#include <vtkImageChangeInformation.h>
#include <vtkImageReslice.h>
#include <vtkMatrix4x4.h>
#include <vtkPolyDataMapper.h>
#include <vtkPlaneSource.h>
#include <vtkTransform.h>
#include <vtkPixel.h>
#include <vtkUnstructuredGrid.h>
#include <vtkDataSetMapper.h>
#include <vtkLine.h>
#include <vtkPolygon.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
#include <vtkAxesActor.h>
#include <vtkTransformPolyDataFilter.h>
namespace camitk {
/**
* @ingroup group_sdk_libraries_core_component
*
* @brief
* Display a slice (i.e. an image or BitMap) of an @ref camitk::ImageComponent "ImageComponent"
* Display a slice (i.e. an image or BitMap) of an @ref camitk::ImageComponent "ImageComponent". Helper class.
*
* This class manages the visual representation of one slice of a volume image.
* The slice depends on the orientation and the currently selected slice index.
*
* A slice is represented in 2D and 3D thanks to:
* - image2DActor that provides a 2D representation (the slice in the world reference frame)
* - image3DActor that provides a 3D representation (the slice at this actual 3D position)
* Both are updated thanks to vtkImageActor::SetDisplayExtent.
*
* \note the setImageWorldTransform(...) methods is used to set the user transform of the image 3D actor.
*
* Uses vtkImageActor::SetDisplayExtent for 3D and 2D Axial, Coronal and Sagittal representaiton.
* Re-position the camera for the 2D views.
* Slice also manages two other actors to visualize user picking inside the image:
* - the picked plane actor (a wireframe box made of 4 quads around the picked plane) that shows the image border
* - the picked pixel actor (two wireframe quads centered on the currently picked pixel) that shows the position
* of the currently picked pixel.
* These two actors are build using unstructured grids.
*
* The picked plane actor is defined by 8 points surrounding the current image plane.
* The points are set at the coordinates of the (red / blue / green) border of the current image plane.
* To make sure that the borders are visible in any specific orientation, four quads are build from this points.
* Each quad goes out of the image plane on both side (back and front).
*
* The picked pixel actor is also made of 8 points that describes the cross centered on the currently picked pixel.
* The points are set at the coordinates of the (red / blue / green) cross around the picked pixel.
* To make sure that the cross is visible in any specific orientation, two quads are build from this 8 points
* Each quad goes out of the image plane on both side
*
* \note (easter egg) hit "t" on any slice viewer and move the camera around to see the quad geometries and
* how these extra actors are build.
*
*
* \verbatim
......@@ -101,12 +113,6 @@ namespace camitk {
class CAMITK_API Slice : public InterfaceBitMap {
public:
/* -------------------------------------------------------------------- */
/**@{ */
/**@name Constructors / Destructors */
/**@{ */
/* -------------------------------------------------------------------- */
/** Common slices orientation: axial, sagittal, coronal axial_neuro.
* Axial, Sagittal and Coronal orientation are given in Radiologist point of view.
* The neurologist point of view is displayed in axial_neuro.
......@@ -137,17 +143,17 @@ public:
ARBITRARY
};
/// @name Constructors / Destructors
/// @{
/// Constructor
Slice(vtkSmartPointer<vtkImageData> volume, SliceOrientation AXIAL_ORIENTATION, vtkSmartPointer<vtkWindowLevelLookupTable> lookupTable = nullptr);
/// virtual destructor
~Slice() override;
/// @}
/* -------------------------------------------------------------------- */
/**@} */
/**@name InterfaceBitMap implementation */
/**@{ */
/* -------------------------------------------------------------------- */
/// @name InterfaceBitMap implementation
/// @{
/// set the original volume image data (the source vtkImageData before any reslice) and refresh the vtk pipeline
void setOriginalVolume(vtkSmartPointer<vtkImageData> img) override;
......@@ -161,31 +167,18 @@ public:
/** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 3D viewers. */
vtkSmartPointer<vtkImageActor> get3DImageActor() const override;
/** Return the vtkActor used to pick pixels in the slices. */
/** Return the vtkActor visualizing the plane of the slices. */
vtkSmartPointer<vtkActor> getPickPlaneActor() const override;
/** Return the vtkActor used to pick pixels in the slices. */
/** Return the vtkActor visualizing the picked pixels in the slices. */
vtkSmartPointer<vtkActor> getPixelActor() override;
/** Return 2D Axes at the proper slice origin */
virtual vtkSmartPointer<vtkAxesActor> get2DAxesActor();
/** This method is called when the associated plane has been picked in the InteractiveViewer,
* the given coordinates is position where the plane was picked.
*/
void pixelPicked(double, double, double) override;
/** Compute the volume coordinates (xyz) from the resliced coordinates (ijk)
* @param ijk: given resliced coordiantes (generally from a pixel picked in the pickPlane)
* @param xyz: output (should be allocated before calling this function)
* volume coordinates (with image at the origin in RAI convention) computed from the input
*/
/// Todo: put this method in abstract slice
void reslicedToVolumeCoords(const double* ijk, double* xyz);
/// Todo, idem...
void volumeToReslicedCoords(const double* xyz, double* ijk);
/// update the position of the plane surrounding the currently selected slice
void updatePickPlane() override;
/** Return the number of slices in the image data set. */
......@@ -214,9 +207,17 @@ public:
/// get the current image data
vtkSmartPointer<vtkImageData> getImageData() const override;
// BEGIN TODO : put all of this into a dedicated interface
/// The additional map for prop (include at least "label" and "glyph")
QMap<QString, vtkSmartPointer<vtkProp> > extraProp;
// @}
/// @name manage extra prop associated with a Slice
/// @{
/// TODO
/// - put all this management into a dedicated interface
/// - remove it from InterfaceBitMap and InterfaceGeometry
/// - remove it from Slice and Geometry helper classes
/// - create a new associated helper class
/// - update Component class and all other code using it (if needed)
/// Note : beware that Geometry requires this to manage to at least "label" and "glyph" extra actors
/// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
vtkSmartPointer<vtkProp> getProp(const QString&) override;
......@@ -236,15 +237,14 @@ public:
* @return true if effictively done
*/
bool removeProp(const QString&) override;