diff --git a/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegato.xml b/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegato.xml
index ffd64fa90..183eb2eaf 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegato.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegato.xml
@@ -85,7 +85,7 @@
-
+
diff --git a/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegatoWithTF.xml b/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegatoWithTF.xml
index e5bf7692b..c2d67f495 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegatoWithTF.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity/rc/configurations/2DNegatoWithTF.xml
@@ -79,7 +79,7 @@
-
+
diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/Properties.cmake b/Bundles/LeafActivity/2DVisualizationActivity2/Properties.cmake
index dc9a22c6c..9d1f1c92f 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity2/Properties.cmake
+++ b/Bundles/LeafActivity/2DVisualizationActivity2/Properties.cmake
@@ -8,6 +8,7 @@ set( REQUIREMENTS
guiQt
uiMeasurement
uiMeasurementQt
+ ctrlCamp
ctrlSelection
uiImageQt
uiVisu
diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml
index 51af1ba33..7182f51e4 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml
@@ -3,14 +3,17 @@
+
+
+
@@ -48,6 +51,7 @@
+
@@ -61,6 +65,10 @@
+
+
+
+
@@ -80,7 +88,7 @@
-
+
@@ -101,6 +109,10 @@
MPRNegato/setCrossScale
+
+
+ pickerInteractor/picked
+
diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegatoWithTF.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegatoWithTF.xml
index 8c9a58a21..e32bb4f18 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegatoWithTF.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegatoWithTF.xml
@@ -3,6 +3,7 @@
+
@@ -13,6 +14,7 @@
+
@@ -50,6 +52,7 @@
+
@@ -77,7 +80,7 @@
-
+
diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml
index 8e2b9f022..21458b5c8 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml
@@ -5,11 +5,14 @@
+
+
+
@@ -17,6 +20,7 @@
+
@@ -26,18 +30,17 @@
+
-
-
-
+
@@ -51,12 +54,10 @@
-
-
-
-
+
+
@@ -70,53 +71,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${advancedLandmarksEditor}
+
+
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+ LoadLandmark/update
+
-
-
+
+
+
+ SaveLandmark/update
+
-
-
+
+
+
+ landmarksEditor/setVisible
+
@@ -127,6 +150,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
hide
@@ -147,6 +187,10 @@
ActionShowFullCross/crossTypeModified
+
+ landmarksEditor/addPickedPoint
+
+
@@ -156,5 +200,13 @@
+
+
+
+
+
+
+
+
diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/plugin.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/plugin.xml
index fc2fbf742..1261d4d6d 100644
--- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/plugin.xml
+++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/plugin.xml
@@ -26,11 +26,15 @@
Image to display.
+
+ Landmarks to display.
+
- ::fwActivities::builder::ActivitySeries
+ ::fwActivities::builder::ActivitySeriesInitData
+
diff --git a/Bundles/LeafActivity/3DVisualizationActivity/rc/configurations/3DNegatoWithAcq.xml b/Bundles/LeafActivity/3DVisualizationActivity/rc/configurations/3DNegatoWithAcq.xml
index 6a94155a0..c623ef226 100644
--- a/Bundles/LeafActivity/3DVisualizationActivity/rc/configurations/3DNegatoWithAcq.xml
+++ b/Bundles/LeafActivity/3DVisualizationActivity/rc/configurations/3DNegatoWithAcq.xml
@@ -100,7 +100,7 @@
-
+
diff --git a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DNegatoWithAcq.xml b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DNegatoWithAcq.xml
index 4075c495d..d7f87ae9c 100644
--- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DNegatoWithAcq.xml
+++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DNegatoWithAcq.xml
@@ -4,16 +4,19 @@
+
+
+
@@ -75,6 +78,7 @@
+
@@ -93,6 +97,10 @@
+
+
+
+
@@ -113,7 +121,7 @@
-
+
@@ -128,6 +136,10 @@
modelSeries/showReconstructions
+
+ pickerInteractor/picked
+
+
snapshotNegatoEditor/snapped
snapshotUID/snap
diff --git a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml
index a8a81a4a3..52066669a 100644
--- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml
+++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml
@@ -11,7 +11,9 @@
+
+
@@ -20,6 +22,7 @@
+
@@ -28,6 +31,7 @@
+
@@ -36,6 +40,7 @@
+
@@ -61,12 +66,10 @@
-
-
-
+
@@ -87,12 +90,10 @@
-
-
-
-
-
-
+
+
+
+
@@ -136,11 +137,13 @@
+
+
@@ -172,6 +175,13 @@
+
+
+
+
+
+
+
@@ -179,8 +189,10 @@
+
+
@@ -188,29 +200,51 @@
+
+
-
-
-
-
+
+
-
-
+
+
+
+ LoadLandmark/update
+
-
-
+
+
+
+ SaveLandmark/update
+
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+ landmarksEditor/setVisible
+
@@ -243,28 +277,34 @@
+
+
+ ${advancedLandmarksEditor}
+
+
ActionHideCross/crossTypeModified
ActionShowNormalCross/crossTypeModified
ActionShowFullCross/crossTypeModified
+
+ landmarksEditor/addPickedPoint
+
+
+
+
+
-
-
-
-
-
-
@@ -272,8 +312,12 @@
+
+
+
+
diff --git a/Bundles/LeafActivity/3DVisualizationActivity2/rc/plugin.xml b/Bundles/LeafActivity/3DVisualizationActivity2/rc/plugin.xml
index f009b3f34..181c15eed 100644
--- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/plugin.xml
+++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/plugin.xml
@@ -24,12 +24,16 @@
Image associated to the model.
OptionalInputImageKey
+
+ Landmarks to display.
+
- ::fwActivities::builder::ActivitySeries
+ ::fwActivities::builder::ActivitySeriesInitData
+
diff --git a/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml b/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml
index 965fee7bf..8502ec3cb 100644
--- a/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml
+++ b/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml
@@ -102,9 +102,6 @@
-
-
-
diff --git a/Bundles/LeafActivity/ioActivity/rc/plugin.xml b/Bundles/LeafActivity/ioActivity/rc/plugin.xml
index b5408a3d5..5c2c445d0 100644
--- a/Bundles/LeafActivity/ioActivity/rc/plugin.xml
+++ b/Bundles/LeafActivity/ioActivity/rc/plugin.xml
@@ -168,7 +168,7 @@
MDAtomsConfig
Reader/Writer for atoms representing a medical data
-
+
VRRenderMedicalDataV2
@@ -183,7 +183,7 @@
.apz
-
+
@@ -211,4 +211,13 @@
+
+
+ LandmarksAtomsConfig
+ Reader/Writer for atoms representing a medical data
+
+
+
+
+
diff --git a/Bundles/LeafActivity/volumeRenderingActivity2/rc/configurations/VolumeRendering.xml b/Bundles/LeafActivity/volumeRenderingActivity2/rc/configurations/VolumeRendering.xml
index be9b7c482..a6ed03b37 100644
--- a/Bundles/LeafActivity/volumeRenderingActivity2/rc/configurations/VolumeRendering.xml
+++ b/Bundles/LeafActivity/volumeRenderingActivity2/rc/configurations/VolumeRendering.xml
@@ -22,6 +22,8 @@
+
+
@@ -337,6 +339,7 @@
+
@@ -392,20 +395,13 @@
5.0
-
+
+
+
+
+
+
ActionHideCross/crossTypeModified
@@ -423,12 +419,14 @@
+
+
diff --git a/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/FocusLandmark.hpp b/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/FocusLandmark.hpp
deleted file mode 100644
index 93d860621..000000000
--- a/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/FocusLandmark.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2015.
- * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
- * published by the Free Software Foundation.
- * ****** END LICENSE BLOCK ****** */
-
-#ifndef __UIMEASUREMENT_ACTION_FOCUSLANDMARK_HPP__
-#define __UIMEASUREMENT_ACTION_FOCUSLANDMARK_HPP__
-
-#include
-
-#include "uiMeasurement/config.hpp"
-
-namespace uiMeasurement
-{
-namespace action
-{
-
-/**
- * @brief This action moves the image slice on chosen landmark.
- * @class FocusLandmark
- */
-class UIMEASUREMENT_CLASS_API FocusLandmark : public ::fwGui::IActionSrv
-{
-
-public:
- fwCoreServiceClassDefinitionsMacro ( (FocusLandmark)( ::fwGui::IActionSrv) );
-
- UIMEASUREMENT_API FocusLandmark() throw();
-
- UIMEASUREMENT_API virtual ~FocusLandmark() throw();
-
-protected:
-
- UIMEASUREMENT_API void starting() throw ( ::fwTools::Failed );
-
- UIMEASUREMENT_API void stopping() throw ( ::fwTools::Failed );
-
- UIMEASUREMENT_API void configuring() throw ( ::fwTools::Failed );
-
- UIMEASUREMENT_API void updating() throw ( ::fwTools::Failed );
-
- UIMEASUREMENT_API void info ( std::ostream &_sstream );
-
-};
-
-} // namespace action
-} // namespace uiMeasurement
-
-#endif // __UIMEASUREMENT_ACTION_FOCUSLANDMARK_HPP__
diff --git a/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/SFocusLandmark.hpp b/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/SFocusLandmark.hpp
new file mode 100644
index 000000000..f185ae6a7
--- /dev/null
+++ b/Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/SFocusLandmark.hpp
@@ -0,0 +1,89 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#ifndef __UIMEASUREMENT_ACTION_SFOCUSLANDMARK_HPP__
+#define __UIMEASUREMENT_ACTION_SFOCUSLANDMARK_HPP__
+
+#include "uiMeasurement/config.hpp"
+
+#include
+
+namespace uiMeasurement
+{
+namespace action
+{
+
+/**
+ * @brief This action moves the image slice on selected landmark.
+ *
+ * @section Slots Slots
+ * - \b selectLandmark(groupName, index) : keep a reference to the selected landmark
+ * - \b deselectLandmark(groupName, index) : deselect the landmark
+ * - \b deselectFromGroup(groupName) : deselect the landmark if it is in the group
+ * - \b renameGroup(oldGroupName, newGroupName) : rename the selected landmark group
+ *
+ * @section XML XML Configuration
+ *
+ * @code{.xml}
+
+
+
+
+ @endcode
+ * @subsection Input Input
+ * - \b landmarks [::fwData::Landmarks]: landmarks to focus.
+ * @subsection In-Out In-Out
+ * - \b image [::fwData::Image]: image to modify the slice.
+ */
+class UIMEASUREMENT_CLASS_API SFocusLandmark : public ::fwGui::IActionSrv
+{
+
+public:
+ fwCoreServiceClassDefinitionsMacro( (SFocusLandmark)( ::fwGui::IActionSrv) );
+
+ UIMEASUREMENT_API SFocusLandmark() throw();
+
+ UIMEASUREMENT_API virtual ~SFocusLandmark() throw();
+
+ /// Defines connection to Landmarks data
+ UIMEASUREMENT_API KeyConnectionsMap getAutoConnections() const;
+
+protected:
+
+ /// Do nothing
+ UIMEASUREMENT_API void starting() throw ( ::fwTools::Failed );
+
+ /// Do nothing
+ UIMEASUREMENT_API void stopping() throw ( ::fwTools::Failed );
+
+ /// Do nothing
+ UIMEASUREMENT_API void configuring() throw ( ::fwTools::Failed );
+
+ /// Focus the image slices on the selected landmark
+ UIMEASUREMENT_API void updating() throw ( ::fwTools::Failed );
+
+private:
+ /// Slot: keep a reference to the selected landmark
+ void selectLandmark(std::string groupName, size_t index);
+
+ /// Slot: deselect the landmark
+ void deselectLandmark(std::string groupName, size_t index);
+
+ /// Slot: deselect the landmark if it is in the group
+ void deselectFromGroup(std::string groupName);
+
+ /// Slot: rename the selected landmark group
+ void renameGroup(std::string oldGroupName, std::string newGroupName);
+
+ std::string m_groupName;
+ size_t m_index;
+ bool m_isSelected;
+};
+
+} // namespace action
+} // namespace uiMeasurement
+
+#endif // __UIMEASUREMENT_ACTION_SFOCUSLANDMARK_HPP__
diff --git a/Bundles/LeafUI/uiMeasurement/rc/plugin.xml b/Bundles/LeafUI/uiMeasurement/rc/plugin.xml
index e21f16b7d..61b802126 100644
--- a/Bundles/LeafUI/uiMeasurement/rc/plugin.xml
+++ b/Bundles/LeafUI/uiMeasurement/rc/plugin.xml
@@ -51,7 +51,7 @@
::fwGui::IActionSrv
- ::uiMeasurement::action::FocusLandmark
+ ::uiMeasurement::action::SFocusLandmark
diff --git a/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/FocusLandmark.cpp b/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/FocusLandmark.cpp
deleted file mode 100644
index 76bbf3363..000000000
--- a/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/FocusLandmark.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2016.
- * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
- * published by the Free Software Foundation.
- * ****** END LICENSE BLOCK ****** */
-
-#include "uiMeasurement/action/FocusLandmark.hpp"
-
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include
-#include
-
-#include
-
-namespace uiMeasurement
-{
-namespace action
-{
-
-fwServicesRegisterMacro( ::fwGui::IActionSrv, ::uiMeasurement::action::FocusLandmark, ::fwData::Image );
-
-//------------------------------------------------------------------------------
-
-FocusLandmark::FocusLandmark( ) throw()
-{
-}
-
-//------------------------------------------------------------------------------
-
-FocusLandmark::~FocusLandmark() throw()
-{
-}
-
-//------------------------------------------------------------------------------
-
-void FocusLandmark::starting() throw ( ::fwTools::Failed )
-{
- this->::fwGui::IActionSrv::actionServiceStarting();
-}
-
-//------------------------------------------------------------------------------
-
-void FocusLandmark::stopping() throw ( ::fwTools::Failed )
-{
- this->::fwGui::IActionSrv::actionServiceStopping();
-}
-
-//------------------------------------------------------------------------------
-
-void FocusLandmark::configuring() throw ( ::fwTools::Failed )
-{
- this->::fwGui::IActionSrv::initialize();
-}
-
-//------------------------------------------------------------------------------
-
-void FocusLandmark::info(std::ostream& _sstream )
-{
- _sstream << "Action for focus a landmark distance" << std::endl;
-}
-
-//------------------------------------------------------------------------------
-
-void FocusLandmark::updating() throw(::fwTools::Failed)
-{
- SLM_TRACE_FUNC();
-
- ::fwData::Image::sptr pImage = this->getObject< ::fwData::Image >();
- if (!::fwDataTools::fieldHelper::MedicalImageHelpers::checkImageValidity(pImage))
- {
- ::fwGui::dialog::MessageDialog messageBox;
- messageBox.setTitle("Add landmarks");
- messageBox.setMessage(
- "It is impossible to add image landmarks. There is no loaded image in the software." );
- messageBox.setIcon(::fwGui::dialog::IMessageDialog::WARNING);
- messageBox.addButton(::fwGui::dialog::IMessageDialog::OK);
- messageBox.show();
- return;
- }
-
- else // Image is defined
- {
- // get landmarks
- namespace ns = ::fwDataTools::fieldHelper;
- ns::MedicalImageHelpers::checkLandmarks( pImage );
- ::fwData::PointList::sptr landmarks = pImage->getField< ::fwData::PointList >(
- ::fwDataTools::fieldHelper::Image::m_imageLandmarksId);
- SLM_ASSERT("landmarks not instanced", landmarks);
-
- if( landmarks->getCRefPoints().empty() )
- {
- ::fwGui::dialog::MessageDialog messageBox;
- messageBox.setTitle("Focus landmarks");
- messageBox.setMessage(
- "It is impossible to focus image landmarks. There are no defined landmarks for this selected image." );
- messageBox.setIcon(::fwGui::dialog::IMessageDialog::WARNING);
- messageBox.addButton(::fwGui::dialog::IMessageDialog::OK);
- messageBox.show();
- }
- else
- {
- // Retrieve point names
- std::vector< std::string > names;
- std::map< std::string, ::fwData::Point::sptr > name2Point;
-
- ::fwData::PointList::PointListContainer points = landmarks->getCRefPoints();
- for(::fwData::Point::sptr point : points)
- {
- std::string name =
- point->getField< ::fwData::String >( ::fwDataTools::fieldHelper::Image::m_labelId )->value();
- OSLM_DEBUG( "Point name " << name );
- names.push_back( name );
- name2Point[name] = point;
- }
-
- // Propose to user to choose a landmark
- ::fwGui::dialog::SelectorDialog::sptr selector = ::fwGui::dialog::SelectorDialog::New();
- selector->setTitle("Select a landmark");
- selector->setSelections(names);
- std::string selection = selector->show();
- if( !selection.empty() )
- {
- ::fwData::Point::sptr selectedPoint = name2Point[ selection ];
- SLM_ASSERT("selectedPoint not instanced", selectedPoint);
- ::fwData::Integer::sptr paramA = ::fwData::Integer::New();
- paramA->value() =
- static_cast((selectedPoint->getRefCoord()[2] - pImage->getOrigin()[2] )/
- pImage->getSpacing()[2] +0.5);
- ::fwData::Integer::sptr paramF = ::fwData::Integer::New();
- paramF->value() =
- static_cast((selectedPoint->getRefCoord()[1] - pImage->getOrigin()[1])/
- pImage->getSpacing()[1] +0.5);
- ::fwData::Integer::sptr paramS = ::fwData::Integer::New();
- paramS->value() =
- static_cast((selectedPoint->getRefCoord()[0] - pImage->getOrigin()[0])/
- pImage->getSpacing()[0] +0.5);
- if( paramS->value() >= 0 &&
- paramF->value() >= 0 &&
- paramA->value() >= 0 &&
- pImage->getSize()[0] > paramS->value() &&
- pImage->getSize()[1] > paramF->value() &&
- pImage->getSize()[2] > paramA->value() )
- {
- pImage->setField( ::fwDataTools::fieldHelper::Image::m_axialSliceIndexId, paramA );
- pImage->setField( ::fwDataTools::fieldHelper::Image::m_frontalSliceIndexId, paramF );
- pImage->setField( ::fwDataTools::fieldHelper::Image::m_sagittalSliceIndexId, paramS );
-
- // notify
- auto sig = pImage->signal< ::fwData::Image::SliceIndexModifiedSignalType >(
- ::fwData::Image::s_SLICE_INDEX_MODIFIED_SIG);
- sig->asyncEmit(paramA->value(), paramF->value(), paramS->value());
- }
- else
- {
- ::fwGui::dialog::MessageDialog::showMessageDialog("Focus landmarks",
- "It is impossible to focus image landmarks: "
- "landmark is outside image.",
- ::fwGui::dialog::IMessageDialog::WARNING);
- }
- }
- }
- }
-}
-
-//------------------------------------------------------------------------------
-
-} // namespace action
-
-} // namespace uiMeasurement
diff --git a/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/SFocusLandmark.cpp b/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/SFocusLandmark.cpp
new file mode 100644
index 000000000..0b634d552
--- /dev/null
+++ b/Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/SFocusLandmark.cpp
@@ -0,0 +1,221 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#include "uiMeasurement/action/SFocusLandmark.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+namespace uiMeasurement
+{
+namespace action
+{
+
+static const ::fwServices::IService::KeyType s_LANDMARKS_INPUT = "landmarks";
+static const ::fwServices::IService::KeyType s_IMAGE_INOUT = "image";
+
+static const ::fwCom::Slots::SlotKeyType s_SELECT_LANDMARK_SLOT = "selectLandmark";
+static const ::fwCom::Slots::SlotKeyType s_DESELECT_LANDMARK_SLOT = "deselectLandmark";
+static const ::fwCom::Slots::SlotKeyType s_DESELECT_FROM_GROUP_SLOT = "deselectFromGroup";
+static const ::fwCom::Slots::SlotKeyType s_RENAME_GROUP_SLOT = "renameGroup";
+
+fwServicesRegisterMacro( ::fwGui::IActionSrv, ::uiMeasurement::action::SFocusLandmark );
+
+//------------------------------------------------------------------------------
+
+SFocusLandmark::SFocusLandmark( ) throw() :
+ m_index(0),
+ m_isSelected(false)
+{
+ newSlot(s_SELECT_LANDMARK_SLOT, &SFocusLandmark::selectLandmark, this);
+ newSlot(s_DESELECT_LANDMARK_SLOT, &SFocusLandmark::deselectLandmark, this);
+ newSlot(s_DESELECT_FROM_GROUP_SLOT, &SFocusLandmark::deselectFromGroup, this);
+ newSlot(s_RENAME_GROUP_SLOT, &SFocusLandmark::renameGroup, this);
+}
+
+//------------------------------------------------------------------------------
+
+SFocusLandmark::~SFocusLandmark() throw()
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::starting() throw ( ::fwTools::Failed )
+{
+ this->::fwGui::IActionSrv::actionServiceStarting();
+ this->setIsExecutable(m_isSelected);
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::stopping() throw ( ::fwTools::Failed )
+{
+ this->::fwGui::IActionSrv::actionServiceStopping();
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::configuring() throw ( ::fwTools::Failed )
+{
+ this->::fwGui::IActionSrv::initialize();
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::updating() throw(::fwTools::Failed)
+{
+ if (m_isSelected)
+ {
+ ::fwData::Image::sptr pImage = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
+ if (!::fwDataTools::fieldHelper::MedicalImageHelpers::checkImageValidity(pImage))
+ {
+ ::fwGui::dialog::MessageDialog messageBox;
+ messageBox.setTitle("Add landmarks");
+ messageBox.setMessage(
+ "It is impossible to add image landmarks. There is no loaded image in the software." );
+ messageBox.setIcon(::fwGui::dialog::IMessageDialog::WARNING);
+ messageBox.addButton(::fwGui::dialog::IMessageDialog::OK);
+ messageBox.show();
+ return;
+ }
+ else // Image is defined
+ {
+ ::fwData::Landmarks::csptr landmarks = this->getInput< ::fwData::Landmarks >(s_LANDMARKS_INPUT);
+
+ try
+ {
+ const ::fwData::Landmarks::PointType& point = landmarks->getPoint(m_groupName, m_index);
+
+ ::fwData::Integer::sptr paramA = ::fwData::Integer::New();
+ paramA->value() =
+ static_cast((point[2] - pImage->getOrigin()[2] ) / pImage->getSpacing()[2] +0.5);
+ ::fwData::Integer::sptr paramF = ::fwData::Integer::New();
+ paramF->value() =
+ static_cast((point[1] - pImage->getOrigin()[1]) / pImage->getSpacing()[1] +0.5);
+ ::fwData::Integer::sptr paramS = ::fwData::Integer::New();
+ paramS->value() =
+ static_cast((point[0] - pImage->getOrigin()[0]) / pImage->getSpacing()[0] +0.5);
+ if( paramS->value() >= 0 &&
+ paramF->value() >= 0 &&
+ paramA->value() >= 0 &&
+ pImage->getSize()[0] > static_cast< ::fwData::Image::SizeType::value_type >(paramS->value()) &&
+ pImage->getSize()[1] > static_cast< ::fwData::Image::SizeType::value_type >(paramF->value()) &&
+ pImage->getSize()[2] > static_cast< ::fwData::Image::SizeType::value_type >(paramA->value()) )
+ {
+ pImage->setField( ::fwDataTools::fieldHelper::Image::m_axialSliceIndexId, paramA );
+ pImage->setField( ::fwDataTools::fieldHelper::Image::m_frontalSliceIndexId, paramF );
+ pImage->setField( ::fwDataTools::fieldHelper::Image::m_sagittalSliceIndexId, paramS );
+
+ // notify
+ auto sig = pImage->signal< ::fwData::Image::SliceIndexModifiedSignalType >(
+ ::fwData::Image::s_SLICE_INDEX_MODIFIED_SIG);
+ sig->asyncEmit(paramA->value(), paramF->value(), paramS->value());
+ }
+ else
+ {
+ ::fwGui::dialog::MessageDialog::showMessageDialog("Focus landmarks",
+ "It is impossible to focus image landmarks: "
+ "landmark is outside image.",
+ ::fwGui::dialog::IMessageDialog::WARNING);
+ }
+ }
+ catch (::fwData::Exception& e )
+ {
+ ::fwGui::dialog::MessageDialog::showMessageDialog("Focus landmarks",
+ "It is impossible to focus image landmarks: "
+ + std::string(e.what()),
+ ::fwGui::dialog::IMessageDialog::WARNING);
+ }
+
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::selectLandmark(std::string groupName, size_t index)
+{
+ m_groupName = groupName;
+ m_index = index;
+ m_isSelected = true;
+ this->setIsExecutable(m_isSelected);
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::deselectLandmark(std::string groupName, size_t index)
+{
+ if (m_groupName == groupName && m_index == index)
+ {
+ m_groupName = "";
+ m_index = 0;
+ m_isSelected = false;
+ }
+ this->setIsExecutable(m_isSelected);
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::deselectFromGroup(std::string groupName)
+{
+ if (m_groupName == groupName)
+ {
+ m_groupName = "";
+ m_index = 0;
+ m_isSelected = false;
+ }
+ this->setIsExecutable(m_isSelected);
+}
+
+//------------------------------------------------------------------------------
+
+void SFocusLandmark::renameGroup(std::string oldGroupName, std::string newGroupName)
+{
+ if (m_groupName == oldGroupName)
+ {
+ m_groupName = newGroupName;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+SFocusLandmark::KeyConnectionsMap SFocusLandmark::getAutoConnections() const
+{
+ KeyConnectionsMap connections;
+
+ connections.push(s_LANDMARKS_INPUT, ::fwData::Landmarks::s_POINT_SELECTED_SIG, s_SELECT_LANDMARK_SLOT);
+ connections.push(s_LANDMARKS_INPUT, ::fwData::Landmarks::s_POINT_DESELECTED_SIG, s_DESELECT_LANDMARK_SLOT);
+ connections.push(s_LANDMARKS_INPUT, ::fwData::Landmarks::s_POINT_REMOVED_SIG, s_DESELECT_LANDMARK_SLOT);
+ connections.push(s_LANDMARKS_INPUT, ::fwData::Landmarks::s_GROUP_REMOVED_SIG, s_DESELECT_FROM_GROUP_SLOT);
+ connections.push(s_LANDMARKS_INPUT, ::fwData::Landmarks::s_GROUP_RENAMED_SIG, s_RENAME_GROUP_SLOT);
+
+ return connections;
+}
+
+//------------------------------------------------------------------------------
+
+} // namespace action
+
+} // namespace uiMeasurement
diff --git a/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp b/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp
new file mode 100644
index 000000000..4d50041da
--- /dev/null
+++ b/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp
@@ -0,0 +1,203 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#ifndef __UIMEASUREMENTQT_EDITOR_SLANDMARKS_HPP__
+#define __UIMEASUREMENTQT_EDITOR_SLANDMARKS_HPP__
+
+#include "uiMeasurementQt/config.hpp"
+
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace uiMeasurementQt
+{
+namespace editor
+{
+
+/**
+ * @brief This service defines a graphical editor to edit landmarks.
+ *
+ * @section Slots Slots
+ * - \b pickPoint(::fwDataTools::PickingInfo) : Add picked landmark.
+ * - \b addPoint(std::string) : Add point to editor.
+ * - \b removePoint(std::string, size_t) : Remove point from editor.
+ * - \b modifyPoint(std::string, size_t) : Update editor when a point has moved.
+ * - \b selectPoint(std::string, size_t) : Select point in editor.
+ * - \b deselectPoint(std::string, size_t) : Deselect item in editor.
+ * - \b addGroup(std::string) : Add group to editor.
+ * - \b removeGroup(std::string) : Removes group from editor.
+ * - \b modifyGroup(std::string) : Update group attributes.
+ * - \b renameGroup(std::string, std::string) : Renames group in editor.
+ *
+ * @section XML XML Configuration
+ *
+ * @code{.xml}
+
+
+ yes
+
+ @endcode
+ * @subsection In-Out In-Out
+ * - \b landmarks [::fwData::Landmarks]: the landmarks structure on which this editor is working.
+ *
+ * @subsection Configuration Configuration
+ * - \b advanced (optional, default="no") : if "yes", use the advanced mode displaying point information
+ * and groups with multiple points.
+ */
+class UIMEASUREMENTQT_CLASS_API SLandmarks : public QObject,
+ public ::gui::editor::IEditor
+{
+
+Q_OBJECT
+
+public:
+
+ fwCoreServiceClassDefinitionsMacro( (SLandmarks)(::gui::editor::IEditor) );
+
+ /// Constructor. Do nothing.
+ UIMEASUREMENTQT_API SLandmarks() throw();
+
+ /// Destructor. Do nothing.
+ UIMEASUREMENTQT_API virtual ~SLandmarks() throw();
+
+ UIMEASUREMENTQT_API virtual KeyConnectionsMap getAutoConnections() const;
+
+protected:
+
+ typedef ::fwRuntime::ConfigurationElement::sptr Configuration;
+
+ /**
+ * @brief Install the layout.
+ *
+ * This method launches the IEditor::starting method.
+ */
+ virtual void starting() throw(::fwTools::Failed);
+
+ /**
+ * @brief Destroy the layout.
+ *
+ * This method launches the IEditor::stopping method.
+ */
+ virtual void stopping() throw(::fwTools::Failed);
+
+ /// Do nothing
+ virtual void updating() throw(::fwTools::Failed);
+
+ virtual void configuring() throw(fwTools::Failed);
+
+private:
+
+ /// This method is called when a color button is clicked
+ void onColorButton();
+
+ /// Called when a group name is changed
+ void onGroupNameEdited(QTreeWidgetItem* item, int column);
+
+ /// Called when a new group is selected in the editor.
+ void onSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
+
+ /// Called when a group's point size is modified.
+ void onSizeChanged(int newSize);
+
+ /// Called when a group's transparency is modified.
+ void onTransparencyChanged(int newTransparency);
+
+ /// Called when a group's visibility is turned on or off.
+ void onVisibilityChanged(int visibility);
+
+ /// Called when the landmarks' shape is changed for a group.
+ void onShapeChanged(const QString& shape);
+
+ /// Called when the new group button is pressed, adds an empty landmark group in our data.
+ void onAddNewGroup();
+
+ /// Called when the remove button is pressed, deletes selected group or point.
+ void onRemoveSelection();
+
+ /// Slot: Adds a new landmark.
+ void addPickedPoint(::fwDataTools::PickingInfo pickingInfo);
+
+ /// Slot: Add point to editor.
+ void addPoint(std::string groupName);
+
+ /// Slot: Update point coordinates in editor.
+ void modifyPoint(std::string groupName, size_t index);
+
+ /// Slot: select the point's corresponding item in editor.
+ void selectPoint(std::string groupName, size_t index);
+
+ /// Slot: deselect the currently selected item.
+ void deselectPoint(std::string groupName, size_t index);
+
+ /// Slot: add a landmark group to the editor.
+ void addGroup(std::string name);
+
+ /// Slot: remove group from editor
+ void removeGroup(std::string name);
+
+ /// Slot: remove point from editor
+ void removePoint(std::string groupName, size_t index);
+
+ /// Slot: rename group in editor.
+ void renameGroup(std::string oldName, std::string newName);
+
+ /// Slot: update group properties in editor.
+ void modifyGroup(std::string name);
+
+ /// Gets the name of the currently selected group, returns false if no group is selected.
+ bool currentSelection(std::string& selection) const;
+
+ /// Get tree item representing the group.
+ QTreeWidgetItem* getGroupItem(const std::string& groupName) const;
+
+ /// Generate a group name that doesn't exist already.
+ std::string generateNewGroupName() const;
+
+ /// Generate a new random color
+ static std::array generateNewColor();
+
+ /// Converts a landmark color to a QColor.
+ static QColor convertToQColor(const ::fwData::Landmarks::ColorType& color);
+
+ /// Draws a colored square on the button.
+ static void setColorButtonIcon(QPushButton* button, const QColor& color);
+
+ QPointer m_treeWidget;
+
+ QPointer m_groupEditorWidget;
+
+ QPointer m_sizeSlider;
+
+ QPointer m_transparencySlider;
+
+ QPointer m_visibilityCheckbox;
+
+ QPointer m_shapeSelector;
+
+ QPointer m_newGroupButton;
+
+ QPointer m_removeButton;
+
+ /// Used to disable/enable advanced mode.
+ bool m_advancedMode;
+
+};
+} // namespace editor
+} // uiMeasurementQt
+
+#endif /*__UIMEASUREMENTQT_EDITOR_SLANDMARKS_HPP__*/
+
diff --git a/Bundles/LeafUI/uiMeasurementQt/rc/plugin.xml b/Bundles/LeafUI/uiMeasurementQt/rc/plugin.xml
index cae0900ec..5fb5e7beb 100644
--- a/Bundles/LeafUI/uiMeasurementQt/rc/plugin.xml
+++ b/Bundles/LeafUI/uiMeasurementQt/rc/plugin.xml
@@ -11,4 +11,9 @@
::uiMeasurement::editor::Distance
+
+
+ ::gui::editor::IEditor
+ ::uiMeasurementQt::editor::SLandmarks
+
diff --git a/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp
new file mode 100644
index 000000000..1c70d6d67
--- /dev/null
+++ b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp
@@ -0,0 +1,944 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#include "uiMeasurementQt/editor/SLandmarks.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace uiMeasurementQt
+{
+namespace editor
+{
+
+fwServicesRegisterMacro( ::gui::editor::IEditor, ::uiMeasurementQt::editor::SLandmarks );
+
+static const ::fwServices::IService::KeyType s_LANDMARKS_INOUT = "landmarks";
+static const char* s_GROUP_PROPERTY_NAME = "group";
+static const int s_GROUP_NAME_ROLE = ::Qt::UserRole + 1;
+static const float s_DEFAULT_POINT_SIZE = 10.;
+
+static const ::fwCom::Slots::SlotKeyType s_ADD_PICKED_POINT_SLOT = "addPickedPoint";
+static const ::fwCom::Slots::SlotKeyType s_ADD_POINT_SLOT = "addPoint";
+static const ::fwCom::Slots::SlotKeyType s_MODIFY_POINT_SLOT = "modifyPoint";
+static const ::fwCom::Slots::SlotKeyType s_SELECT_POINT_SLOT = "selectPoint";
+static const ::fwCom::Slots::SlotKeyType s_DESELECT_POINT_SLOT = "deselectPoint";
+static const ::fwCom::Slots::SlotKeyType s_REMOVE_POINT_SLOT = "removePoint";
+static const ::fwCom::Slots::SlotKeyType s_ADD_GROUP_SLOT = "addGroup";
+static const ::fwCom::Slots::SlotKeyType s_REMOVE_GROUP_SLOT = "removeGroup";
+static const ::fwCom::Slots::SlotKeyType s_MODIFY_GROUP_SLOT = "modifyGroup";
+static const ::fwCom::Slots::SlotKeyType s_RENAME_GROUP_SLOT = "renameGroup";
+
+SLandmarks::SLandmarks() throw() :
+ m_advancedMode(false)
+{
+ newSlot(s_ADD_PICKED_POINT_SLOT, &SLandmarks::addPickedPoint, this);
+ newSlot(s_ADD_POINT_SLOT, &SLandmarks::addPoint, this);
+ newSlot(s_MODIFY_POINT_SLOT, &SLandmarks::modifyPoint, this);
+ newSlot(s_SELECT_POINT_SLOT, &SLandmarks::selectPoint, this);
+ newSlot(s_DESELECT_POINT_SLOT, &SLandmarks::deselectPoint, this);
+ newSlot(s_ADD_GROUP_SLOT, &SLandmarks::addGroup, this);
+ newSlot(s_REMOVE_POINT_SLOT, &SLandmarks::removePoint, this);
+ newSlot(s_REMOVE_GROUP_SLOT, &SLandmarks::removeGroup, this);
+ newSlot(s_MODIFY_GROUP_SLOT, &SLandmarks::modifyGroup, this);
+ newSlot(s_RENAME_GROUP_SLOT, &SLandmarks::renameGroup, this);
+
+ std::srand(::fwTools::numericRoundCast(std::time(NULL)));
+}
+
+//------------------------------------------------------------------------------
+
+SLandmarks::~SLandmarks() throw()
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::configuring() throw(fwTools::Failed)
+{
+ this->::fwGui::IGuiContainerSrv::initialize();
+
+ const ::fwServices::IService::ConfigType config = this->getConfigTree().get_child("service");
+
+ const std::string advancedMode = config.get_optional("advanced").get_value_or("no");
+
+ SLM_FATAL_IF("'advanced' value must be 'yes' or 'no', here : '" + advancedMode + "'.",
+ advancedMode != "yes" && advancedMode != "no");
+
+ m_advancedMode = (advancedMode == "yes");
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::starting() throw(::fwTools::Failed)
+{
+ this->::fwGui::IGuiContainerSrv::create();
+
+ ::fwGuiQt::container::QtContainer::sptr qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast(
+ this->getContainer() );
+ QWidget* const container = qtContainer->getQtContainer();
+ SLM_ASSERT("container not instanced", container);
+
+ QVBoxLayout* layout = new QVBoxLayout();
+ QGridLayout* gridLayout = new QGridLayout();
+
+ m_visibilityCheckbox = new QCheckBox();
+ QLabel* visibilityLabel = new QLabel(QString("Visibility"));
+ m_sizeSlider = new QSlider(Qt::Horizontal);
+ m_sizeSlider->setMinimum(1);
+ m_sizeSlider->setMaximum(100);
+ QLabel* sizeLabel = new QLabel(QString("Size"));
+ m_transparencySlider = new QSlider(Qt::Horizontal);
+ QLabel* transparencyLabel = new QLabel("Opacity");
+ m_shapeSelector = new QComboBox();
+ m_shapeSelector->addItem(QString("Cube"));
+ m_shapeSelector->addItem(QString("Sphere"));
+ QLabel* shapeLabel = new QLabel("Shape");
+
+ m_newGroupButton = m_advancedMode ? new QPushButton("New Group") : nullptr;
+
+ m_removeButton = new QPushButton("Delete");
+ m_removeButton->setShortcut(QKeySequence::Delete);
+
+ gridLayout->addWidget(visibilityLabel, 0, 0);
+ gridLayout->addWidget(m_visibilityCheckbox, 0, 1);
+ gridLayout->addWidget(sizeLabel, 1, 0);
+ gridLayout->addWidget(m_sizeSlider, 1, 1);
+ gridLayout->addWidget(transparencyLabel, 2, 0);
+ gridLayout->addWidget(m_transparencySlider, 2, 1);
+ gridLayout->addWidget(shapeLabel, 3, 0);
+ gridLayout->addWidget(m_shapeSelector, 3, 1);
+ gridLayout->addWidget(m_removeButton, 4, 1);
+
+ m_groupEditorWidget = new QWidget();
+ m_groupEditorWidget->setLayout(gridLayout);
+
+ m_treeWidget = new QTreeWidget(container);
+ QLabel* helperTextLabel = new QLabel("Use 'Ctrl+Left Click' to add new landmarks");
+ layout->addWidget(helperTextLabel);
+
+ if(m_advancedMode)
+ {
+ layout->addWidget(m_newGroupButton);
+ }
+
+ layout->addWidget(m_treeWidget);
+ layout->addWidget(m_groupEditorWidget);
+ m_groupEditorWidget->hide();
+
+ QStringList headers;
+ headers << "Group" << "Color";
+
+ if(m_advancedMode)
+ {
+ // Add empty third column to display and edit point coordinates.
+ headers << "";
+ }
+
+ m_treeWidget->setHeaderLabels(headers);
+
+ container->setLayout( layout );
+
+ this->updating();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::updating() throw(::fwTools::Failed)
+{
+ m_treeWidget->blockSignals(true);
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ m_treeWidget->clear();
+
+ for (const auto& name : landmarks->getGroupNames())
+ {
+ this->addGroup(name);
+ this->addPoint(name);
+ }
+
+ QObject::connect(m_treeWidget.data(), &QTreeWidget::itemChanged, this, &SLandmarks::onGroupNameEdited);
+ QObject::connect(m_treeWidget.data(), &QTreeWidget::currentItemChanged, this, &SLandmarks::onSelectionChanged);
+ QObject::connect(m_sizeSlider.data(), &QSlider::valueChanged, this, &SLandmarks::onSizeChanged);
+ QObject::connect(m_transparencySlider.data(), &QSlider::valueChanged, this, &SLandmarks::onTransparencyChanged);
+ QObject::connect(m_visibilityCheckbox.data(), &QCheckBox::stateChanged, this, &SLandmarks::onVisibilityChanged);
+ QObject::connect(m_shapeSelector.data(), &QComboBox::currentTextChanged, this, &SLandmarks::onShapeChanged);
+ QObject::connect(m_removeButton.data(), &QPushButton::clicked, this, &SLandmarks::onRemoveSelection);
+ QObject::connect(m_newGroupButton.data(), &QPushButton::clicked, this, &SLandmarks::onAddNewGroup);
+
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::stopping() throw(::fwTools::Failed)
+{
+ this->getContainer()->clean();
+ this->::fwGui::IGuiContainerSrv::destroy();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onColorButton()
+{
+ QObject* sender = this->sender();
+
+ // Create Color choice dialog.
+ auto qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast( this->getContainer() );
+ QWidget* const container = qtContainer->getQtContainer();
+ SLM_ASSERT("container not instanced", container);
+
+ const QColor oldColor = sender->property("color").value();
+ const QColor colorQt = QColorDialog::getColor(oldColor, container);
+ if(colorQt.isValid())
+ {
+ const QString key = sender->property("key").toString();
+
+ QPushButton* colorButton = dynamic_cast(sender);
+ colorButton->setProperty("color", colorQt);
+
+ setColorButtonIcon(colorButton, colorQt);
+
+ const std::string groupName = colorButton->property(s_GROUP_PROPERTY_NAME).value().toStdString();
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ auto& group = landmarks->getGroup(groupName);
+ ::fwData::Landmarks::ColorType color = {{colorQt.red()/255.f, colorQt.green()/255.f, colorQt.blue()/255.f,
+ colorQt.alpha()/255.f}};
+
+ group.m_color = color;
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupModifiedSignalType >(
+ ::fwData::Landmarks::s_GROUP_MODIFIED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_MODIFY_GROUP_SLOT)));
+ sig->asyncEmit(groupName);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onGroupNameEdited(QTreeWidgetItem* item, int column)
+{
+ OSLM_ERROR_IF("A column different from the group's name is being edited", column != 0);
+ m_treeWidget->blockSignals(true);
+
+ if(column == 0)
+ {
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ QString oldGroupName = item->data(0, s_GROUP_NAME_ROLE).toString();
+ QString newGroupName = item->text(0);
+
+ if(newGroupName.isEmpty())
+ {
+ QString msg = "The new group name for '" + oldGroupName +
+ "' is empty. Please enter a valid name and try again";
+ QMessageBox msgBox(QMessageBox::Warning, "No group name", msg, QMessageBox::Ok);
+ msgBox.exec();
+
+ item->setText(0, oldGroupName);
+ }
+ else if(oldGroupName != newGroupName)
+ {
+ try
+ {
+ landmarks->renameGroup(oldGroupName.toStdString(), newGroupName.toStdString());
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupRenamedSignalType >(
+ ::fwData::Landmarks::s_GROUP_RENAMED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_RENAME_GROUP_SLOT)));
+ sig->asyncEmit(oldGroupName.toStdString(), newGroupName.toStdString());
+ }
+
+ item->setData(0, s_GROUP_NAME_ROLE, newGroupName);
+ QWidget* widget = m_treeWidget->itemWidget(item, 1);
+
+ widget->setProperty(s_GROUP_PROPERTY_NAME, newGroupName);
+ }
+ catch(::fwData::Exception& e)
+ {
+ QString msg = "Can't rename '" + oldGroupName +"' as '" + newGroupName + ".\n" +
+ QString(e.what());
+ QMessageBox msgBox(QMessageBox::Warning, "Can't rename" + oldGroupName, msg, QMessageBox::Ok);
+ msgBox.exec();
+
+ item->setText(0, oldGroupName);
+ }
+ }
+ }
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ if(previous)
+ {
+ auto deselectSig = landmarks->signal< ::fwData::Landmarks::PointDeselectedSignalType >(
+ ::fwData::Landmarks::s_POINT_DESELECTED_SIG);
+
+ ::fwCom::Connection::Blocker block(deselectSig->getConnection(this->slot(s_DESELECT_POINT_SLOT)));
+
+ if(m_advancedMode)
+ {
+ QTreeWidgetItem* previousParent = previous->parent();
+
+ if(previousParent != nullptr)
+ {
+ const std::string& groupName = previousParent->text(0).toStdString();
+
+ size_t index = static_cast(previousParent->indexOfChild(previous));
+
+ SLM_ASSERT("index must be inferior to the number of points in '" + groupName +"'.",
+ index < landmarks->getNumberOfPoints(groupName));
+
+ deselectSig->asyncEmit(groupName, index);
+ }
+ }
+ else
+ {
+ const std::string& groupName = previous->text(0).toStdString();
+
+ deselectSig->asyncEmit(groupName, 0);
+ }
+ }
+
+ if(current)
+ {
+ auto selectSig = landmarks->signal< ::fwData::Landmarks::PointSelectedSignalType >(
+ ::fwData::Landmarks::s_POINT_SELECTED_SIG);
+
+ std::string groupName;
+ if(m_advancedMode)
+ {
+ QTreeWidgetItem* currentParent = current->parent();
+
+ if(currentParent != nullptr)
+ {
+ groupName = currentParent->text(0).toStdString();
+
+ size_t index = static_cast(currentParent->indexOfChild(current));
+
+ SLM_ASSERT("index must be inferior to the number of points in '" + groupName +"'.",
+ index < landmarks->getNumberOfPoints(groupName));
+
+ ::fwCom::Connection::Blocker block(selectSig->getConnection(this->slot(s_SELECT_POINT_SLOT)));
+ selectSig->asyncEmit(groupName, index);
+ }
+ else
+ {
+ groupName = current->text(0).toStdString();
+ }
+ }
+ else
+ {
+ groupName = current->text(0).toStdString();
+
+ ::fwCom::Connection::Blocker block(selectSig->getConnection(this->slot(s_SELECT_POINT_SLOT)));
+ selectSig->asyncEmit(groupName, 0);
+ }
+
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(groupName);
+
+ // Set widget values
+ m_sizeSlider->setValue(static_cast(group.m_size));
+ m_visibilityCheckbox->setChecked(group.m_visibility);
+
+ const QString shapeText = group.m_shape == ::fwData::Landmarks::Shape::CUBE ? "Cube" : "Sphere";
+ m_shapeSelector->setCurrentText(shapeText);
+
+ float transparency = group.m_color[3];
+ m_transparencySlider->setValue(static_cast(transparency * m_transparencySlider->maximum()));
+
+ }
+
+ m_groupEditorWidget->setHidden(current == nullptr);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onSizeChanged(int newSize)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const ::fwData::Landmarks::SizeType realSize = static_cast< ::fwData::Landmarks::SizeType >(newSize);
+
+ std::string groupName;
+ if(currentSelection(groupName))
+ {
+ landmarks->setGroupSize(groupName, realSize);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupModifiedSignalType >(
+ ::fwData::Landmarks::s_GROUP_MODIFIED_SIG);
+
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_MODIFY_GROUP_SLOT)));
+
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onTransparencyChanged(int newTransparency)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const float sliderSize = static_cast( m_transparencySlider->maximum() - m_transparencySlider->minimum());
+
+ const float realTransparency = static_cast(newTransparency) / sliderSize;
+
+ std::string groupName;
+ if(currentSelection(groupName))
+ {
+ const auto groupColor = landmarks->getGroup(groupName).m_color;
+
+ ::fwData::Landmarks::ColorType newGroupColor
+ = {{groupColor[0], groupColor[1], groupColor[2], realTransparency}};
+
+ landmarks->setGroupColor(groupName, newGroupColor);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupModifiedSignalType >(
+ ::fwData::Landmarks::s_GROUP_MODIFIED_SIG);
+
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_MODIFY_GROUP_SLOT)));
+
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onVisibilityChanged(int visibility)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ std::string groupName;
+ if(currentSelection(groupName))
+ {
+ landmarks->setGroupVisibility(groupName, static_cast(visibility));
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupModifiedSignalType >(
+ ::fwData::Landmarks::s_GROUP_MODIFIED_SIG);
+
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_MODIFY_GROUP_SLOT)));
+
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onShapeChanged(const QString& shape)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ std::string groupName;
+ if(currentSelection(groupName))
+ {
+ SLM_ASSERT("Shape must be 'Cube' or 'Sphere'.", shape == "Cube" || shape == "Sphere");
+ ::fwData::Landmarks::Shape s
+ = (shape == "Cube") ? ::fwData::Landmarks::Shape::CUBE : ::fwData::Landmarks::Shape::SPHERE;
+
+ landmarks->setGroupShape(groupName, s);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupModifiedSignalType >(
+ ::fwData::Landmarks::s_GROUP_MODIFIED_SIG);
+
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_MODIFY_GROUP_SLOT)));
+
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onAddNewGroup()
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const std::string groupName = this->generateNewGroupName();
+ landmarks->addGroup(groupName, this->generateNewColor(), s_DEFAULT_POINT_SIZE);
+
+ this->addGroup(groupName);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupAddedSignalType >(
+ ::fwData::Landmarks::s_GROUP_ADDED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_ADD_GROUP_SLOT)));
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::onRemoveSelection()
+{
+ m_treeWidget->blockSignals(true);
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+ QTreeWidgetItem* item = m_treeWidget->currentItem();
+
+ if(item != nullptr)
+ {
+ const int topLevelIndex = m_treeWidget->indexOfTopLevelItem(item);
+
+ if(m_advancedMode && topLevelIndex == -1) // Delete point
+ {
+ QTreeWidgetItem* itemParent = item->parent();
+
+ const size_t index = static_cast(itemParent->indexOfChild(item));
+ const std::string& groupName = itemParent->text(0).toStdString();
+
+ landmarks->removePoint(groupName, index);
+ itemParent->removeChild(item);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::PointRemovedSignalType >(
+ ::fwData::Landmarks::s_POINT_REMOVED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_REMOVE_POINT_SLOT)));
+ sig->asyncEmit(groupName, index);
+ }
+ }
+ else
+ {
+ const std::string& groupName = item->text(0).toStdString();
+
+ landmarks->removeGroup(groupName);
+ delete m_treeWidget->takeTopLevelItem(topLevelIndex);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupRemovedSignalType >(
+ ::fwData::Landmarks::s_GROUP_REMOVED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_REMOVE_GROUP_SLOT)));
+ sig->asyncEmit(groupName);
+ }
+ }
+
+ m_treeWidget->setCurrentItem(nullptr);
+ m_groupEditorWidget->setHidden(true);
+ }
+
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::addPickedPoint(::fwDataTools::PickingInfo pickingInfo)
+{
+ if(pickingInfo.m_eventId == ::fwDataTools::PickingInfo::Event::MOUSE_LEFT_UP &&
+ pickingInfo.m_modifierMask & ::fwDataTools::PickingInfo::CTRL)
+ {
+ double* pickedPos = pickingInfo.m_worldPos;
+ ::fwData::Landmarks::PointType newPoint = {{ pickedPos[0], pickedPos[1], pickedPos[2] }};
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ std::string groupName;
+ QTreeWidgetItem* item = m_treeWidget->currentItem();
+
+ if(item == nullptr || !m_advancedMode) // No selection or simple mode, create a new group.
+ {
+ groupName = this->generateNewGroupName();
+ landmarks->addGroup(groupName, this->generateNewColor(), s_DEFAULT_POINT_SIZE);
+
+ this->addGroup(groupName);
+
+ auto sig = landmarks->signal< ::fwData::Landmarks::GroupAddedSignalType >(
+ ::fwData::Landmarks::s_GROUP_ADDED_SIG);
+
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_ADD_GROUP_SLOT)));
+ sig->asyncEmit(groupName);
+ }
+ }
+ else // Advanced mode and a point or a group is selected.
+ {
+ const int topLevelIndex = m_treeWidget->indexOfTopLevelItem(item);
+
+ if(topLevelIndex == -1) // Point selected, add new point to parent group.
+ {
+ item = item->parent();
+ }
+ groupName = item->text(0).toStdString();
+ }
+
+ landmarks->addPoint(groupName, newPoint);
+ this->addPoint(groupName);
+
+ auto sig =
+ landmarks->signal< ::fwData::Landmarks::PointAddedSignalType >(::fwData::Landmarks::s_POINT_ADDED_SIG);
+
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_ADD_POINT_SLOT)));
+ sig->asyncEmit(groupName);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::addPoint(std::string groupName)
+{
+ if(m_advancedMode)
+ {
+ m_treeWidget->blockSignals(true);
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ QTreeWidgetItem* item = getGroupItem(groupName);
+
+ const size_t nbChilds = static_cast(item->childCount());
+ const size_t nbPoints = landmarks->getNumberOfPoints(groupName);
+ for(size_t idx = nbChilds; idx < nbPoints; ++idx)
+ {
+ const ::fwData::Landmarks::PointType& newPoint = landmarks->getPoint(groupName, idx);
+
+ QTreeWidgetItem* pt = new QTreeWidgetItem();
+ for(int i = 0; i < 3; ++i)
+ {
+ pt->setText(i, QString::fromStdString(std::to_string(newPoint[static_cast(i)])));
+ }
+ item->addChild(pt);
+ }
+
+ m_treeWidget->blockSignals(false);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::addGroup(std::string name)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const auto& group = landmarks->getGroup(name);
+
+ QTreeWidgetItem* item = new QTreeWidgetItem();
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ item->setData(0, s_GROUP_NAME_ROLE, QString::fromStdString(name));
+
+ m_treeWidget->addTopLevelItem(item);
+
+ item->setText(0, QString::fromStdString(name));
+ QPushButton* button = new QPushButton();
+
+ const QColor color = convertToQColor(group.m_color);
+
+ setColorButtonIcon(button, color);
+ button->setProperty("color", color);
+ button->setProperty(s_GROUP_PROPERTY_NAME, QString::fromStdString(name));
+
+ QObject::connect(button, &QPushButton::clicked, this, &SLandmarks::onColorButton);
+
+ m_treeWidget->setItemWidget(item, 1, button);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::removeGroup(std::string name)
+{
+ QTreeWidgetItem* item = getGroupItem(name);
+
+ while(item->childCount() != 0)
+ {
+ item->removeChild(item->child(0));
+ }
+ const int index = m_treeWidget->indexOfTopLevelItem(item);
+ QTreeWidgetItem* topItem = m_treeWidget->takeTopLevelItem(index);
+ delete topItem;
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::removePoint(std::string groupName, size_t index)
+{
+ m_treeWidget->blockSignals(true);
+
+ QTreeWidgetItem* item = getGroupItem(groupName);
+
+ OSLM_ASSERT("Index must be less than " << item->childCount(), static_cast(index) < item->childCount());
+
+ QTreeWidgetItem* pointItem = item->child(static_cast(index));
+ item->removeChild(pointItem);
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::renameGroup(std::string oldName, std::string newName)
+{
+ m_treeWidget->blockSignals(true);
+
+ QString qtNewName = QString::fromStdString(newName);
+ QTreeWidgetItem* item = getGroupItem(oldName);
+ item->setData(0, s_GROUP_NAME_ROLE, qtNewName);
+ QWidget* widget = m_treeWidget->itemWidget(item, 1);
+ widget->setProperty(s_GROUP_PROPERTY_NAME, qtNewName);
+
+ item->setText(0, qtNewName);
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::modifyGroup(std::string name)
+{
+ QTreeWidgetItem* item = getGroupItem(name);
+
+ item->setText(0, name.c_str());
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name);
+
+ QPushButton* colorButton = dynamic_cast< QPushButton* >(m_treeWidget->itemWidget(item, 1));
+
+ const QColor color = convertToQColor(group.m_color);
+
+ setColorButtonIcon(colorButton, color);
+
+ bool groupSelected = item->isSelected();
+
+ if(m_advancedMode) // Check if a child is selected.
+ {
+ for(int i = 0; i < item->childCount() && !groupSelected; ++i)
+ {
+ groupSelected = item->child(i)->isSelected();
+ }
+ }
+
+ if(groupSelected)
+ {
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name);
+
+ // Set widget values
+ m_sizeSlider->setValue(static_cast(group.m_size));
+ m_visibilityCheckbox->setChecked(group.m_visibility);
+
+ QString shapeText = group.m_shape == ::fwData::Landmarks::Shape::CUBE ? "Cube" : "Sphere";
+ m_shapeSelector->setCurrentText(shapeText);
+
+ float transparency = group.m_color[3];
+ m_transparencySlider->setValue(static_cast(transparency * m_transparencySlider->maximum()));
+ }
+
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::modifyPoint(std::string groupName, size_t index)
+{
+ if( m_advancedMode )
+ {
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ auto itemList = m_treeWidget->findItems(QString::fromStdString(groupName), Qt::MatchExactly);
+
+ SLM_ASSERT("Only a single item can be named '" + groupName + "'", itemList.size() == 1);
+
+ QTreeWidgetItem* item = itemList.at(0);
+
+ OSLM_ASSERT("Index must be less than " << item->childCount(), static_cast(index) < item->childCount());
+
+ QTreeWidgetItem* pointItem = item->child(static_cast(index));
+ const ::fwData::Landmarks::PointType& point = landmarks->getPoint(groupName, index);
+
+ m_treeWidget->blockSignals(true);
+ for(int i = 0; i < 3; ++i)
+ {
+ pointItem->setText(i, QString("%1").arg(point[static_cast(i)]));
+ }
+ m_treeWidget->blockSignals(false);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::selectPoint(std::string groupName, size_t index)
+{
+ m_treeWidget->blockSignals(true);
+
+ QTreeWidgetItem* currentItem = getGroupItem(groupName);
+
+ if(m_advancedMode)
+ {
+ OSLM_ASSERT(
+ "Index must be less than " << currentItem->childCount(),
+ static_cast(index) < currentItem->childCount());
+
+ currentItem = currentItem->child(static_cast(index));
+ }
+ m_treeWidget->setCurrentItem(currentItem);
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(groupName);
+
+ // Set widget values
+ m_sizeSlider->setValue(static_cast(group.m_size));
+ m_visibilityCheckbox->setChecked(group.m_visibility);
+
+ const QString shapeText = group.m_shape == ::fwData::Landmarks::Shape::CUBE ? "Cube" : "Sphere";
+ m_shapeSelector->setCurrentText(shapeText);
+
+ float transparency = group.m_color[3];
+ m_transparencySlider->setValue(static_cast(transparency * m_transparencySlider->maximum()));
+
+ m_groupEditorWidget->show();
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::deselectPoint(std::string, size_t)
+{
+ m_treeWidget->blockSignals(true);
+ m_treeWidget->setCurrentItem(nullptr);
+ m_groupEditorWidget->hide();
+ m_treeWidget->blockSignals(false);
+}
+
+//------------------------------------------------------------------------------
+
+std::string SLandmarks::generateNewGroupName() const
+{
+ static size_t groupCount = 0;
+
+ ::fwData::Landmarks::sptr landmarks = this->getInOut< ::fwData::Landmarks >(s_LANDMARKS_INOUT);
+
+ ::fwData::Landmarks::GroupNameContainer groupNames = landmarks->getGroupNames();
+
+ const std::string newGroupNamePrefix = m_advancedMode ? "Group_" : "Point_";
+
+ while(std::find(groupNames.begin(), groupNames.end(),
+ newGroupNamePrefix + std::to_string(groupCount)) != groupNames.end())
+ {
+ ++groupCount;
+ }
+
+ return newGroupNamePrefix + std::to_string(groupCount);
+}
+
+//------------------------------------------------------------------------------
+
+std::array SLandmarks::generateNewColor()
+{
+ std::array color = {{rand()%255/255.f, rand()%255/255.f, rand()%255/255.f, 1.f}};
+ return color;
+}
+
+//------------------------------------------------------------------------------
+
+bool SLandmarks::currentSelection(std::string& selection) const
+{
+ QTreeWidgetItem* item = m_treeWidget->currentItem();
+
+ const bool selectedGroup = (item != nullptr);
+
+ if(selectedGroup)
+ {
+ const int topLevelIndex = m_treeWidget->indexOfTopLevelItem(item);
+
+ if(m_advancedMode && topLevelIndex == -1)
+ {
+ item = item->parent();
+ }
+
+ selection = item->text(0).toStdString();
+ }
+
+ return selectedGroup;
+}
+
+//------------------------------------------------------------------------------
+
+QColor SLandmarks::convertToQColor(const ::fwData::Landmarks::ColorType& color)
+{
+ return QColor(
+ static_cast(color[0]*255),
+ static_cast(color[1]*255),
+ static_cast(color[2]*255),
+ static_cast(color[3]*255)
+ );
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::setColorButtonIcon(QPushButton* button, const QColor& color)
+{
+ const int iconSize = button->style()->pixelMetric(QStyle::PM_LargeIconSize);
+ QPixmap pix(iconSize, iconSize);
+ pix.fill(color);
+
+ button->setIcon(QIcon(pix));
+}
+
+//------------------------------------------------------------------------------
+
+QTreeWidgetItem* SLandmarks::getGroupItem(const std::string& groupName) const
+{
+ const auto itemList = m_treeWidget->findItems(QString::fromStdString(groupName), Qt::MatchExactly);
+
+ SLM_ASSERT("Only a single item can be named '" + groupName + "'", itemList.size() == 1);
+
+ return itemList.at(0);
+}
+
+//------------------------------------------------------------------------------
+
+::fwServices::IService::KeyConnectionsMap SLandmarks::getAutoConnections() const
+{
+ KeyConnectionsMap connections;
+
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_MODIFIED_SIG, s_UPDATE_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_POINT_ADDED_SIG, s_ADD_POINT_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_POINT_MODIFIED_SIG, s_MODIFY_POINT_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_POINT_SELECTED_SIG, s_SELECT_POINT_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_POINT_DESELECTED_SIG, s_DESELECT_POINT_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_GROUP_ADDED_SIG, s_ADD_GROUP_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_GROUP_REMOVED_SIG, s_REMOVE_GROUP_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_POINT_REMOVED_SIG, s_REMOVE_POINT_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_GROUP_MODIFIED_SIG, s_MODIFY_GROUP_SLOT);
+ connections.push(s_LANDMARKS_INOUT, ::fwData::Landmarks::s_GROUP_RENAMED_SIG, s_RENAME_GROUP_SLOT);
+
+ return connections;
+}
+
+} // namespace editor
+} // namespace uiMeasurementQt
+
diff --git a/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/ImageLandmarks.hpp b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/ImageLandmarks.hpp
deleted file mode 100644
index 8ed81581f..000000000
--- a/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/ImageLandmarks.hpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2016.
- * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
- * published by the Free Software Foundation.
- * ****** END LICENSE BLOCK ****** */
-
-#ifndef __VISUVTKADAPTOR_IMAGELANDMARKS_HPP__
-#define __VISUVTKADAPTOR_IMAGELANDMARKS_HPP__
-
-#include "visuVTKAdaptor/config.hpp"
-
-#include
-
-
-class vtkCommand;
-
-namespace visuVTKAdaptor
-{
-
-
-/**
- * @brief Adaptor for landmarks in the field of an image.
- *
- * Registers a ::fwData::PointList in to the generic scene for the landmarks in the given Image
- *
- * @section Slots Slots
- * - \b updateLandmaks() : Updates the rendering on the scene
- * - \b updateLandmaksField() : Tests if the added field is a landmark image type and updates the rendering accordingly.
- * @section XML XML Configuration
- *
- * @code{.xml}
-
-
-
- @endcode
- *
- */
-class VISUVTKADAPTOR_CLASS_API ImageLandmarks : public ::fwRenderVTK::IVtkAdaptorService
-{
-
-public:
-
- fwCoreServiceClassDefinitionsMacro ( (ImageLandmarks)(::fwRenderVTK::IVtkAdaptorService) );
-
- VISUVTKADAPTOR_API ImageLandmarks() throw();
-
- VISUVTKADAPTOR_API virtual ~ImageLandmarks() throw();
-
- VISUVTKADAPTOR_API virtual void show(bool b = true);
-
- /**
- * @brief Returns proposals to connect service slots to associated object signals,
- * this method is used for obj/srv auto connection
- *
- * Connect Image::s_LANDMARK_ADDED_SIG to this::s_UPDATE_LANDMARKS_SLOT
- * Connect Image::s_LANDMARK_REMOVED_SIG to this::s_UPDATE_LANDMARKS_SLOT
- * Connect Image::s_LANDMARK_DISPLAYED_SIG to this::s_UPDATE_LANDMARKS_SLOT
- */
- VISUVTKADAPTOR_API virtual KeyConnectionsType getObjSrvConnections() const;
-
-protected:
-
- VISUVTKADAPTOR_API void doStart() throw(fwTools::Failed);
- VISUVTKADAPTOR_API void doStop() throw(fwTools::Failed);
-
- VISUVTKADAPTOR_API void doConfigure() throw(fwTools::Failed);
- VISUVTKADAPTOR_API void doSwap() throw(fwTools::Failed);
- VISUVTKADAPTOR_API void doUpdate() throw(fwTools::Failed);
-
- std::list< ::fwRenderVTK::IVtkAdaptorService::sptr > m_subServices;
-
- vtkCommand* m_rightButtonCommand;
-
- bool m_needSubservicesDeletion;
-
-private:
-
- /// Slot: update landmarks sub-adaptors
- void updateLandmaks();
-
- /// Slot: tests if the added field is a landmark, if it is, updates the vrkPoints.
- void updateLandmaksField(::fwData::Object::FieldsContainerType fieldsContainer);
-
-};
-
-} //namespace visuVTKAdaptor
-
-#endif // __VISUVTKADAPTOR_IMAGELANDMARKS_HPP__
diff --git a/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp
new file mode 100644
index 000000000..23c2ab666
--- /dev/null
+++ b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp
@@ -0,0 +1,177 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#ifndef __VISUVTKADAPTOR_SLANDMARKS_HPP__
+#define __VISUVTKADAPTOR_SLANDMARKS_HPP__
+
+#include "visuVTKAdaptor/config.hpp"
+
+#include
+
+#include
+#include
+
+#include
+
+#include
+#include
+
+class vtkCommand;
+class vtkActor2D;
+
+namespace visuVTKAdaptor
+{
+
+/**
+ * @brief Adaptor for landmarks in the field of an image.
+ *
+ * Registers a ::fwData::PointList in to the generic scene for the landmarks in the given Image
+ *
+ * @section Slots Slots
+ * - \b addPoint(groupName): add the new point in the scene
+ * - \b insertPoint(groupName, index): add the new point in the scene
+ * - \b removePoint(groupName, index): remove the point from the scene
+ * - \b modifyGroup(groupName): modify the landmarks color, label, visibility, ...
+ * - \b removeGroup(groupName): remove the group's landmarks from the scene
+ * - \b addGroup(groupName): add group's landmarks to the scene
+ * - \b modifyPoint(groupName, index): modify point position
+ * - \b renameGroup(oldName, newName): update the label with the new name
+ * - \b selectPoint(groupName, index): select the point (blink from point color to green)
+ * - \b deselectPoint(groupName, index): deselect the point (reset current color)
+ * - \b show(bool): show or hide the landmarks
+ *
+ * @section XML XML Configuration
+ *
+ * @code{.xml}
+
+
+
+ @endcode
+ *
+ */
+class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorService
+{
+
+public:
+
+ fwCoreServiceClassDefinitionsMacro( (SLandmarks)(::fwRenderVTK::IVtkAdaptorService) );
+ fwCoreAllowSharedFromThis();
+
+ /// Widget used to display and interact with landmarks.
+ typedef vtkSmartPointer< vtkHandleWidget > LandmarkWidgetType;
+ typedef vtkSmartPointer< vtkActor2D > LabelActorType;
+
+ VISUVTKADAPTOR_API SLandmarks() throw();
+
+ VISUVTKADAPTOR_API virtual ~SLandmarks() throw();
+
+ VISUVTKADAPTOR_API virtual void show(bool b = true);
+
+ /**
+ * @brief Returns proposals to connect service slots to associated object signals,
+ * this method is used for obj/srv auto connection
+ *
+ * Connect Image::s_LANDMARK_ADDED_SIG to this::s_UPDATE_LANDMARKS_SLOT
+ * Connect Image::s_LANDMARK_REMOVED_SIG to this::s_UPDATE_LANDMARKS_SLOT
+ * Connect Image::s_LANDMARK_DISPLAYED_SIG to this::s_UPDATE_LANDMARKS_SLOT
+ */
+ VISUVTKADAPTOR_API virtual KeyConnectionsType getObjSrvConnections() const;
+
+ /// Deselect the current point and emit the corresponding Landmarks signal
+ void deselect();
+
+protected:
+
+ VISUVTKADAPTOR_API void doStart() throw(fwTools::Failed);
+ VISUVTKADAPTOR_API void doStop() throw(fwTools::Failed);
+
+ VISUVTKADAPTOR_API void doConfigure() throw(fwTools::Failed);
+ VISUVTKADAPTOR_API void doSwap() throw(fwTools::Failed);
+ VISUVTKADAPTOR_API void doUpdate() throw(fwTools::Failed);
+
+private:
+
+ /// Stores a group of widgets.
+ typedef std::vector< LandmarkWidgetType > LandmarksWidgetContainerType;
+
+ /// Maps group names to widget groups.
+ typedef std::map< std::string, LandmarksWidgetContainerType > GroupWidgetsMapType;
+
+ /// Maps Landmarks widget to labels
+ typedef std::map< LandmarkWidgetType, LabelActorType > WidgetLabelMapType;
+
+ /// Maps Landmarks widget to its vtkCommand
+ typedef std::map< LandmarkWidgetType, vtkCommand* > WidgetCommandMapType;
+
+ typedef std::pair< std::string, size_t > PointPairType;
+
+ /// Slot: called when a new point is appended to the group.
+ void addPoint(std::string groupName);
+
+ /// Slot: called when a landmark is inserted inside a group.
+ void insertPoint(std::string groupName, size_t index);
+
+ /// Slot: called when a landmark is removed.
+ void removePoint(std::string groupName, size_t index);
+
+ /// Slot: called when a group attribute (other than it's points) is modified.
+ void modifyGroup(std::string groupName);
+
+ /// Slot: called when a group has been removed.
+ void removeGroup(std::string groupName);
+
+ /// Slot: called when a new landmark group is created.
+ void addGroup(std::string groupName);
+
+ /// Slot: called when a point is modified
+ void modifyPoint(std::string groupName, size_t index);
+
+ /// Slot: called when a group is renamed
+ void renameGroup(std::string oldName, std::string newName);
+
+ /// Slot: called when a point is selected
+ void selectPoint(std::string groupName, size_t index);
+
+ /// Slot: called when a point is deselected
+ void deselectPoint(std::string groupName, size_t index);
+
+ /// Switch color for selected point: (even: green, odd: point default color). Called by the timer
+ void changeColor(const vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D >& rep,
+ const std::array& color1, const std::array& color2);
+
+ /// Remove all the points from the scene
+ void clearLandmarks();
+
+ /// Creates a new handle configured with it's group attributes and it's position.
+ vtkSmartPointer newHandle(const ::fwData::Landmarks::sptr& landmarks,
+ const std::string& groupName,
+ size_t pointIndex);
+
+ /// command to listen left click outside landmarks to deselect them
+ vtkCommand* m_noSelectionCommand;
+
+ /// Structure holding all widgets groups and mapping them to their names.
+ GroupWidgetsMapType m_handles;
+
+ /// Structure to associate widgets to label
+ WidgetLabelMapType m_labels;
+
+ /// Structure to associate widgets to vtkCommand
+ WidgetCommandMapType m_commands;
+
+ /// Timer used to blink selected point
+ ::fwThread::Timer::sptr m_timer;
+
+ /// Selected point information (groupName, index)
+ PointPairType m_selectedPoint;
+
+ /// Counter to switch color for selected point: (even: green, odd: point default color)
+ size_t m_count;
+};
+
+} //namespace visuVTKAdaptor
+
+#endif // __VISUVTKADAPTOR_SLANDMARKS_HPP__
diff --git a/Bundles/LeafVisu/visuVTKAdaptor/rc/plugin.xml b/Bundles/LeafVisu/visuVTKAdaptor/rc/plugin.xml
index d72a9ad53..7117f9d3c 100644
--- a/Bundles/LeafVisu/visuVTKAdaptor/rc/plugin.xml
+++ b/Bundles/LeafVisu/visuVTKAdaptor/rc/plugin.xml
@@ -98,8 +98,8 @@
::fwRenderVTK::IVtkAdaptorService
- ::visuVTKAdaptor::ImageLandmarks
-
+ ::visuVTKAdaptor::SLandmarks
+
diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/ImageLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/ImageLandmarks.cpp
deleted file mode 100644
index 2bdb2d54f..000000000
--- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/ImageLandmarks.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2016.
- * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
- * published by the Free Software Foundation.
- * ****** END LICENSE BLOCK ****** */
-
-#include "visuVTKAdaptor/ImageLandmarks.hpp"
-
-#include "visuVTKAdaptor/PointLabel.hpp"
-#include "visuVTKAdaptor/PointList.hpp"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-fwServicesRegisterMacro( ::fwRenderVTK::IVtkAdaptorService, ::visuVTKAdaptor::ImageLandmarks, ::fwData::Image );
-
-namespace visuVTKAdaptor
-{
-
-static const ::fwCom::Slots::SlotKeyType s_UPDATE_LANDMARKS_SLOT = "updateLandmaks";
-static const ::fwCom::Slots::SlotKeyType s_UPDATE_LANDMARKS_FIELD_SLOT = "updateLandmarksField";
-
-//------------------------------------------------------------------------------
-
-void notifyRemoveLandMark( ::fwData::Image::sptr image, ::fwServices::IService* _service, ::fwData::Point::sptr point )
-{
- SLM_ASSERT("NULL Service", _service);
-
- ::fwData::PointList::sptr pointList = image->getField< ::fwData::PointList >(
- ::fwDataTools::fieldHelper::Image::m_imageLandmarksId );
-
- auto sig =
- pointList->signal< ::fwData::PointList::PointRemovedSignalType >(::fwData::PointList::s_POINT_REMOVED_SIG);
- sig->asyncEmit(point);
-
- auto sigImg = image->signal< ::fwData::Image::LandmarkRemovedSignalType >(
- ::fwData::Image::s_LANDMARK_REMOVED_SIG );
- sigImg->asyncEmit(point);
-}
-
-//------------------------------------------------------------------------------
-
-class vtkPointDeleteCallBack : public vtkCommand
-{
-
-public:
- static vtkPointDeleteCallBack* New( ::fwRenderVTK::IVtkAdaptorService* service)
- {
- return new vtkPointDeleteCallBack(service);
- }
-
- vtkPointDeleteCallBack( ::fwRenderVTK::IVtkAdaptorService* service )
- : m_service(service),
- m_picker( vtkCellPicker::New() ),
- m_propCollection( vtkPropCollection::New() )
- {
- m_lastPos[0] = -1;
- m_lastPos[1] = -1;
- m_picker->PickFromListOn();
- m_picker->SetTolerance(0.001);
-
- m_display[2] = 0.0;
- }
-
- ~vtkPointDeleteCallBack( )
- {
- m_picker->Delete();
- m_picker = NULL;
-
- m_propCollection->Delete();
- m_propCollection = NULL;
- }
-
-
- void fillPickList()
- {
- m_picker->InitializePickList();
- m_propCollection->RemoveAllItems();
- m_service->getAllSubProps(m_propCollection);
- m_propCollection->InitTraversal();
-
- vtkProp* prop;
-
- while ( (prop = m_propCollection->GetNextProp()) )
- {
- m_picker->AddPickList(prop);
- }
- }
-
- virtual void Execute( vtkObject* caller, unsigned long eventId, void*)
- {
- int pos[2];
- m_service->getInteractor()->GetLastEventPosition(pos);
- OSLM_TRACE( "EventId: " << eventId);
-
- if ( eventId == vtkCommand::RightButtonPressEvent )
- {
- std::copy(pos, pos+1, m_lastPos);
- m_display[0] = pos[0];
- m_display[1] = pos[1];
-
- this->fillPickList();
- if (m_picker->Pick( m_display, m_service->getRenderer() ) )
- {
- if(getSelectedPoint())
- {
- SetAbortFlag(1);
- }
- else
- {
- m_pickedPoint.reset();
- m_pickedPointList.reset();
- }
- }
- }
- else if ( (eventId == vtkCommand::RightButtonReleaseEvent ) && !m_pickedPoint.expired() &&
- !m_pickedPointList.expired() && std::equal(pos, pos+1, m_lastPos) )
- {
- ::fwData::Image::sptr image = m_service->getObject< ::fwData::Image >();
- ::fwData::PointList::PointListContainer::iterator itr = std::find(
- m_pickedPointList.lock()->getRefPoints().begin(),
- m_pickedPointList.lock()->getRefPoints().end(), m_pickedPoint.lock() );
- if(itr != m_pickedPointList.lock()->getRefPoints().end())
- {
- ::fwData::Point::sptr point = *itr;
- m_pickedPointList.lock()->getRefPoints().erase(itr);
- notifyRemoveLandMark(image, m_service, point);
- }
- }
- }
- bool getSelectedPoint()
- {
- bool isFind = false;
- vtkPropCollection* propc = m_picker->GetActors();
- vtkProp* prop;
-
- propc->InitTraversal();
- while ( (prop = propc->GetNextProp()) )
- {
- m_pickedPoint = ::fwData::Point::dynamicCast(m_service->getAssociatedObject(prop,2));
- m_pickedPointList = ::fwData::PointList::dynamicCast(m_service->getAssociatedObject(prop,1));
-
- if( !m_pickedPoint.expired() && !m_pickedPointList.expired() )
- {
- ::fwData::PointList::PointListContainer::iterator itr = std::find(
- m_pickedPointList.lock()->getRefPoints().begin(),
- m_pickedPointList.lock()->getRefPoints().end(), m_pickedPoint.lock());
- if(itr != m_pickedPointList.lock()->getRefPoints().end() )
- {
- isFind = true;
- break;
- }
- }
- }
- return isFind;
- }
-
-protected:
- ::fwRenderVTK::IVtkAdaptorService *m_service;
- vtkPicker* m_picker;
- vtkPropCollection* m_propCollection;
- double m_display[3];
- int m_lastPos[2];
- ::fwData::Point::wptr m_pickedPoint;
- ::fwData::PointList::wptr m_pickedPointList;
-
-};
-
-//------------------------------------------------------------------------------
-
-ImageLandmarks::ImageLandmarks() throw() :
- m_rightButtonCommand(nullptr),
- m_needSubservicesDeletion(false)
-{
- newSlot(s_UPDATE_LANDMARKS_SLOT, &ImageLandmarks::updateLandmaks, this);
- newSlot(s_UPDATE_LANDMARKS_FIELD_SLOT, &ImageLandmarks::updateLandmaksField, this);
-}
-
-//------------------------------------------------------------------------------
-
-ImageLandmarks::~ImageLandmarks() throw()
-{
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::doConfigure() throw(fwTools::Failed)
-{
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::doStart() throw(fwTools::Failed)
-{
- SLM_TRACE_FUNC();
-
- m_rightButtonCommand = vtkPointDeleteCallBack::New(this);
- this->getInteractor()->AddObserver( "RightButtonPressEvent", m_rightButtonCommand, 1 );
- this->getInteractor()->AddObserver( "RightButtonReleaseEvent", m_rightButtonCommand, 1 );
-
- this->doUpdate();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::doSwap() throw(fwTools::Failed)
-{
- SLM_TRACE("SWAPPING ImageLandmarks **TODO**");
- this->doStop();
- this->doStart();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::doUpdate() throw(fwTools::Failed)
-{
- // get PointList in image Field then install distance service if required
- ::fwData::Image::sptr image = this->getObject< ::fwData::Image >();
-
- ::fwData::PointList::sptr landmarks;
- bool isShown;
- landmarks = image->getField< ::fwData::PointList >( ::fwDataTools::fieldHelper::Image::m_imageLandmarksId );
- isShown = image->getField("ShowLandmarks", ::fwData::Boolean::New(true))->value();
-
- if (!isShown || !landmarks || m_needSubservicesDeletion)
- {
- this->unregisterServices();
- m_needSubservicesDeletion = false;
- }
-
- if( isShown && landmarks )
- {
- if ( !landmarks->getPoints().empty() )
- {
- ::fwRenderVTK::IVtkAdaptorService::sptr servicePointList;
- servicePointList = ::fwServices::add< ::fwRenderVTK::IVtkAdaptorService >( landmarks,
- "::visuVTKAdaptor::PointList");
- SLM_ASSERT("servicePointList not instanced", servicePointList);
-
- servicePointList->setPickerId( this->getPickerId() );
- servicePointList->setRenderService( this->getRenderService() );
- servicePointList->setAutoRender( this->getAutoRender() );
- servicePointList->start();
-
- this->registerService( servicePointList );
-
-
- for( ::fwData::Point::sptr point : landmarks->getRefPoints() )
- {
- ::fwRenderVTK::IVtkAdaptorService::sptr serviceLabel;
- serviceLabel = ::fwServices::add< ::fwRenderVTK::IVtkAdaptorService >(point,
- "::visuVTKAdaptor::PointLabel");
- SLM_ASSERT("serviceLabel not instanced", serviceLabel);
- serviceLabel->setRenderService( this->getRenderService() );
- serviceLabel->setAutoRender( this->getAutoRender() );
- serviceLabel->start();
- this->registerService( serviceLabel );
- }
- }
- }
- this->setVtkPipelineModified();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::updateLandmaks()
-{
- m_needSubservicesDeletion = true; // to manage point deletion
- this->updating();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::updateLandmaksField(::fwData::Object::FieldsContainerType fieldsContainer)
-{
- auto landmarkFound = fieldsContainer.find(::fwDataTools::fieldHelper::Image::m_imageLandmarksId);
-
- if( landmarkFound != fieldsContainer.end())
- {
- m_needSubservicesDeletion = true; // to manage point deletion
- this->updating();
- }
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::doStop() throw(fwTools::Failed)
-{
- if ( m_rightButtonCommand ) // can be not instanciated (use of ImageLandmarks::show() )
- {
- this->getInteractor()->RemoveObserver(m_rightButtonCommand);
- m_rightButtonCommand->Delete();
- m_rightButtonCommand = 0;
- }
-
- this->unregisterServices();
-}
-
-//------------------------------------------------------------------------------
-
-void ImageLandmarks::show(bool b)
-{
- if (b)
- {
- this->doStart();
- }
- else
- {
- this->doStop();
- }
-}
-
-//------------------------------------------------------------------------------
-
-::fwServices::IService::KeyConnectionsType ImageLandmarks::getObjSrvConnections() const
-{
- KeyConnectionsType connections;
- connections.push_back( std::make_pair( ::fwData::Image::s_LANDMARK_ADDED_SIG, s_UPDATE_LANDMARKS_SLOT ) );
- connections.push_back( std::make_pair( ::fwData::Image::s_LANDMARK_REMOVED_SIG, s_UPDATE_LANDMARKS_SLOT ) );
- connections.push_back( std::make_pair( ::fwData::Image::s_LANDMARK_DISPLAYED_SIG, s_UPDATE_LANDMARKS_SLOT ) );
- connections.push_back( std::make_pair( ::fwData::Image::s_ADDED_FIELDS_SIG, s_UPDATE_LANDMARKS_FIELD_SLOT ) );
-
- return connections;
-}
-
-//------------------------------------------------------------------------------
-
-} //namespace visuVTKAdaptor
diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp
new file mode 100644
index 000000000..9b20319b2
--- /dev/null
+++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp
@@ -0,0 +1,760 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#include "visuVTKAdaptor/SLandmarks.hpp"
+
+#include "visuVTKAdaptor/PointLabel.hpp"
+#include "visuVTKAdaptor/PointList.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+fwServicesRegisterMacro( ::fwRenderVTK::IVtkAdaptorService, ::visuVTKAdaptor::SLandmarks, ::fwData::Landmarks );
+
+namespace visuVTKAdaptor
+{
+
+static const ::fwCom::Slots::SlotKeyType s_ADD_POINT_SLOT = "addPoint";
+static const ::fwCom::Slots::SlotKeyType s_INSERT_POINT_SLOT = "insertPoint";
+static const ::fwCom::Slots::SlotKeyType s_REMOVE_POINT_SLOT = "removePoint";
+static const ::fwCom::Slots::SlotKeyType s_ADD_GROUP_SLOT = "addGroup";
+static const ::fwCom::Slots::SlotKeyType s_REMOVE_GROUP_SLOT = "removeGroup";
+static const ::fwCom::Slots::SlotKeyType s_MODIFY_GROUP_SLOT = "modifyGroup";
+static const ::fwCom::Slots::SlotKeyType s_MODIFY_POINT_SLOT = "modifyPoint";
+static const ::fwCom::Slots::SlotKeyType s_RENAME_GROUP_SLOT = "renameGroup";
+static const ::fwCom::Slots::SlotKeyType s_SELECT_POINT_SLOT = "selectPoint";
+static const ::fwCom::Slots::SlotKeyType s_DESELECT_POINT_SLOT = "deselectPoint";
+static const ::fwCom::Slots::SlotKeyType s_SHOW_SLOT = "show";
+
+//------------------------------------------------------------------------------
+
+class vtkLandmarkUpdateCallBack : public vtkCommand
+{
+
+public:
+
+//------------------------------------------------------------------------------
+
+ static vtkLandmarkUpdateCallBack* New( ::fwData::Landmarks::sptr landmarks,
+ const ::fwCom::SlotBase::sptr& pointModifiedSlot,
+ const std::string& groupName,
+ size_t pointIndex,
+ vtkAbstractPropPicker* picker,
+ vtkRenderer* renderer,
+ SLandmarks::LabelActorType& labelActor)
+ {
+ return new vtkLandmarkUpdateCallBack(landmarks, pointModifiedSlot, groupName, pointIndex, picker, renderer,
+ labelActor);
+ }
+
+//------------------------------------------------------------------------------
+
+ vtkLandmarkUpdateCallBack( ::fwData::Landmarks::sptr landmarks,
+ const ::fwCom::SlotBase::sptr& pointModifiedSlot,
+ const std::string& groupName,
+ size_t pointIndex,
+ vtkAbstractPropPicker* picker,
+ vtkRenderer* renderer,
+ SLandmarks::LabelActorType& labelActor) :
+ m_landmarks(landmarks),
+ m_pointModifiedSlot(pointModifiedSlot),
+ m_groupName(groupName),
+ m_pointIndex(pointIndex),
+ m_picker(picker),
+ m_renderer(renderer),
+ m_labelActor(labelActor)
+ {
+ }
+
+//------------------------------------------------------------------------------
+
+ void updateInfo(const std::string& groupName, size_t pointIndex)
+ {
+ m_groupName = groupName;
+ m_pointIndex = pointIndex;
+ }
+
+//------------------------------------------------------------------------------
+
+ virtual void Execute( vtkObject* caller, unsigned long eventId, void*)
+ {
+ vtkHandleWidget* handler = vtkHandleWidget::SafeDownCast(caller);
+ if (!handler)
+ {
+ return;
+ }
+
+ if ( eventId == vtkCommand::StartInteractionEvent)
+ {
+ handler->AddObserver(vtkCommand::EndInteractionEvent, this );
+ handler->AddObserver(vtkCommand::InteractionEvent, this );
+
+ }
+ else if ( eventId == vtkCommand::EndInteractionEvent )
+ {
+ handler->RemoveObservers(vtkCommand::EndInteractionEvent, this );
+ handler->RemoveObservers(vtkCommand::InteractionEvent, this );
+ }
+
+ vtkHandleRepresentation* representation = handler->GetHandleRepresentation();
+ SLM_ASSERT("handler not instanced", handler);
+ double* world = representation->GetWorldPosition();
+
+ if ( eventId == vtkCommand::InteractionEvent)
+ {
+ double display[3];
+ int x, y;
+ handler->GetInteractor()->GetLastEventPosition(x, y);
+ display[0] = x;
+ display[1] = y;
+ display[2] = 0;
+
+ if ( m_picker && m_picker->Pick( display, m_renderer ) )
+ {
+ ::fwRenderVTK::vtk::getNearestPickedPosition(m_picker, m_renderer, world);
+ }
+
+ auto& point = m_landmarks->getPoint(m_groupName, m_pointIndex);
+ std::copy( world, world+3, point.begin() );
+
+ representation->SetWorldPosition(world);
+ m_labelActor->GetPositionCoordinate()->SetValue(world);
+
+ auto sig = m_landmarks->signal< ::fwData::Landmarks::PointModifiedSigType >
+ ( ::fwData::Landmarks::s_POINT_MODIFIED_SIG );
+ {
+ ::fwCom::Connection::Blocker block(sig->getConnection(m_pointModifiedSlot));
+ sig->asyncEmit(m_groupName, m_pointIndex);
+ }
+ }
+ else if (eventId == vtkCommand::StartInteractionEvent)
+ {
+ auto sig = m_landmarks->signal< ::fwData::Landmarks::PointSelectedSignalType >
+ (::fwData::Landmarks::s_POINT_SELECTED_SIG);
+ sig->asyncEmit(m_groupName, m_pointIndex);
+ }
+ }
+
+protected:
+
+ ::fwData::Landmarks::sptr m_landmarks;
+
+ const ::fwCom::SlotBase::sptr m_pointModifiedSlot;
+
+ std::string m_groupName;
+
+ size_t m_pointIndex;
+
+ vtkAbstractPropPicker* m_picker;
+
+ vtkRenderer* m_renderer;
+
+ SLandmarks::LabelActorType m_labelActor;
+};
+
+//------------------------------------------------------------------------------
+
+class vtkDeselectLandmarksCallBack : public vtkCommand
+{
+
+public:
+
+//------------------------------------------------------------------------------
+
+ static vtkDeselectLandmarksCallBack* New()
+ {
+ return new vtkDeselectLandmarksCallBack();
+ }
+
+//------------------------------------------------------------------------------
+
+ vtkDeselectLandmarksCallBack()
+ {
+ }
+
+ //------------------------------------------------------------------------------
+
+ void setAdaptor(const SLandmarks::sptr& adaptor)
+ {
+ m_adaptor = adaptor;
+ }
+
+//------------------------------------------------------------------------------
+
+ virtual void Execute( vtkObject* caller, unsigned long eventId, void*)
+ {
+ m_adaptor->deselect();
+ }
+
+protected:
+
+ SLandmarks::sptr m_adaptor;
+};
+
+//------------------------------------------------------------------------------
+
+SLandmarks::SLandmarks() throw() :
+ m_noSelectionCommand(nullptr),
+ m_count(0)
+{
+ this->newSlot(s_ADD_POINT_SLOT, &SLandmarks::addPoint, this);
+ this->newSlot(s_INSERT_POINT_SLOT, &SLandmarks::insertPoint, this);
+ this->newSlot(s_REMOVE_POINT_SLOT, &SLandmarks::removePoint, this);
+ this->newSlot(s_MODIFY_POINT_SLOT, &SLandmarks::modifyPoint, this);
+ this->newSlot(s_ADD_GROUP_SLOT, &SLandmarks::addGroup, this);
+ this->newSlot(s_REMOVE_GROUP_SLOT, &SLandmarks::removeGroup, this);
+ this->newSlot(s_MODIFY_GROUP_SLOT, &SLandmarks::modifyGroup, this);
+ this->newSlot(s_RENAME_GROUP_SLOT, &SLandmarks::renameGroup, this);
+ this->newSlot(s_SELECT_POINT_SLOT, &SLandmarks::selectPoint, this);
+ this->newSlot(s_DESELECT_POINT_SLOT, &SLandmarks::deselectPoint, this);
+ this->newSlot(s_SHOW_SLOT, &SLandmarks::show, this);
+}
+
+//------------------------------------------------------------------------------
+
+SLandmarks::~SLandmarks() throw()
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::doConfigure() throw(fwTools::Failed)
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::doStart() throw(fwTools::Failed)
+{
+ vtkDeselectLandmarksCallBack* callback = vtkDeselectLandmarksCallBack::New();
+ callback->setAdaptor(this->getSptr());
+ m_noSelectionCommand = callback;
+ this->getInteractor()->AddObserver(vtkCommand::RightButtonPressEvent, m_noSelectionCommand);
+ this->getInteractor()->AddObserver(vtkCommand::RightButtonReleaseEvent, m_noSelectionCommand);
+
+ this->doUpdate();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::doSwap() throw(fwTools::Failed)
+{
+ this->doStop();
+ this->doStart();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::doUpdate() throw(fwTools::Failed)
+{
+ this->clearLandmarks();
+
+ ::fwData::Landmarks::csptr landmarks = this->getObject< ::fwData::Landmarks >();
+
+ ::fwData::Landmarks::GroupNameContainer groupNames = landmarks->getGroupNames();
+
+ for(auto& name : groupNames)
+ {
+ this->addGroup(name);
+ }
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::doStop() throw(fwTools::Failed)
+{
+ this->clearLandmarks();
+ if (m_noSelectionCommand)
+ {
+ this->getInteractor()->RemoveObserver(m_noSelectionCommand);
+ m_noSelectionCommand->Delete();
+ m_noSelectionCommand = nullptr;
+ }
+
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::addPoint(std::string groupName)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getObject< ::fwData::Landmarks >();
+
+ for(size_t i = m_handles[groupName].size(); i < landmarks->getNumberOfPoints(groupName); ++i)
+ {
+ auto handle = this->newHandle(landmarks, groupName, i);
+ m_handles[groupName].push_back(handle);
+ }
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::insertPoint(std::string groupName, size_t index)
+{
+ ::fwData::Landmarks::sptr landmarks = this->getObject< ::fwData::Landmarks >();
+
+ auto handle = this->newHandle(landmarks, groupName, index);
+
+ LandmarksWidgetContainerType& landmarkHandleGroup = m_handles[groupName];
+ landmarkHandleGroup.insert(
+ landmarkHandleGroup.begin() + static_cast(index), handle);
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::removePoint(std::string groupName, size_t index)
+{
+ if (m_timer && m_selectedPoint.first == groupName && m_selectedPoint.second == index)
+ {
+ m_timer->stop();
+ m_timer.reset();
+ }
+ LandmarksWidgetContainerType& landmarkHandleGroup = m_handles[groupName];
+
+ auto& handleToRemove = landmarkHandleGroup[index];
+
+ LabelActorType& label = m_labels[handleToRemove];
+ this->getRenderer()->RemoveViewProp(label);
+ label->Delete();
+
+ vtkCommand* command = m_commands[handleToRemove];
+ handleToRemove->RemoveObserver(command);
+ command->Delete();
+
+ handleToRemove->Off();
+ handleToRemove->SetInteractor(nullptr);
+
+ this->m_propCollection->RemoveItem(handleToRemove->GetRepresentation());
+
+ m_commands.erase(handleToRemove);
+ m_labels.erase(handleToRemove);
+ landmarkHandleGroup.erase(landmarkHandleGroup.begin() + static_cast(index));
+
+ for(size_t i = index; i < landmarkHandleGroup.size(); ++i)
+ {
+ auto& handle = landmarkHandleGroup.at(i);
+ vtkLandmarkUpdateCallBack* commandToUpdate = dynamic_cast(m_commands[handle]);
+ commandToUpdate->updateInfo(groupName, i);
+
+ LabelActorType& labelToUpdate = m_labels[handle];
+ vtkSmartPointer textMapper = vtkTextMapper::SafeDownCast(labelToUpdate->GetMapper());
+ const std::string label = groupName + "_" + std::to_string(i);
+ textMapper->SetInput(label.c_str());
+ }
+
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::modifyGroup(std::string groupName)
+{
+ ::fwData::Landmarks::csptr landmarks = this->getObject< ::fwData::Landmarks >();
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(groupName);
+
+ LandmarksWidgetContainerType& landmarkHandleGroup = m_handles[groupName];
+
+ for(auto& handle : landmarkHandleGroup)
+ {
+ const ::fwData::Landmarks::ColorType& color = group.m_color;
+
+ vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D> rep =
+ ::fwRenderVTK::vtk::fwHandleRepresentation3D::SafeDownCast(handle->GetHandleRepresentation());
+
+ if (group.m_shape == ::fwData::Landmarks::Shape::CUBE)
+ {
+ rep->SetShapeRepresentation(::fwRenderVTK::vtk::fwHandleRepresentation3D::CUBE);
+ }
+ else
+ {
+ rep->SetShapeRepresentation(::fwRenderVTK::vtk::fwHandleRepresentation3D::SPHERE);
+ }
+
+ rep->GetSelectedProperty()->SetOpacity(color[3]);
+ rep->GetMarkerProperty()->SetOpacity(color[3]);
+ rep->GetProperty()->SetColor(color[0], color[1], color[2]);
+ rep->GetProperty()->SetOpacity(color[3]);
+ rep->SetHandleSize(group.m_size);
+ rep->SetVisibility(group.m_visibility);
+
+ LabelActorType& textActor = m_labels[handle];
+ vtkSmartPointer textMapper = vtkTextMapper::SafeDownCast(textActor->GetMapper());
+ textMapper->GetTextProperty()->SetColor(color[0], color[1], color[2]);
+ textActor->SetVisibility(group.m_visibility);
+ }
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::removeGroup(std::string groupName)
+{
+ const size_t nbPoints = m_handles[groupName].size();
+
+ // It is more efficient to walk through our vector backwards.
+ // That way we avoid useless label renaming.
+ for(size_t i = nbPoints; i > 0; --i)
+ {
+ this->removePoint(groupName, i - 1);
+ }
+
+ m_handles.erase(groupName);
+
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::addGroup(std::string groupName)
+{
+ const ::fwData::Landmarks::sptr& landmarks = this->getObject< ::fwData::Landmarks >();
+ const size_t ptNumber = landmarks->getNumberOfPoints(groupName);
+
+ for(size_t index = 0; index < ptNumber; ++index)
+ {
+ auto handle = this->newHandle(landmarks, groupName, index);
+ m_handles[groupName].push_back(handle);
+ }
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::modifyPoint(std::string groupName, size_t index)
+{
+ const ::fwData::Landmarks::sptr& landmarks = this->getObject< ::fwData::Landmarks >();
+
+ ::fwData::Landmarks::PointType& point = landmarks->getPoint(groupName, index);
+ LandmarkWidgetType& widget = m_handles.at(groupName).at(index);
+
+ vtkHandleRepresentation* handleRep = vtkHandleRepresentation::SafeDownCast(widget->GetRepresentation());
+ handleRep->SetWorldPosition(point.data());
+
+ LabelActorType textActor = m_labels[widget];
+ textActor->GetPositionCoordinate()->SetValue(point.data());
+
+ this->getRenderer()->ResetCameraClippingRange();
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::renameGroup(std::string oldName, std::string newName)
+{
+ LandmarksWidgetContainerType& landmarkHandleGroup = m_handles[oldName];
+ m_handles.insert(std::make_pair(newName, landmarkHandleGroup));
+
+ size_t count = 0;
+ for(auto& handle : landmarkHandleGroup)
+ {
+ LabelActorType& textActor = m_labels[handle];
+
+ vtkCommand* command = m_commands[handle];
+ vtkLandmarkUpdateCallBack* updateCallback = dynamic_cast(command);
+ SLM_ASSERT("Missing landmark command", updateCallback);
+ updateCallback->updateInfo(newName, count);
+
+ vtkSmartPointer textMapper = vtkTextMapper::SafeDownCast(textActor->GetMapper());
+ const std::string label = newName + "_" + std::to_string(count);
+ textMapper->SetInput(label.c_str());
+ ++count;
+ }
+
+ m_handles.erase(oldName);
+
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::selectPoint(std::string groupName, size_t index)
+{
+ // deselect the current selected point
+ if (m_timer)
+ {
+ this->deselectPoint(m_selectedPoint.first, m_selectedPoint.second);
+ }
+
+ m_selectedPoint.first = groupName;
+ m_selectedPoint.second = index;
+
+ LandmarkWidgetType& widget =
+ m_handles.at(groupName).at(index);
+
+ vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D> rep =
+ ::fwRenderVTK::vtk::fwHandleRepresentation3D::SafeDownCast(widget->GetHandleRepresentation());
+
+ const double* color = rep->GetProperty()->GetColor();
+
+ m_timer = m_associatedWorker->createTimer();
+
+ ::fwThread::Timer::TimeDurationType duration = ::boost::chrono::milliseconds(500);
+
+ const std::array color1 = {{color[0], color[1], color[2]}};
+ const std::array color2 = {{0., 1., 0.}};
+
+ m_count = 0;
+ m_timer->setFunction(std::bind(&SLandmarks::changeColor, this, rep, color1, color2));
+ m_timer->setDuration(duration);
+ m_timer->start();
+
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::deselectPoint(std::string groupName, size_t index)
+{
+ if(m_timer)
+ {
+ m_timer->stop();
+ m_timer.reset();
+ }
+
+ const ::fwData::Landmarks::sptr& landmarks = this->getObject< ::fwData::Landmarks >();
+
+ LandmarkWidgetType& widget = m_handles.at(groupName).at(index);
+
+ vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D> rep =
+ ::fwRenderVTK::vtk::fwHandleRepresentation3D::SafeDownCast(widget->GetHandleRepresentation());
+
+ ::fwData::Landmarks::ColorType& color = landmarks->getGroup(groupName).m_color;
+
+ double castedColour[3] = { static_cast< double >(color[0]),
+ static_cast< double >(color[1]),
+ static_cast< double >(color[2]) };
+
+ rep->GetProperty()->SetColor(castedColour);
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::deselect()
+{
+ if (m_timer)
+ {
+ const ::fwData::Landmarks::csptr& landmarks = this->getObject< ::fwData::Landmarks >();
+
+ this->deselectPoint(m_selectedPoint.first, m_selectedPoint.second);
+ auto sig = landmarks->signal< ::fwData::Landmarks::PointDeselectedSignalType >(
+ ::fwData::Landmarks::s_POINT_DESELECTED_SIG);
+ ::fwCom::Connection::Blocker block(sig->getConnection(this->slot(s_DESELECT_POINT_SLOT)));
+ sig->asyncEmit(m_selectedPoint.first, m_selectedPoint.second);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::changeColor(const vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D >& rep,
+ const std::array& color1, const std::array& color2)
+{
+ std::array color;
+ if (m_count%2 == 0)
+ {
+ color = color2;
+ }
+ else
+ {
+ color = color1;
+ }
+
+ rep->GetProperty()->SetColor(color.data());
+
+ ++m_count;
+ this->setVtkPipelineModified();
+ this->requestRender();
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::clearLandmarks()
+{
+ while (!m_handles.empty())
+ {
+ const std::string name = m_handles.begin()->first;
+ this->removeGroup(name);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+vtkSmartPointer< vtkHandleWidget > SLandmarks::newHandle(const ::fwData::Landmarks::sptr& landmarks,
+ const std::string& groupName,
+ size_t pointIndex)
+{
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(groupName);
+ ::fwData::Landmarks::PointType& point = landmarks->getPoint(groupName, pointIndex);
+
+ vtkSmartPointer< vtkHandleWidget > handle = vtkHandleWidget::New();
+
+ const ::fwData::Landmarks::ColorType& color = group.m_color;
+
+ // TODO add option for cube representation
+ vtkSmartPointer< ::fwRenderVTK::vtk::fwHandleRepresentation3D > pointRep =
+ ::fwRenderVTK::vtk::fwHandleRepresentation3D::New();
+
+ if (group.m_shape == ::fwData::Landmarks::Shape::SPHERE)
+ {
+
+ pointRep->SetShapeRepresentation(::fwRenderVTK::vtk::fwHandleRepresentation3D::SPHERE);
+ }
+ else
+ {
+ pointRep->SetShapeRepresentation(::fwRenderVTK::vtk::fwHandleRepresentation3D::CUBE);
+ }
+ pointRep->GetSelectedProperty()->SetOpacity(color[3]);
+ pointRep->GetMarkerProperty()->SetOpacity(color[3]);
+ pointRep->GetProperty()->SetColor(color[0], color[1], color[2]);
+ pointRep->GetProperty()->SetOpacity(color[3]);
+ pointRep->SetHandleSize(group.m_size);
+ pointRep->SetVisibility(group.m_visibility);
+
+ pointRep->SetWorldPosition(point.data());
+
+ handle->SetRepresentation(pointRep);
+ handle->SetPriority(0.8f);
+
+ handle->SetInteractor( this->getInteractor() );
+ handle->KeyPressActivationOff();
+
+ handle->On();
+
+ // We don't want to add m_representation to the renderer, m_handle
+ // is already managing that.
+ this->registerProp(pointRep);
+
+ // create label
+ const std::string label = groupName + "_" + std::to_string(pointIndex);
+
+ vtkSmartPointer textActor = vtkActor2D::New();
+ vtkSmartPointer textMapper = vtkTextMapper::New();
+ textMapper->GetTextProperty()->SetFontFamilyToCourier(); // Fixed-width font
+ textMapper->GetTextProperty()->ShadowOn(); // better contrast
+ textMapper->GetTextProperty()->BoldOn();
+ textMapper->GetTextProperty()->SetFontSize(15);
+ textMapper->GetTextProperty()->SetColor(color[0], color[1], color[2]);
+ textMapper->SetInput(label.c_str());
+
+ textActor->SetMapper(textMapper);
+ textActor->GetPositionCoordinate()->SetCoordinateSystemToWorld();
+ textActor->GetPosition2Coordinate()->SetCoordinateSystemToWorld();
+ textActor->GetPositionCoordinate()->SetValue(point.data());
+
+ m_labels.insert(std::make_pair(handle, textActor));
+
+ this->addToRenderer(textActor);
+
+ const auto& slot = this->slot(s_MODIFY_POINT_SLOT);
+
+ vtkLandmarkUpdateCallBack* updateCallback;
+ updateCallback = vtkLandmarkUpdateCallBack::New(landmarks, slot, groupName, pointIndex, this->getPicker(),
+ this->getRenderer(), textActor);
+
+ m_commands.insert(std::make_pair(handle, updateCallback));
+
+ handle->AddObserver(vtkCommand::StartInteractionEvent, updateCallback);
+
+ return handle;
+}
+
+//------------------------------------------------------------------------------
+
+void SLandmarks::show(bool b)
+{
+ if (b)
+ {
+ this->doStart();
+ }
+ else
+ {
+ this->doStop();
+ }
+}
+
+//------------------------------------------------------------------------------
+
+::fwServices::IService::KeyConnectionsType SLandmarks::getObjSrvConnections() const
+{
+ KeyConnectionsType connections;
+
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_ADDED_SIG, s_ADD_POINT_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_INSERTED_SIG, s_INSERT_POINT_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_REMOVED_SIG, s_REMOVE_POINT_SLOT ));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_GROUP_ADDED_SIG, s_ADD_GROUP_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_GROUP_REMOVED_SIG, s_REMOVE_GROUP_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_GROUP_MODIFIED_SIG, s_MODIFY_GROUP_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_MODIFIED_SIG, s_MODIFY_POINT_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_MODIFIED_SIG, s_UPDATE_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_GROUP_RENAMED_SIG, s_RENAME_GROUP_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_SELECTED_SIG, s_SELECT_POINT_SLOT));
+ connections.push_back(std::make_pair(::fwData::Landmarks::s_POINT_DESELECTED_SIG, s_DESELECT_POINT_SLOT));
+
+ return connections;
+}
+
+//------------------------------------------------------------------------------
+
+} //namespace visuVTKAdaptor
diff --git a/SrcLib/core/fwAtomConversion/include/fwAtomConversion/mapper/Landmarks.hpp b/SrcLib/core/fwAtomConversion/include/fwAtomConversion/mapper/Landmarks.hpp
new file mode 100644
index 000000000..2c379998c
--- /dev/null
+++ b/SrcLib/core/fwAtomConversion/include/fwAtomConversion/mapper/Landmarks.hpp
@@ -0,0 +1,64 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#ifndef __FWATOMCONVERSION_MAPPER_LANDMARKS_HPP__
+#define __FWATOMCONVERSION_MAPPER_LANDMARKS_HPP__
+
+#include "fwAtomConversion/AtomVisitor.hpp"
+#include "fwAtomConversion/config.hpp"
+#include "fwAtomConversion/mapper/Base.hpp"
+
+namespace fwAtoms
+{
+class Object;
+}
+
+namespace fwData
+{
+class Object;
+}
+
+namespace fwAtomConversion
+{
+namespace mapper
+{
+
+/**
+ * @brief Specific mapper used to convert a ::fwData::Landmarks.
+ *
+ * The attribute ::fwData::Landmarks::m_landmarks is represented in fwAtoms world like a fwAtoms::Map that contains
+ * fwAtoms::Object with five attributes "color", "size", "shape", "visibility" and "points". The points are store in a
+ * ::fwAtoms::Sequence.
+ */
+class FWATOMCONVERSION_CLASS_API Landmarks : public Base
+{
+public:
+
+ /**
+ * @brief Convert a ::fwData::Object to a ::fwAtoms::Object.
+ * @param object data to convert. It must be a ::fwData::Landmarks.
+ * @param cache cache to register the data already converted, used when a data is referenced multiple times.
+ */
+ FWATOMCONVERSION_API virtual SPTR(::fwAtoms::Object) convert( SPTR(::fwData::Object) object,
+ DataVisitor::AtomCacheType & cache );
+
+ /**
+ * @brief Convert a ::fwAtoms::Object to a ::fwData::Object (which represent a ::fwData::Landmarks).
+ * @param atom atom to convert
+ * @param cache cache to register the atoms already converted, used when an atom is referenced multiple times.
+ * @param uuidPolicy AtomVisitor policy
+ */
+ FWATOMCONVERSION_API virtual SPTR(::fwData::Object) convert( SPTR(::fwAtoms::Object) atom,
+ AtomVisitor::DataCacheType & cache,
+ const AtomVisitor::IReadPolicy &uuidPolicy
+ );
+
+};
+
+}
+}
+
+#endif /* __FWATOMCONVERSION_MAPPER_LANDMARKS_HPP__*/
diff --git a/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp b/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp
new file mode 100644
index 000000000..1e289b75b
--- /dev/null
+++ b/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp
@@ -0,0 +1,191 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * FW4SPL - Copyright (C) IRCAD, 2017.
+ * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
+ * published by the Free Software Foundation.
+ * ****** END LICENSE BLOCK ****** */
+
+#include "fwAtomConversion/mapper/Landmarks.hpp"
+
+#include "fwAtomConversion/convert.hpp"
+#include "fwAtomConversion/exception/ConversionNotManaged.hpp"
+#include "fwAtomConversion/mapper/registry/macros.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+namespace fwAtomConversion
+{
+namespace mapper
+{
+
+//-----------------------------------------------------------------------------
+
+fwAtomConversionRegisterMacro( ::fwAtomConversion::mapper::Landmarks, ::fwData::Landmarks);
+
+//-----------------------------------------------------------------------------
+
+::fwAtoms::Object::sptr Landmarks::convert( ::fwData::Object::sptr object,
+ DataVisitor::AtomCacheType& cache )
+{
+ const camp::Class& metaclass = ::camp::classByName( object->getClassname() );
+ ::fwAtomConversion::DataVisitor visitor( object, cache );
+ metaclass.visit(visitor);
+ ::fwAtoms::Object::sptr atom = visitor.getAtomObject();
+
+ ::fwData::Landmarks::csptr landmarks = ::fwData::Landmarks::dynamicCast(object);
+
+ ::fwAtoms::Map::sptr map = ::fwAtoms::Map::New();
+
+ ::fwData::Landmarks::GroupNameContainer names = landmarks->getGroupNames();
+ for (const auto& name: names)
+ {
+ const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name);
+ ::fwAtoms::Object::sptr atomGroup = ::fwAtoms::Object::New();
+ atomGroup->setMetaInfo("ID_METAINFO", ::fwTools::UUID::generateUUID());
+
+ const std::string colorStr = std::to_string(group.m_color[0]) + ";" +
+ std::to_string(group.m_color[1]) + ";" +
+ std::to_string(group.m_color[2]) + ";" +
+ std::to_string(group.m_color[3]);
+ atomGroup->setAttribute("color", ::fwAtoms::String::New(colorStr));
+ atomGroup->setAttribute("size", ::fwAtoms::Numeric::New(group.m_size));
+ const std::string shapeStr = (group.m_shape == ::fwData::Landmarks::Shape::SPHERE) ? "SPHERE" : "CUBE";
+ atomGroup->setAttribute("shape", ::fwAtoms::String::New(shapeStr));
+ atomGroup->setAttribute("visibility", ::fwAtoms::Boolean::New(group.m_visibility));
+
+ ::fwAtoms::Sequence::sptr seq = ::fwAtoms::Sequence::New();
+
+ for (const auto& point : group.m_points)
+ {
+ const std::string pointStr = std::to_string(point[0]) + ";" +
+ std::to_string(point[1]) + ";" +
+ std::to_string(point[2]);
+ seq->push_back(::fwAtoms::String::New(pointStr));
+ }
+ atomGroup->setAttribute("points", seq);
+ map->insert(name, atomGroup);
+ }
+ atom->setAttribute("landmarks", map );
+
+ return atom;
+}
+
+//-----------------------------------------------------------------------------
+
+::fwData::Object::sptr Landmarks::convert( ::fwAtoms::Object::sptr atom,
+ AtomVisitor::DataCacheType& cache,
+ const AtomVisitor::IReadPolicy& uuidPolicy
+ )
+{
+ ::fwAtomConversion::AtomVisitor visitor( atom, cache, uuidPolicy );
+ visitor.visit();
+ ::fwData::Object::sptr data = visitor.getDataObject();
+ ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::dynamicCast(data);
+
+ ::fwAtoms::Map::sptr map = ::fwAtoms::Map::dynamicCast(atom->getAttribute("landmarks"));
+
+ for (const auto& elt : map->getValue())
+ {
+ const std::string name = elt.first;
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atoms stored in fwAtom::Map 'landmarks' must be atom objects"),
+ elt.second->type() != ::fwAtoms::Base::OBJECT );
+ ::fwAtoms::Object::sptr obj = ::fwAtoms::Object::dynamicCast(elt.second);
+
+ // get color
+ ::fwAtoms::String::csptr colorObj = ::fwAtoms::String::dynamicCast(obj->getAttribute("color"));
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atom 'color' stored in fwAtom::Object 'landmarks' must be ::fwAtoms::String"),
+ !colorObj );
+
+ const std::string& colorStr = colorObj->getValue();
+
+ std::vector< std::string> result;
+ ::boost::split(result, colorStr, ::boost::is_any_of(";"));
+
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged("'color' atom must be of type rgba"),
+ result.size() != 4 );
+ const ::fwData::Landmarks::ColorType color = {{
+ std::stof(result[0]), std::stof(result[1]),
+ std::stof(result[2]), std::stof(result[3])
+ }};
+
+ // get size
+ ::fwAtoms::Numeric::csptr sizeObj = ::fwAtoms::Numeric::dynamicCast(obj->getAttribute("size"));
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atom 'size' stored in fwAtom::Object 'landmarks' must be ::fwAtoms::Numeric"),
+ !sizeObj );
+ const ::fwData::Landmarks::SizeType size = sizeObj->getValue< ::fwData::Landmarks::SizeType >();
+
+ // get shape
+ ::fwAtoms::String::csptr shapeObj = ::fwAtoms::String::dynamicCast(obj->getAttribute("shape"));
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atom 'shape' stored in fwAtom::Object 'landmarks' must be ::fwAtoms::String"),
+ !shapeObj );
+
+ const std::string& shapeStr = shapeObj->getValue();
+ ::fwData::Landmarks::Shape shape;
+ if (shapeStr == "SPHERE")
+ {
+ shape = ::fwData::Landmarks::Shape::SPHERE;
+ }
+ else if (shapeStr == "CUBE")
+ {
+ shape = ::fwData::Landmarks::Shape::CUBE;
+ }
+ else
+ {
+ FW_RAISE_EXCEPTION(exception::ConversionNotManaged("'shape' value '"+ shapeStr +"' is not managed"));
+ }
+
+ // get visibility
+ ::fwAtoms::Boolean::csptr visuObj = ::fwAtoms::Boolean::dynamicCast(obj->getAttribute("visibility"));
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atom 'visibility' stored in 'landmarks' must be ::fwAtoms::Boolean"),
+ !visuObj );
+ const bool visibility = visuObj->getValue();
+
+ landmarks->addGroup(name, color, size, shape, visibility);
+
+ // get points
+ ::fwAtoms::Sequence::csptr seq = ::fwAtoms::Sequence::dynamicCast(obj->getAttribute("points"));
+ for (const auto& elt : seq->getValue())
+ {
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged(
+ "sub atoms stored in 'points' must be ::fwAtoms::String"),
+ elt->type() != ::fwAtoms::Base::STRING );
+
+ ::fwAtoms::String::csptr ptStrObj = ::fwAtoms::String::dynamicCast(elt);
+ const std::string& ptStr = ptStrObj->getValue();
+
+ std::vector< std::string> resultPt;
+ ::boost::split(resultPt, ptStr, ::boost::is_any_of(";"));
+
+ FW_RAISE_EXCEPTION_IF( exception::ConversionNotManaged("point atom must be of type x;y;z"),
+ resultPt.size() != 3 );
+
+ ::fwData::Landmarks::PointType pt = {{
+ std::stod(resultPt[0]), std::stod(resultPt[1]),
+ std::stod(resultPt[2])
+ }};
+ landmarks->addPoint(name, pt);
+ }
+ }
+
+ return landmarks;
+}
+
+//-----------------------------------------------------------------------------
+
+} //namespace mapper
+} //namespace fwAtomConversion
diff --git a/SrcLib/core/fwAtomConversion/test/tu/include/ConversionTest.hpp b/SrcLib/core/fwAtomConversion/test/tu/include/ConversionTest.hpp
index 14eb65b05..dec578e4f 100644
--- a/SrcLib/core/fwAtomConversion/test/tu/include/ConversionTest.hpp
+++ b/SrcLib/core/fwAtomConversion/test/tu/include/ConversionTest.hpp
@@ -1,5 +1,5 @@
/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2015.
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
* Distributed under the terms of the GNU Lesser General Public License (LGPL) as
* published by the Free Software Foundation.
* ****** END LICENSE BLOCK ****** */
@@ -31,6 +31,7 @@ CPPUNIT_TEST( dataFactoryNotFoundExceptionTest );
CPPUNIT_TEST( campFactoryNotFoundExceptionTest );
CPPUNIT_TEST( conversionNotManagedExceptionTest );
CPPUNIT_TEST( nullPtrManagmentTest );
+CPPUNIT_TEST( landmarksConversionTest );
CPPUNIT_TEST_SUITE_END();
public:
@@ -60,7 +61,6 @@ CPPUNIT_TEST_SUITE_END();
/// Test recursive data conversion
void recursiveObjectTest();
-
/// Test exception throwing if uuid already exist
void uuidExceptionTest();
@@ -82,12 +82,12 @@ CPPUNIT_TEST_SUITE_END();
/// Test null ptr management (null ptr attribut, null ptr in vector, null ptr in map)
void nullPtrManagmentTest();
-};
+ //// Test fwData::Landmarks conversion
+ void landmarksConversionTest();
+};
} // namespace ut
} // namespace fwAtomConversion
-
-
#endif // __FWATOMCONVERSION_UT_CONVERSIONTEST_HPP__
diff --git a/SrcLib/core/fwAtomConversion/test/tu/src/ConversionTest.cpp b/SrcLib/core/fwAtomConversion/test/tu/src/ConversionTest.cpp
index 4562365f7..784aab378 100644
--- a/SrcLib/core/fwAtomConversion/test/tu/src/ConversionTest.cpp
+++ b/SrcLib/core/fwAtomConversion/test/tu/src/ConversionTest.cpp
@@ -1,52 +1,54 @@
/* ***** BEGIN LICENSE BLOCK *****
- * FW4SPL - Copyright (C) IRCAD, 2009-2016.
+ * FW4SPL - Copyright (C) IRCAD, 2009-2017.
* Distributed under the terms of the GNU Lesser General Public License (LGPL) as
* published by the Free Software Foundation.
* ****** END LICENSE BLOCK ****** */
#include "ConversionTest.hpp"
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
#include
-#include
#include
-#include
-#include
-#include
-#include
#include
-#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
-#include
-#include
+#include
#include
#include
-#include
+#include
+#include
#include
-#include
-
-#include
-
-#include
-#include
-#include
+#include
+#include
#include
-#include
-#include
-#include
+#include
-#include
#include
+#include
-#include