diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.cpp b/Modules/ContourModel/DataManagement/mitkContourElement.cpp index 97b3becdc2..fdd0edfff4 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourElement.cpp @@ -1,389 +1,414 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include mitk::ContourElement::ConstVertexIterator mitk::ContourElement::ConstIteratorBegin() const { return this->begin(); } mitk::ContourElement::ConstVertexIterator mitk::ContourElement::ConstIteratorEnd() const { return this->end(); } mitk::ContourElement::VertexIterator mitk::ContourElement::IteratorBegin() { return this->begin(); } mitk::ContourElement::VertexIterator mitk::ContourElement::IteratorEnd() { return this->end(); } mitk::ContourElement::ConstVertexIterator mitk::ContourElement::begin() const { return this->m_Vertices.begin(); } mitk::ContourElement::ConstVertexIterator mitk::ContourElement::end() const { return this->m_Vertices.end(); } mitk::ContourElement::VertexIterator mitk::ContourElement::begin() { return this->m_Vertices.begin(); } mitk::ContourElement::VertexIterator mitk::ContourElement::end() { return this->m_Vertices.end(); } mitk::ContourElement::ContourElement(const mitk::ContourElement &other) : itk::LightObject(), m_IsClosed(other.m_IsClosed) { - for (const auto& v : m_Vertices) + for (const auto& v : other.m_Vertices) { m_Vertices.push_back(new ContourModelVertex(*v)); } } +mitk::ContourElement& mitk::ContourElement::operator = (const ContourElement& other) +{ + if (this != &other) + { + this->Clear(); + for (const auto& v : other.m_Vertices) + { + m_Vertices.push_back(new ContourModelVertex(*v)); + } + } + + this->m_IsClosed = other.m_IsClosed; + return *this; +} + +mitk::ContourElement::~ContourElement() +{ + this->Clear(); +} + +mitk::ContourElement::VertexSizeType mitk::ContourElement::GetSize() const +{ + return this->m_Vertices.size(); +} + void mitk::ContourElement::AddVertex(const mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices.push_back(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertexAtFront(const mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices.push_front(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::InsertVertexAtIndex(const mitk::Point3D &vertex, bool isControlPoint, VertexSizeType index) { if (index >= 0 && this->GetSize() > index) { auto _where = this->m_Vertices.begin(); _where += index; this->m_Vertices.insert(_where, new VertexType(vertex, isControlPoint)); } } void mitk::ContourElement::SetVertexAt(VertexSizeType pointId, const Point3D &point) { if (pointId >= 0 && this->GetSize() > pointId) { - this->m_Vertices.at(pointId)->Coordinates = point; + this->m_Vertices[pointId]->Coordinates = point; } } void mitk::ContourElement::SetVertexAt(VertexSizeType pointId, const VertexType *vertex) { if (nullptr == vertex) { mitkThrow() << "Cannot set vertex. Passed vertex instance is invalid. Index to set: " << pointId; } if (pointId >= 0 && this->GetSize() > pointId) { - this->m_Vertices.at(pointId)->Coordinates = vertex->Coordinates; - this->m_Vertices.at(pointId)->IsControlPoint = vertex->IsControlPoint; + this->m_Vertices[pointId]->Coordinates = vertex->Coordinates; + this->m_Vertices[pointId]->IsControlPoint = vertex->IsControlPoint; } } mitk::ContourElement::VertexType *mitk::ContourElement::GetVertexAt(VertexSizeType index) { return this->m_Vertices.at(index); } const mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(VertexSizeType index) const { return this->m_Vertices.at(index); } bool mitk::ContourElement::IsEmpty() const { return this->m_Vertices.empty(); } mitk::ContourElement::VertexType *mitk::ContourElement::GetVertexAt(const mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should some kind of an octree with spatial query*/ if (eps > 0) { // currently no method with better performance is available return BruteForceGetVertexAt(point, eps); } // if eps < 0 return nullptr; } mitk::ContourElement::VertexType *mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, double eps) { if (eps > 0) { std::deque> nearestlist; ConstVertexIterator it = this->m_Vertices.begin(); ConstVertexIterator end = this->m_Vertices.end(); while (it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; double distance = currentPoint.EuclideanDistanceTo(point); if (distance < eps) { // if list is emtpy, add point to list if (nearestlist.size() < 1) { nearestlist.push_front(std::pair((*it)->Coordinates.EuclideanDistanceTo(point), (*it))); } // found an approximate point - check if current is closer then first in nearestlist else if (distance < nearestlist.front().first) { // found even closer vertex nearestlist.push_front(std::pair((*it)->Coordinates.EuclideanDistanceTo(point), (*it))); } } // if distance > eps it++; } // while if (nearestlist.size() > 0) { /*++++++++++++++++++++ return the nearest active point if one was found++++++++++++++++++*/ auto it = nearestlist.begin(); auto end = nearestlist.end(); while (it != end) { if ((*it).second->IsControlPoint) { return (*it).second; } it++; } /*---------------------------------------------------------------------------------------*/ // return closest point return nearestlist.front().second; } } return nullptr; } const mitk::ContourElement::VertexListType *mitk::ContourElement::GetVertexList() const { return &(this->m_Vertices); } bool mitk::ContourElement::IsClosed() const { return this->m_IsClosed; } bool mitk::ContourElement::IsNearContour(const mitk::Point3D &point, float eps) const { ConstVertexIterator it1 = this->m_Vertices.begin(); ConstVertexIterator it2 = this->m_Vertices.begin(); it2++; // it2 runs one position ahead ConstVertexIterator end = this->m_Vertices.end(); int counter = 0; for (; it1 != end; it1++, it2++, counter++) { if (it2 == end) it2 = this->m_Vertices.begin(); mitk::Point3D v1 = (*it1)->Coordinates; mitk::Point3D v2 = (*it2)->Coordinates; const float l2 = v1.SquaredEuclideanDistanceTo(v2); mitk::Vector3D p_v1 = point - v1; mitk::Vector3D v2_v1 = v2 - v1; double tc = (p_v1 * v2_v1) / l2; // take into account we have line segments and not (infinite) lines if (tc < 0.0) tc = 0.0; if (tc > 1.0) tc = 1.0; mitk::Point3D crossPoint = v1 + v2_v1 * tc; double distance = point.SquaredEuclideanDistanceTo(crossPoint); if (distance < eps) { return true; } } return false; } void mitk::ContourElement::Close() { this->m_IsClosed = true; } void mitk::ContourElement::Open() { this->m_IsClosed = false; } void mitk::ContourElement::SetClosed(bool isClosed) { isClosed ? this->Close() : this->Open(); } mitk::ContourElement::VertexListType mitk::ContourElement::GetControlVertices() const { VertexListType controlVertices; std::copy_if(this->m_Vertices.begin(), this->m_Vertices.end(), std::back_inserter(controlVertices), [](const VertexType* v) {return v->IsControlPoint; }); return controlVertices; } void mitk::ContourElement::Concatenate(const mitk::ContourElement *other, bool check) { if (other->GetSize() > 0) { for (const auto& sourceVertex : other->m_Vertices) { if (check) { auto finding = std::find_if(this->m_Vertices.begin(), this->m_Vertices.end(), [sourceVertex](const VertexType* v) {return sourceVertex->Coordinates == v->Coordinates; }); if (finding == this->m_Vertices.end()) { this->m_Vertices.push_back(new ContourModelVertex(*sourceVertex)); } } else { this->m_Vertices.push_back(new ContourModelVertex(*sourceVertex)); } } } } mitk::ContourElement::VertexSizeType mitk::ContourElement::GetIndex(const VertexType* vertex) const { VertexSizeType result = NPOS; auto finding = std::find(this->m_Vertices.begin(), this->m_Vertices.end(), vertex); if (finding != this->m_Vertices.end()) { result = finding - this->m_Vertices.begin(); } return result; } bool mitk::ContourElement::RemoveVertex(const VertexType *vertex) { auto finding = std::find(this->m_Vertices.begin(), this->m_Vertices.end(), vertex); return RemoveVertexByIterator(finding); } bool mitk::ContourElement::RemoveVertexAt(VertexSizeType index) { if (index >= 0 && index < this->m_Vertices.size()) { auto delIter = this->m_Vertices.begin() + index; return RemoveVertexByIterator(delIter); } return false; } bool mitk::ContourElement::RemoveVertexAt(const mitk::Point3D &point, double eps) { if (eps > 0) { auto finding = std::find_if(this->m_Vertices.begin(), this->m_Vertices.end(), [point, eps](const VertexType* v) {return v->Coordinates.EuclideanDistanceTo(point) < eps; }); return RemoveVertexByIterator(finding); } return false; } bool mitk::ContourElement::RemoveVertexByIterator(VertexListType::iterator& iter) { if (iter != this->m_Vertices.end()) { delete* iter; this->m_Vertices.erase(iter); return true; } return false; } void mitk::ContourElement::Clear() { for (auto vertex : m_Vertices) { delete vertex; } this->m_Vertices.clear(); } //---------------------------------------------------------------------- void mitk::ContourElement::RedistributeControlVertices(const VertexType *selected, int period) { int counter = 0; auto _where = this->m_Vertices.begin(); if (selected != nullptr) { auto finding = std::find(this->m_Vertices.begin(), this->m_Vertices.end(), selected); if (finding != this->m_Vertices.end()) { _where = finding; } } auto _iter = _where; while (_iter != this->m_Vertices.end()) { div_t divresult; divresult = div(counter, period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter++; } _iter = _where; counter = 0; while (_iter != this->m_Vertices.begin()) { div_t divresult; divresult = div(counter, period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter--; } } diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.h b/Modules/ContourModel/DataManagement/mitkContourElement.h index f302ddc574..03139130b2 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.h +++ b/Modules/ContourModel/DataManagement/mitkContourElement.h @@ -1,248 +1,263 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _mitkContourElement_H_ #define _mitkContourElement_H_ #include "mitkCommon.h" #include #include #include namespace mitk { /** \brief Represents a contour in 3D space. A ContourElement is consisting of linked vertices implicitely defining the contour. They are stored in a double ended queue making it possible to add vertices at front and end of the contour and to iterate in both directions. To mark a vertex as a special one it can be set as a control point. \note This class assumes that it manages its vertices. So if a vertex instance is added to this class the ownership of the vertex is transfered to the ContourElement instance. The ContourElement instance takes care of deleting vertex instances if needed. It is highly not recommend to use this class directly as it is designed as a internal class of ContourModel. Therefore it is adviced to use ContourModel if contour representations are needed in MITK. */ class MITKCONTOURMODEL_EXPORT ContourElement : public itk::LightObject { public: mitkClassMacroItkParent(ContourElement, itk::LightObject); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** \brief Represents a single vertex of a contour. */ struct ContourModelVertex { ContourModelVertex(const mitk::Point3D& point, bool active = false) : IsControlPoint(active), Coordinates(point) {}; ContourModelVertex(const ContourModelVertex& other) : IsControlPoint(other.IsControlPoint), Coordinates(other.Coordinates) { }; /** \brief Treat point special. */ bool IsControlPoint; /** \brief Coordinates in 3D space. */ mitk::Point3D Coordinates; + + bool operator ==(const ContourModelVertex& other) + { + return this->Coordinates == other.Coordinates && this->IsControlPoint == other.IsControlPoint; + }; }; using VertexType = ContourModelVertex; using VertexListType = std::deque; using VertexIterator = VertexListType::iterator; using ConstVertexIterator = VertexListType::const_iterator; using VertexSizeType = VertexListType::size_type; - /**Indicates an invalid index.*/ + /**Indicates an invalid index. + * It is always the maximum of the unsigned int type.*/ static const VertexSizeType NPOS = -1; /** \brief Return a const iterator a the front. */ ConstVertexIterator ConstIteratorBegin() const; /** \brief Return a const iterator a the end. */ ConstVertexIterator ConstIteratorEnd() const; /** \brief Return an iterator a the front. */ VertexIterator IteratorBegin(); /** \brief Return an iterator a the end. */ VertexIterator IteratorEnd(); /** \brief Return a const iterator a the front. * For easier support of stl functionality. */ ConstVertexIterator begin() const; /** \brief Return a const iterator a the end. * For easier support of stl functionality. */ ConstVertexIterator end() const; /** \brief Return an iterator a the front. * For easier support of stl functionality. */ VertexIterator begin(); /** \brief Return an iterator a the end. * For easier support of stl functionality. */ VertexIterator end(); /** \brief Returns the number of contained vertices. */ - VertexSizeType GetSize() const { return this->m_Vertices.size(); } + VertexSizeType GetSize() const; /** \brief Add a vertex at the end of the contour \param point - coordinates in 3D space. \param isControlPoint - is the vertex a special control point. */ void AddVertex(const mitk::Point3D &point, bool isControlPoint); /** \brief Add a vertex at the front of the contour \param point - coordinates in 3D space. \param isControlPoint - is the vertex a control point. */ void AddVertexAtFront(const mitk::Point3D &point, bool isControlPoint); /** \brief Add a vertex at a given index of the contour \param point - coordinates in 3D space. \param isControlPoint - is the vertex a special control point. \param index - the index to be inserted at. */ void InsertVertexAtIndex(const mitk::Point3D &point, bool isControlPoint, VertexSizeType index); /** \brief Set coordinates a given index. \param pointId Index of vertex. \param point Coordinates. */ void SetVertexAt(VertexSizeType pointId, const mitk::Point3D &point); /** \brief Set vertex a given index (by copying the values). \param pointId Index of vertex. \param vertex Vertex. \pre Passed vertex is a valid instance */ void SetVertexAt(VertexSizeType pointId, const VertexType* vertex); /** \brief Returns the vertex a given index \param index \pre index must be valid. */ VertexType* GetVertexAt(VertexSizeType index); const VertexType* GetVertexAt(VertexSizeType index) const; /** \brief Returns the approximate nearest vertex a given posoition in 3D space \param point - query position in 3D space. \param eps - the error bound for search algorithm. */ VertexType *GetVertexAt(const mitk::Point3D &point, float eps); /** \brief Returns the index of the given vertex within the contour. \param vertex - the vertex to be searched. - \return index of vertex. Returns NPOS (==-1) if not found. + \return index of vertex. Returns ContourElement::NPOS if not found. */ VertexSizeType GetIndex(const VertexType *vertex) const; /** \brief Returns the container of the vertices. */ const VertexListType *GetVertexList() const; /** \brief Returns whether the contour element is empty. */ bool IsEmpty() const; /** \brief Returns if the conour is closed or not. */ bool IsClosed() const; /** \brief Returns whether a given point is near a contour, according to eps. \param point - query position in 3D space. \param eps - the error bound for search algorithm. */ bool IsNearContour(const mitk::Point3D &point, float eps) const; /** \brief Close the contour. Connect first with last element. */ void Close(); /** \brief Open the contour. Disconnect first and last element. */ void Open(); /** \brief Set the contours IsClosed property. \param isClosed - true = closed; false = open; */ void SetClosed(bool isClosed); /** \brief Concatenate the contuor with a another contour. All vertices of the other contour will be cloned and added after last vertex. \param other - the other contour \param check - set it true to avoid adding of vertices that are already in the source contour */ void Concatenate(const mitk::ContourElement *other, bool check); /** \brief Remove the given vertex from the container if exists. \param vertex - the vertex to be removed. */ bool RemoveVertex(const VertexType *vertex); /** \brief Remove a vertex at given index within the container if exists. \param index - the index where the vertex should be removed. */ bool RemoveVertexAt(VertexSizeType index); /** \brief Remove the approximate nearest vertex at given position in 3D space if one exists. \param point - query point in 3D space. \param eps - error bound for search algorithm. */ bool RemoveVertexAt(const mitk::Point3D &point, double eps); /** \brief Clear the storage container. */ void Clear(); /** \brief Returns the approximate nearest vertex a given posoition in 3D space \param point - query position in 3D space. \param eps - the error bound for search algorithm. */ VertexType *BruteForceGetVertexAt(const mitk::Point3D &point, double eps); + /** Returns a list pointing to all vertices that are indicated to be control + points. + \remark It is important to note, that the vertex pointers in the returned + list directly point to the vertices stored interanlly. So they are still + owned by the ContourElement instance that returns the list. If one wants + to take over ownership, one has to clone the vertex instances. + */ VertexListType GetControlVertices() const; /** \brief Uniformly redistribute control points with a given period (in number of vertices) \param vertex - the vertex around which the redistribution is done. \param period - number of vertices between control points. */ void RedistributeControlVertices(const VertexType *vertex, int period); protected: mitkCloneMacro(Self); ContourElement() = default; ContourElement(const mitk::ContourElement &other); - ~ContourElement() = default; + ~ContourElement(); + + ContourElement& operator = (const ContourElement & other); /** Internal helper function to correctly remove the element indicated by the iterator from the list. After the call the iterator is invalid. Caller of the function must ensure that the iterator is valid!. \result Indicates if the element indicated by the iterator was removed. If iterator points to end it returns false.*/ bool RemoveVertexByIterator(VertexListType::iterator& iter); VertexListType m_Vertices; // double ended queue with vertices bool m_IsClosed = false; }; } // namespace mitk #endif // _mitkContourElement_H_ diff --git a/Modules/ContourModel/DataManagement/mitkContourModel.cpp b/Modules/ContourModel/DataManagement/mitkContourModel.cpp index bd4b4ae39b..d6e04cb150 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourModel.cpp @@ -1,628 +1,628 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include mitk::ContourModel::ContourModel() : m_UpdateBoundingBox(true) { // set to initial state this->InitializeEmpty(); } mitk::ContourModel::ContourModel(const ContourModel &other) : BaseData(other), m_ContourSeries(other.m_ContourSeries), m_lineInterpolation(other.m_lineInterpolation) { m_SelectedVertex = nullptr; } mitk::ContourModel::~ContourModel() { m_SelectedVertex = nullptr; this->m_ContourSeries.clear(); // TODO check destruction } void mitk::ContourModel::AddVertex(const Point3D &vertex, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->AddVertex(vertex, false, timestep); } } void mitk::ContourModel::AddVertex(const Point3D &vertex, bool isControlPoint, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertex(vertex, isControlPoint); this->InvokeEvent(ContourModelSizeChangeEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertex(const VertexType &vertex, TimeStepType timestep) { this->AddVertex(vertex.Coordinates, vertex.IsControlPoint, timestep); } void mitk::ContourModel::AddVertexAtFront(const Point3D &vertex, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->AddVertexAtFront(vertex, false, timestep); } } void mitk::ContourModel::AddVertexAtFront(const Point3D &vertex, bool isControlPoint, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertexAtFront(vertex, isControlPoint); this->InvokeEvent(ContourModelSizeChangeEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertexAtFront(const VertexType &vertex, TimeStepType timestep) { this->AddVertexAtFront(vertex.Coordinates, vertex.IsControlPoint, timestep); } bool mitk::ContourModel::SetVertexAt(int pointId, const Point3D &point, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > ContourElement::VertexSizeType(pointId)) { this->m_ContourSeries[timestep]->SetVertexAt(pointId, point); this->Modified(); this->m_UpdateBoundingBox = true; return true; } return false; } return false; } bool mitk::ContourModel::SetVertexAt(int pointId, const VertexType *vertex, TimeStepType timestep) { if (vertex == nullptr) return false; if (!this->IsEmptyTimeStep(timestep)) { if (pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > ContourElement::VertexSizeType(pointId)) { this->m_ContourSeries[timestep]->SetVertexAt(pointId, vertex); this->Modified(); this->m_UpdateBoundingBox = true; return true; } return false; } return false; } void mitk::ContourModel::InsertVertexAtIndex(const Point3D &vertex, int index, bool isControlPoint, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (index >= 0 && this->m_ContourSeries[timestep]->GetSize() > ContourElement::VertexSizeType(index)) { this->m_ContourSeries[timestep]->InsertVertexAtIndex(vertex, isControlPoint, index); this->InvokeEvent(ContourModelSizeChangeEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } } void mitk::ContourModel::UpdateContour(const ContourModel* sourceModel, TimeStepType destinationTimeStep, TimeStepType sourceTimeStep) { if (nullptr == sourceModel) { mitkThrow() << "Cannot update contour. Passed source model is invalid."; } if (!sourceModel->GetTimeGeometry()->IsValidTimeStep(sourceTimeStep)) { mitkThrow() << "Cannot update contour. Source contour time geometry does not support passed time step. Invalid time step: " << sourceTimeStep; } if (!this->GetTimeGeometry()->IsValidTimeStep(destinationTimeStep)) { MITK_WARN << "Cannot update contour. Contour time geometry does not support passed time step. Invalid time step: " << destinationTimeStep; return; } this->Clear(destinationTimeStep); std::for_each(sourceModel->Begin(sourceTimeStep), sourceModel->End(sourceTimeStep), [this, destinationTimeStep](ContourElement::VertexType* vertex) { this->m_ContourSeries[destinationTimeStep]->AddVertex(vertex->Coordinates, vertex->IsControlPoint); }); this->InvokeEvent(ContourModelSizeChangeEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } bool mitk::ContourModel::IsEmpty(TimeStepType timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsEmpty(); } return true; } bool mitk::ContourModel::IsEmpty() const { return this->IsEmpty(0); } int mitk::ContourModel::GetNumberOfVertices(TimeStepType timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetSize(); } return -1; } const mitk::ContourModel::VertexType *mitk::ContourModel::GetVertexAt(int index, TimeStepType timestep) const { - if (!this->IsEmptyTimeStep(timestep) && this->m_ContourSeries[timestep]->GetSize()>mitk::ContourElement::VertexSizeType(index)) + if (!this->IsEmptyTimeStep(timestep) && this->m_ContourSeries[timestep]->GetSize() > mitk::ContourElement::VertexSizeType(index)) { return this->m_ContourSeries[timestep]->GetVertexAt(index); } return nullptr; } int mitk::ContourModel::GetIndex(const VertexType *vertex, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetIndex(vertex); } return -1; } void mitk::ContourModel::Close(TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Close(); this->InvokeEvent(ContourModelClosedEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::Open(TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Open(); this->InvokeEvent(ContourModelClosedEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::SetClosed(bool isClosed, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->SetClosed(isClosed); this->InvokeEvent(ContourModelClosedEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } bool mitk::ContourModel::IsEmptyTimeStep(unsigned int t) const { return (this->m_ContourSeries.size() <= t); } bool mitk::ContourModel::IsNearContour(Point3D &point, float eps, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsNearContour(point, eps); } return false; } void mitk::ContourModel::Concatenate(ContourModel *other, TimeStepType timestep, bool check) { if (!this->IsEmptyTimeStep(timestep)) { if (!this->m_ContourSeries[timestep]->IsClosed()) { this->m_ContourSeries[timestep]->Concatenate(other->m_ContourSeries[timestep], check); this->InvokeEvent(ContourModelSizeChangeEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } } mitk::ContourModel::VertexIterator mitk::ContourModel::Begin(TimeStepType timestep) const { return this->IteratorBegin(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorBegin(TimeStepType timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorBegin(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } mitk::ContourModel::VertexIterator mitk::ContourModel::End(TimeStepType timestep) const { return this->IteratorEnd(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorEnd(TimeStepType timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorEnd(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } bool mitk::ContourModel::IsClosed(int timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsClosed(); } return false; } bool mitk::ContourModel::SelectVertexAt(Point3D &point, float eps, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); } return this->m_SelectedVertex != nullptr; } bool mitk::ContourModel::SelectVertexAt(int index, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep) && index >= 0) { return (this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(index)); } return false; } bool mitk::ContourModel::SetControlVertexAt(Point3D &point, float eps, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { VertexType *vertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); if (vertex != nullptr) { vertex->IsControlPoint = true; return true; } } return false; } bool mitk::ContourModel::SetControlVertexAt(int index, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep) && index >= 0) { VertexType *vertex = this->m_ContourSeries[timestep]->GetVertexAt(index); if (vertex != nullptr) { vertex->IsControlPoint = true; return true; } } return false; } bool mitk::ContourModel::RemoveVertex(const VertexType *vertex, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (this->m_ContourSeries[timestep]->RemoveVertex(vertex)) { this->Modified(); this->m_UpdateBoundingBox = true; this->InvokeEvent(ContourModelSizeChangeEvent()); return true; } } return false; } bool mitk::ContourModel::RemoveVertexAt(int index, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (this->m_ContourSeries[timestep]->RemoveVertexAt(index)) { this->Modified(); this->m_UpdateBoundingBox = true; this->InvokeEvent(ContourModelSizeChangeEvent()); return true; } } return false; } bool mitk::ContourModel::RemoveVertexAt(Point3D &point, float eps, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (this->m_ContourSeries[timestep]->RemoveVertexAt(point, eps)) { this->Modified(); this->m_UpdateBoundingBox = true; this->InvokeEvent(ContourModelSizeChangeEvent()); return true; } } return false; } void mitk::ContourModel::ShiftSelectedVertex(Vector3D &translate) { if (this->m_SelectedVertex) { this->ShiftVertex(this->m_SelectedVertex, translate); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::ShiftContour(Vector3D &translate, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { // shift all vertices for (auto vertex : *(this->m_ContourSeries[timestep])) { this->ShiftVertex(vertex, translate); } this->Modified(); this->m_UpdateBoundingBox = true; this->InvokeEvent(ContourModelShiftEvent()); } } void mitk::ContourModel::ShiftVertex(VertexType *vertex, Vector3D &vector) { vertex->Coordinates[0] += vector[0]; vertex->Coordinates[1] += vector[1]; vertex->Coordinates[2] += vector[2]; } void mitk::ContourModel::Clear(TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { // clear data at timestep this->m_ContourSeries[timestep]->Clear(); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::Expand(unsigned int timeSteps) { std::size_t oldSize = this->m_ContourSeries.size(); if (static_cast(timeSteps) > oldSize) { Superclass::Expand(timeSteps); // insert contours for each new timestep for (std::size_t i = oldSize; i < static_cast(timeSteps); i++) { m_ContourSeries.push_back(ContourElement::New()); } this->InvokeEvent(ContourModelExpandTimeBoundsEvent()); } } void mitk::ContourModel::SetRequestedRegionToLargestPossibleRegion() { // no support for regions } bool mitk::ContourModel::RequestedRegionIsOutsideOfTheBufferedRegion() { // no support for regions return false; } bool mitk::ContourModel::VerifyRequestedRegion() { // no support for regions return true; } void mitk::ContourModel::SetRequestedRegion(const itk::DataObject * /*data*/) { // no support for regions } void mitk::ContourModel::Clear() { // clear data and set to initial state again this->ClearData(); this->InitializeEmpty(); this->Modified(); this->m_UpdateBoundingBox = true; } void mitk::ContourModel::RedistributeControlVertices(int period, TimeStepType timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->RedistributeControlVertices(this->GetSelectedVertex(), period); this->InvokeEvent(ContourModelClosedEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::ClearData() { // call the superclass, this releases the data of BaseData Superclass::ClearData(); // clear out the time resolved contours this->m_ContourSeries.clear(); } void mitk::ContourModel::Initialize() { this->InitializeEmpty(); this->Modified(); this->m_UpdateBoundingBox = true; } void mitk::ContourModel::Initialize(const ContourModel &other) { TimeStepType numberOfTimesteps = other.GetTimeGeometry()->CountTimeSteps(); this->InitializeTimeGeometry(numberOfTimesteps); for (TimeStepType currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { this->m_ContourSeries.push_back(ContourElement::New()); this->SetClosed(other.IsClosed(currentTimestep), currentTimestep); } m_SelectedVertex = nullptr; this->m_lineInterpolation = other.m_lineInterpolation; this->Modified(); this->m_UpdateBoundingBox = true; } void mitk::ContourModel::InitializeEmpty() { // clear data at timesteps this->m_ContourSeries.resize(0); this->m_ContourSeries.push_back(ContourElement::New()); // set number of timesteps to one this->InitializeTimeGeometry(1); m_SelectedVertex = nullptr; this->m_lineInterpolation = ContourModel::LINEAR; } void mitk::ContourModel::UpdateOutputInformation() { if (this->GetSource()) { this->GetSource()->UpdateOutputInformation(); } if (this->m_UpdateBoundingBox) { // update the bounds of the geometry according to the stored vertices ScalarType mitkBounds[6]; // calculate the boundingbox at each timestep typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::PointsContainer PointsContainer; int timesteps = this->GetTimeSteps(); // iterate over the timesteps for (int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++) { if (dynamic_cast(this->GetGeometry(currenTimeStep))) { // do not update bounds for 2D geometries, as they are unfortunately defined with min bounds 0! return; } else { // we have a 3D geometry -> let's update bounds // only update bounds if the contour was modified if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime()) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; BoundingBoxType::Pointer boundingBox = BoundingBoxType::New(); PointsContainer::Pointer points = PointsContainer::New(); auto it = this->IteratorBegin(currenTimeStep); auto end = this->IteratorEnd(currenTimeStep); // fill the boundingbox with the points while (it != end) { Point3D currentP = (*it)->Coordinates; BoundingBoxType::PointType p; p.CastFrom(currentP); points->InsertElement(points->Size(), p); it++; } // construct the new boundingBox boundingBox->SetPoints(points); boundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; // set boundingBox at current timestep BaseGeometry *geometry3d = this->GetGeometry(currenTimeStep); geometry3d->SetBounds(mitkBounds); } } } this->m_UpdateBoundingBox = false; } GetTimeGeometry()->Update(); } void mitk::ContourModel::ExecuteOperation(Operation * /*operation*/) { // not supported yet } diff --git a/Modules/ContourModel/Testing/mitkContourElementTest.cpp b/Modules/ContourModel/Testing/mitkContourElementTest.cpp index 3fed64aba4..b75a434883 100644 --- a/Modules/ContourModel/Testing/mitkContourElementTest.cpp +++ b/Modules/ContourModel/Testing/mitkContourElementTest.cpp @@ -1,344 +1,349 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourElement.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include class mitkContourElementTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkContourElementTestSuite); // Test the append method MITK_TEST(Iterator); MITK_TEST(AddVertex); MITK_TEST(AddVertexAtFront); MITK_TEST(InsertVertexAtIndex); MITK_TEST(GetSetVertexAt); MITK_TEST(OpenAndClose); MITK_TEST(OtherGetters); MITK_TEST(Concatenate); MITK_TEST(RemoveVertex); MITK_TEST(Clear); MITK_TEST(GetControlVertices); MITK_TEST(RedistributeControlVertices); MITK_TEST(Others); CPPUNIT_TEST_SUITE_END(); private: mitk::ContourElement::Pointer m_Contour1to4; mitk::ContourElement::Pointer m_Contour5to6; mitk::ContourElement::Pointer m_Contour_empty; mitk::Point3D m_p1; mitk::Point3D m_p2; mitk::Point3D m_p3; mitk::Point3D m_p4; mitk::Point3D m_p5; mitk::Point3D m_p6; mitk::Point3D m_p7; public: static mitk::Point3D GeneratePoint(double val) { return mitk::Point3D(val); } void setUp() override { m_p1 = GeneratePoint(1); m_p2 = GeneratePoint(2); m_p3 = GeneratePoint(3); m_p4 = GeneratePoint(4); m_p5 = GeneratePoint(5); m_p6 = GeneratePoint(6); m_p7 = GeneratePoint(7); m_Contour1to4 = mitk::ContourElement::New(); m_Contour5to6 = mitk::ContourElement::New(); m_Contour_empty = mitk::ContourElement::New(); m_Contour1to4->AddVertex(m_p1, true); m_Contour1to4->AddVertex(m_p2, false); m_Contour1to4->AddVertex(m_p3, true); m_Contour1to4->AddVertex(m_p4, false); m_Contour5to6->AddVertex(m_p5, false); m_Contour5to6->AddVertex(m_p6, true); } void tearDown() override {} void Iterator() { mitk::ContourElement::ConstPointer constcontour = m_Contour5to6.GetPointer(); CPPUNIT_ASSERT_MESSAGE("Begin does not point to correct element", m_Contour1to4->IteratorBegin().operator*()->Coordinates == m_p1); CPPUNIT_ASSERT_MESSAGE("Begin does not point to correct element", m_Contour1to4->ConstIteratorBegin().operator*()->Coordinates == m_p1); CPPUNIT_ASSERT_MESSAGE("Begin does not point to correct element", m_Contour5to6->begin().operator*()->Coordinates == m_p5); CPPUNIT_ASSERT_MESSAGE("Begin does not point to correct element", constcontour->begin().operator*()->Coordinates == m_p5); CPPUNIT_ASSERT_MESSAGE("End does not point to correct element", m_Contour_empty->ConstIteratorBegin() == m_Contour_empty->ConstIteratorEnd()); CPPUNIT_ASSERT_MESSAGE("End does not point to correct element", m_Contour_empty->IteratorBegin() == m_Contour_empty->IteratorEnd()); CPPUNIT_ASSERT_MESSAGE("End does not point to correct element", m_Contour_empty->begin() == m_Contour_empty->end()); } void AddVertex() { m_Contour_empty->AddVertex(m_p1, false); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour_empty->GetSize() == 1); m_Contour_empty->AddVertex(m_p7, true); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(1)->Coordinates == m_p7); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(1)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour_empty->GetSize() == 2); } void AddVertexAtFront() { m_Contour_empty->AddVertexAtFront(m_p1, false); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour_empty->GetSize() == 1); m_Contour_empty->AddVertexAtFront(m_p7, true); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(1)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(1)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->Coordinates == m_p7); CPPUNIT_ASSERT(m_Contour_empty->GetVertexAt(0)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour_empty->GetSize() == 2); } void InsertVertexAtIndex() { mitk::Point3D outOfBountPoint; m_Contour1to4->InsertVertexAtIndex(m_p5, false, 0); m_Contour1to4->InsertVertexAtIndex(m_p7, true, 2); m_Contour1to4->InsertVertexAtIndex(outOfBountPoint, true, 6); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->Coordinates == m_p5); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(2)->Coordinates == m_p7); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(2)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(3)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(3)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 6); } void GetSetVertexAt() { mitk::ContourElement::ConstPointer constcontour = m_Contour1to4.GetPointer(); auto v0 = m_Contour1to4->GetVertexAt(0); auto v1 = m_Contour1to4->GetVertexAt(1); CPPUNIT_ASSERT(v0->Coordinates == m_p1); CPPUNIT_ASSERT(v0->IsControlPoint == true); CPPUNIT_ASSERT(v1->Coordinates == m_p2); CPPUNIT_ASSERT(v1->IsControlPoint == false); CPPUNIT_ASSERT(constcontour->GetVertexAt(0)->Coordinates == m_p1); CPPUNIT_ASSERT(constcontour->GetVertexAt(0)->IsControlPoint == true); CPPUNIT_ASSERT(constcontour->GetVertexAt(1)->Coordinates == m_p2); CPPUNIT_ASSERT(constcontour->GetVertexAt(1)->IsControlPoint == false); m_Contour1to4->SetVertexAt(0, m_p7); CPPUNIT_ASSERT(v0->Coordinates == m_p7); CPPUNIT_ASSERT(v0->IsControlPoint == true); m_Contour1to4->SetVertexAt(1, m_Contour5to6->GetVertexAt(1)); CPPUNIT_ASSERT(v1->Coordinates == m_Contour5to6->GetVertexAt(1)->Coordinates); CPPUNIT_ASSERT(v1->IsControlPoint == m_Contour5to6->GetVertexAt(1)->IsControlPoint); CPPUNIT_ASSERT(v1 != m_Contour5to6->GetVertexAt(1)); mitk::Point3D search = GeneratePoint(6.05); auto finding = m_Contour1to4->GetVertexAt(search, 0.); CPPUNIT_ASSERT(nullptr == finding); finding = m_Contour1to4->GetVertexAt(search, 0.1); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1) == finding); } void OpenAndClose() { CPPUNIT_ASSERT(!m_Contour1to4->IsClosed()); CPPUNIT_ASSERT(!m_Contour_empty->IsClosed()); m_Contour1to4->Close(); m_Contour_empty->SetClosed(true); CPPUNIT_ASSERT(m_Contour1to4->IsClosed()); CPPUNIT_ASSERT(m_Contour_empty->IsClosed()); m_Contour1to4->Open(); m_Contour_empty->SetClosed(false); CPPUNIT_ASSERT(!m_Contour1to4->IsClosed()); CPPUNIT_ASSERT(!m_Contour_empty->IsClosed()); } void OtherGetters() { CPPUNIT_ASSERT(m_Contour1to4->GetIndex(m_Contour1to4->GetVertexAt(0)) == 0); CPPUNIT_ASSERT(m_Contour1to4->GetIndex(m_Contour1to4->GetVertexAt(1)) == 1); CPPUNIT_ASSERT(m_Contour1to4->GetIndex(m_Contour1to4->GetVertexAt(3)) == 3); CPPUNIT_ASSERT(m_Contour1to4->GetIndex(m_Contour5to6->GetVertexAt(0)) == mitk::ContourElement::NPOS); } void Concatenate() { m_Contour5to6->Concatenate(m_Contour1to4, true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->Coordinates == m_p5); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->Coordinates == m_p6); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->Coordinates == m_p3); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->Coordinates == m_p4); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetSize() == 6); m_Contour_empty->AddVertex(m_p1, false); m_Contour5to6->Concatenate(m_Contour_empty, true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->Coordinates == m_p5); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->Coordinates == m_p6); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->Coordinates == m_p3); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->Coordinates == m_p4); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetSize() == 6); m_Contour5to6->Concatenate(m_Contour_empty, false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->Coordinates == m_p5); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->Coordinates == m_p6); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(1)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(2)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(3)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->Coordinates == m_p3); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(4)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->Coordinates == m_p4); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(5)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(6)->Coordinates == m_p1); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(6)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour5to6->GetSize() == 7); } void RemoveVertex() { CPPUNIT_ASSERT(m_Contour1to4->RemoveVertex(m_Contour1to4->GetVertexAt(0))); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 3); CPPUNIT_ASSERT(!m_Contour1to4->RemoveVertex(m_Contour5to6->GetVertexAt(0))); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 3); CPPUNIT_ASSERT(m_Contour1to4->RemoveVertexAt(1)); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->Coordinates == m_p2); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->Coordinates == m_p4); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 2); CPPUNIT_ASSERT(!m_Contour1to4->RemoveVertexAt(2)); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 2); mitk::Point3D search = GeneratePoint(6.05); CPPUNIT_ASSERT(!m_Contour1to4->RemoveVertexAt(search,0.1)); CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 2); CPPUNIT_ASSERT(m_Contour5to6->RemoveVertexAt(search, 0.1)); CPPUNIT_ASSERT(m_Contour5to6->GetSize() == 1); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->Coordinates == m_p5); CPPUNIT_ASSERT(m_Contour5to6->GetVertexAt(0)->IsControlPoint == false); } void Clear() { m_Contour1to4->Clear(); CPPUNIT_ASSERT(m_Contour1to4->IsEmpty()); m_Contour_empty->Clear(); CPPUNIT_ASSERT(m_Contour_empty->IsEmpty()); } void GetControlVertices() { auto controlVs = m_Contour1to4->GetControlVertices(); CPPUNIT_ASSERT(controlVs.size() == 2); CPPUNIT_ASSERT(controlVs[0] == m_Contour1to4->GetVertexAt(0)); CPPUNIT_ASSERT(controlVs[1] == m_Contour1to4->GetVertexAt(2)); controlVs = m_Contour_empty->GetControlVertices(); CPPUNIT_ASSERT(controlVs.empty()); } void RedistributeControlVertices() { //just adding more nodes to better check the redistribution m_Contour1to4->Concatenate(m_Contour1to4, false); m_Contour1to4->Concatenate(m_Contour1to4, false); m_Contour1to4->RedistributeControlVertices(nullptr, 3); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(2)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(3)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(4)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(5)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(6)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(7)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(8)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(9)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(10)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(11)->IsControlPoint == false); m_Contour1to4->RedistributeControlVertices(m_Contour1to4->GetVertexAt(4), 4); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(0)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(1)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(2)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(3)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(4)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(5)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(6)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(7)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(8)->IsControlPoint == true); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(9)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(10)->IsControlPoint == false); CPPUNIT_ASSERT(m_Contour1to4->GetVertexAt(11)->IsControlPoint == false); } void Others() { CPPUNIT_ASSERT(m_Contour1to4->GetSize() == 4); CPPUNIT_ASSERT(m_Contour_empty->GetSize() == 0); CPPUNIT_ASSERT(!m_Contour1to4->IsEmpty()); CPPUNIT_ASSERT(m_Contour_empty->IsEmpty()); + + mitk::ContourElement::Pointer copyConstructed = m_Contour5to6->Clone(); + CPPUNIT_ASSERT(*(m_Contour5to6->GetVertexAt(0)) == *(copyConstructed->GetVertexAt(0))); + CPPUNIT_ASSERT(*(m_Contour5to6->GetVertexAt(1)) == *(copyConstructed->GetVertexAt(1))); + CPPUNIT_ASSERT(m_Contour5to6->GetSize() == copyConstructed->GetSize()); } }; MITK_TEST_SUITE_REGISTRATION(mitkContourElement)