From aeca32d8845ff17651bfb245e5c1b1458e9ab24c Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Wed, 8 Feb 2017 12:51:02 +0100 Subject: [PATCH 01/18] feat(Landmarks) : new Landmarks data Added the new Landmarks structure in fwData. Added unit test. --- .../core/fwData/include/fwData/Landmarks.hpp | 270 ++++++++++++++ SrcLib/core/fwData/src/fwData/Landmarks.cpp | 271 ++++++++++++++ .../fwData/test/tu/include/LandmarksTest.hpp | 47 +++ .../core/fwData/test/tu/src/LandmarksTest.cpp | 350 ++++++++++++++++++ 4 files changed, 938 insertions(+) create mode 100644 SrcLib/core/fwData/include/fwData/Landmarks.hpp create mode 100644 SrcLib/core/fwData/src/fwData/Landmarks.cpp create mode 100644 SrcLib/core/fwData/test/tu/include/LandmarksTest.hpp create mode 100644 SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp 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..fad4275d5 --- /dev/null +++ b/SrcLib/core/fwData/src/fwData/Landmarks.cpp @@ -0,0 +1,271 @@ +/* ***** 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); + OSLM_LOG("point: " << m_landmarks.at(name).m_points.size()); +} + +//------------------------------------------------------------------------------ + +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() + 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() + index; + OSLM_LOG(this->getNumberOfPoints()); + group.m_points.erase(iter); + OSLM_LOG(this->getNumberOfPoints()); +} + +//------------------------------------------------------------------------------ + +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..11a8d7735 --- /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 From 52296462fcc793869470f7cdb63cd4c9d88cd90f Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Thu, 9 Feb 2017 10:43:22 +0100 Subject: [PATCH 02/18] feat(Landmarks): Landmarks conversion to Atoms Added camp managment and atom conversion for ::fwData::Landmarks. --- .../fwAtomConversion/mapper/Landmarks.hpp | 64 ++++++ .../src/fwAtomConversion/mapper/Landmarks.cpp | 191 ++++++++++++++++ .../test/tu/include/ConversionTest.hpp | 10 +- .../test/tu/src/ConversionTest.cpp | 212 +++++++++++++----- SrcLib/core/fwData/src/fwData/Landmarks.cpp | 4 +- .../include/fwDataCamp/autoload.hpp | 22 +- .../fwDataCamp/src/fwDataCamp/Landmarks.cpp | 19 ++ .../test/tu/include/LandmarksTest.hpp | 35 +++ .../fwDataCamp/test/tu/src/LandmarksTest.cpp | 64 ++++++ 9 files changed, 542 insertions(+), 79 deletions(-) create mode 100644 SrcLib/core/fwAtomConversion/include/fwAtomConversion/mapper/Landmarks.hpp create mode 100644 SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp create mode 100644 SrcLib/core/fwDataCamp/src/fwDataCamp/Landmarks.cpp create mode 100644 SrcLib/core/fwDataCamp/test/tu/include/LandmarksTest.hpp create mode 100644 SrcLib/core/fwDataCamp/test/tu/src/LandmarksTest.cpp 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..5a57e632b --- /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::stof(resultPt[0]), std::stof(resultPt[1]), + std::stof(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/src/fwData/Landmarks.cpp b/SrcLib/core/fwData/src/fwData/Landmarks.cpp index fad4275d5..dae74b4ba 100644 --- a/SrcLib/core/fwData/src/fwData/Landmarks.cpp +++ b/SrcLib/core/fwData/src/fwData/Landmarks.cpp @@ -193,7 +193,7 @@ void Landmarks::addPoint(const std::string& name, const Landmarks::PointType& po 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() + index; + auto iter = group.m_points.begin() + static_cast< PointContainer::difference_type >(index); group.m_points.insert(iter, point); } @@ -230,7 +230,7 @@ void Landmarks::removePoint(const std::string& name, size_t index) 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() + index; + auto iter = group.m_points.begin() + static_cast< PointContainer::difference_type >(index); OSLM_LOG(this->getNumberOfPoints()); group.m_points.erase(iter); OSLM_LOG(this->getNumberOfPoints()); 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 From 42645842c27a615cd5dcdaf2bcc3ab3246c7a08d Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Thu, 9 Feb 2017 15:32:09 +0100 Subject: [PATCH 03/18] feat(Landmarks): patch to convert image landmarks to the new structure. Added semantic patch to convert the "m_imageLandmarksId" field of image from PointList to Landmarks. Added graphlink from V09ALA to V10. Now the data version is V10. --- Bundles/LeafActivity/ioActivity/rc/plugin.xml | 4 +- .../src/fwAtomConversion/mapper/Landmarks.cpp | 4 +- SrcLib/core/fwData/src/fwData/Landmarks.cpp | 3 - .../V09ALA/V10/fwData/Image.hpp | 57 ++++++ .../rc/V09ALAToV10.graphlink | 7 + .../patch/fwMDSemanticPatch/rc/V10.versions | 53 +++++ .../src/fwMDSemanticPatch/PatchLoader.cpp | 10 +- .../V09ALA/V10/fwData/Image.cpp | 136 +++++++++++++ .../V09ALA/V10/fwData/autoload.cpp | 38 ++++ .../fwMDSemanticPatch/test/CMakeLists.txt | 7 + .../fwMDSemanticPatch/test/Properties.cmake | 6 + .../test/tu/include/ImageV09ALAToV10Test.hpp | 41 ++++ .../test/tu/src/ImageV09ALAToV10Test.cpp | 184 ++++++++++++++++++ .../creator/fwData/Landmarks1.hpp | 45 +++++ .../fwStructuralPatch/creator/autoload.cpp | 15 +- .../creator/fwData/Landmarks1.cpp | 57 ++++++ 16 files changed, 650 insertions(+), 17 deletions(-) create mode 100644 SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/rc/V09ALAToV10.graphlink create mode 100644 SrcLib/patch/fwMDSemanticPatch/rc/V10.versions create mode 100644 SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/autoload.cpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/CMakeLists.txt create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/Properties.cmake create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV09ALAToV10Test.hpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp create mode 100644 SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/Landmarks1.hpp create mode 100644 SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/Landmarks1.cpp diff --git a/Bundles/LeafActivity/ioActivity/rc/plugin.xml b/Bundles/LeafActivity/ioActivity/rc/plugin.xml index b5408a3d5..11c20d527 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 - + diff --git a/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp b/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp index 5a57e632b..1e289b75b 100644 --- a/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp +++ b/SrcLib/core/fwAtomConversion/src/fwAtomConversion/mapper/Landmarks.cpp @@ -175,8 +175,8 @@ ::fwData::Object::sptr Landmarks::convert( ::fwAtoms::Object::sptr atom, resultPt.size() != 3 ); ::fwData::Landmarks::PointType pt = {{ - std::stof(resultPt[0]), std::stof(resultPt[1]), - std::stof(resultPt[2]) + std::stod(resultPt[0]), std::stod(resultPt[1]), + std::stod(resultPt[2]) }}; landmarks->addPoint(name, pt); } diff --git a/SrcLib/core/fwData/src/fwData/Landmarks.cpp b/SrcLib/core/fwData/src/fwData/Landmarks.cpp index dae74b4ba..e119e8555 100644 --- a/SrcLib/core/fwData/src/fwData/Landmarks.cpp +++ b/SrcLib/core/fwData/src/fwData/Landmarks.cpp @@ -185,7 +185,6 @@ void Landmarks::addPoint(const std::string& name, const Landmarks::PointType& po { Landmarks::LandmarksGroup& group = this->getGroup(name); group.m_points.push_back(point); - OSLM_LOG("point: " << m_landmarks.at(name).m_points.size()); } //------------------------------------------------------------------------------ @@ -231,9 +230,7 @@ void Landmarks::removePoint(const std::string& name, size_t index) index >= group.m_points.size()); auto iter = group.m_points.begin() + static_cast< PointContainer::difference_type >(index); - OSLM_LOG(this->getNumberOfPoints()); group.m_points.erase(iter); - OSLM_LOG(this->getNumberOfPoints()); } //------------------------------------------------------------------------------ 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..af1570336 --- /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. + */ + 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/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/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..948750b4a --- /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_imageLandmarksId", 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/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/src/ImageV09ALAToV10Test.cpp b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp new file mode 100644 index 000000000..78cd9792b --- /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_imageLandmarksId") != newFieldMap->end()); + ::fwAtoms::Object::sptr landmarks = ::fwAtoms::Object::dynamicCast((*newFieldMap)["m_imageLandmarksId"]); + 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/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/src/fwStructuralPatch/creator/autoload.cpp b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp index 66a54d499..cf4a9043c 100644 --- a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp +++ b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp @@ -1,17 +1,18 @@ /* ***** 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/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 +31,8 @@ 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()); } 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 From 3b5b47d96e27cdaea2d31630b28cb6a3cbd3acf0 Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Thu, 9 Feb 2017 16:58:49 +0100 Subject: [PATCH 04/18] feat(Landmarks): patch to convert Landmarks to PointList Added patch to convert Landmarkd (V10) to PointList (V09ALA) New landmarks field is m_landmarksId instead of m_imageLandmarksId --- .../V09ALA/V10/fwData/Image.hpp | 2 +- .../V10/V09ALA/fwData/Image.hpp | 57 ++++++ .../rc/V10ToV09ALA.graphlink | 7 + .../V09ALA/V10/fwData/Image.cpp | 2 +- .../V10/V09ALA/fwData/Image.cpp | 134 ++++++++++++++ .../V10/V09ALA/fwData/autoload.cpp | 38 ++++ .../test/tu/include/ImageV10ToV09ALATest.hpp | 41 +++++ .../test/tu/src/ImageV09ALAToV10Test.cpp | 4 +- .../test/tu/src/ImageV10ToV09ALATest.cpp | 165 ++++++++++++++++++ .../creator/fwData/PointList1.hpp | 45 +++++ .../fwStructuralPatch/creator/autoload.cpp | 2 + .../creator/fwData/PointList1.cpp | 57 ++++++ 12 files changed, 550 insertions(+), 4 deletions(-) create mode 100644 SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V10/V09ALA/fwData/Image.hpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/rc/V10ToV09ALA.graphlink create mode 100644 SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/Image.cpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V10/V09ALA/fwData/autoload.cpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/tu/include/ImageV10ToV09ALATest.hpp create mode 100644 SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV10ToV09ALATest.cpp create mode 100644 SrcLib/patch/fwStructuralPatch/include/fwStructuralPatch/creator/fwData/PointList1.hpp create mode 100644 SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/fwData/PointList1.cpp diff --git a/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp index af1570336..e5416ed7c 100644 --- a/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp +++ b/SrcLib/patch/fwMDSemanticPatch/include/fwMDSemanticPatch/V09ALA/V10/fwData/Image.hpp @@ -39,7 +39,7 @@ class FWMDSEMANTICPATCH_CLASS_API Image : public ::fwAtomsPatch::ISemanticPatch /** * @brief Applies patch. * - * Converts the "m_imageLandmarksId" field from a ::fwData::PointList to a ::fwData::Landmarks. + * 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, 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/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/V09ALA/V10/fwData/Image.cpp b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp index 948750b4a..12610ab76 100644 --- a/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp +++ b/SrcLib/patch/fwMDSemanticPatch/src/fwMDSemanticPatch/V09ALA/V10/fwData/Image.cpp @@ -73,7 +73,7 @@ void Image::apply( ::fwAtomsPatch::helper::Object helperLandmarks( currentLandmarks ); ::fwAtoms::Map::sptr currentFieldMap = ::fwAtoms::Map::dynamicCast(current->getAttribute("fields")); - currentFieldMap->insert("m_imageLandmarksId", currentLandmarks); + currentFieldMap->insert("m_landmarksId", currentLandmarks); ::fwAtoms::Map::sptr landmarksMap = ::fwAtoms::Map::dynamicCast(currentLandmarks->getAttribute("landmarks")); 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/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 index 78cd9792b..627106833 100644 --- a/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp +++ b/SrcLib/patch/fwMDSemanticPatch/test/tu/src/ImageV09ALAToV10Test.cpp @@ -109,8 +109,8 @@ void ImageV09ALAToV10Test::applyPatchTest() ::fwAtoms::Map::sptr newFieldMap = ::fwAtoms::Map::dynamicCast(patchedObj->getAttribute("fields")); CPPUNIT_ASSERT(newFieldMap); - CPPUNIT_ASSERT(newFieldMap->find("m_imageLandmarksId") != newFieldMap->end()); - ::fwAtoms::Object::sptr landmarks = ::fwAtoms::Object::dynamicCast((*newFieldMap)["m_imageLandmarksId"]); + 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")); 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/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 cf4a9043c..9669cfedc 100644 --- a/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp +++ b/SrcLib/patch/fwStructuralPatch/src/fwStructuralPatch/creator/autoload.cpp @@ -5,6 +5,7 @@ * ****** END LICENSE BLOCK ****** */ #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" @@ -33,6 +34,7 @@ struct runner 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/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 From 1ee89ef25841fbf22577769dff62e317ef529002 Mon Sep 17 00:00:00 2001 From: Kevin GAUDET Date: Thu, 9 Feb 2017 17:24:18 +0100 Subject: [PATCH 05/18] feat(LandmarksAdaptor) added new landmarks adaptor This adaptor replace the old ImageLandmarks. It displays landmarks as discribed in the sturctue: - sphere or cube - color - label - size --- .../include/visuVTKAdaptor/ImageLandmarks.hpp | 88 --- .../include/visuVTKAdaptor/SLandmarks.hpp | 170 +++++ Bundles/LeafVisu/visuVTKAdaptor/rc/plugin.xml | 4 +- .../src/visuVTKAdaptor/ImageLandmarks.cpp | 356 --------- .../src/visuVTKAdaptor/SLandmarks.cpp | 706 ++++++++++++++++++ .../vtk/fwHandleRepresentation3D.hpp | 126 ++++ .../vtk/fwHandleRepresentation3D.cpp | 309 ++++++++ 7 files changed, 1313 insertions(+), 446 deletions(-) delete mode 100644 Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/ImageLandmarks.hpp create mode 100644 Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp delete mode 100644 Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/ImageLandmarks.cpp create mode 100644 Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp create mode 100644 SrcLib/visu/fwRenderVTK/include/fwRenderVTK/vtk/fwHandleRepresentation3D.hpp create mode 100644 SrcLib/visu/fwRenderVTK/src/fwRenderVTK/vtk/fwHandleRepresentation3D.cpp 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..f100b0b9f --- /dev/null +++ b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp @@ -0,0 +1,170 @@ +/* ***** 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): deselec the point (reset current color) + * + * @section XML XML Configuration + * + * @code{.xml} + + + + @endcode + * + */ +class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorService +{ + +public: + + fwCoreServiceClassDefinitionsMacro( (SLandmarks)(::fwRenderVTK::IVtkAdaptorService) ); + + /// 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; + + /// Returns point associated to widget. + fwData::Landmarks::PointType* getPoint(const LandmarkWidgetType& widget); + +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: + + /// 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; + + /// 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); + + /// 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); + + /// 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; + + /// 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..f70428e5e --- /dev/null +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -0,0 +1,706 @@ +/* ***** 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"; + +//------------------------------------------------------------------------------ + +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|| eventId == vtkCommand::EndInteractionEvent ) + { + 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); + } + } + 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); + } + + 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); + } + + if (eventId == vtkCommand::EndInteractionEvent) + { + auto sigDeselect = m_landmarks->signal< ::fwData::Landmarks::PointDeselectedSignalType > + (::fwData::Landmarks::s_POINT_DESELECTED_SIG); + sigDeselect->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; +}; + +//------------------------------------------------------------------------------ + +SLandmarks::SLandmarks() throw() : + m_rightButtonCommand(nullptr), + m_needSubservicesDeletion(false), + 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); +} + +//------------------------------------------------------------------------------ + +SLandmarks::~SLandmarks() throw() +{ +} + +//------------------------------------------------------------------------------ + +void SLandmarks::doConfigure() throw(fwTools::Failed) +{ +} + +//------------------------------------------------------------------------------ + +void SLandmarks::doStart() throw(fwTools::Failed) +{ + this->doUpdate(); +} + +//------------------------------------------------------------------------------ + +void SLandmarks::doSwap() throw(fwTools::Failed) +{ + this->doStop(); + this->doStart(); +} + +//------------------------------------------------------------------------------ + +void SLandmarks::doUpdate() throw(fwTools::Failed) +{ + this->doStop(); + + ::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::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) +{ + 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->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) +{ + 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(); + + if (m_timer) + { + m_timer->stop(); + m_timer.reset(); + } + 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) +{ + m_timer->stop(); + 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::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(); +} + +//------------------------------------------------------------------------------ + +::fwData::Landmarks::PointType* SLandmarks::getPoint(const SLandmarks::LandmarkWidgetType& widget) +{ + ::fwData::Landmarks::PointType* result = nullptr; + + ::fwData::Landmarks::sptr landmarks = this->getObject< ::fwData::Landmarks >(); + + const ::fwData::Landmarks::GroupNameContainer groupNames = landmarks->getGroupNames(); + + for(const auto& name : groupNames) + { + auto widgetGroup = m_handles[name]; + + auto pointIter = std::find(widgetGroup.begin(), widgetGroup.end(), widget); + + if(pointIter != widgetGroup.end()) + { + auto group = landmarks->getGroup(name); + + size_t pointIndex = static_cast(std::distance(widgetGroup.begin(), pointIter)); + + result = &group.m_points[pointIndex]; + break; + } + } + + return result; +} + +//------------------------------------------------------------------------------ + +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::doStop() throw(fwTools::Failed) +{ + while (!m_handles.empty()) + { + const std::string name = m_handles.begin()->first; + this->removeGroup(name); + } +} + +//------------------------------------------------------------------------------ + +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/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 From c5bbde2a2ed26e057db23c200251ab66950d7142 Mon Sep 17 00:00:00 2001 From: Kevin Gaudet Date: Tue, 14 Feb 2017 17:51:56 +0100 Subject: [PATCH 06/18] feat(LandmarksEditor): added Landmarks editor This editor has two mode : basic and advance In the basic mode, a group contains only one point. Set new random color when adding a new group --- .../rc/configurations/2DNegato.xml | 9 + .../rc/configurations/2DVisualization.xml | 30 + .../uiMeasurementQt/editor/SLandmarks.hpp | 203 ++++ Bundles/LeafUI/uiMeasurementQt/rc/plugin.xml | 5 + .../src/uiMeasurementQt/editor/SLandmarks.cpp | 930 ++++++++++++++++++ 5 files changed, 1177 insertions(+) create mode 100644 Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp create mode 100644 Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml index 51af1ba33..cc676bd1c 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml @@ -7,6 +7,7 @@ + @@ -61,6 +62,10 @@ + + + + @@ -101,6 +106,10 @@ MPRNegato/setCrossScale + + + pickerInteractor/picked + diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml index 8e2b9f022..b52ec5935 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml @@ -10,6 +10,7 @@ + @@ -17,6 +18,7 @@ + @@ -26,6 +28,7 @@ + @@ -72,6 +75,7 @@ + @@ -80,6 +84,7 @@ + @@ -88,14 +93,29 @@ + + + + + + + + + + + + + yes + + @@ -147,6 +167,10 @@ ActionShowFullCross/crossTypeModified + + landmarksEditor/addPoint + + @@ -156,5 +180,11 @@ + + + + + + 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..e37c64dec --- /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); + + /// Generate a group name that doesn't exist already. + std::string generateNewGroupName() const; + + /// Generate a new random color + std::array generateNewColor() const; + + /// Gets the name of the currently selected group, returns false if no group is selected. + bool currentSelection(std::string& selection) const; + + /// Converts a landmark color to a QColor. + QColor convertToQColor(const ::fwData::Landmarks::ColorType& color) const; + + /// Draws a colored square on the button. + void setColorButtonIcon(QPushButton* button, const QColor& color) const; + + /// Get tree item representing the group. + QTreeWidgetItem* getGroupItem(const std::string& groupName) const; + + 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..6fcf32834 --- /dev/null +++ b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp @@ -0,0 +1,930 @@ +/* ***** 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. + { + 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)); + } + 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); + 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() const +{ + 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) const +{ + 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 +{ + 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 + From 5fb830eb34d48bec7246ebecc960ade6920d79ec Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Fri, 17 Feb 2017 12:03:54 +0100 Subject: [PATCH 07/18] feat(LandmarksConfig): updated activities to use Landmarks Updated 2D and 3DVisualization activities to store Landmarks in the ActivitySeries. Updated landmarks load/save using SIOSelector Updates VolumeRendering activity to use new landmarks data --- .../rc/configurations/2DNegato.xml | 2 +- .../rc/configurations/2DNegatoWithTF.xml | 2 +- .../2DVisualizationActivity2/Properties.cmake | 1 + .../rc/configurations/2DNegato.xml | 5 +- .../rc/configurations/2DNegatoWithTF.xml | 5 +- .../rc/configurations/2DVisualization.xml | 82 ++++++++++------- .../2DVisualizationActivity2/rc/plugin.xml | 6 +- .../rc/configurations/3DNegatoWithAcq.xml | 2 +- .../rc/configurations/3DNegatoWithAcq.xml | 14 ++- .../rc/configurations/3DVisualization.xml | 88 ++++++++++++++----- .../3DVisualizationActivity2/rc/plugin.xml | 6 +- .../configurations/TransferFunctionEditor.xml | 2 +- Bundles/LeafActivity/ioActivity/rc/plugin.xml | 9 ++ .../rc/configurations/VolumeRendering.xml | 24 +++-- 14 files changed, 171 insertions(+), 77 deletions(-) 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 cc676bd1c..7182f51e4 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DNegato.xml @@ -3,6 +3,7 @@ + @@ -12,6 +13,7 @@ + @@ -49,6 +51,7 @@ + @@ -85,7 +88,7 @@ - + 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 b52ec5935..861f1f32c 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml @@ -5,12 +5,13 @@ + - + @@ -18,7 +19,7 @@ - + @@ -28,19 +29,17 @@ - + - - - + @@ -54,12 +53,10 @@ - - - + @@ -73,6 +70,7 @@ + @@ -82,6 +80,7 @@ + @@ -91,19 +90,18 @@ + - - - - - - - + + + + + @@ -112,7 +110,7 @@ - + yes @@ -123,20 +121,23 @@ - - - - - - - - + + + + LoadLandmark/update + - - + + + + SaveLandmark/update + - - + + + + landmarksEditor/setVisible + @@ -147,6 +148,23 @@ + + + + + + + + + + + + + + + + + hide @@ -168,7 +186,7 @@ - landmarksEditor/addPoint + landmarksEditor/addPickedPoint @@ -180,9 +198,11 @@ + + + - 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 9733eb4ea..74828e4c7 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..d2d48f3c6 100644 --- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml +++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml @@ -11,6 +11,7 @@ + @@ -20,6 +21,7 @@ + @@ -28,6 +30,7 @@ + @@ -36,6 +39,7 @@ + @@ -61,12 +65,10 @@ - - - + @@ -87,12 +89,10 @@ - - - - + + - + @@ -136,11 +136,13 @@ + + @@ -172,6 +174,13 @@ + + + + + + + @@ -179,8 +188,10 @@ + + @@ -188,8 +199,10 @@ + + @@ -197,20 +210,39 @@ - - + + + + LoadLandmark/update + - - + + + + SaveLandmark/update + - - + + + + + + + - - + + + + + + + - - + + + + landmarksEditor/setVisible + @@ -243,28 +275,33 @@ + + + + ActionHideCross/crossTypeModified ActionShowNormalCross/crossTypeModified ActionShowFullCross/crossTypeModified + + landmarksEditor/addPickedPoint + + + + + - - - - - - @@ -273,7 +310,10 @@ + + + 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..393578283 100644 --- a/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml +++ b/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml @@ -102,7 +102,7 @@ - + diff --git a/Bundles/LeafActivity/ioActivity/rc/plugin.xml b/Bundles/LeafActivity/ioActivity/rc/plugin.xml index 11c20d527..5c2c445d0 100644 --- a/Bundles/LeafActivity/ioActivity/rc/plugin.xml +++ b/Bundles/LeafActivity/ioActivity/rc/plugin.xml @@ -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 @@ + + From 30ac8ba357b374cdc498b06dd794b9be2cd66ad0 Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Thu, 16 Feb 2017 17:45:44 +0100 Subject: [PATCH 08/18] feat(Landmarks): updated FocusLandmarks to use new Landmarks data. --- .../rc/configurations/2DVisualization.xml | 7 +- .../rc/configurations/3DVisualization.xml | 8 +- .../uiMeasurement/action/FocusLandmark.hpp | 50 ---- .../uiMeasurement/action/SFocusLandmark.hpp | 89 +++++++ Bundles/LeafUI/uiMeasurement/rc/plugin.xml | 2 +- .../uiMeasurement/action/FocusLandmark.cpp | 182 --------------- .../uiMeasurement/action/SFocusLandmark.cpp | 221 ++++++++++++++++++ 7 files changed, 320 insertions(+), 239 deletions(-) delete mode 100644 Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/FocusLandmark.hpp create mode 100644 Bundles/LeafUI/uiMeasurement/include/uiMeasurement/action/SFocusLandmark.hpp delete mode 100644 Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/FocusLandmark.cpp create mode 100644 Bundles/LeafUI/uiMeasurement/src/uiMeasurement/action/SFocusLandmark.cpp diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml index 861f1f32c..02424c952 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml @@ -55,7 +55,7 @@ - + @@ -118,8 +118,9 @@ - - + + + diff --git a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml index d2d48f3c6..8df7fd65f 100644 --- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml +++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml @@ -91,7 +91,7 @@ - + @@ -207,8 +207,9 @@ - - + + + @@ -309,6 +310,7 @@ + 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 From a49f51bab7603421e4f346c6f328db3f56d93ddc Mon Sep 17 00:00:00 2001 From: Kevin Gaudet Date: Tue, 28 Feb 2017 15:21:16 +0100 Subject: [PATCH 09/18] style(LandmarksEditor): fixed small style issues. Added missing consts, statics and '::'. --- .../uiMeasurementQt/editor/SLandmarks.hpp | 18 +++++++++--------- .../src/uiMeasurementQt/editor/SLandmarks.cpp | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp b/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp index e37c64dec..4d50041da 100644 --- a/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp +++ b/Bundles/LeafUI/uiMeasurementQt/include/uiMeasurementQt/editor/SLandmarks.hpp @@ -158,23 +158,23 @@ Q_OBJECT /// 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 - std::array generateNewColor() const; - - /// Gets the name of the currently selected group, returns false if no group is selected. - bool currentSelection(std::string& selection) const; + static std::array generateNewColor(); /// Converts a landmark color to a QColor. - QColor convertToQColor(const ::fwData::Landmarks::ColorType& color) const; + static QColor convertToQColor(const ::fwData::Landmarks::ColorType& color); /// Draws a colored square on the button. - void setColorButtonIcon(QPushButton* button, const QColor& color) const; - - /// Get tree item representing the group. - QTreeWidgetItem* getGroupItem(const std::string& groupName) const; + static void setColorButtonIcon(QPushButton* button, const QColor& color); QPointer m_treeWidget; diff --git a/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp index 6fcf32834..2eb23ec85 100644 --- a/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp +++ b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp @@ -560,7 +560,7 @@ void SLandmarks::onRemoveSelection() //------------------------------------------------------------------------------ -void SLandmarks::addPickedPoint(fwDataTools::PickingInfo pickingInfo) +void SLandmarks::addPickedPoint(::fwDataTools::PickingInfo pickingInfo) { if(pickingInfo.m_eventId == ::fwDataTools::PickingInfo::Event::MOUSE_LEFT_UP && pickingInfo.m_modifierMask & ::fwDataTools::PickingInfo::CTRL) @@ -590,7 +590,7 @@ void SLandmarks::addPickedPoint(fwDataTools::PickingInfo pickingInfo) } else // Advanced mode and a point or a group is selected. { - int topLevelIndex = m_treeWidget->indexOfTopLevelItem(item); + const int topLevelIndex = m_treeWidget->indexOfTopLevelItem(item); if(topLevelIndex == -1) // Point selected, add new point to parent group. { @@ -678,7 +678,7 @@ void SLandmarks::removeGroup(std::string name) { item->removeChild(item->child(0)); } - int index = m_treeWidget->indexOfTopLevelItem(item); + const int index = m_treeWidget->indexOfTopLevelItem(item); QTreeWidgetItem* topItem = m_treeWidget->takeTopLevelItem(index); delete topItem; } @@ -842,7 +842,7 @@ std::string SLandmarks::generateNewGroupName() const //------------------------------------------------------------------------------ -std::array SLandmarks::generateNewColor() const +std::array SLandmarks::generateNewColor() { std::array color = {{rand()%255/255.f, rand()%255/255.f, rand()%255/255.f, 1.f}}; return color; @@ -873,7 +873,7 @@ bool SLandmarks::currentSelection(std::string& selection) const //------------------------------------------------------------------------------ -QColor SLandmarks::convertToQColor(const fwData::Landmarks::ColorType& color) const +QColor SLandmarks::convertToQColor(const ::fwData::Landmarks::ColorType& color) { return QColor( static_cast(color[0]*255), @@ -885,7 +885,7 @@ QColor SLandmarks::convertToQColor(const fwData::Landmarks::ColorType& color) co //------------------------------------------------------------------------------ -void SLandmarks::setColorButtonIcon(QPushButton* button, const QColor& color) const +void SLandmarks::setColorButtonIcon(QPushButton* button, const QColor& color) { const int iconSize = button->style()->pixelMetric(QStyle::PM_LargeIconSize); QPixmap pix(iconSize, iconSize); From 04ad70af82ef781a717708690dbe703541ce9031 Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Thu, 16 Feb 2017 17:45:44 +0100 Subject: [PATCH 10/18] fix(Landmarks): fixed warnings in LandmarksTest --- SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp b/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp index 11a8d7735..1580b85d4 100644 --- a/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp +++ b/SrcLib/core/fwData/test/tu/src/LandmarksTest.cpp @@ -51,10 +51,10 @@ void LandmarksTest::copyTest() 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}; + 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)); From 9e1586a118ee895568a1de610e01564fade6556d Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Tue, 28 Feb 2017 11:38:16 +0100 Subject: [PATCH 11/18] fix(LandmarksConfig): removed useless Landmark adaptor in Blend config --- .../blendActivity/rc/configurations/TransferFunctionEditor.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml b/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml index 393578283..8502ec3cb 100644 --- a/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml +++ b/Bundles/LeafActivity/blendActivity/rc/configurations/TransferFunctionEditor.xml @@ -102,9 +102,6 @@ - - - From 326f21bd3da7530cae4aefd9422fdd9f8a5a4b7a Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Wed, 1 Mar 2017 16:08:21 +0100 Subject: [PATCH 12/18] feat(LandmarksAdaptor): improved point selection The selection is kept even if the handle is released. To deselect the point, you must right click (or left click outside the image). Fixed point movinfg on click (it was posed on the first picked object) : now, the point only moves if the mouse moves. --- .../include/visuVTKAdaptor/SLandmarks.hpp | 25 ++- .../src/visuVTKAdaptor/SLandmarks.cpp | 170 +++++++++++------- 2 files changed, 123 insertions(+), 72 deletions(-) diff --git a/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp index f100b0b9f..23c2ab666 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/include/visuVTKAdaptor/SLandmarks.hpp @@ -40,7 +40,8 @@ namespace visuVTKAdaptor * - \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): deselec the point (reset current color) + * - \b deselectPoint(groupName, index): deselect the point (reset current color) + * - \b show(bool): show or hide the landmarks * * @section XML XML Configuration * @@ -57,6 +58,7 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer public: fwCoreServiceClassDefinitionsMacro( (SLandmarks)(::fwRenderVTK::IVtkAdaptorService) ); + fwCoreAllowSharedFromThis(); /// Widget used to display and interact with landmarks. typedef vtkSmartPointer< vtkHandleWidget > LandmarkWidgetType; @@ -78,8 +80,8 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer */ VISUVTKADAPTOR_API virtual KeyConnectionsType getObjSrvConnections() const; - /// Returns point associated to widget. - fwData::Landmarks::PointType* getPoint(const LandmarkWidgetType& widget); + /// Deselect the current point and emit the corresponding Landmarks signal + void deselect(); protected: @@ -90,12 +92,6 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer 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: /// Stores a group of widgets. @@ -110,6 +106,8 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer /// 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); @@ -144,11 +142,17 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer 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; @@ -161,6 +165,9 @@ class VISUVTKADAPTOR_CLASS_API SLandmarks : public ::fwRenderVTK::IVtkAdaptorSer /// 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; }; diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp index f70428e5e..1748d5593 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -64,6 +64,7 @@ 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"; //------------------------------------------------------------------------------ @@ -139,7 +140,7 @@ class vtkLandmarkUpdateCallBack : public vtkCommand SLM_ASSERT("handler not instanced", handler); double* world = representation->GetWorldPosition(); - if ( eventId == vtkCommand::InteractionEvent|| eventId == vtkCommand::EndInteractionEvent ) + if ( eventId == vtkCommand::InteractionEvent) { double display[3]; int x, y; @@ -152,6 +153,19 @@ class vtkLandmarkUpdateCallBack : public vtkCommand { ::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) { @@ -159,26 +173,6 @@ class vtkLandmarkUpdateCallBack : public vtkCommand (::fwData::Landmarks::s_POINT_SELECTED_SIG); sig->asyncEmit(m_groupName, m_pointIndex); } - - 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); - } - - if (eventId == vtkCommand::EndInteractionEvent) - { - auto sigDeselect = m_landmarks->signal< ::fwData::Landmarks::PointDeselectedSignalType > - (::fwData::Landmarks::s_POINT_DESELECTED_SIG); - sigDeselect->asyncEmit(m_groupName, m_pointIndex); - } } protected: @@ -200,9 +194,47 @@ class vtkLandmarkUpdateCallBack : public vtkCommand //------------------------------------------------------------------------------ +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_rightButtonCommand(nullptr), - m_needSubservicesDeletion(false), + m_noSelectionCommand(nullptr), m_count(0) { this->newSlot(s_ADD_POINT_SLOT, &SLandmarks::addPoint, this); @@ -215,6 +247,7 @@ SLandmarks::SLandmarks() throw() : 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); } //------------------------------------------------------------------------------ @@ -233,6 +266,12 @@ 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::LeftButtonPressEvent, m_noSelectionCommand); + this->getInteractor()->AddObserver(vtkCommand::RightButtonReleaseEvent, m_noSelectionCommand); + this->doUpdate(); } @@ -248,7 +287,7 @@ void SLandmarks::doSwap() throw(fwTools::Failed) void SLandmarks::doUpdate() throw(fwTools::Failed) { - this->doStop(); + this->clearLandmarks(); ::fwData::Landmarks::csptr landmarks = this->getObject< ::fwData::Landmarks >(); @@ -265,6 +304,20 @@ void SLandmarks::doUpdate() throw(fwTools::Failed) //------------------------------------------------------------------------------ +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 >(); @@ -470,6 +523,15 @@ void SLandmarks::renameGroup(std::string oldName, std::string newName) 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); @@ -478,11 +540,6 @@ void SLandmarks::selectPoint(std::string groupName, size_t index) const double* color = rep->GetProperty()->GetColor(); - if (m_timer) - { - m_timer->stop(); - m_timer.reset(); - } m_timer = m_associatedWorker->createTimer(); ::fwThread::Timer::TimeDurationType duration = ::boost::chrono::milliseconds(500); @@ -504,6 +561,7 @@ void SLandmarks::selectPoint(std::string groupName, size_t index) void SLandmarks::deselectPoint(std::string groupName, size_t index) { m_timer->stop(); + m_timer.reset(); const ::fwData::Landmarks::sptr& landmarks = this->getObject< ::fwData::Landmarks >(); LandmarkWidgetType& widget = m_handles.at(groupName).at(index); @@ -524,6 +582,22 @@ void SLandmarks::deselectPoint(std::string groupName, size_t index) //------------------------------------------------------------------------------ +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) { @@ -546,32 +620,13 @@ void SLandmarks::changeColor(const vtkSmartPointer< ::fwRenderVTK::vtk::fwHandle //------------------------------------------------------------------------------ -::fwData::Landmarks::PointType* SLandmarks::getPoint(const SLandmarks::LandmarkWidgetType& widget) +void SLandmarks::clearLandmarks() { - ::fwData::Landmarks::PointType* result = nullptr; - - ::fwData::Landmarks::sptr landmarks = this->getObject< ::fwData::Landmarks >(); - - const ::fwData::Landmarks::GroupNameContainer groupNames = landmarks->getGroupNames(); - - for(const auto& name : groupNames) + while (!m_handles.empty()) { - auto widgetGroup = m_handles[name]; - - auto pointIter = std::find(widgetGroup.begin(), widgetGroup.end(), widget); - - if(pointIter != widgetGroup.end()) - { - auto group = landmarks->getGroup(name); - - size_t pointIndex = static_cast(std::distance(widgetGroup.begin(), pointIter)); - - result = &group.m_points[pointIndex]; - break; - } + const std::string name = m_handles.begin()->first; + this->removeGroup(name); } - - return result; } //------------------------------------------------------------------------------ @@ -657,17 +712,6 @@ vtkSmartPointer< vtkHandleWidget > SLandmarks::newHandle(const ::fwData::Landmar //------------------------------------------------------------------------------ -void SLandmarks::doStop() throw(fwTools::Failed) -{ - while (!m_handles.empty()) - { - const std::string name = m_handles.begin()->first; - this->removeGroup(name); - } -} - -//------------------------------------------------------------------------------ - void SLandmarks::show(bool b) { if (b) From 7696876b29dd28b6f365fdc8ec2c8bb298f8599d Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Wed, 1 Mar 2017 16:09:34 +0100 Subject: [PATCH 13/18] refactor(LandmarksEditor): update the group parameters when a point is selected. --- .../src/uiMeasurementQt/editor/SLandmarks.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp index 2eb23ec85..1c70d6d67 100644 --- a/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp +++ b/Bundles/LeafUI/uiMeasurementQt/src/uiMeasurementQt/editor/SLandmarks.cpp @@ -803,8 +803,22 @@ void SLandmarks::selectPoint(std::string groupName, size_t index) 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); } From 2d46722f73306a5995cef4193de9e38b44d6abaa Mon Sep 17 00:00:00 2001 From: Kevin Gaudet Date: Wed, 1 Mar 2017 16:51:46 +0100 Subject: [PATCH 14/18] fix(LandmarksAdaptor): Deselect deleted point. --- .../visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp index 1748d5593..61b99a4d4 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -354,6 +354,7 @@ void SLandmarks::insertPoint(std::string groupName, size_t index) void SLandmarks::removePoint(std::string groupName, size_t index) { + this->deselect(); LandmarksWidgetContainerType& landmarkHandleGroup = m_handles[groupName]; auto& handleToRemove = landmarkHandleGroup[index]; @@ -560,8 +561,12 @@ void SLandmarks::selectPoint(std::string groupName, size_t index) void SLandmarks::deselectPoint(std::string groupName, size_t index) { - m_timer->stop(); - m_timer.reset(); + 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); From a2c7ef94f63bdb1e692fc3bf0272e5b500c75454 Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Mon, 6 Mar 2017 09:48:39 +0100 Subject: [PATCH 15/18] fix(LandmarksAdaptor): reset clipping range when the point move. --- .../LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp index 61b99a4d4..4540f0e87 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -487,6 +487,7 @@ void SLandmarks::modifyPoint(std::string groupName, size_t index) LabelActorType textActor = m_labels[widget]; textActor->GetPositionCoordinate()->SetValue(point.data()); + this->getRenderer()->ResetCameraClippingRange(); this->setVtkPipelineModified(); this->requestRender(); } From e786e4e805ebbea930d49562a383488a1ec6532a Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Tue, 7 Mar 2017 17:26:45 +0100 Subject: [PATCH 16/18] fix(LandmarksAdaptor): fixed remove point Stop selection timer when the point is removed. --- .../visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp index 4540f0e87..c67a2c46a 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -354,7 +354,11 @@ void SLandmarks::insertPoint(std::string groupName, size_t index) void SLandmarks::removePoint(std::string groupName, size_t index) { - this->deselect(); + 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]; From 7cf67d54757b0c775eb6e94cc4e3ace2309fe107 Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Wed, 8 Mar 2017 17:16:46 +0100 Subject: [PATCH 17/18] feat(Landmarks): updated 2D and 3D visualization to configure editor mode. --- .../rc/configurations/2DVisualization.xml | 3 ++- .../rc/configurations/3DVisualization.xml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml index 02424c952..21458b5c8 100644 --- a/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml +++ b/Bundles/LeafActivity/2DVisualizationActivity2/rc/configurations/2DVisualization.xml @@ -6,6 +6,7 @@ + @@ -111,7 +112,7 @@ - yes + ${advancedLandmarksEditor} diff --git a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml index 8df7fd65f..52066669a 100644 --- a/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml +++ b/Bundles/LeafActivity/3DVisualizationActivity2/rc/configurations/3DVisualization.xml @@ -13,6 +13,7 @@ + @@ -278,6 +279,7 @@ + ${advancedLandmarksEditor} From 46d5b6de8b8341a28a645b675c47a2a95b876f0b Mon Sep 17 00:00:00 2001 From: Emilie Wernert Date: Wed, 8 Mar 2017 17:07:53 +0100 Subject: [PATCH 18/18] refactor(SLandmarksAdaptor): improved landmarks deselection The point is deselected on right click. Depending on the scene (images or meshes), we received PressEvent or ReleaseEvent. --- .../LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp index c67a2c46a..9b20319b2 100644 --- a/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp +++ b/Bundles/LeafVisu/visuVTKAdaptor/src/visuVTKAdaptor/SLandmarks.cpp @@ -269,7 +269,7 @@ void SLandmarks::doStart() throw(fwTools::Failed) vtkDeselectLandmarksCallBack* callback = vtkDeselectLandmarksCallBack::New(); callback->setAdaptor(this->getSptr()); m_noSelectionCommand = callback; - this->getInteractor()->AddObserver(vtkCommand::LeftButtonPressEvent, m_noSelectionCommand); + this->getInteractor()->AddObserver(vtkCommand::RightButtonPressEvent, m_noSelectionCommand); this->getInteractor()->AddObserver(vtkCommand::RightButtonReleaseEvent, m_noSelectionCommand); this->doUpdate();