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 ::fwData::Image 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 ::fwData::Image + + + ::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 - ::fwData::Image + ::visuVTKAdaptor::SLandmarks + ::fwData::Landmarks 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 -#include -#include -#include -#include +#include #include @@ -205,7 +207,7 @@ void ConversionTest::materialConversionTest() void ConversionTest::graphConversionTest() { ::fwAtoms::Object::sptr atom; - ::fwTools::UUID::UUIDType gID,n1ID,n2ID,n3ID,e12ID,e23ID; + ::fwTools::UUID::UUIDType gID, n1ID, n2ID, n3ID, e12ID, e23ID; { ::fwData::Graph::sptr g = ::fwData::Graph::New(); gID = ::fwTools::UUID::get(g); @@ -230,14 +232,14 @@ void ConversionTest::graphConversionTest() n2->addOutputPort( ::fwData::Port::New() ); n3->addInputPort( ::fwData::Port::New() ); - e12->setIdentifiers("IDNOTdefined","IDNOTdefined"); - e23->setIdentifiers("IDNOTdefined","IDNOTdefined"); + e12->setIdentifiers("IDNOTdefined", "IDNOTdefined"); + e23->setIdentifiers("IDNOTdefined", "IDNOTdefined"); - g->addEdge(e12,n1,n2); - g->addEdge(e23,n2,n3); + g->addEdge(e12, n1, n2); + g->addEdge(e23, n2, n3); // Test field on edge - e12->setField("infoTest",::fwData::String::New("valueInfoTest")); + e12->setField("infoTest", ::fwData::String::New("valueInfoTest")); // Create Atom atom = ::fwAtomConversion::convert( g ); @@ -250,12 +252,12 @@ void ConversionTest::graphConversionTest() ::fwData::Node::sptr n1, n2, n3; // Test nodes - const ::fwData::Graph::NodeContainer & nodes = newGraph->getCRefNodes(); - CPPUNIT_ASSERT_EQUAL_MESSAGE("Graph nodes size", (size_t)3, nodes.size() ); + const ::fwData::Graph::NodeContainer& nodes = newGraph->getCRefNodes(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Graph nodes size", (size_t)3, nodes.size() ); for( ::fwData::Node::sptr node : nodes ) { ::fwTools::UUID::UUIDType nodeID = ::fwTools::UUID::get(node); - CPPUNIT_ASSERT_MESSAGE("Test node uuid", nodeID == n1ID || nodeID == n2ID || nodeID == n3ID ); + CPPUNIT_ASSERT_MESSAGE("Test node uuid", nodeID == n1ID || nodeID == n2ID || nodeID == n3ID ); if ( nodeID == n1ID ) { n1 = node; @@ -275,12 +277,12 @@ void ConversionTest::graphConversionTest() CPPUNIT_ASSERT_MESSAGE("Test node n3", n3 ); // Test edges - const ::fwData::Graph::ConnectionContainer & connections = newGraph->getCRefConnections(); - CPPUNIT_ASSERT_EQUAL_MESSAGE("Graph connections size", (size_t)2, connections.size() ); + const ::fwData::Graph::ConnectionContainer& connections = newGraph->getCRefConnections(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Graph connections size", (size_t)2, connections.size() ); for( ::fwData::Graph::ConnectionContainer::value_type elem : connections ) { ::fwTools::UUID::UUIDType edgeID = ::fwTools::UUID::get(elem.first); - CPPUNIT_ASSERT_MESSAGE("Test edge uuid", edgeID == e12ID || edgeID == e23ID ); + CPPUNIT_ASSERT_MESSAGE("Test edge uuid", edgeID == e12ID || edgeID == e23ID ); if ( edgeID == e12ID ) { CPPUNIT_ASSERT( newGraph->getSourceNode( elem.first ) == n1 ); @@ -326,7 +328,6 @@ void ConversionTest::seriesDBConversionTest() // Create Atom atom = ::fwAtomConversion::convert( sdb ); - ::fwMedData::SeriesDB::sptr newSdb = ::fwMedData::SeriesDB::dynamicCast( ::fwAtomConversion::convert(atom) ); @@ -335,6 +336,96 @@ void ConversionTest::seriesDBConversionTest() //----------------------------------------------------------------------------- +void ConversionTest::landmarksConversionTest() +{ + { + // Basic test with empty structure + ::fwAtoms::Object::sptr atom; + + ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::New(); + + // Create Atom + atom = ::fwAtomConversion::convert( landmarks ); + + ::fwData::Landmarks::sptr newLandmarks = + ::fwData::Landmarks::dynamicCast( ::fwAtomConversion::convert(atom) ); + + compare(landmarks, newLandmarks); + } + + { + const std::string GROUP1 = "group_1"; + const std::string GROUP2 = "group_2"; + const std::string GROUP3 = "group_3"; + const ::fwData::Landmarks::ColorType COLOR1 = {{1.f, 0.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR2 = {{0.f, 1.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR3 = {{0.f, 0.0f, 1.0f, 1.0f}}; + const ::fwData::Landmarks::SizeType SIZE1 = 3.45f; + const ::fwData::Landmarks::SizeType SIZE2 = 7.5f; + const ::fwData::Landmarks::SizeType SIZE3 = 1.3f; + const ::fwData::Landmarks::Shape SHAPE1 = ::fwData::Landmarks::Shape::SPHERE; + const ::fwData::Landmarks::Shape SHAPE2 = ::fwData::Landmarks::Shape::CUBE; + const ::fwData::Landmarks::Shape SHAPE3 = ::fwData::Landmarks::Shape::SPHERE; + const bool VISIBILITY1 = true; + const bool VISIBILITY2 = false; + const bool VISIBILITY3 = true; + + const ::fwData::Landmarks::PointType POINT1 = {{3.5, 5.8, 2.56}}; + const ::fwData::Landmarks::PointType POINT2 = {{8.25, 56.0, 45.4}}; + const ::fwData::Landmarks::PointType POINT3 = {{0.0, 0.0, 0.0}}; + const ::fwData::Landmarks::PointType POINT4 = {{0.5, 0.6, 0.7}}; + + ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::New(); + + landmarks->addGroup(GROUP1, COLOR1, SIZE1, SHAPE1, VISIBILITY1); + landmarks->addGroup(GROUP2, COLOR2, SIZE2, SHAPE2, VISIBILITY2); + landmarks->addGroup(GROUP3, COLOR3, SIZE3, SHAPE3, VISIBILITY3); + landmarks->addPoint(GROUP1, POINT1); + landmarks->addPoint(GROUP2, POINT2); + landmarks->addPoint(GROUP3, POINT3); + landmarks->addPoint(GROUP1, POINT4); + + // Create Atom + ::fwAtoms::Object::sptr atom = ::fwAtomConversion::convert( landmarks ); + + ::fwData::Landmarks::sptr newLandmarks = + ::fwData::Landmarks::dynamicCast( ::fwAtomConversion::convert(atom) ); + + CPPUNIT_ASSERT(newLandmarks); + + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfGroups(), newLandmarks->getNumberOfGroups()); + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfPoints(), newLandmarks->getNumberOfPoints()); + + const ::fwData::Landmarks::GroupNameContainer names = landmarks->getGroupNames(); + + for (const auto& name : names) + { + CPPUNIT_ASSERT_NO_THROW(newLandmarks->getGroup(name)); + + const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name); + const ::fwData::Landmarks::LandmarksGroup& newGroup = newLandmarks->getGroup(name); + + CPPUNIT_ASSERT(group.m_color == newGroup.m_color); + CPPUNIT_ASSERT_EQUAL(group.m_points.size(), newGroup.m_points.size()); + + for (size_t i = 0; i < group.m_points.size(); ++i) + { + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("point[" + std::to_string(i) + "][0]", + group.m_points[i][0], newGroup.m_points[i][0], 0.00001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("point[" + std::to_string(i) + "][1]", + group.m_points[i][1], newGroup.m_points[i][1], 0.00001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("point[" + std::to_string(i) + "][2]", + group.m_points[i][2], newGroup.m_points[i][2], 0.00001); + } + CPPUNIT_ASSERT_EQUAL(group.m_size, newGroup.m_size); + CPPUNIT_ASSERT_EQUAL(int(group.m_shape), int(newGroup.m_shape)); + CPPUNIT_ASSERT_EQUAL(group.m_visibility, newGroup.m_visibility); + } + } +} + +//----------------------------------------------------------------------------- + void ConversionTest::objectMultiReferencedTest() { ::fwAtoms::Object::sptr atom; @@ -351,7 +442,7 @@ void ConversionTest::objectMultiReferencedTest() // Create Data from Atom ::fwData::Composite::sptr newComposite = ::fwData::Composite::dynamicCast( ::fwAtomConversion::convert(atom) ); - ::fwData::Composite::ContainerType & dataMap = newComposite->getContainer(); + ::fwData::Composite::ContainerType& dataMap = newComposite->getContainer(); CPPUNIT_ASSERT( dataMap.find("key1") != dataMap.end() ); CPPUNIT_ASSERT( dataMap.find("key2") != dataMap.end() ); CPPUNIT_ASSERT( dataMap["key1"] ); @@ -381,7 +472,7 @@ void ConversionTest::recursiveObjectTest() // Create Data from Atom ::fwData::Composite::sptr newComposite = ::fwData::Composite::dynamicCast( ::fwAtomConversion::convert(atom) ); - ::fwData::Composite::ContainerType & dataMap = newComposite->getContainer(); + ::fwData::Composite::ContainerType& dataMap = newComposite->getContainer(); CPPUNIT_ASSERT( dataMap.find("key") != dataMap.end() ); CPPUNIT_ASSERT( newComposite == dataMap["key"] ); } @@ -428,7 +519,6 @@ void ConversionTest::uuidExceptionTest() ::fwAtomConversion::exception::DuplicatedDataUUID ); } - //----------------------------------------------------------------------------- void ConversionTest::uuidChangeTest() @@ -454,7 +544,6 @@ void ConversionTest::uuidChangeTest() } - //----------------------------------------------------------------------------- void ConversionTest::uuidReuseTest() @@ -467,7 +556,6 @@ void ConversionTest::uuidReuseTest() // Create Atom ::fwAtoms::Object::sptr atom = ::fwAtomConversion::convert( composite ); - ::fwData::Composite::sptr compositeReloaded; ::fwData::String::sptr dataReloaded; @@ -488,17 +576,20 @@ class ClassNotCamped : public ::fwData::Object public: fwCoreClassDefinitionsWithNFactoriesMacro( (ClassNotCamped)(::fwData::Object), - ((::fwData::factory::New< ClassNotCamped >,() )) ); + ((::fwData::factory::New< ClassNotCamped >, () )) ); ClassNotCamped(::fwData::Object::Key key) { } - void cachedDeepCopy(const Object::csptr &_source, DeepCopyCacheType &cache ) + //------------------------------------------------------------------------------ + + void cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache ) { } }; +//------------------------------------------------------------------------------ void ConversionTest::campFactoryNotFoundExceptionTest() { @@ -551,7 +642,7 @@ void ConversionTest::nullPtrManagmentTest() ::fwData::Composite::sptr newComposite = ::fwData::Composite::dynamicCast( ::fwAtomConversion::convert(atom) ); - ::fwData::Composite::ContainerType & dataMap = newComposite->getContainer(); + ::fwData::Composite::ContainerType& dataMap = newComposite->getContainer(); CPPUNIT_ASSERT( newComposite ); CPPUNIT_ASSERT_EQUAL( (size_t)2, dataMap.size() ); CPPUNIT_ASSERT( dataMap["key1"] ); @@ -577,8 +668,8 @@ void ConversionTest::nullPtrManagmentTest() CPPUNIT_ASSERT( !(*seq)[1] ); } - ::fwData::Vector::sptr newVector = ::fwData::Vector::dynamicCast( ::fwAtomConversion::convert(atom) ); - ::fwData::Vector::ContainerType & dataVec = newVector->getContainer(); + ::fwData::Vector::sptr newVector = ::fwData::Vector::dynamicCast( ::fwAtomConversion::convert(atom) ); + ::fwData::Vector::ContainerType& dataVec = newVector->getContainer(); CPPUNIT_ASSERT( newVector ); CPPUNIT_ASSERT_EQUAL( (size_t)2, dataVec.size() ); CPPUNIT_ASSERT( dataVec[0] ); @@ -586,14 +677,13 @@ void ConversionTest::nullPtrManagmentTest() } } - } // namespace ut } // namespace fwAtomConversion //----------------------------------------------------------------------------- #define EMTPY_CLASS_API -fwCampAutoDeclareDataMacro((fwAtomConversion)(ut)(ClassNotManaged),EMTPY_CLASS_API); +fwCampAutoDeclareDataMacro((fwAtomConversion)(ut)(ClassNotManaged), EMTPY_CLASS_API); namespace fwAtomConversion { @@ -606,7 +696,7 @@ class ClassNotManaged : public ::fwData::Object public: fwCoreClassDefinitionsWithNFactoriesMacro( (ClassNotManaged)(::fwData::Object), - ((::fwData::factory::New< ClassNotManaged >,() )) ); + ((::fwData::factory::New< ClassNotManaged >, () )) ); fwCampMakeFriendDataMacro((fwAtomConversion)(ut)(ClassNotManaged)); @@ -615,7 +705,9 @@ class ClassNotManaged : public ::fwData::Object m_values.insert( std::make_pair( ::fwData::String::New(), 0.2 ) ); } - void cachedDeepCopy(const Object::csptr &_source, DeepCopyCacheType &cache ) + //------------------------------------------------------------------------------ + + void cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache ) { } @@ -623,10 +715,9 @@ class ClassNotManaged : public ::fwData::Object }; -} // namespace ut +} // namespace ut } // namespace fwAtomConversion - fwCampImplementDataMacro((fwAtomConversion)(ut)(ClassNotManaged)) { builder @@ -641,6 +732,8 @@ namespace fwAtomConversion namespace ut { +//------------------------------------------------------------------------------ + void ConversionTest::conversionNotManagedExceptionTest() { // Test ConversionNotManaged throwing during data to atom conversion @@ -670,10 +763,10 @@ void ConversionTest::conversionNotManagedExceptionTest() atomObj->setMetaInfo( DataVisitor::ID_METAINFO, ::fwTools::UUID::generateUUID()); ::fwAtoms::Map::sptr atomFields = ::fwAtoms::Map::New(); - atomObj->setAttribute("fields",atomFields); + atomObj->setAttribute("fields", atomFields); ::fwAtoms::Sequence::sptr atomSeq = ::fwAtoms::Sequence::New(); - atomObj->setAttribute("values",atomSeq); + atomObj->setAttribute("values", atomSeq); ::fwAtoms::Map::sptr atomBasicMap = ::fwAtoms::Map::New(); atomSeq->push_back( atomBasicMap ); @@ -683,7 +776,6 @@ void ConversionTest::conversionNotManagedExceptionTest() } } -} // namespace ut +} // namespace ut } // namespace fwAtomConversion - diff --git a/SrcLib/core/fwData/include/fwData/Landmarks.hpp b/SrcLib/core/fwData/include/fwData/Landmarks.hpp new file mode 100644 index 000000000..b1933100f --- /dev/null +++ b/SrcLib/core/fwData/include/fwData/Landmarks.hpp @@ -0,0 +1,270 @@ +/* ***** 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 __FWDATA_LANDMARKS_HPP__ +#define __FWDATA_LANDMARKS_HPP__ + +#include "fwData/config.hpp" +#include "fwData/factory/new.hpp" +#include "fwData/Object.hpp" + +#include +#include +#include + +fwCampAutoDeclareDataMacro((fwData)(Landmarks), FWDATA_API); + +namespace fwData +{ +/** + * @brief This class defines a list of 3D points inside groups. + */ +class FWDATA_CLASS_API Landmarks : public Object +{ + +public: + + typedef std::array< float, 4 > ColorType; + typedef std::array< double, 3 > PointType; + typedef float SizeType; + typedef std::vector< PointType > PointContainer; + typedef std::vector< std::string > GroupNameContainer; + + enum class Shape + { + SPHERE, + CUBE + }; + + struct LandmarksGroup + { + LandmarksGroup(ColorType color, SizeType size, Shape shape, bool visibility) : + m_color(color), + m_size(size), + m_shape(shape), + m_visibility(visibility) + { + } + + ColorType m_color; + SizeType m_size; + Shape m_shape; + bool m_visibility; + PointContainer m_points; + }; + + fwCoreClassDefinitionsWithFactoryMacro( (Landmarks)(::fwData::Object), (()), ::fwData::factory::New< Landmarks > ); + + fwCampMakeFriendDataMacro((fwData)(Landmarks)); + + /** + * @brief Constructor + * @param key Private construction key + */ + FWDATA_API Landmarks(::fwData::Object::Key key); + + /// Destructor + FWDATA_API virtual ~Landmarks(); + + /// Defines shallow copy + FWDATA_API void shallowCopy( const Object::csptr& _source ); + + /// Defines deep copy + FWDATA_API void cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache); + + /** + * @brief Add a new landmark group + * + * @throw ::fwData::Exception if a group exists with the given name + */ + FWDATA_API void addGroup(const std::string& name, const ColorType& color = {{1.0f, 1.0f, 1.0f, 1.0f}}, + const SizeType size = 1.0f, const Shape shape = Shape::SPHERE, + const bool visibility = true); + + /// Return all group names + FWDATA_API const GroupNameContainer getGroupNames() const; + + /** + * @brief Get the group properties + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API const LandmarksGroup& getGroup(const std::string& name) const; + + /** + * @brief Get the group properties + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API LandmarksGroup& getGroup(const std::string& name); + + /** + * @brief Rename the group + * + * @throw ::fwData::Exception if the group does not exist or if a group exists with the new name + */ + FWDATA_API void renameGroup(const std::string& oldName, const std::string& newName); + + /** + * @brief Remove the group + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void removeGroup(const std::string& name); + + /** + * @brief Set the group's color. + * + * The color is encoded as a rgba float array ranging from 0 to 1 + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void setGroupColor(const std::string& name, const ColorType& color); + + /** + * @brief Set the group's landmark size + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void setGroupSize(const std::string& name, const SizeType size); + + /** + * @brief Set the group's shape (SPHERE or CUBE) + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void setGroupShape(const std::string& name, const Shape shape); + + /** + * @brief Set the group's visibility + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void setGroupVisibility(const std::string& name, const bool visibility); + + /** + * @brief Add a point to the group + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void addPoint(const std::string& name, const PointType& point); + + /** + * @brief Insert a point to the group at the given index + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void insertPoint(const std::string& name, const size_t index, const PointType& point); + + /** + * @brief Get the point at the given index + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API const PointType& getPoint(const std::string& name, size_t index) const; + + /** + * @brief Get the point at the given index + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API PointType& getPoint(const std::string& name, size_t index); + + /** + * @brief Get all group's points + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API const PointContainer& getPoints(const std::string& name) const; + + /** + * @brief Remove the point at the given index + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void removePoint(const std::string& name, size_t index); + + /** + * @brief Remove all the group's points + * + * @throw ::fwData::Exception if the group does not exist + */ + FWDATA_API void clearPoints(const std::string& name); + + /// Return the number of groups + size_t getNumberOfGroups() const; + + /// Return the number of points in the entire structure + FWDATA_API size_t getNumberOfPoints() const; + + /// Return the number of points in the group + FWDATA_API size_t getNumberOfPoints(const std::string& name) const; + + /** + * @name Signals + * @{ + */ + /// Type of signal when a group is added + typedef ::fwCom::Signal< void (std::string name) > GroupAddedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_GROUP_ADDED_SIG; + + /// Type of signal when a group is removed + typedef ::fwCom::Signal< void (std::string name) > GroupRemovedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_GROUP_REMOVED_SIG; + + /// Type of signal when a point is added + typedef ::fwCom::Signal< void (std::string name) > PointAddedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_ADDED_SIG; + + /// Type of signal when a point is removed + typedef ::fwCom::Signal< void (std::string name, size_t index) > PointRemovedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_REMOVED_SIG; + + /// Type of signal when a point is inserted + typedef ::fwCom::Signal< void (std::string name, size_t index) > PointInsertedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_INSERTED_SIG; + + /// Type of signal when a point is modified + typedef ::fwCom::Signal< void (std::string name, size_t index) > PointModifiedSigType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_MODIFIED_SIG; + + /// Type of signal when group properties changed + typedef ::fwCom::Signal< void (std::string name) > GroupModifiedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_GROUP_MODIFIED_SIG; + + /// Type of signal when a group is renamed + typedef ::fwCom::Signal< void (std::string oldName, std::string newName) > GroupRenamedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_GROUP_RENAMED_SIG; + + /// Type of signal when point is selected + typedef ::fwCom::Signal< void (std::string name, size_t index) > PointSelectedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_SELECTED_SIG; + + /// Type of signal when point is deselected + typedef ::fwCom::Signal< void (std::string name, size_t index) > PointDeselectedSignalType; + FWDATA_API static const ::fwCom::Signals::SignalKeyType s_POINT_DESELECTED_SIG; + + /** + * @} + */ + +private: + + typedef std::map< std::string, LandmarksGroup > LandmarksContainer; + LandmarksContainer m_landmarks; +}; // end class Landmarks + +//------------------------------------------------------------------------------ + +inline size_t Landmarks::getNumberOfGroups() const +{ + return m_landmarks.size(); +} + +} // end namespace fwData + +#endif // __FWDATA_LANDMARKS_HPP__ + diff --git a/SrcLib/core/fwData/src/fwData/Landmarks.cpp b/SrcLib/core/fwData/src/fwData/Landmarks.cpp new file mode 100644 index 000000000..e119e8555 --- /dev/null +++ b/SrcLib/core/fwData/src/fwData/Landmarks.cpp @@ -0,0 +1,268 @@ +/* ***** 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 "fwData/Landmarks.hpp" + +#include "fwData/Exception.hpp" +#include "fwData/registry/macros.hpp" + +#include +#include + +fwDataRegisterMacro( ::fwData::Landmarks ); + +namespace fwData +{ + +const ::fwCom::Signals::SignalKeyType Landmarks::s_GROUP_ADDED_SIG = "groupAdded"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_GROUP_REMOVED_SIG = "groupemoved"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_ADDED_SIG = "pointAdded"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_REMOVED_SIG = "pointRemoved"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_INSERTED_SIG = "pointInserted"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_GROUP_MODIFIED_SIG = "groupModified"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_MODIFIED_SIG = "pointModified"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_GROUP_RENAMED_SIG = "groupRenamed"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_SELECTED_SIG = "pointSelected"; +const ::fwCom::Signals::SignalKeyType Landmarks::s_POINT_DESELECTED_SIG = "pointDeselected"; + +//------------------------------------------------------------------------------ + +Landmarks::Landmarks(::fwData::Object::Key key) +{ + newSignal(s_GROUP_ADDED_SIG); + newSignal(s_GROUP_REMOVED_SIG); + newSignal(s_POINT_ADDED_SIG); + newSignal(s_POINT_REMOVED_SIG); + newSignal(s_POINT_INSERTED_SIG); + newSignal(s_GROUP_MODIFIED_SIG); + newSignal(s_POINT_MODIFIED_SIG); + newSignal(s_GROUP_RENAMED_SIG); + newSignal(s_POINT_SELECTED_SIG); + newSignal(s_POINT_DESELECTED_SIG); +} + +//------------------------------------------------------------------------------ + +Landmarks::~Landmarks () +{ +} + +//------------------------------------------------------------------------------ + +void Landmarks::shallowCopy(const Object::csptr& _source ) +{ + Landmarks::csptr other = Landmarks::dynamicConstCast(_source); + FW_RAISE_EXCEPTION_IF( ::fwData::Exception( + "Unable to copy" + (_source ? _source->getClassname() : std::string("")) + + " to " + this->getClassname()), !bool(other) ); + this->fieldShallowCopy( _source ); + + m_landmarks = other->m_landmarks; +} + +//------------------------------------------------------------------------------ + +void Landmarks::cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache) +{ + Landmarks::csptr other = Landmarks::dynamicConstCast(_source); + FW_RAISE_EXCEPTION_IF( ::fwData::Exception( + "Unable to copy" + (_source ? _source->getClassname() : std::string("")) + + " to " + this->getClassname()), !bool(other) ); + this->fieldDeepCopy( _source, cache ); + + m_landmarks = other->m_landmarks; +} + +//------------------------------------------------------------------------------ + +void Landmarks::addGroup(const std::string& name, const Landmarks::ColorType& color, const Landmarks::SizeType size, + const Landmarks::Shape shape, const bool visibility) +{ + LandmarksGroup group(color, size, shape, visibility); + const auto iter = m_landmarks.find(name); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + name + "' already exists"), iter != m_landmarks.end()); + m_landmarks.insert(std::make_pair(name, group)); +} + +//------------------------------------------------------------------------------ + +const Landmarks::GroupNameContainer Landmarks::getGroupNames() const +{ + Landmarks::GroupNameContainer names; + + std::transform( + m_landmarks.begin(), + m_landmarks.end(), + std::back_inserter(names), + [](const LandmarksContainer::value_type& pair){return pair.first; }); + + return names; +} + +//------------------------------------------------------------------------------ + +const Landmarks::LandmarksGroup& Landmarks::getGroup(const std::string& name) const +{ + const auto iter = m_landmarks.find(name); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + name + "' does not exist"), iter == m_landmarks.end()); + const Landmarks::LandmarksGroup& group = iter->second; + return group; +} + +//------------------------------------------------------------------------------ + +Landmarks::LandmarksGroup& Landmarks::getGroup(const std::string& name) +{ + auto iter = m_landmarks.find(name); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + name + "' does not exist"), iter == m_landmarks.end()); + + Landmarks::LandmarksGroup& group = iter->second; + return group; +} + +//------------------------------------------------------------------------------ + +void Landmarks::renameGroup(const std::string& oldName, const std::string& newName) +{ + const auto iter = m_landmarks.find(oldName); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + oldName + "' does not exist"), iter == m_landmarks.end()); + const auto iter2 = m_landmarks.find(newName); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + newName + "' already exists"), iter2 != m_landmarks.end()); + + const Landmarks::LandmarksGroup group = iter->second; + m_landmarks.insert(std::make_pair(newName, group)); + m_landmarks.erase(oldName); +} + +//------------------------------------------------------------------------------ + +void Landmarks::removeGroup(const std::string& name) +{ + const auto iter = m_landmarks.find(name); + FW_RAISE_EXCEPTION_IF(::fwData::Exception("Group '" + name + "' does not exist"), iter == m_landmarks.end()); + + m_landmarks.erase(name); +} + +//------------------------------------------------------------------------------ + +void Landmarks::setGroupColor(const std::string& name, const Landmarks::ColorType& color) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_color = color; +} + +//------------------------------------------------------------------------------ + +void Landmarks::setGroupSize(const std::string& name, const Landmarks::SizeType size) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_size = size; +} + +//------------------------------------------------------------------------------ + +void Landmarks::setGroupShape(const std::string& name, const Landmarks::Shape shape) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_shape = shape; +} + +//------------------------------------------------------------------------------ + +void Landmarks::setGroupVisibility(const std::string& name, const bool visibility) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_visibility = visibility; +} + +//------------------------------------------------------------------------------ + +void Landmarks::addPoint(const std::string& name, const Landmarks::PointType& point) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_points.push_back(point); +} + +//------------------------------------------------------------------------------ + +void Landmarks::insertPoint(const std::string& name, const size_t index, const Landmarks::PointType& point) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + auto iter = group.m_points.begin() + static_cast< PointContainer::difference_type >(index); + group.m_points.insert(iter, point); +} + +//------------------------------------------------------------------------------ + +const Landmarks::PointType& Landmarks::getPoint(const std::string& name, size_t index) const +{ + const Landmarks::LandmarksGroup& group = this->getGroup(name); + return group.m_points.at(index); +} + +//------------------------------------------------------------------------------ + +Landmarks::PointType& Landmarks::getPoint(const std::string& name, size_t index) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + return group.m_points.at(index); +} + +//------------------------------------------------------------------------------ + +const Landmarks::PointContainer& Landmarks::getPoints(const std::string& name) const +{ + const Landmarks::LandmarksGroup& group = this->getGroup(name); + return group.m_points; +} + +//------------------------------------------------------------------------------ + +void Landmarks::removePoint(const std::string& name, size_t index) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + + FW_RAISE_EXCEPTION_IF(std::out_of_range("index out of range in group '" + name + "'"), + index >= group.m_points.size()); + + auto iter = group.m_points.begin() + static_cast< PointContainer::difference_type >(index); + group.m_points.erase(iter); +} + +//------------------------------------------------------------------------------ + +void Landmarks::clearPoints(const std::string& name) +{ + Landmarks::LandmarksGroup& group = this->getGroup(name); + group.m_points.clear(); +} + +//------------------------------------------------------------------------------ + +size_t Landmarks::getNumberOfPoints() const +{ + size_t nb = 0; + for (const auto& elt: m_landmarks) + { + const LandmarksGroup group = elt.second; + nb += group.m_points.size(); + } + return nb; +} + +//------------------------------------------------------------------------------ + +size_t Landmarks::getNumberOfPoints(const std::string& name) const +{ + const LandmarksGroup& group = this->getGroup(name); + return group.m_points.size(); +} + +//------------------------------------------------------------------------------ + +} // namespace fwData + diff --git a/SrcLib/core/fwData/test/tu/include/LandmarksTest.hpp b/SrcLib/core/fwData/test/tu/include/LandmarksTest.hpp new file mode 100644 index 000000000..5aab50467 --- /dev/null +++ b/SrcLib/core/fwData/test/tu/include/LandmarksTest.hpp @@ -0,0 +1,47 @@ +/* ***** 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 __FWDATA_UT_LANDMARKSTEST_HPP__ +#define __FWDATA_UT_LANDMARKSTEST_HPP__ + +#include + +namespace fwData +{ +namespace ut +{ +/** + * @brief The PointListTest class + * This class is used to test ::fwData::PointList + */ +class LandmarksTest : public CPPUNIT_NS::TestFixture +{ +private: + CPPUNIT_TEST_SUITE( LandmarksTest ); + CPPUNIT_TEST( copyTest ); + CPPUNIT_TEST( groupTest ); + CPPUNIT_TEST( pointsTest ); + CPPUNIT_TEST_SUITE_END(); + +public: + // interface + void setUp(); + void tearDown(); + + /// test deep and shallow copy + void copyTest(); + + /// test to add/remove groups and change properties + void groupTest(); + + /// test to add/ remove points in group + void pointsTest(); + +}; + +} //namespace ut +} //namespace fwData +#endif //__FWDATA_UT_LANDMARKSTEST_HPP__ diff --git a/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp b/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp new file mode 100644 index 000000000..1580b85d4 --- /dev/null +++ b/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp @@ -0,0 +1,350 @@ +/* ***** 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 "LandmarksTest.hpp" + +#include +#include + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( ::fwData::ut::LandmarksTest ); + +namespace fwData +{ +namespace ut +{ + +//------------------------------------------------------------------------------ + +void LandmarksTest::setUp() +{ + // Set up context before running a test. +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::tearDown() +{ + // Clean up after the test run. +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::copyTest() +{ + ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::New(); + const std::string GROUP1 = "group_1"; + const std::string GROUP2 = "group_2"; + const std::string GROUP3 = "group_3"; + const ::fwData::Landmarks::ColorType COLOR1 = {{1.f, 0.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR2 = {{0.f, 1.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR3 = {{0.f, 0.0f, 1.0f, 1.0f}}; + const ::fwData::Landmarks::SizeType SIZE1 = 3.45f; + const ::fwData::Landmarks::SizeType SIZE2 = 7.5f; + const ::fwData::Landmarks::SizeType SIZE3 = 1.3f; + const ::fwData::Landmarks::Shape SHAPE1 = ::fwData::Landmarks::Shape::SPHERE; + const ::fwData::Landmarks::Shape SHAPE2 = ::fwData::Landmarks::Shape::CUBE; + const ::fwData::Landmarks::Shape SHAPE3 = ::fwData::Landmarks::Shape::SPHERE; + const bool VISIBILITY1 = true; + const bool VISIBILITY2 = false; + const bool VISIBILITY3 = true; + const ::fwData::Landmarks::PointType POINT1 = {{3.5, 5.8, 2.56}}; + const ::fwData::Landmarks::PointType POINT2 = {{8.25, 56.0, 45.4}}; + const ::fwData::Landmarks::PointType POINT3 = {{0.0, 0.0, 0.0}}; + const ::fwData::Landmarks::PointType POINT4 = {{0.5, 0.6, 0.7}}; + + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP1, COLOR1, SIZE1, SHAPE1, VISIBILITY1)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP2, COLOR2, SIZE2, SHAPE2, VISIBILITY2)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP3, COLOR3, SIZE3, SHAPE3, VISIBILITY3)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP1, POINT1)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP2, POINT2)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP3, POINT3)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP1, POINT4)); + + CPPUNIT_ASSERT(landmarks); + + { + // Check deep copy + ::fwData::Landmarks::csptr landmarksCopy = ::fwData::Object::copy(landmarks); + CPPUNIT_ASSERT(landmarksCopy); + + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfGroups(), landmarksCopy->getNumberOfGroups()); + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfPoints(), landmarksCopy->getNumberOfPoints()); + + const ::fwData::Landmarks::GroupNameContainer names = landmarks->getGroupNames(); + + for (const auto& name : names) + { + CPPUNIT_ASSERT_NO_THROW(landmarksCopy->getGroup(name)); + + const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name); + const ::fwData::Landmarks::LandmarksGroup& groupCopy = landmarksCopy->getGroup(name); + + CPPUNIT_ASSERT(group.m_color == groupCopy.m_color); + CPPUNIT_ASSERT_EQUAL(group.m_points.size(), groupCopy.m_points.size()); + CPPUNIT_ASSERT(group.m_points == groupCopy.m_points); + CPPUNIT_ASSERT_EQUAL(group.m_size, groupCopy.m_size); + CPPUNIT_ASSERT_EQUAL(int(group.m_shape), int(groupCopy.m_shape)); + CPPUNIT_ASSERT_EQUAL(group.m_visibility, groupCopy.m_visibility); + } + } + + { + // Check shallow copy + ::fwData::Landmarks::sptr landmarksCopy = ::fwData::Landmarks::New(); + landmarksCopy->shallowCopy(landmarks); + CPPUNIT_ASSERT(landmarksCopy); + + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfGroups(), landmarksCopy->getNumberOfGroups()); + CPPUNIT_ASSERT_EQUAL(landmarks->getNumberOfPoints(), landmarksCopy->getNumberOfPoints()); + + const ::fwData::Landmarks::GroupNameContainer names = landmarks->getGroupNames(); + for (const auto& name : names) + { + CPPUNIT_ASSERT_NO_THROW(landmarksCopy->getGroup(name)); + + const ::fwData::Landmarks::LandmarksGroup& group = landmarks->getGroup(name); + const ::fwData::Landmarks::LandmarksGroup& groupCopy = landmarksCopy->getGroup(name); + + CPPUNIT_ASSERT(group.m_color == groupCopy.m_color); + CPPUNIT_ASSERT_EQUAL(group.m_points.size(), groupCopy.m_points.size()); + CPPUNIT_ASSERT(group.m_points == groupCopy.m_points); + CPPUNIT_ASSERT_EQUAL(group.m_size, groupCopy.m_size); + CPPUNIT_ASSERT_EQUAL(int(group.m_shape), int(groupCopy.m_shape)); + CPPUNIT_ASSERT_EQUAL(group.m_visibility, groupCopy.m_visibility); + } + } +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::groupTest() +{ + const std::string GROUP1 = "group_1"; + const std::string GROUP2 = "group_2"; + const std::string GROUP3 = "group_3"; + const std::string NO_GROUP = "no_group"; + const ::fwData::Landmarks::ColorType COLOR1 = {{1.f, 0.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR2 = {{0.f, 1.0f, 0.0f, 1.0f}}; + const ::fwData::Landmarks::ColorType COLOR3 = {{0.f, 0.0f, 1.0f, 1.0f}}; + const ::fwData::Landmarks::SizeType SIZE1 = 3.45f; + const ::fwData::Landmarks::SizeType SIZE2 = 7.5f; + const ::fwData::Landmarks::SizeType SIZE3 = 1.3f; + const ::fwData::Landmarks::Shape SHAPE1 = ::fwData::Landmarks::Shape::SPHERE; + const ::fwData::Landmarks::Shape SHAPE2 = ::fwData::Landmarks::Shape::CUBE; + const ::fwData::Landmarks::Shape SHAPE3 = ::fwData::Landmarks::Shape::SPHERE; + const bool VISIBILITY1 = true; + const bool VISIBILITY2 = false; + const bool VISIBILITY3 = true; + + ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::New(); + CPPUNIT_ASSERT_EQUAL(size_t(0), landmarks->getNumberOfGroups()); + CPPUNIT_ASSERT_EQUAL(size_t(0), landmarks->getNumberOfPoints()); + + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP1, COLOR1, SIZE1, SHAPE1, VISIBILITY1)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP2, COLOR2, SIZE2, SHAPE2, VISIBILITY2)); + CPPUNIT_ASSERT_THROW(landmarks->addGroup(GROUP1), ::fwData::Exception); + + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfGroups()); + CPPUNIT_ASSERT_EQUAL(size_t(0), landmarks->getNumberOfPoints()); + + const ::fwData::Landmarks::GroupNameContainer names = landmarks->getGroupNames(); + CPPUNIT_ASSERT_EQUAL(size_t(2), names.size()); + + CPPUNIT_ASSERT_EQUAL(GROUP1, names[0]); + CPPUNIT_ASSERT_EQUAL(GROUP2, names[1]); + + // Check group 1 + CPPUNIT_ASSERT_NO_THROW(landmarks->getGroup(GROUP1)); + const ::fwData::Landmarks::LandmarksGroup& group1 = landmarks->getGroup(GROUP1); + CPPUNIT_ASSERT(COLOR1 == group1.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE1, group1.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE1), int(group1.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY1, group1.m_visibility); + + // Check group 2 + CPPUNIT_ASSERT_NO_THROW(landmarks->getGroup(GROUP2)); + const ::fwData::Landmarks::LandmarksGroup& group2 = landmarks->getGroup(GROUP2); + CPPUNIT_ASSERT(COLOR2 == group2.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE2, group2.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE2), int(group2.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY2, group2.m_visibility); + + // Check not existing group + CPPUNIT_ASSERT_THROW(landmarks->getGroup(NO_GROUP), ::fwData::Exception); + + // check rename of a non existing group + CPPUNIT_ASSERT_THROW(landmarks->renameGroup(NO_GROUP, GROUP3), ::fwData::Exception); + + // check rename to an existing group + CPPUNIT_ASSERT_THROW(landmarks->renameGroup(GROUP1, GROUP2), ::fwData::Exception); + + // Remove group 1 + CPPUNIT_ASSERT_NO_THROW(landmarks->removeGroup(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfGroups()); + const ::fwData::Landmarks::GroupNameContainer names2 = landmarks->getGroupNames(); + CPPUNIT_ASSERT_EQUAL(size_t(1), names2.size()); + + CPPUNIT_ASSERT_EQUAL(GROUP2, names2[0]); + + // Rename group_2 to group_1 + CPPUNIT_ASSERT_NO_THROW(landmarks->renameGroup(GROUP2, GROUP3)); + + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfGroups()); + const ::fwData::Landmarks::GroupNameContainer names3 = landmarks->getGroupNames(); + CPPUNIT_ASSERT_EQUAL(size_t(1), names3.size()); + + CPPUNIT_ASSERT_EQUAL(GROUP3, names3[0]); + + { + const ::fwData::Landmarks::LandmarksGroup& group3 = landmarks->getGroup(GROUP3); + CPPUNIT_ASSERT(COLOR2 == group3.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE2, group3.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE2), int(group3.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY2, group3.m_visibility); + } + + // change color + CPPUNIT_ASSERT_NO_THROW(landmarks->setGroupColor(GROUP3, COLOR3)); + + { + const ::fwData::Landmarks::LandmarksGroup& group3 = landmarks->getGroup(GROUP3); + CPPUNIT_ASSERT(COLOR3 == group3.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE2, group3.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE2), int(group3.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY2, group3.m_visibility); + } + + // change size + CPPUNIT_ASSERT_NO_THROW(landmarks->setGroupSize(GROUP3, SIZE3)); + + { + const ::fwData::Landmarks::LandmarksGroup& group3 = landmarks->getGroup(GROUP3); + CPPUNIT_ASSERT(COLOR3 == group3.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE3, group3.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE2), int(group3.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY2, group3.m_visibility); + } + + // change shape + CPPUNIT_ASSERT_NO_THROW(landmarks->setGroupShape(GROUP3, SHAPE3)); + + { + const ::fwData::Landmarks::LandmarksGroup& group3 = landmarks->getGroup(GROUP3); + CPPUNIT_ASSERT(COLOR3 == group3.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE3, group3.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE3), int(group3.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY2, group3.m_visibility); + } + + // change shape + CPPUNIT_ASSERT_NO_THROW(landmarks->setGroupVisibility(GROUP3, VISIBILITY3)); + + { + const ::fwData::Landmarks::LandmarksGroup& group3 = landmarks->getGroup(GROUP3); + CPPUNIT_ASSERT(COLOR3 == group3.m_color); + CPPUNIT_ASSERT_EQUAL(SIZE3, group3.m_size); + CPPUNIT_ASSERT_EQUAL(int(SHAPE3), int(group3.m_shape)); + CPPUNIT_ASSERT_EQUAL(VISIBILITY3, group3.m_visibility); + } +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::pointsTest() +{ + const std::string GROUP1 = "group_1"; + const std::string GROUP2 = "group_2"; + const std::string GROUP3 = "group_3"; + const std::string NO_GROUP = "no_group"; + + const ::fwData::Landmarks::PointType POINT1 = {{3.5, 5.8, 2.56}}; + const ::fwData::Landmarks::PointType POINT2 = {{8.25, 56.0, 45.4}}; + const ::fwData::Landmarks::PointType POINT3 = {{0.0, 0.0, 0.0}}; + const ::fwData::Landmarks::PointType POINT4 = {{0.5, 0.6, 0.7}}; + + ::fwData::Landmarks::sptr landmarks = ::fwData::Landmarks::New(); + + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP1)); + CPPUNIT_ASSERT_NO_THROW(landmarks->addGroup(GROUP2)); + + CPPUNIT_ASSERT_THROW(landmarks->addPoint(NO_GROUP, POINT1), ::fwData::Exception); + + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP1, POINT1)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints()); + + const ::fwData::Landmarks::PointContainer& points = landmarks->getPoints(GROUP1); + CPPUNIT_ASSERT_EQUAL(size_t(1), points.size()); + CPPUNIT_ASSERT(POINT1 == points[0]); + CPPUNIT_ASSERT(POINT1 == landmarks->getPoint(GROUP1, 0)); + CPPUNIT_ASSERT_THROW(landmarks->getPoint(GROUP1, 23), std::out_of_range); + + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP2, POINT2)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints(GROUP2)); + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfPoints()); + + CPPUNIT_ASSERT_NO_THROW(landmarks->addPoint(GROUP2, POINT3)); + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfPoints(GROUP2)); + CPPUNIT_ASSERT_EQUAL(size_t(3), landmarks->getNumberOfPoints()); + + const ::fwData::Landmarks::PointContainer& points2 = landmarks->getPoints(GROUP2); + CPPUNIT_ASSERT_EQUAL(size_t(2), points2.size()); + CPPUNIT_ASSERT(POINT2 == points2[0]); + CPPUNIT_ASSERT(POINT3 == points2[1]); + CPPUNIT_ASSERT(POINT2 == landmarks->getPoint(GROUP2, 0)); + CPPUNIT_ASSERT(POINT3 == landmarks->getPoint(GROUP2, 1)); + + // Check rename group + CPPUNIT_ASSERT_NO_THROW(landmarks->renameGroup(GROUP2, GROUP3)); + const ::fwData::Landmarks::PointContainer& points3 = landmarks->getPoints(GROUP3); + CPPUNIT_ASSERT_EQUAL(size_t(2), points3.size()); + CPPUNIT_ASSERT(POINT2 == points3[0]); + CPPUNIT_ASSERT(POINT3 == points3[1]); + CPPUNIT_ASSERT(POINT2 == landmarks->getPoint(GROUP3, 0)); + CPPUNIT_ASSERT(POINT3 == landmarks->getPoint(GROUP3, 1)); + + // Check remove point + CPPUNIT_ASSERT_THROW(landmarks->removePoint(NO_GROUP, 0), ::fwData::Exception); + CPPUNIT_ASSERT_THROW(landmarks->removePoint(GROUP1, 2), std::out_of_range); + CPPUNIT_ASSERT_NO_THROW(landmarks->removePoint(GROUP3, 1)); + + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints(GROUP3)); + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfPoints()); + CPPUNIT_ASSERT(POINT2 == landmarks->getPoint(GROUP3, 0)); + + // Check remove group + CPPUNIT_ASSERT_NO_THROW(landmarks->removeGroup(GROUP3)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(1), landmarks->getNumberOfPoints()); + CPPUNIT_ASSERT_THROW(landmarks->getPoints(GROUP3), ::fwData::Exception); + + // Check insert point + CPPUNIT_ASSERT_NO_THROW(landmarks->insertPoint(GROUP1, 0, POINT4)); + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfPoints(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(2), landmarks->getNumberOfPoints()); + + const ::fwData::Landmarks::PointContainer& points4 = landmarks->getPoints(GROUP1); + CPPUNIT_ASSERT_EQUAL(size_t(2), points4.size()); + CPPUNIT_ASSERT(POINT4 == points4[0]); + CPPUNIT_ASSERT(POINT1 == points4[1]); + CPPUNIT_ASSERT(POINT4 == landmarks->getPoint(GROUP1, 0)); + CPPUNIT_ASSERT(POINT1 == landmarks->getPoint(GROUP1, 1)); + + ::fwData::Landmarks::PointType& point = landmarks->getPoint(GROUP1, 0); + point[2] = 18.6; + CPPUNIT_ASSERT_DOUBLES_EQUAL(18.6, landmarks->getPoint(GROUP1, 0)[2], 0.000001); + + // check clear points + CPPUNIT_ASSERT_NO_THROW(landmarks->clearPoints(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(0), landmarks->getNumberOfPoints(GROUP1)); + CPPUNIT_ASSERT_EQUAL(size_t(0), landmarks->getNumberOfPoints()); +} + +//------------------------------------------------------------------------------ + +} //namespace ut +} //namespace fwData diff --git a/SrcLib/core/fwDataCamp/include/fwDataCamp/autoload.hpp b/SrcLib/core/fwDataCamp/include/fwDataCamp/autoload.hpp index cbeeac076..83385aa3f 100644 --- a/SrcLib/core/fwDataCamp/include/fwDataCamp/autoload.hpp +++ b/SrcLib/core/fwDataCamp/include/fwDataCamp/autoload.hpp @@ -1,5 +1,5 @@ /* ***** 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 ****** */ @@ -7,8 +7,11 @@ #ifndef __FWDATACAMP_AUTOLOAD_HPP__ #define __FWDATACAMP_AUTOLOAD_HPP__ -#include +#include "fwDataCamp/Material.hpp" +#include "fwDataCamp/StructureTraits.hpp" +#include "fwDataCamp/TransferFunction.hpp" +#include #include #include @@ -20,8 +23,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -30,24 +36,17 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include #include #include -#include -#include - -#include "fwDataCamp/Material.hpp" -#include "fwDataCamp/StructureTraits.hpp" -#include "fwDataCamp/TransferFunction.hpp" - namespace fwDataCamp { @@ -100,12 +99,11 @@ struct runner localDeclarefwDatalocationSingleFile(); localDeclarefwDataProcessObject(); localDeclarefwDataTag(); + localDeclarefwDataLandmarks(); } static runner r; }; } //end namespace fwDataCamp - - #endif //__FWDATACAMP_AUTOLOAD_HPP__ diff --git a/SrcLib/core/fwDataCamp/src/fwDataCamp/Landmarks.cpp b/SrcLib/core/fwDataCamp/src/fwDataCamp/Landmarks.cpp new file mode 100644 index 000000000..e679db758 --- /dev/null +++ b/SrcLib/core/fwDataCamp/src/fwDataCamp/Landmarks.cpp @@ -0,0 +1,19 @@ +/* ***** 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 + +#include + +fwCampImplementDataMacro((fwData)(Landmarks)) +{ + builder.base< ::fwData::Object>() + .tag("object_version", "1") + .tag("lib_name", "fwData"); + // property 'landmarks' is not introspected because it contains a struct that is not managed by camp + //.property("landmarks", &::fwData::Landmarks::m_landmarks); +} + diff --git a/SrcLib/core/fwDataCamp/test/tu/include/LandmarksTest.hpp b/SrcLib/core/fwDataCamp/test/tu/include/LandmarksTest.hpp new file mode 100644 index 000000000..3ce8c1ada --- /dev/null +++ b/SrcLib/core/fwDataCamp/test/tu/include/LandmarksTest.hpp @@ -0,0 +1,35 @@ +/* ***** 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 __FWDATACAMP_UT_LANDMARKSTEST_HPP__ +#define __FWDATACAMP_UT_LANDMARKSTEST_HPP__ + +#include + +namespace fwMedDataCamp +{ +namespace ut +{ + +class LandmarksTest : public CPPUNIT_NS::TestFixture +{ +CPPUNIT_TEST_SUITE( LandmarksTest ); +CPPUNIT_TEST( propertiesTest ); +CPPUNIT_TEST_SUITE_END(); + +public: + // interface + void setUp(); + void tearDown(); + + void propertiesTest(); + +}; + +} //namespace ut +} //namespace fwMedDataCamp + +#endif // __FWDATACAMP_UT_LANDMARKSTEST_HPP__ diff --git a/SrcLib/core/fwDataCamp/test/tu/src/LandmarksTest.cpp b/SrcLib/core/fwDataCamp/test/tu/src/LandmarksTest.cpp new file mode 100644 index 000000000..4f21446e5 --- /dev/null +++ b/SrcLib/core/fwDataCamp/test/tu/src/LandmarksTest.cpp @@ -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 ****** */ + +#include "LandmarksTest.hpp" + +#include "DataCampHelper.hpp" + +#include + +#include +#include + +#include + +using namespace ::boost::assign; + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( ::fwMedDataCamp::ut::LandmarksTest ); + +namespace fwMedDataCamp +{ +namespace ut +{ + +//------------------------------------------------------------------------------ + +void LandmarksTest::setUp() +{ + // Set up context before running a test. + //Force link with fwMedDataCamp + const int version = ::fwDataCamp::Version::s_CURRENT_VERSION; + FwCoreNotUsedMacro(version); +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::tearDown() +{ + // Clean up after the test run. +} + +//------------------------------------------------------------------------------ + +void LandmarksTest::propertiesTest() +{ + const std::string VALUE_NAME = "myValueName"; + const std::string VALUE = "myValue"; + ::DataCampHelper::PropertiesNameType dataProperties = list_of("fields"); + + ::fwData::Landmarks::sptr obj = ::fwData::Landmarks::New(); + ::fwData::String::sptr str = ::fwData::String::New(VALUE); + obj->setField(VALUE_NAME, str); + + ::DataCampHelper::visitProperties(obj->getClassname(), dataProperties); + ::DataCampHelper::compareSimplePropertyValue(obj, "@fields.myValueName", VALUE); +} + +//------------------------------------------------------------------------------ + +} //namespace ut +} //namespace fwMedDataCamp diff --git a/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp new file mode 100644 index 000000000..e5416ed7c --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp @@ -0,0 +1,57 @@ +/* ***** 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 __FWMDSEMANTICPATCH_V09ALA_V10_FWDATA_IMAGE_HPP__ +#define __FWMDSEMANTICPATCH_V09ALA_V10_FWDATA_IMAGE_HPP__ + +#include "fwMDSemanticPatch/config.hpp" + +#include + +namespace fwMDSemanticPatch +{ +namespace V09ALA +{ +namespace V10 +{ +namespace fwData +{ + +/// Patch the 'landmarks' field of an image from version 'V9ALA' to 'V10' within 'MedicalData' context. +class FWMDSEMANTICPATCH_CLASS_API Image : public ::fwAtomsPatch::ISemanticPatch +{ +public: + fwCoreClassDefinitionsWithFactoryMacro( + (Image)(::fwAtomsPatch::ISemanticPatch), (()), new Image); + + /// Constructor + FWMDSEMANTICPATCH_API Image(); + + /// Destructor + FWMDSEMANTICPATCH_API ~Image(); + + /// Copy constructor + FWMDSEMANTICPATCH_API Image( const Image& cpy ); + + /** + * @brief Applies patch. + * + * Converts the "m_imageLandmarksId" field from a ::fwData::PointList to a ::fwData::Landmarks in "m_landmarksId" . + */ + FWMDSEMANTICPATCH_API virtual void apply( + const ::fwAtoms::Object::sptr& previous, + const ::fwAtoms::Object::sptr& current, + ::fwAtomsPatch::IPatch::NewVersionsType& newVersions); + +}; + +} // namespace fwData +} // namespace V10 +} // namespace V09ALA +} // namespace fwMDSemanticPatch + +#endif /* __FWMDSEMANTICPATCH_V09ALA_V10_FWDATA_IMAGE_HPP__ */ + diff --git a/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp new file mode 100644 index 000000000..ca95ad141 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp @@ -0,0 +1,57 @@ +/* ***** 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 __FWMDSEMANTICPATCH_V10_V09ALA_FWDATA_IMAGE_HPP__ +#define __FWMDSEMANTICPATCH_V10_V09ALA_FWDATA_IMAGE_HPP__ + +#include "fwMDSemanticPatch/config.hpp" + +#include + +namespace fwMDSemanticPatch +{ +namespace V10 +{ +namespace V09ALA +{ +namespace fwData +{ + +/// Patch the 'landmarks' field of an image from version 'V10' to 'V09ALA' within 'MedicalData' context. +class FWMDSEMANTICPATCH_CLASS_API Image : public ::fwAtomsPatch::ISemanticPatch +{ +public: + fwCoreClassDefinitionsWithFactoryMacro( + (Image)(::fwAtomsPatch::ISemanticPatch), (()), new Image); + + /// Constructor + FWMDSEMANTICPATCH_API Image(); + + /// Destructor + FWMDSEMANTICPATCH_API ~Image(); + + /// Copy constructor + FWMDSEMANTICPATCH_API Image( const Image& cpy ); + + /** + * @brief Applies patch. + * + * Converts the "m_landmarksId" field from a ::fwData::Landmarks to a ::fwData::PointList in "m_imageLandmarksId" . + */ + FWMDSEMANTICPATCH_API virtual void apply( + const ::fwAtoms::Object::sptr& previous, + const ::fwAtoms::Object::sptr& current, + ::fwAtomsPatch::IPatch::NewVersionsType& newVersions); + +}; + +} // namespace fwData +} // namespace V09ALA +} // namespace V10 +} // namespace fwMDSemanticPatch + +#endif /* __FWMDSEMANTICPATCH_V10_V09ALA_FWDATA_IMAGE_HPP__ */ + diff --git a/SrcLib/patch/fwMDSemanticPatch/rc/V09ALAToV10.graphlink b/SrcLib/patch/fwMDSemanticPatch/rc/V09ALAToV10.graphlink new file mode 100644 index 000000000..925a3178d --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/rc/V09ALAToV10.graphlink @@ -0,0 +1,7 @@ +{ + "context" : "MedicalData", + "origin_version" : "V09ALA", + "target_version" : "V10", + "patcher" : "DefaultPatcher", + "links" : [] +} diff --git a/SrcLib/patch/fwMDSemanticPatch/rc/V10.versions b/SrcLib/patch/fwMDSemanticPatch/rc/V10.versions new file mode 100644 index 000000000..536d16fc7 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/rc/V10.versions @@ -0,0 +1,53 @@ +{ + "context": "MedicalData", + "version_name": "V10", + "versions": { + "::fwData::Array": "1", + "::fwData::Boolean": "1", + "::fwData::Color": "1", + "::fwData::Composite": "1", + "::fwData::Edge": "1", + "::fwData::Float": "1", + "::fwData::Graph": "1", + "::fwData::Histogram": "1", + "::fwData::Image": "2", + "::fwData::Integer": "1", + "::fwData::Landmarks": "1", + "::fwData::Line": "1", + "::fwData::List": "1", + "::fwData::Material": "4", + "::fwData::Mesh": "3", + "::fwData::Node": "1", + "::fwData::Plane": "1", + "::fwData::PlaneList": "1", + "::fwData::Point": "1", + "::fwData::PointList": "1", + "::fwData::Port": "1", + "::fwData::ProcessObject": "1", + "::fwData::ROITraits": "1", + "::fwData::Reconstruction": "3", + "::fwData::ReconstructionTraits": "1", + "::fwData::Resection": "1", + "::fwData::ResectionDB": "1", + "::fwData::String": "1", + "::fwData::StructureTraits": "1", + "::fwData::StructureTraitsDictionary": "1", + "::fwData::Tag": "1", + "::fwData::TransferFunction": "1", + "::fwData::TransformationMatrix3D": "2", + "::fwData::Vector": "1", + "::fwData::location::Folder": "1", + "::fwData::location::SingleFile": "1", + "::fwMedData::ActivitySeries": "1", + "::fwMedData::AttachmentSeries": "1", + "::fwMedData::DicomSeries": "1", + "::fwMedData::Equipment": "1", + "::fwMedData::ImageSeries": "1", + "::fwMedData::ModelSeries": "1", + "::fwMedData::NavigationSeries": "1", + "::fwMedData::Patient": "1", + "::fwMedData::Series": "1", + "::fwMedData::SeriesDB": "1", + "::fwMedData::Study": "1" + } +} diff --git a/SrcLib/patch/fwMDSemanticPatch/rc/V10ToV09ALA.graphlink b/SrcLib/patch/fwMDSemanticPatch/rc/V10ToV09ALA.graphlink new file mode 100644 index 000000000..5dc9122c4 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/rc/V10ToV09ALA.graphlink @@ -0,0 +1,7 @@ +{ + "context" : "MedicalData", + "origin_version" : "V10", + "target_version" : "V09ALA", + "patcher" : "DefaultPatcher", + "links" : [] +} diff --git a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/PatchLoader.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/PatchLoader.cpp index cce2fc833..598de2c03 100644 --- a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/PatchLoader.cpp +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/PatchLoader.cpp @@ -1,16 +1,18 @@ /* ***** 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 - #include "fwMDSemanticPatch/PatchLoader.hpp" +#include + namespace fwMDSemanticPatch { +//------------------------------------------------------------------------------ + void PatchLoader::loadPatches() { SPTR(::fwAtomsPatch::VersionsManager) versionManager = ::fwAtomsPatch::VersionsManager::getDefault(); @@ -22,7 +24,7 @@ void PatchLoader::loadPatches() std::string PatchLoader::getCurrentVersion() { - return "V09ALA"; + return "V10"; } } //namespace fwMDSemanticPatch diff --git a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp new file mode 100644 index 000000000..12610ab76 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp @@ -0,0 +1,136 @@ +/* ***** 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 "fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace fwMDSemanticPatch +{ +namespace V09ALA +{ +namespace V10 +{ +namespace fwData +{ + +Image::Image() : + ::fwAtomsPatch::ISemanticPatch() +{ + m_originClassname = "::fwData::Image"; + m_originVersion = "2"; + this->addContext("MedicalData", "V09ALA", "V10"); +} + +// ---------------------------------------------------------------------------- + +Image::~Image() +{ +} + +// ---------------------------------------------------------------------------- + +Image::Image( const Image& cpy ) : + ::fwAtomsPatch::ISemanticPatch(cpy) +{ +} + +// ---------------------------------------------------------------------------- + +void Image::apply( + const ::fwAtoms::Object::sptr& previous, + const ::fwAtoms::Object::sptr& current, + ::fwAtomsPatch::IPatch::NewVersionsType& newVersions) +{ + ISemanticPatch::apply(previous, current, newVersions); + ::fwAtomsPatch::helper::cleanFields( current ); + ::fwAtomsPatch::helper::Object helper( current ); + + ::fwAtoms::Map::csptr previousFieldMap = ::fwAtoms::Map::dynamicCast(previous->getAttribute("fields")); + SLM_ASSERT("Image does not have field map", previousFieldMap); + + const auto& iter = previousFieldMap->find("m_imageLandmarksId"); + if (iter != previousFieldMap->end()) + { + // create new Landmarks structure + ::fwAtomsPatch::StructuralCreatorDB::sptr creators = ::fwAtomsPatch::StructuralCreatorDB::getDefault(); + + ::fwAtoms::Object::sptr currentLandmarks = creators->create( "::fwData::Landmarks", "1"); + ::fwAtomsPatch::helper::Object helperLandmarks( currentLandmarks ); + + ::fwAtoms::Map::sptr currentFieldMap = ::fwAtoms::Map::dynamicCast(current->getAttribute("fields")); + currentFieldMap->insert("m_landmarksId", currentLandmarks); + + ::fwAtoms::Map::sptr landmarksMap = ::fwAtoms::Map::dynamicCast(currentLandmarks->getAttribute("landmarks")); + + // Convert previous PointList + ::fwAtoms::Object::sptr previousPL = ::fwAtoms::Object::dynamicCast(iter->second); + + ::fwAtoms::Sequence::sptr previousPLSeq = ::fwAtoms::Sequence::dynamicCast(previousPL->getAttribute("points")); + + size_t count = 0; + for (const auto& obj : previousPLSeq->getValue()) + { + // get point coordinates + ::fwAtoms::Object::csptr point = ::fwAtoms::Object::dynamicCast(obj); + ::fwAtoms::Sequence::csptr pointCoords = ::fwAtoms::Sequence::dynamicCast(point->getAttribute("coord")); + ::fwAtoms::Numeric::csptr coordX = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[0]); + ::fwAtoms::Numeric::csptr coordY = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[1]); + ::fwAtoms::Numeric::csptr coordZ = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[2]); + const std::string coords = coordX->getString() + ";" + coordY->getString() + ";" + coordZ->getString(); + + // get point label + ::fwAtoms::Map::csptr pointFieldMap = ::fwAtoms::Map::dynamicCast(point->getAttribute("fields")); + + std::string label; + const auto& it = pointFieldMap->find("m_labelId"); + if (it != pointFieldMap->end()) + { + ::fwAtoms::Object::csptr labelObj = ::fwAtoms::Object::dynamicCast(it->second); + ::fwAtoms::String::csptr labelStr = ::fwAtoms::String::dynamicCast(labelObj->getAttribute("value")); + label = labelStr->getValue(); + } + if (label.empty()) + { + label = "label_" + std::to_string(count++); + } + + // create one landmark group per point + ::fwAtoms::Object::sptr atomGroup = ::fwAtoms::Object::New(); + atomGroup->setMetaInfo("ID_METAINFO", ::fwTools::UUID::generateUUID()); + + atomGroup->setAttribute("color", ::fwAtoms::String::New("1;1;1;1")); + atomGroup->setAttribute("size", ::fwAtoms::Numeric::New(1)); + atomGroup->setAttribute("shape", ::fwAtoms::String::New("SPHERE")); + atomGroup->setAttribute("visibility", ::fwAtoms::Boolean::New(true)); + + ::fwAtoms::Sequence::sptr seq = ::fwAtoms::Sequence::New(); + + seq->push_back(::fwAtoms::String::New(coords)); + atomGroup->setAttribute("points", seq); + landmarksMap->insert(label, atomGroup); + } + } +} + +// ---------------------------------------------------------------------------- + +} // namespace fwData +} // namespace V10 +} // namespace V09ALA +} // namespace fwMDSemanticPatch + diff --git a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/autoload.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/autoload.cpp new file mode 100644 index 000000000..057ef0027 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/autoload.cpp @@ -0,0 +1,38 @@ +/* ***** 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 "fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp" + +#include + +namespace fwMDSemanticPatch +{ +namespace V09ALA +{ +namespace V10 +{ +namespace fwData +{ + +/// Registers contextual patches dedicated to conversions from version 'V2' to version 'V03AGO'. +struct runner +{ + runner() + { + ::fwAtomsPatch::SemanticPatchDB::sptr contextPatchDB = ::fwAtomsPatch::SemanticPatchDB::getDefault(); + contextPatchDB->registerPatch(::fwMDSemanticPatch::V09ALA::V10::fwData::Image::New()); + } + + static runner r; +}; + +runner runner::r; + +} // namespace fwData +} // namespace V10 +} // namespace V09ALA +} // namespace fwMDSemanticPatch + diff --git a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/Image.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/Image.cpp new file mode 100644 index 000000000..d1631992f --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/Image.cpp @@ -0,0 +1,134 @@ +/* ***** 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 "fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +namespace fwMDSemanticPatch +{ +namespace V10 +{ +namespace V09ALA +{ +namespace fwData +{ + +Image::Image() : + ::fwAtomsPatch::ISemanticPatch() +{ + m_originClassname = "::fwData::Image"; + m_originVersion = "2"; + this->addContext("MedicalData", "V10", "V09ALA"); +} + +// ---------------------------------------------------------------------------- + +Image::~Image() +{ +} + +// ---------------------------------------------------------------------------- + +Image::Image( const Image& cpy ) : + ::fwAtomsPatch::ISemanticPatch(cpy) +{ +} + +// ---------------------------------------------------------------------------- + +void Image::apply( + const ::fwAtoms::Object::sptr& previous, + const ::fwAtoms::Object::sptr& current, + ::fwAtomsPatch::IPatch::NewVersionsType& newVersions) +{ + ISemanticPatch::apply(previous, current, newVersions); + ::fwAtomsPatch::helper::cleanFields( current ); + ::fwAtomsPatch::helper::Object helper( current ); + + ::fwAtoms::Map::csptr previousFieldMap = ::fwAtoms::Map::dynamicCast(previous->getAttribute("fields")); + SLM_ASSERT("Image does not have field map", previousFieldMap); + + const auto& iter = previousFieldMap->find("m_landmarksId"); + if (iter != previousFieldMap->end()) + { + // create new Landmarks structure + ::fwAtomsPatch::StructuralCreatorDB::sptr creators = ::fwAtomsPatch::StructuralCreatorDB::getDefault(); + + ::fwAtoms::Object::sptr currentPL = creators->create( "::fwData::PointList", "1"); + ::fwAtomsPatch::helper::Object helperPL( currentPL ); + + ::fwAtoms::Map::sptr currentFieldMap = ::fwAtoms::Map::dynamicCast(current->getAttribute("fields")); + currentFieldMap->insert("m_imageLandmarksId", currentPL); + + ::fwAtoms::Sequence::sptr plSeq = ::fwAtoms::Sequence::dynamicCast(currentPL->getAttribute("points")); + + // Convert previous Landmarks + ::fwAtoms::Object::sptr previousLandmarks = ::fwAtoms::Object::dynamicCast(iter->second); + + ::fwAtoms::Map::sptr previousLandmarksMap = + ::fwAtoms::Map::dynamicCast(previousLandmarks->getAttribute("landmarks")); + + for (const auto& elt : previousLandmarksMap->getValue()) + { + ::fwAtoms::Object::csptr atomGroup = ::fwAtoms::Object::dynamicCast(elt.second); + ::fwAtoms::Sequence::csptr points = ::fwAtoms::Sequence::dynamicCast(atomGroup->getAttribute("points")); + + size_t count = 0; + for (const auto& ptObj : points->getValue()) + { + ::fwAtoms::String::csptr previousPt = ::fwAtoms::String::dynamicCast(ptObj); + std::vector res; + const std::string coords = previousPt->getValue(); + ::boost::split(res, coords, ::boost::is_any_of(";")); + + ::fwAtoms::Object::sptr point = ::fwAtoms::Object::New(); + ::fwAtomsPatch::helper::setClassname(point, "::fwData::Point"); + ::fwAtomsPatch::helper::setVersion(point, "1"); + ::fwAtomsPatch::helper::generateID(point); + + plSeq->push_back(point); + + ::fwAtomsPatch::helper::Object helperPt( point ); + ::fwAtoms::Sequence::sptr pointCoord = ::fwAtoms::Sequence::New(); + helperPt.addAttribute("coord", pointCoord); + pointCoord->push_back(::fwAtoms::Numeric::New(std::stod(res[0]))); + pointCoord->push_back(::fwAtoms::Numeric::New(std::stod(res[1]))); + pointCoord->push_back(::fwAtoms::Numeric::New(std::stod(res[2]))); + + // set point label + ::fwAtoms::Map::sptr pointFieldMap = ::fwAtoms::Map::New(); + helperPt.addAttribute("fields", pointFieldMap); + + const std::string label = elt.first + "_" + std::to_string(count); + + pointFieldMap->insert("m_labelId", ::fwAtoms::String::New(label)); + ++count; + } + } + } +} + +// ---------------------------------------------------------------------------- + +} // namespace fwData +} // namespace V09ALA +} // namespace V10 +} // namespace fwMDSemanticPatch + diff --git a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/autoload.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/autoload.cpp new file mode 100644 index 000000000..dbc1449e3 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/autoload.cpp @@ -0,0 +1,38 @@ +/* ***** 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 "fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp" + +#include + +namespace fwMDSemanticPatch +{ +namespace V10 +{ +namespace V09ALA +{ +namespace fwData +{ + +/// Registers contextual patches dedicated to conversions from version 'V2' to version 'V03AGO'. +struct runner +{ + runner() + { + ::fwAtomsPatch::SemanticPatchDB::sptr contextPatchDB = ::fwAtomsPatch::SemanticPatchDB::getDefault(); + contextPatchDB->registerPatch(::fwMDSemanticPatch::V10::V09ALA::fwData::Image::New()); + } + + static runner r; +}; + +runner runner::r; + +} // namespace fwData +} // namespace V09ALA +} // namespace V10 +} // namespace fwMDSemanticPatch + diff --git a/SrcLib/patch/fwMDSemanticPatch/test/CMakeLists.txt b/SrcLib/patch/fwMDSemanticPatch/test/CMakeLists.txt new file mode 100644 index 000000000..388199671 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/CMakeLists.txt @@ -0,0 +1,7 @@ +fwLoadProperties() +find_package(CppUnit) +fwInclude(${CPPUNIT_INCLUDE_DIR}) +fwLink(${CPPUNIT_LIBRARY}) + + + diff --git a/SrcLib/patch/fwMDSemanticPatch/test/Properties.cmake b/SrcLib/patch/fwMDSemanticPatch/test/Properties.cmake new file mode 100644 index 000000000..fe5f29f89 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/Properties.cmake @@ -0,0 +1,6 @@ + +set( NAME fwMDSemanticPatchTest ) +set( VERSION ) +set( TYPE TEST ) +set( DEPENDENCIES fwCore fwTest fwMDSemanticPatch fwStructuralPatch fwAtomsPatch fwAtoms) +set( REQUIREMENTS ) diff --git a/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV09ALAToV10Test.hpp b/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV09ALAToV10Test.hpp new file mode 100644 index 000000000..73c0a4e23 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV09ALAToV10Test.hpp @@ -0,0 +1,41 @@ +/* ***** 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 __FWMDSEMANTICPATCH_UT_IMAGEV09ALATOV10TEST_HPP__ +#define __FWMDSEMANTICPATCH_UT_IMAGEV09ALATOV10TEST_HPP__ + +#include + +#include + +namespace fwMDSemanticPatch +{ +namespace ut +{ +/** + * @brief Test patch to convert 'm_imageLandmarksId' field of '::fwData::Image' from '::fwData::PointList' to + * `::fwData::Landmarks`. + */ +class ImageV09ALAToV10Test : public CPPUNIT_NS::TestFixture +{ +CPPUNIT_TEST_SUITE( ImageV09ALAToV10Test ); +CPPUNIT_TEST( applyPatchTest ); +CPPUNIT_TEST_SUITE_END(); + +public: + // interface + void setUp(); + void tearDown(); + + void applyPatchTest(); + + void addPoint(::fwAtoms::Sequence::sptr seq, const std::array& pt, const std::string& label); +}; + +} //namespace ut +} //namespace fwMDSemanticPatch + +#endif //__FWMDSEMANTICPATCH_UT_IMAGEV09ALATOV10TEST_HPP__ diff --git a/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV10ToV09ALATest.hpp b/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV10ToV09ALATest.hpp new file mode 100644 index 000000000..c0ba67742 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV10ToV09ALATest.hpp @@ -0,0 +1,41 @@ +/* ***** 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 __FWMDSEMANTICPATCH_UT_IMAGEV10TOV09ALATEST_HPP__ +#define __FWMDSEMANTICPATCH_UT_IMAGEV10TOV09ALATEST_HPP__ + +#include + +#include + +namespace fwMDSemanticPatch +{ +namespace ut +{ +/** + * @brief Test patch to convert 'm_imageLandmarksId' field of '::fwData::Image' from '::fwData::PointList' to + * `::fwData::Landmarks`. + */ +class ImageV10ToV09ALATest : public CPPUNIT_NS::TestFixture +{ +CPPUNIT_TEST_SUITE( ImageV10ToV09ALATest ); +CPPUNIT_TEST( applyPatchTest ); +CPPUNIT_TEST_SUITE_END(); + +public: + // interface + void setUp(); + void tearDown(); + + void applyPatchTest(); + + void addPoint(::fwAtoms::Map::sptr map, const std::array& pt, const std::string& label); +}; + +} //namespace ut +} //namespace fwMDSemanticPatch + +#endif //__FWMDSEMANTICPATCH_UT_IMAGEV10TOV09ALATEST_HPP__ diff --git a/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp new file mode 100644 index 000000000..627106833 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp @@ -0,0 +1,184 @@ +/* ***** 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 "ImageV09ALAToV10Test.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( ::fwMDSemanticPatch::ut::ImageV09ALAToV10Test ); + +namespace fwMDSemanticPatch +{ +namespace ut +{ + +//------------------------------------------------------------------------------ + +void ImageV09ALAToV10Test::setUp() +{ + // Set up context before running a test. + ::fwStructuralPatch::PatchLoader::loadPatches(); +} + +//------------------------------------------------------------------------------ + +void ImageV09ALAToV10Test::tearDown() +{ + // Clean up after the test run. +} + +//------------------------------------------------------------------------------ + +void ImageV09ALAToV10Test::applyPatchTest() +{ + const std::array P1 = {{33.5, 25.54, 45.45}}; + const std::array P2 = {{45.45, 54.4, 42.5}}; + const std::array P3 = {{5.4, 5.5, 4.5}}; + const std::array P4 = {{465.5, 5.4, 89.5}}; + const std::array P5 = {{3.5, 8.3, 0.}}; + + std::vector > pts; + pts.push_back(P1); + pts.push_back(P2); + pts.push_back(P3); + pts.push_back(P4); + pts.push_back(P5); + + ::fwAtoms::Object::sptr image = ::fwAtoms::Object::New(); + ::fwAtoms::Object::sptr patchedObj; + + ::fwAtomsPatch::helper::setClassname(image, "::fwData::Image"); + ::fwAtomsPatch::helper::setVersion(image, "2"); + + ::fwAtomsPatch::helper::Object helperImage(image); + + ::fwAtoms::Map::sptr fieldMap = ::fwAtoms::Map::New(); + + helperImage.addAttribute("fields", fieldMap); + + // create PointList + ::fwAtoms::Object::sptr pl = ::fwAtoms::Object::New(); + ::fwAtomsPatch::helper::setClassname(pl, "::fwData::PointList"); + ::fwAtomsPatch::helper::setVersion(pl, "1"); + ::fwAtomsPatch::helper::Object helperPL(pl); + + ::fwAtoms::Sequence::sptr seq = ::fwAtoms::Sequence::New(); + helperPL.addAttribute("points", seq); + this->addPoint(seq, P1, "point_1"); + this->addPoint(seq, P2, "point_2"); + this->addPoint(seq, P3, "point_3"); + this->addPoint(seq, P4, "point_4"); + this->addPoint(seq, P5, "point_5"); + + fieldMap->insert("m_imageLandmarksId", pl); + + patchedObj = ::fwAtoms::Object::dynamicCast(image->clone()); + + ::fwAtomsPatch::IPatch::NewVersionsType newVersions; + newVersions[image] = patchedObj; + + ::fwMDSemanticPatch::V09ALA::V10::fwData::Image::sptr patcher = + ::fwMDSemanticPatch::V09ALA::V10::fwData::Image::New(); + CPPUNIT_ASSERT_NO_THROW(patcher->apply(image, patchedObj, newVersions)); + + CPPUNIT_ASSERT(patchedObj->getAttribute("fields")); + ::fwAtoms::Map::sptr newFieldMap = ::fwAtoms::Map::dynamicCast(patchedObj->getAttribute("fields")); + CPPUNIT_ASSERT(newFieldMap); + + CPPUNIT_ASSERT(newFieldMap->find("m_landmarksId") != newFieldMap->end()); + ::fwAtoms::Object::sptr landmarks = ::fwAtoms::Object::dynamicCast((*newFieldMap)["m_landmarksId"]); + CPPUNIT_ASSERT(landmarks); + CPPUNIT_ASSERT_EQUAL(std::string("::fwData::Landmarks"), ::fwAtomsPatch::helper::getClassname(landmarks)); + CPPUNIT_ASSERT(landmarks->getAttribute("landmarks")); + ::fwAtoms::Map::sptr landmarksMap = ::fwAtoms::Map::dynamicCast(landmarks->getAttribute("landmarks")); + CPPUNIT_ASSERT(landmarksMap); + CPPUNIT_ASSERT_EQUAL(size_t(5), landmarksMap->size()); + + size_t count = 0; + for (const auto& elt: landmarksMap->getValue()) + { + ::fwAtoms::Object::csptr atomGroup = ::fwAtoms::Object::dynamicCast(elt.second); + CPPUNIT_ASSERT(atomGroup); + ::fwAtoms::String::csptr color = ::fwAtoms::String::dynamicCast(atomGroup->getAttribute("color")); + CPPUNIT_ASSERT(color); + CPPUNIT_ASSERT_EQUAL(std::string("1;1;1;1"), color->getValue()); + ::fwAtoms::Numeric::csptr size = ::fwAtoms::Numeric::dynamicCast(atomGroup->getAttribute("size")); + CPPUNIT_ASSERT(size); + CPPUNIT_ASSERT_EQUAL(1.f, size->getValue()); + ::fwAtoms::String::csptr shape = ::fwAtoms::String::dynamicCast(atomGroup->getAttribute("shape")); + CPPUNIT_ASSERT(shape); + CPPUNIT_ASSERT_EQUAL(std::string("SPHERE"), shape->getValue()); + ::fwAtoms::Boolean::csptr visibility = ::fwAtoms::Boolean::dynamicCast(atomGroup->getAttribute("visibility")); + CPPUNIT_ASSERT(visibility); + CPPUNIT_ASSERT_EQUAL(true, visibility->getValue()); + + ::fwAtoms::Sequence::csptr points = ::fwAtoms::Sequence::dynamicCast(atomGroup->getAttribute("points")); + CPPUNIT_ASSERT(points); + CPPUNIT_ASSERT_EQUAL(size_t(1), points->size()); + ::fwAtoms::String::csptr ptStr = ::fwAtoms::String::dynamicCast(points->getValue()[0]); + + std::vector res; + const std::string coords = ptStr->getValue(); + ::boost::split(res, coords, ::boost::is_any_of(";")); + CPPUNIT_ASSERT_DOUBLES_EQUAL(pts[count][0], std::stod(res[0]), 0.000001); + ++count; + } +} + +//------------------------------------------------------------------------------ + +void ImageV09ALAToV10Test::addPoint(::fwAtoms::Sequence::sptr seq, const std::array& pt, + const std::string& label) +{ + ::fwAtoms::Object::sptr point = ::fwAtoms::Object::New(); + ::fwAtomsPatch::helper::setClassname(point, "::fwData::Point"); + ::fwAtomsPatch::helper::setVersion(point, "1"); + ::fwAtomsPatch::helper::Object helper(point); + + seq->push_back(point); + + ::fwAtoms::Sequence::sptr ptSeq = ::fwAtoms::Sequence::New(); + helper.addAttribute("coord", ptSeq); + ptSeq->push_back(::fwAtoms::Numeric::New(pt[0])); + ptSeq->push_back(::fwAtoms::Numeric::New(pt[1])); + ptSeq->push_back(::fwAtoms::Numeric::New(pt[2])); + + ::fwAtoms::Map::sptr fieldMap = ::fwAtoms::Map::New(); + helper.addAttribute("fields", fieldMap); + + ::fwAtoms::Object::sptr labelObj = ::fwAtoms::Object::New(); + ::fwAtomsPatch::helper::setClassname(labelObj, "::fwData::String"); + ::fwAtomsPatch::helper::setVersion(labelObj, "1"); + ::fwAtomsPatch::helper::Object helperLabel(labelObj); + helperLabel.addAttribute("value", ::fwAtoms::String::New(label)); + + fieldMap->insert("m_labelId", labelObj); +} + +//------------------------------------------------------------------------------ +} //namespace ut +} //namespace fwMDSemanticPatch diff --git a/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV10ToV09ALATest.cpp b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV10ToV09ALATest.cpp new file mode 100644 index 000000000..6bc2732e3 --- /dev/null +++ b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV10ToV09ALATest.cpp @@ -0,0 +1,165 @@ +/* ***** 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 "ImageV10ToV09ALATest.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +// Registers the fixture into the 'registry' +CPPUNIT_TEST_SUITE_REGISTRATION( ::fwMDSemanticPatch::ut::ImageV10ToV09ALATest ); + +namespace fwMDSemanticPatch +{ +namespace ut +{ + +//------------------------------------------------------------------------------ + +void ImageV10ToV09ALATest::setUp() +{ + // Set up context before running a test. +} + +//------------------------------------------------------------------------------ + +void ImageV10ToV09ALATest::tearDown() +{ + // Clean up after the test run. +} + +//------------------------------------------------------------------------------ + +void ImageV10ToV09ALATest::applyPatchTest() +{ + const std::array P1 = {{33.5, 25.54, 45.45}}; + const std::array P2 = {{45.45, 54.4, 42.5}}; + const std::array P3 = {{5.4, 5.5, 4.5}}; + const std::array P4 = {{465.5, 5.4, 89.5}}; + const std::array P5 = {{3.5, 8.3, 0.}}; + + std::vector > pts; + pts.push_back(P1); + pts.push_back(P2); + pts.push_back(P3); + pts.push_back(P4); + pts.push_back(P5); + + ::fwAtoms::Object::sptr image = ::fwAtoms::Object::New(); + ::fwAtoms::Object::sptr patchedObj; + + ::fwAtomsPatch::helper::setClassname(image, "::fwData::Image"); + ::fwAtomsPatch::helper::setVersion(image, "2"); + + ::fwAtomsPatch::helper::Object helperImage(image); + + ::fwAtoms::Map::sptr fieldMap = ::fwAtoms::Map::New(); + + helperImage.addAttribute("fields", fieldMap); + + // create PointList + ::fwAtoms::Object::sptr landmarks = ::fwAtoms::Object::New(); + ::fwAtomsPatch::helper::setClassname(landmarks, "::fwData::Landmarks"); + ::fwAtomsPatch::helper::setVersion(landmarks, "1"); + ::fwAtomsPatch::helper::Object helperLandmarks(landmarks); + + ::fwAtoms::Map::sptr map = ::fwAtoms::Map::New(); + helperLandmarks.addAttribute("landmarks", map); + this->addPoint(map, P1, "point_1"); + this->addPoint(map, P2, "point_2"); + this->addPoint(map, P3, "point_3"); + this->addPoint(map, P4, "point_4"); + this->addPoint(map, P5, "point_5"); + + fieldMap->insert("m_landmarksId", landmarks); + + patchedObj = ::fwAtoms::Object::dynamicCast(image->clone()); + + ::fwAtomsPatch::IPatch::NewVersionsType newVersions; + newVersions[image] = patchedObj; + + ::fwMDSemanticPatch::V10::V09ALA::fwData::Image::sptr patcher = + ::fwMDSemanticPatch::V10::V09ALA::fwData::Image::New(); + CPPUNIT_ASSERT_NO_THROW(patcher->apply(image, patchedObj, newVersions)); + + CPPUNIT_ASSERT(patchedObj->getAttribute("fields")); + ::fwAtoms::Map::sptr newFieldMap = ::fwAtoms::Map::dynamicCast(patchedObj->getAttribute("fields")); + CPPUNIT_ASSERT(newFieldMap); + + CPPUNIT_ASSERT(newFieldMap->find("m_imageLandmarksId") != newFieldMap->end()); + ::fwAtoms::Object::sptr pl = ::fwAtoms::Object::dynamicCast((*newFieldMap)["m_imageLandmarksId"]); + CPPUNIT_ASSERT(pl); + CPPUNIT_ASSERT_EQUAL(std::string("::fwData::PointList"), ::fwAtomsPatch::helper::getClassname(pl)); + CPPUNIT_ASSERT(pl->getAttribute("points")); + ::fwAtoms::Sequence::sptr plSeq = ::fwAtoms::Sequence::dynamicCast(pl->getAttribute("points")); + CPPUNIT_ASSERT(plSeq); + CPPUNIT_ASSERT_EQUAL(size_t(5), plSeq->size()); + + size_t count = 0; + for (const auto& elt: plSeq->getValue()) + { + ::fwAtoms::Object::sptr point = ::fwAtoms::Object::dynamicCast(elt); + CPPUNIT_ASSERT(point); + CPPUNIT_ASSERT_EQUAL(std::string("::fwData::Point"), ::fwAtomsPatch::helper::getClassname(point)); + ::fwAtoms::Sequence::csptr pointCoords = ::fwAtoms::Sequence::dynamicCast(point->getAttribute("coord")); + CPPUNIT_ASSERT_EQUAL(size_t(3), pointCoords->size()); + ::fwAtoms::Numeric::csptr coordX = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[0]); + CPPUNIT_ASSERT(coordX); + CPPUNIT_ASSERT_EQUAL(pts[count][0], coordX->getValue()); + ::fwAtoms::Numeric::csptr coordY = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[1]); + CPPUNIT_ASSERT(coordY); + CPPUNIT_ASSERT_EQUAL(pts[count][1], coordY->getValue()); + ::fwAtoms::Numeric::csptr coordZ = ::fwAtoms::Numeric::dynamicCast(pointCoords->getValue()[2]); + CPPUNIT_ASSERT(coordZ); + CPPUNIT_ASSERT_EQUAL(pts[count][2], coordZ->getValue()); + ++count; + } +} + +//------------------------------------------------------------------------------ + +void ImageV10ToV09ALATest::addPoint(::fwAtoms::Map::sptr map, const std::array& pt, + const std::string& label) +{ + ::fwAtoms::Object::sptr atomGroup = ::fwAtoms::Object::New(); + atomGroup->setMetaInfo("ID_METAINFO", ::fwTools::UUID::generateUUID()); + + atomGroup->setAttribute("color", ::fwAtoms::String::New("1;1;1;1")); + atomGroup->setAttribute("size", ::fwAtoms::Numeric::New(1)); + atomGroup->setAttribute("shape", ::fwAtoms::String::New("SPHERE")); + atomGroup->setAttribute("visibility", ::fwAtoms::Boolean::New(true)); + + ::fwAtoms::Sequence::sptr seq = ::fwAtoms::Sequence::New(); + + const std::string coords = std::to_string(pt[0]) + ";" + std::to_string(pt[1]) + ";" + + std::to_string(pt[2]); + seq->push_back(::fwAtoms::String::New(coords)); + atomGroup->setAttribute("points", seq); + map->insert(label, atomGroup); +} + +//------------------------------------------------------------------------------ +} //namespace ut +} //namespace fwMDSemanticPatch diff --git a/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/Landmarks1.hpp b/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/Landmarks1.hpp new file mode 100644 index 000000000..309875133 --- /dev/null +++ b/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/Landmarks1.hpp @@ -0,0 +1,45 @@ +/* ***** 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 __FWSTRUCTURALPATCH_CREATOR_FWDATA_LANDMARKS1_HPP__ +#define __FWSTRUCTURALPATCH_CREATOR_FWDATA_LANDMARKS1_HPP__ + +#include "fwStructuralPatch/config.hpp" + +#include + +namespace fwStructuralPatch +{ +namespace creator +{ +namespace fwData +{ + +/// Structural creator for ::fwData::Landmarks version '1'. +class FWSTRUCTURALPATCH_CLASS_API Landmarks1 : public ::fwAtomsPatch::IStructuralCreator +{ +public: + fwCoreClassDefinitionsWithFactoryMacro( (Landmarks1)(::fwAtomsPatch::IStructuralCreator), (()), new Landmarks1); + + /// Constructor + FWSTRUCTURALPATCH_API Landmarks1(); + + /// Destructor + FWSTRUCTURALPATCH_API ~Landmarks1(); + + /// Copy constructor + FWSTRUCTURALPATCH_API Landmarks1( const Landmarks1& cpy ); + + /// Create the specified object (sets 'landmarks' attribute). + FWSTRUCTURALPATCH_API virtual ::fwAtoms::Object::sptr create(); + +}; + +} // namespace fwData +} // namespace creator +} // namespace fwStructuralPatch + +#endif // __FWSTRUCTURALPATCH_CREATOR_FWDATA_LANDMARKS1_HPP__ diff --git a/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/PointList1.hpp b/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/PointList1.hpp new file mode 100644 index 000000000..a9e6d605a --- /dev/null +++ b/SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/PointList1.hpp @@ -0,0 +1,45 @@ +/* ***** 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 __FWSTRUCTURALPATCH_CREATOR_FWDATA_POINTLIST1_HPP__ +#define __FWSTRUCTURALPATCH_CREATOR_FWDATA_POINTLIST1_HPP__ + +#include "fwStructuralPatch/config.hpp" + +#include + +namespace fwStructuralPatch +{ +namespace creator +{ +namespace fwData +{ + +/// Structural creator for ::fwData::PointList version '1'. +class FWSTRUCTURALPATCH_CLASS_API PointList1 : public ::fwAtomsPatch::IStructuralCreator +{ +public: + fwCoreClassDefinitionsWithFactoryMacro( (PointList1)(::fwAtomsPatch::IStructuralCreator), (()), new PointList1); + + /// Constructor + FWSTRUCTURALPATCH_API PointList1(); + + /// Destructor + FWSTRUCTURALPATCH_API ~PointList1(); + + /// Copy constructor + FWSTRUCTURALPATCH_API PointList1( const PointList1& cpy ); + + /// Create the specified object (sets 'points' attribute). + FWSTRUCTURALPATCH_API virtual ::fwAtoms::Object::sptr create(); + +}; + +} // namespace fwData +} // namespace creator +} // namespace fwStructuralPatch + +#endif // __FWSTRUCTURALPATCH_CREATOR_FWDATA_POINTLIST1_HPP__ diff --git a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp index 66a54d499..9669cfedc 100644 --- a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp +++ b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp @@ -1,17 +1,19 @@ /* ***** 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 ****** */ -#include - +#include "fwStructuralPatch/creator/fwData/Landmarks1.hpp" +#include "fwStructuralPatch/creator/fwData/PointList1.hpp" +#include "fwStructuralPatch/creator/fwMedData/ActivitySeries1.hpp" #include "fwStructuralPatch/creator/fwMedData/Equipment1.hpp" +#include "fwStructuralPatch/creator/fwMedData/ImageSeries1.hpp" +#include "fwStructuralPatch/creator/fwMedData/ModelSeries1.hpp" #include "fwStructuralPatch/creator/fwMedData/Patient1.hpp" #include "fwStructuralPatch/creator/fwMedData/Study1.hpp" -#include "fwStructuralPatch/creator/fwMedData/ModelSeries1.hpp" -#include "fwStructuralPatch/creator/fwMedData/ImageSeries1.hpp" -#include "fwStructuralPatch/creator/fwMedData/ActivitySeries1.hpp" + +#include namespace fwStructuralPatch { @@ -30,6 +32,9 @@ struct runner creators->registerCreator(::fwStructuralPatch::creator::fwMedData::ModelSeries1::New()); creators->registerCreator(::fwStructuralPatch::creator::fwMedData::ImageSeries1::New()); creators->registerCreator(::fwStructuralPatch::creator::fwMedData::ActivitySeries1::New()); + creators->registerCreator(::fwStructuralPatch::creator::fwMedData::ActivitySeries1::New()); + creators->registerCreator(::fwStructuralPatch::creator::fwData::Landmarks1::New()); + creators->registerCreator(::fwStructuralPatch::creator::fwData::PointList1::New()); } static runner r; diff --git a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/Landmarks1.cpp b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/Landmarks1.cpp new file mode 100644 index 000000000..3b7190115 --- /dev/null +++ b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/Landmarks1.cpp @@ -0,0 +1,57 @@ +/* ***** 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 "fwStructuralPatch/creator/fwData/Landmarks1.hpp" + +#include + +#include + +namespace fwStructuralPatch +{ +namespace creator +{ +namespace fwData +{ + +// ---------------------------------------------------------------------------- + +Landmarks1::Landmarks1() +{ + m_classname = "::fwData::Landmarks"; + m_version = "1"; +} + +// ---------------------------------------------------------------------------- + +Landmarks1::~Landmarks1() +{ +} + +// ---------------------------------------------------------------------------- + +Landmarks1::Landmarks1( const Landmarks1& cpy ) : + ::fwAtomsPatch::IStructuralCreator(cpy) +{ +} + +// ---------------------------------------------------------------------------- + +::fwAtoms::Object::sptr Landmarks1::create() +{ + ::fwAtoms::Object::sptr landmarks = this->createObjBase(); + ::fwAtomsPatch::helper::Object helper(landmarks); + + helper.addAttribute("landmarks", ::fwAtoms::Map::New()); + + return landmarks; +} + +// ---------------------------------------------------------------------------- + +} // namespace fwMedData +} // namespace creator +} // namespace fwStructuralPatch diff --git a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/PointList1.cpp b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/PointList1.cpp new file mode 100644 index 000000000..5ec577d0a --- /dev/null +++ b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/PointList1.cpp @@ -0,0 +1,57 @@ +/* ***** 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 "fwStructuralPatch/creator/fwData/PointList1.hpp" + +#include + +#include + +namespace fwStructuralPatch +{ +namespace creator +{ +namespace fwData +{ + +// ---------------------------------------------------------------------------- + +PointList1::PointList1() +{ + m_classname = "::fwData::PointList"; + m_version = "1"; +} + +// ---------------------------------------------------------------------------- + +PointList1::~PointList1() +{ +} + +// ---------------------------------------------------------------------------- + +PointList1::PointList1( const PointList1& cpy ) : + ::fwAtomsPatch::IStructuralCreator(cpy) +{ +} + +// ---------------------------------------------------------------------------- + +::fwAtoms::Object::sptr PointList1::create() +{ + ::fwAtoms::Object::sptr pl = this->createObjBase(); + ::fwAtomsPatch::helper::Object helper(pl); + + helper.addAttribute("points", ::fwAtoms::Sequence::New()); + + return pl; +} + +// ---------------------------------------------------------------------------- + +} // namespace fwMedData +} // namespace creator +} // namespace fwStructuralPatch diff --git a/SrcLib/visu/fwRenderVTK/include/fwRenderVTK/vtk/fwHandleRepresentation3D.hpp b/SrcLib/visu/fwRenderVTK/include/fwRenderVTK/vtk/fwHandleRepresentation3D.hpp new file mode 100644 index 000000000..e9c8120fb --- /dev/null +++ b/SrcLib/visu/fwRenderVTK/include/fwRenderVTK/vtk/fwHandleRepresentation3D.hpp @@ -0,0 +1,126 @@ +/* ***** 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 __FWRENDERVTK_VTK_FWHANDLEREPRESENTATION3D_HPP__ +#define __FWRENDERVTK_VTK_FWHANDLEREPRESENTATION3D_HPP__ + +#include "fwRenderVTK/config.hpp" + +#include +#include + +class vtkCubeSource; +class vtkSphereSource; +class vtkCleanPolyData; +class vtkPolyDataAlgorithm; + +namespace fwRenderVTK +{ + +namespace vtk +{ + +/** + * @brief 3D Representation to be used with vtkHandleWidget (represents a cube or a sphere). + */ +class FWRENDERVTK_CLASS_API fwHandleRepresentation3D : public vtkPolygonalHandleRepresentation3D +{ +public: + + enum Shape + { + SPHERE, + CUBE + }; + + // Description: + // Instantiate this class. + FWRENDERVTK_API static fwHandleRepresentation3D* New(); + + // Description: + // Standard vtk methods + vtkTypeMacro(fwHandleRepresentation3D, + vtkPolygonalHandleRepresentation3D); + FWRENDERVTK_API void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Set the position of the point in world and display coordinates. + FWRENDERVTK_API virtual void SetWorldPosition(double p[3]); + + // Description: + // Set/Get the radius factor of the marker (must be > 1 to be visible) + FWRENDERVTK_API vtkSetMacro( MarkerRadiusFactor, double ); + FWRENDERVTK_API vtkGetMacro( MarkerRadiusFactor, double ); + + // Description: + // Define the shape of the representation (SPHERE or CUBE) + FWRENDERVTK_API void SetShapeRepresentation( Shape shape); + FWRENDERVTK_API vtkGetMacro( ShapeRepresentation, Shape ); + + // Description: + // Set/Get the handle properties for marker. + FWRENDERVTK_API void SetMarkerProperty(vtkProperty*); + FWRENDERVTK_API vtkGetObjectMacro(MarkerProperty, vtkProperty); + + // Description: + // For some exporters and other other operations we must be + // able to collect all the actors or volumes. These methods + // are used in that process. + FWRENDERVTK_API virtual void GetActors(vtkPropCollection*); + + // Description: + // Release any graphics resources that are being consumed by this actor. + // The parameter window could be used to determine which graphic + // resources to release. + FWRENDERVTK_API virtual void ReleaseGraphicsResources(vtkWindow*); + + // Description: + // Support the standard render methods. + FWRENDERVTK_API virtual int RenderOpaqueGeometry(vtkViewport* viewport); + FWRENDERVTK_API virtual int RenderTranslucentPolygonalGeometry(vtkViewport* viewport); + + // Description: + // Does this prop have some translucent polygonal geometry? + FWRENDERVTK_API virtual int HasTranslucentPolygonalGeometry(); + +protected: + fwHandleRepresentation3D(); + ~fwHandleRepresentation3D(); + + // Description: + // Recomputes the handle world size based on the set display size. + virtual void BuildRepresentation(); + + // Create default properties for markers + void CreateDefaultProperties(); + + vtkSmartPointer CubeSource; + vtkSmartPointer SphereSource; + Shape ShapeRepresentation; + + // the cursor3D + vtkSmartPointer Follower; + vtkSmartPointer CleanPolyData; + vtkSmartPointer MarkerMapper; + vtkSmartPointer Marker; + + double MarkerRadiusFactor; + + // Properties used to control the appearance of selected objects and + // the manipulator in general. + vtkProperty* MarkerProperty; + +private: + fwHandleRepresentation3D(const fwHandleRepresentation3D&); //Not implemented + void operator=(const fwHandleRepresentation3D&); //Not implemented +}; + +} // namespace vtk + +} // namespace fwRenderVTK + +#endif //__FWRENDERVTK_VTK_FWHANDLEREPRESENTATION3D_HPP__ + diff --git a/SrcLib/visu/fwRenderVTK/src/fwRenderVTK/vtk/fwHandleRepresentation3D.cpp b/SrcLib/visu/fwRenderVTK/src/fwRenderVTK/vtk/fwHandleRepresentation3D.cpp new file mode 100644 index 000000000..0ef8c4008 --- /dev/null +++ b/SrcLib/visu/fwRenderVTK/src/fwRenderVTK/vtk/fwHandleRepresentation3D.cpp @@ -0,0 +1,309 @@ +/* ***** 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 "fwRenderVTK/vtk/fwHandleRepresentation3D.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fwRenderVTK +{ + +namespace vtk +{ + +vtkStandardNewMacro(fwHandleRepresentation3D); + +//---------------------------------------------------------------------- +fwHandleRepresentation3D::fwHandleRepresentation3D() +{ + // Instantiate a handle template shape as a cube + this->CubeSource = vtkCubeSource::New(); + + // Instantiate a handle template shape as a sphere + this->SphereSource = vtkSphereSource::New(); + this->SphereSource->SetThetaResolution(20); + this->SphereSource->SetPhiResolution(20); + this->SphereSource->Update(); + this->SetHandle(this->SphereSource->GetOutput()); + + this->GetSelectedProperty()->SetColor(0., 1., 0.); + + this->ShapeRepresentation = SPHERE; + + vtkSmartPointer cynlinderSource = vtkCylinderSource::New(); + cynlinderSource->SetCenter(0., -1., 0.); + cynlinderSource->SetResolution(64); + cynlinderSource->SetHeight(0.); + this->Marker = cynlinderSource; + + this->CleanPolyData = vtkCleanPolyData::New(); + this->CleanPolyData->PointMergingOn(); + this->CleanPolyData->CreateDefaultLocator(); + this->CleanPolyData->SetInputConnection(0, this->Marker->GetOutputPort(0)); + + vtkPolyDataNormals* MarkerNormals = vtkPolyDataNormals::New(); + MarkerNormals->SetInputConnection( 0, this->CleanPolyData->GetOutputPort(0) ); + + this->MarkerMapper = vtkPolyDataMapper::New(); + this->MarkerMapper->SetInputConnection( MarkerNormals->GetOutputPort() ); + MarkerNormals->Delete(); + + this->Follower = vtkFollower::New(); + this->Follower->SetMapper(this->MarkerMapper); + this->Follower->RotateX(90); + + // Set up the initial properties, parent's one is called in parent's constructor + this->CreateDefaultProperties(); + + this->MarkerRadiusFactor = 1.2; + this->SetMarkerProperty(this->MarkerProperty); + cynlinderSource->SetRadius(this->MarkerRadiusFactor * this->SphereSource->GetRadius()); +} + +//---------------------------------------------------------------------- + +fwHandleRepresentation3D::~fwHandleRepresentation3D() +{ + +} + +//----------------------------------------------------------------------------- + +void fwHandleRepresentation3D::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "HandleSize: " << this->HandleSize << endl; + os << indent << "ShapeRepresentation: " << (this->ShapeRepresentation == SPHERE ? "SPHERE" : "CUBE") << endl; + if (this->SphereSource) + { + this->SphereSource->PrintSelf(os, indent.GetNextIndent()); + } + if (this->CubeSource) + { + this->CubeSource->PrintSelf(os, indent.GetNextIndent()); + } +} + +//------------------------------------------------------------------------- + +void fwHandleRepresentation3D::SetWorldPosition(double p[3]) +{ + this->vtkPolygonalHandleRepresentation3D::SetWorldPosition(p); + this->Follower->SetPosition(this->GetWorldPosition());// p may have been clamped + + this->UpdateLabel(); +} + +//---------------------------------------------------------------------- + +void fwHandleRepresentation3D::CreateDefaultProperties() +{ + this->MarkerProperty = vtkProperty::New(); + this->MarkerProperty->SetColor(1., 1., 0.); + this->MarkerProperty->SetOpacity(1.); +} + +//--------------------------------------------------------------------------- + +void fwHandleRepresentation3D::SetShapeRepresentation( Shape shape) +{ + this->ShapeRepresentation = shape; + if (this->ShapeRepresentation == SPHERE) + { + vtkSmartPointer cynlinderSource = vtkCylinderSource::SafeDownCast(this->Marker); + if (!cynlinderSource) + { + cynlinderSource = vtkCylinderSource::New(); + cynlinderSource->SetCenter(0., -1., 0.); + cynlinderSource->SetResolution(64); + cynlinderSource->SetHeight(0.); + cynlinderSource->SetRadius(this->MarkerRadiusFactor * this->SphereSource->GetRadius() ); + this->Marker = cynlinderSource; + this->CleanPolyData->SetInputConnection(0, this->Marker->GetOutputPort(0)); + } + + this->SetHandle(this->SphereSource->GetOutput()); + } + else + { + vtkSmartPointer cubeSource = vtkCubeSource::SafeDownCast(this->Marker); + if (!cubeSource) + { + cubeSource = vtkCubeSource::New(); + cubeSource->SetCenter(0., -1., 0.); + cubeSource->SetXLength(this->MarkerRadiusFactor * this->CubeSource->GetXLength() ); + cubeSource->SetYLength(0.); + cubeSource->SetZLength(this->MarkerRadiusFactor * this->CubeSource->GetXLength() ); + this->Marker = cubeSource; + this->CleanPolyData->SetInputConnection(0, this->Marker->GetOutputPort(0)); + } + + this->SetHandle(this->CubeSource->GetOutput()); + } +} + +//--------------------------------------------------------------------------- +void fwHandleRepresentation3D::BuildRepresentation() +{ + if (!this->GetRenderer() || + !this->GetRenderer()->GetActiveCamera()) + { + return; + } + + double currLength; + if (this->ShapeRepresentation == SPHERE) + { + currLength = this->SphereSource->GetRadius()*2; + } + else + { + currLength = this->CubeSource->GetXLength(); + } + + if (currLength != this->HandleSize) + { + // Generate a handle with a radius of w_r in physical units + if (this->ShapeRepresentation == SPHERE) + { + this->SphereSource->SetRadius(this->HandleSize / 2.); + this->SphereSource->Update(); + + vtkSmartPointer cynlinderSource = vtkCylinderSource::SafeDownCast(this->Marker); + if (cynlinderSource) + { + cynlinderSource->SetRadius(this->MarkerRadiusFactor * this->HandleSize / 2. ); + } + + this->SetHandle(this->SphereSource->GetOutput()); + } + else + { + this->CubeSource->SetXLength(this->HandleSize); + this->CubeSource->SetYLength(this->HandleSize); + this->CubeSource->SetZLength(this->HandleSize); + this->CubeSource->Update(); + + vtkSmartPointer cubeSource = vtkCubeSource::SafeDownCast(this->Marker); + if (cubeSource) + { + cubeSource->SetXLength(this->MarkerRadiusFactor * this->HandleSize ); + cubeSource->SetYLength(0.); + cubeSource->SetZLength(this->MarkerRadiusFactor * this->HandleSize ); + } + + this->SetHandle(this->CubeSource->GetOutput()); + } + + this->Follower->SetCamera( this->GetRenderer()->GetActiveCamera() ); + this->Marker->Update(); + + const double textScale = 10; + this->SetLabelTextScale(textScale, textScale, textScale); + + // Update the label, + this->UpdateLabel(); + + this->BuildTime.Modified(); + } +} + +//---------------------------------------------------------------------- + +void fwHandleRepresentation3D::GetActors(vtkPropCollection* pc) +{ + this->Actor->GetActors(pc); + this->LabelTextActor->GetActors(pc); + this->Follower->GetActors(pc); +} + +//---------------------------------------------------------------------- + +void fwHandleRepresentation3D::ReleaseGraphicsResources(vtkWindow* win) +{ + this->Actor->ReleaseGraphicsResources(win); + this->LabelTextActor->ReleaseGraphicsResources(win); + this->Follower->ReleaseGraphicsResources(win); +} + +//---------------------------------------------------------------------- + +int fwHandleRepresentation3D::RenderOpaqueGeometry(vtkViewport* viewport) +{ + this->BuildRepresentation(); + int ret = 0; + if (this->GetRenderer()->GetActiveCamera()->GetParallelProjection()) + { + ret = this->Follower->RenderOpaqueGeometry(viewport); + } + if (this->HandleVisibility) + { + ret += this->Actor->RenderOpaqueGeometry(viewport); + } + if (this->LabelVisibility) + { + ret += this->LabelTextActor->RenderOpaqueGeometry(viewport); + } + + return ret; +} + +//---------------------------------------------------------------------- + +int fwHandleRepresentation3D::RenderTranslucentPolygonalGeometry(vtkViewport* viewport) +{ + this->BuildRepresentation(); + int ret = 0; + if (this->GetRenderer()->GetActiveCamera()->GetParallelProjection()) + { + ret = this->Follower->RenderTranslucentPolygonalGeometry(viewport); + } + if (this->HandleVisibility) + { + ret += this->Actor->RenderTranslucentPolygonalGeometry(viewport); + } + if (this->LabelVisibility) + { + ret += this->LabelTextActor->RenderTranslucentPolygonalGeometry(viewport); + } + return this->Actor->RenderTranslucentPolygonalGeometry(viewport) + ret; +} + +//---------------------------------------------------------------------- + +int fwHandleRepresentation3D::HasTranslucentPolygonalGeometry() +{ + return 1; +} + +//---------------------------------------------------------------------- + +void fwHandleRepresentation3D::SetMarkerProperty(vtkProperty* p) +{ + vtkSetObjectBodyMacro(MarkerProperty, vtkProperty, p); + if (p) + { + this->Follower->SetProperty( p ); + } +} + +} // namespace vtk + +} // namespace fwRenderVTK