diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.cpp b/Modules/ContourModel/DataManagement/mitkContourElement.cpp index 94b99f27a3..f6d7430cc3 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourElement.cpp @@ -1,469 +1,515 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ContourElement::ContourElement() { this->m_Vertices = new VertexListType(); this->m_IsClosed = false; } mitk::ContourElement::ContourElement(const mitk::ContourElement &other) : m_Vertices(other.m_Vertices), m_IsClosed(other.m_IsClosed) { } mitk::ContourElement::~ContourElement() { delete this->m_Vertices; } void mitk::ContourElement::AddVertex(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_back(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertex(VertexType &vertex) { this->m_Vertices->push_back(&vertex); } void mitk::ContourElement::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_front(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertexAtFront(VertexType &vertex) { this->m_Vertices->push_front(&vertex); } void mitk::ContourElement::InsertVertexAtIndex(mitk::Point3D &vertex, bool isControlPoint, int index) { if(index > 0 && this->GetSize() > index) { VertexIterator _where = this->m_Vertices->begin(); _where += index; this->m_Vertices->insert(_where, new VertexType(vertex, isControlPoint)); } } +void mitk::ContourElement::SetVertexAt(int pointId, mitk::Point3D &point) +{ + if(index > 0 && this->GetSize() > pointId) + { + this->m_Vertices->at(pointId)->Coordinates = point; + } +} + + + +void mitk::ContourElement::SetVertexAt(int pointId, const VertexType* vertex) +{ + if(index > 0 && this->GetSize() > pointId) + { + this->m_Vertices->at(pointId)->Coordinates = vertex->Coordinates; + this->m_Vertices->at(pointId)->IsControlPoint = vertex->IsControlPoint; + } +} + + + mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(int index) { return this->m_Vertices->at(index); } bool mitk::ContourElement::IsEmpty() { 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 NULL; } mitk::ContourElement::VertexType* mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, float eps) { if(eps > 0) { std::deque< std::pair > 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++++++++++++++++++*/ std::deque< std::pair >::iterator it = nearestlist.begin(); std::deque< std::pair >::iterator end = nearestlist.end(); while(it != end) { if( (*it).second->IsControlPoint ) { return (*it).second; } it++; } /*---------------------------------------------------------------------------------------*/ //return closest point return nearestlist.front().second; } } return NULL; } /*mitk::ContourElement::VertexType* mitk::ContourElement::OptimizedGetVertexAt(const mitk::Point3D &point, float eps) { if( (eps > 0) && (this->m_Vertices->size()>0) ) { int k = 1; int dim = 3; int nPoints = this->m_Vertices->size(); ANNpointArray pointsArray; ANNpoint queryPoint; ANNidxArray indexArray; ANNdistArray distanceArray; ANNkd_tree* kdTree; queryPoint = annAllocPt(dim); pointsArray = annAllocPts(nPoints, dim); indexArray = new ANNidx[k]; distanceArray = new ANNdist[k]; int i = 0; //fill points array with our control points for(VertexIterator it = this->m_Vertices->begin(); it != this->m_Vertices->end(); it++, i++) { mitk::Point3D cur = (*it)->Coordinates; pointsArray[i][0]= cur[0]; pointsArray[i][1]= cur[1]; pointsArray[i][2]= cur[2]; } //create the kd tree kdTree = new ANNkd_tree(pointsArray,nPoints, dim); //fill mitk::Point3D into ANN query point queryPoint[0] = point[0]; queryPoint[1] = point[1]; queryPoint[2] = point[2]; //k nearest neighbour search kdTree->annkSearch(queryPoint, k, indexArray, distanceArray, eps); VertexType* ret = NULL; try { ret = this->m_Vertices->at(indexArray[0]); } catch(std::out_of_range ex) { //ret stays NULL return ret; } //clean up ANN delete [] indexArray; delete [] distanceArray; delete kdTree; annClose(); return ret; } return NULL; } */ mitk::ContourElement::VertexListType* mitk::ContourElement::GetVertexList() { return this->m_Vertices; } bool mitk::ContourElement::IsClosed() { return this->m_IsClosed; } bool mitk::ContourElement::IsNearContour(const mitk::Point3D &point, float eps) { 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::SetIsClosed( bool isClosed) { isClosed ? this->Close() : this->Open(); } mitk::ContourElement::VertexListType* mitk::ContourElement::GetControlVertices() { VertexListType* newVertices = new VertexListType(); VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); while(it != end) { if((*it)->IsControlPoint) { newVertices->push_back((*it)); } it++; } return newVertices; } void mitk::ContourElement::Concatenate(mitk::ContourElement* other, bool check) { if( other->GetSize() > 0) { ConstVertexIterator otherIt = other->m_Vertices->begin(); ConstVertexIterator otherEnd = other->m_Vertices->end(); while(otherIt != otherEnd) { if (check) { ConstVertexIterator thisIt = this->m_Vertices->begin(); ConstVertexIterator thisEnd = this->m_Vertices->end(); bool found = false; while(thisIt != thisEnd) { if ( (*thisIt)->Coordinates == (*otherIt)->Coordinates ) { found = true; break; } thisIt++; } if (!found) this->m_Vertices->push_back(*otherIt); } else { this->m_Vertices->push_back(*otherIt); } otherIt++; } } } -bool mitk::ContourElement::RemoveVertex(mitk::ContourElement::VertexType* vertex) +bool mitk::ContourElement::RemoveVertex(const VertexType *vertex) { VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); //search for vertex and remove it if exists while(it != end) { if((*it) == vertex) { this->m_Vertices->erase(it); return true; } it++; } return false; } +int mitk::ContourElement::GetIndex(const VertexType *vertex) +{ + VertexIterator it = this->m_Vertices->begin(); + + VertexIterator end = this->m_Vertices->end(); + + int index = 0; + + //search for vertex + while(it != end) + { + if((*it) == vertex) + { + return index; + } + + it++; + ++index; + } + + return -1;//not found +} + + + bool mitk::ContourElement::RemoveVertexAt(int index) { if( index >= 0 && index < this->m_Vertices->size() ) { this->m_Vertices->erase(this->m_Vertices->begin()+index); return true; } else { return false; } } bool mitk::ContourElement::RemoveVertexAt(mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should be some kind of an octree with spatial query*/ if(eps > 0){ VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); while(it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; if(currentPoint.EuclideanDistanceTo(point) < eps) { //approximate point found //now erase it this->m_Vertices->erase(it); return true; } it++; } } return false; } void mitk::ContourElement::Clear() { this->m_Vertices->clear(); } //---------------------------------------------------------------------- void mitk::ContourElement::RedistributeControlVertices(const VertexType* selected, int period) { int counter = 0; VertexIterator _where = this->m_Vertices->begin(); if (selected != NULL) { while (_where != this->m_Vertices->end()) { if ((*_where) == selected) { break; } _where++; } } VertexIterator _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 ec553416be..a4b5ad2025 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.h +++ b/Modules/ContourModel/DataManagement/mitkContourElement.h @@ -1,247 +1,270 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _mitkContourElement_H_ #define _mitkContourElement_H_ #include "mitkCommon.h" #include "ContourModelExports.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 It is highly not recommend to use this class directly as no secure mechanism is used here. Use mitk::ContourModel instead providing some additional features. */ class ContourModel_EXPORT ContourElement : public itk::LightObject { public: mitkClassMacro(ContourElement, itk::LightObject); itkNewMacro(Self); mitkCloneMacro(Self); // Data container representing vertices /** \brief Represents a single vertex of contour. */ struct ContourModelVertex { ContourModelVertex(mitk::Point3D &point, bool active=false) - : Coordinates(point), IsControlPoint(active) + : 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; }; // END Data container representing vertices typedef ContourModelVertex VertexType; typedef std::deque VertexListType; typedef VertexListType::iterator VertexIterator; typedef VertexListType::const_iterator ConstVertexIterator; // start of inline methods /** \brief Return a const iterator a the front. */ virtual ConstVertexIterator ConstIteratorBegin() { return this->m_Vertices->begin(); } /** \brief Return a const iterator a the end. */ virtual ConstVertexIterator ConstIteratorEnd() { return this->m_Vertices->end(); } /** \brief Return an iterator a the front. */ virtual VertexIterator IteratorBegin() { return this->m_Vertices->begin(); } /** \brief Return an iterator a the end. */ virtual VertexIterator IteratorEnd() { return this->m_Vertices->end(); } /** \brief Returns the number of contained vertices. */ virtual int GetSize() { return this->m_Vertices->size(); } // end of inline methods /** \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. */ virtual void AddVertex(mitk::Point3D &point, bool isControlPoint); /** \brief Add a vertex at the end of the contour \param vertex - a contour element vertex. */ virtual void AddVertex(VertexType &vertex); /** \brief Add a vertex at the front of the contour \param point - coordinates in 3D space. \param isControlPoint - is the vertex a control point. */ virtual void AddVertexAtFront(mitk::Point3D &point, bool isControlPoint); /** \brief Add a vertex at the front of the contour \param vertex - a contour element vertex. */ virtual void AddVertexAtFront(VertexType &vertex); /** \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. */ virtual void InsertVertexAtIndex(mitk::Point3D &point, bool isControlPoint, int index); + /** \brief Set coordinates a given index. + \param pointId Index of vertex. + \param point Coordinates. + */ + virtual void SetVertexAt(int pointId, mitk::Point3D &point); + + /** \brief Set vertex a given index. + \param pointId Index of vertex. + \param vertex Vertex. + */ + virtual void SetVertexAt(int pointId, const VertexType* vertex); + /** \brief Returns the vertex a given index \param index */ virtual VertexType* GetVertexAt(int index); /** \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. */ virtual 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. -1 if not found. + */ + virtual int GetIndex(const VertexType* vertex); + /** \brief Returns the container of the vertices. */ VertexListType* GetVertexList(); /** \brief Returns whether the contour element is empty. */ bool IsEmpty(); /** \brief Returns if the conour is closed or not. */ virtual bool IsClosed(); /** \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. */ virtual bool IsNearContour(const mitk::Point3D &point, float eps); /** \brief Close the contour. Connect first with last element. */ virtual void Close(); /** \brief Open the contour. Disconnect first and last element. */ virtual void Open(); /** \brief Set the contours IsClosed property. \param isClosed - true = closed; false = open; */ virtual void SetIsClosed(bool isClosed); /** \brief Concatenate the contuor with a another contour. All vertices of the other contour will be added after last vertex. \param other - the other contour \param check - set it true to avoid intersections */ void Concatenate(mitk::ContourElement* other, bool check); /** \brief Remove the given vertex from the container if exists. \param vertex - the vertex to be removed. */ - virtual bool RemoveVertex(VertexType* vertex); + virtual 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. */ virtual bool RemoveVertexAt(int 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. */ virtual bool RemoveVertexAt(mitk::Point3D &point, float eps); /** \brief Clear the storage container. */ virtual 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, float eps); /** \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* OptimizedGetVertexAt(const mitk::Point3D &point, float eps); VertexListType* GetControlVertices(); /** \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: ContourElement(); ContourElement(const mitk::ContourElement &other); virtual ~ContourElement(); VertexListType* m_Vertices; //double ended queue with vertices bool m_IsClosed; }; } // namespace mitk #endif // _mitkContourElement_H_ diff --git a/Modules/ContourModel/DataManagement/mitkContourModel.cpp b/Modules/ContourModel/DataManagement/mitkContourModel.cpp index 9fe3519768..59a68847d8 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourModel.cpp @@ -1,639 +1,708 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include mitk::ContourModel::ContourModel() : m_UpdateBoundingBox(true) { //set to initial state this->InitializeEmpty(); } mitk::ContourModel::ContourModel(const mitk::ContourModel &other) : m_ContourSeries(other.m_ContourSeries), m_lineInterpolation(other.m_lineInterpolation) { m_SelectedVertex = NULL; } mitk::ContourModel::~ContourModel() { m_SelectedVertex = NULL; this->m_ContourSeries.clear();//TODO check destruction } void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep) ) { this->AddVertex(vertex, false, timestep); } } void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, bool isControlPoint, int 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(VertexType &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertex(vertex); this->InvokeEvent( ContourModelSizeChangeEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } +void mitk::ContourModel::AddVertex(const VertexType* vertex, int timestep) +{ + if(vertex != NULL) + { + this->AddVertex(const_cast(vertex), timestep); + } +} + + void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep) ) { this->AddVertexAtFront(vertex, false, timestep); } } void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertexAtFront(vertex, isControlPoint); this->InvokeEvent( ContourModelSizeChangeEvent() ); - this->Modified();this->m_UpdateBoundingBox = true; + this->Modified(); + this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::AddVertexAtFront(VertexType &vertex, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->AddVertexAtFront(vertex); this->InvokeEvent( ContourModelSizeChangeEvent() ); - this->Modified();this->m_UpdateBoundingBox = true; + this->Modified(); + this->m_UpdateBoundingBox = true; } } +bool mitk::ContourModel::SetVertexAt(int pointId, mitk::Point3D &point, unsigned int timestep) +{ + if(!this->IsEmptyTimeStep(timestep)) + { + if(index > 0 && this->m_ContourSeries[timestep]->GetSize() > 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, unsigned int timestep) +{ + if(vertex==NULL) return false; + + if(!this->IsEmptyTimeStep(timestep)) + { + if(index > 0 && this->m_ContourSeries[timestep]->GetSize() > pointId) + { + this->m_ContourSeries[timestep]->SetVertexAt( pointId, vertex ); + this->Modified(); + this->m_UpdateBoundingBox = true; + return true; + } + return false; + } + return false; +} + + + void mitk::ContourModel::InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { if(index > 0 && this->m_ContourSeries[timestep]->GetSize() > index) { this->m_ContourSeries[timestep]->InsertVertexAtIndex(vertex, isControlPoint, index); this->InvokeEvent( ContourModelSizeChangeEvent() ); - this->Modified();this->m_UpdateBoundingBox = true; + this->Modified(); + this->m_UpdateBoundingBox = true; } } } -bool mitk::ContourModel::IsEmpty( int timestep) +bool mitk::ContourModel::IsEmpty( int 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( int timestep) const { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetSize(); } return -1; } const mitk::ContourModel::VertexType* mitk::ContourModel::GetVertexAt(int index, int timestep) const { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->GetVertexAt(index); } return NULL; } +int mitk::ContourModel::GetIndex(const VertexType *vertex, int timestep) +{ + if(!this->IsEmptyTimeStep(timestep)) + { + return this->m_ContourSeries[timestep]->GetIndex(vertex); + } + return -1; +} + + + void mitk::ContourModel::Close( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Close(); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::Open( int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->Open(); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::SetIsClosed(bool isClosed, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->SetIsClosed(isClosed); this->InvokeEvent( ContourModelClosedEvent() ); this->Modified();this->m_UpdateBoundingBox = true; } } -bool mitk::ContourModel::IsEmptyTimeStep( int t) const +bool mitk::ContourModel::IsEmptyTimeStep(unsigned int t) const { - return (t < 0) || (this->m_ContourSeries.size() <= t); + return (this->m_ContourSeries.size() <= t); } bool mitk::ContourModel::IsNearContour(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsNearContour(point, eps); } return false; } void mitk::ContourModel::Concatenate(mitk::ContourModel* other, int 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( int timestep) { return this->IteratorBegin(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorBegin( int timestep) { 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( int timestep) { return this->IteratorEnd(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorEnd( int timestep) { 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) { if(!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsClosed(); } return false; } bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); } return this->m_SelectedVertex != NULL; } bool mitk::ContourModel::SelectVertexAt(int index, int timestep) { if(!this->IsEmptyTimeStep(timestep) && index >= 0) { return (this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(index)); } return false; } bool mitk::ContourModel::SetControlVertexAt(mitk::Point3D &point, float eps, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps); if (vertex != NULL) { vertex->IsControlPoint = true; return true; } } return false; } bool mitk::ContourModel::SetControlVertexAt(int index, int timestep) { if(!this->IsEmptyTimeStep(timestep) && index >= 0) { VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(index); if (vertex != NULL) { vertex->IsControlPoint = true; return true; } } return false; } -bool mitk::ContourModel::RemoveVertex(VertexType* vertex, int timestep) +bool mitk::ContourModel::RemoveVertex(const VertexType *vertex, int 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, int 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(mitk::Point3D &point, float eps, int 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(mitk::Vector3D &translate) { if(this->m_SelectedVertex) { this->ShiftVertex(this->m_SelectedVertex,translate); this->Modified();this->m_UpdateBoundingBox = true; } } void mitk::ContourModel::ShiftContour(mitk::Vector3D &translate, int timestep) { if(!this->IsEmptyTimeStep(timestep)) { VertexListType* vList = this->m_ContourSeries[timestep]->GetVertexList(); VertexIterator it = vList->begin(); VertexIterator end = vList->end(); //shift all vertices while(it != end) { this->ShiftVertex((*it),translate); it++; } this->Modified();this->m_UpdateBoundingBox = true; this->InvokeEvent( ContourModelShiftEvent() ); } } void mitk::ContourModel::ShiftVertex(VertexType* vertex, mitk::Vector3D &vector) { vertex->Coordinates[0] += vector[0]; vertex->Coordinates[1] += vector[1]; vertex->Coordinates[2] += vector[2]; } void mitk::ContourModel::Clear(int timestep) { if(!this->IsEmptyTimeStep(timestep)) { //clear data at timestep this->m_ContourSeries[timestep]->Clear(); this->InitializeEmpty(); this->Modified();this->m_UpdateBoundingBox = true; } } -void mitk::ContourModel::Expand( int timeSteps ) +void mitk::ContourModel::Expand(unsigned int timeSteps ) { int oldSize = this->m_ContourSeries.size(); - if( timeSteps > 0 && timeSteps > oldSize ) + if( timeSteps > oldSize ) { Superclass::Expand(timeSteps); //insert contours for each new timestep for( int i = oldSize; i < timeSteps; i++) { m_ContourSeries.push_back(mitk::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; } const mitk::Geometry3D * mitk::ContourModel::GetUpdatedGeometry (int t) { return Superclass::GetUpdatedGeometry(t); } mitk::Geometry3D* mitk::ContourModel::GetGeometry (int t)const { return Superclass::GetGeometry(t); } 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, int 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(mitk::ContourModel &other) { unsigned int numberOfTimesteps = other.GetTimeSlicedGeometry()->GetTimeSteps(); this->InitializeTimeSlicedGeometry(numberOfTimesteps); for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { this->m_ContourSeries.push_back(mitk::ContourElement::New()); this->SetIsClosed(other.IsClosed(currentTimestep),currentTimestep); } m_SelectedVertex = NULL; 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(mitk::ContourElement::New()); //set number of timesteps to one this->InitializeTimeSlicedGeometry(1); m_SelectedVertex = NULL; 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 float 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< mitk::PlaneGeometry* >(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(); VertexIterator it = this->IteratorBegin(currenTimeStep); VertexIterator 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 Geometry3D* geometry3d = this->GetGeometry(currenTimeStep); geometry3d->SetBounds(mitkBounds); } } } this->m_UpdateBoundingBox = false; } GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::ContourModel::ExecuteOperation(mitk::Operation* operation) { //not supported yet } diff --git a/Modules/ContourModel/DataManagement/mitkContourModel.h b/Modules/ContourModel/DataManagement/mitkContourModel.h index 0ae7bfcd7a..23eab68b22 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.h +++ b/Modules/ContourModel/DataManagement/mitkContourModel.h @@ -1,446 +1,475 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_CONTOURMODEL_H_ #define _MITK_CONTOURMODEL_H_ #include "mitkCommon.h" #include "ContourModelExports.h" #include "mitkBaseData.h" #include namespace mitk { /** \brief ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are stored in a mitk::ContourElement is stored for each timestep. The contour line segments are implicitly defined by the given linked vertices. By default two control points are are linked by a straight line.It is possible to add vertices at front and end of the contour and to iterate in both directions. Points are specified containing coordinates and additional (data) information, see mitk::ContourElement. For accessing a specific vertex either an index or a position in 3D Space can be used. The vertices are best accessed by using a VertexIterator. Interaction with the contour is thus available without any mitk interactor class using the api of ContourModel. It is possible to shift single vertices also as shifting the whole contour. A contour can be either open like a single curved line segment or closed. A closed contour can for example represent a jordan curve. \section mitkContourModelDisplayOptions Display Options The default mappers for this data structure are mitk::ContourModelGLMapper2D and mitk::ContourModelMapper3D. See these classes for display options which can can be set via properties. */ class ContourModel_EXPORT ContourModel : public BaseData { public: mitkClassMacro(ContourModel, BaseData); itkNewMacro(Self); mitkCloneMacro(Self); /*+++++++++++++++ typedefs +++++++++++++++++++++++++++++++*/ typedef mitk::ContourElement::VertexType VertexType; typedef mitk::ContourElement::VertexListType VertexListType; typedef mitk::ContourElement::VertexIterator VertexIterator; typedef mitk::ContourElement::ConstVertexIterator ConstVertexIterator; typedef std::vector< mitk::ContourElement::Pointer > ContourModelSeries; /*+++++++++++++++ END typedefs ++++++++++++++++++++++++++++*/ /** \brief Possible interpolation of the line segments between control points */ enum LineSegmentInterpolation{ LINEAR, B_SPLINE }; /*++++++++++++++++ inline methods +++++++++++++++++++++++*/ /** \brief Get the current selected vertex. */ VertexType* GetSelectedVertex() { return this->m_SelectedVertex; } /** \brief Deselect vertex. */ void Deselect() { this->m_SelectedVertex = NULL; } /** \brief Set selected vertex as control point */ void SetSelectedVertexAsControlPoint(bool isControlPoint=true) { if (this->m_SelectedVertex) { m_SelectedVertex->IsControlPoint = isControlPoint; this->Modified(); } } /** \brief Set the interpolation of the line segments between control points. */ void SetLineSegmentInterpolation(LineSegmentInterpolation interpolation) { this->m_lineInterpolation = interpolation; this->Modified(); } /** \brief Get the interpolation of the line segments between control points. */ LineSegmentInterpolation GetLineSegmentInterpolation() { return this->m_lineInterpolation; } /*++++++++++++++++ END inline methods +++++++++++++++++++++++*/ /** \brief Add a vertex to the contour at given timestep. The vertex is added at the end of contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertex(mitk::Point3D &vertex, int timestep=0); /** \brief Add a vertex to the contour at given timestep. The vertex is added at the end of contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertex(VertexType &vertex, int timestep=0); + /** \brief Add a vertex to the contour at given timestep. + The vertex is added at the end of contour. + + \param vertex - coordinate representation of a control point + \param timestep - the timestep at which the vertex will be add ( default 0) + + @Note Adding a vertex to a timestep which exceeds the timebounds of the contour + will not be added, the TimeSlicedGeometry will not be expanded. + */ + void AddVertex(const VertexType* vertex, int timestep=0); + /** \brief Add a vertex to the contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) \param isControlPoint - specifies the vertex to be handled in a special way (e.g. control points will be rendered). @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep=0); /** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour. The vertex is added at the FRONT of contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertexAtFront(mitk::Point3D &vertex, int timestep=0); /** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour. The vertex is added at the FRONT of contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertexAtFront(VertexType &vertex, int timestep=0); /** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour. \param vertex - coordinate representation of a control point \param timestep - the timestep at which the vertex will be add ( default 0) \param isControlPoint - specifies the vertex to be handled in a special way (e.g. control points will be rendered). @Note Adding a vertex to a timestep which exceeds the timebounds of the contour will not be added, the TimeSlicedGeometry will not be expanded. */ void AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep=0); /** \brief Insert a vertex at given index. */ void InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint=false, int timestep=0); + /** \brief Set a coordinates for point at given index. + */ + bool SetVertexAt(int pointId, mitk::Point3D &point, unsigned int timestep=0); + + /** \brief Set a coordinates for point at given index. + */ + bool SetVertexAt(int pointId, const VertexType* vertex, unsigned int timestep=0); + /** \brief Return if the contour is closed or not. */ bool IsClosed( int timestep=0); /** \brief Concatenate two contours. The starting control point of the other will be added at the end of the contour. \pararm timestep - the timestep at which the vertex will be add ( default 0) \pararm check - check for intersections ( default false) */ void Concatenate(mitk::ContourModel* other, int timestep=0, bool check=false); /** \brief Returns a const VertexIterator at the start element of the contour. @throw mitk::Exception if the timestep is invalid. */ VertexIterator Begin( int timestep=0); /** \brief Returns a const VertexIterator at the start element of the contour. @throw mitk::Exception if the timestep is invalid. */ VertexIterator IteratorBegin( int timestep=0); /** \brief Returns a const VertexIterator at the end element of the contour. @throw mitk::Exception if the timestep is invalid. */ VertexIterator End( int timestep=0); /** \brief Returns a const VertexIterator at the end element of the contour. @throw mitk::Exception if the timestep is invalid. */ VertexIterator IteratorEnd( int timestep=0); /** \brief Close the contour. The last control point will be linked with the first point. */ virtual void Close( int timestep=0); /** \brief Set isClosed to false contour. The link between the last control point the first point will be removed. */ virtual void Open( int timestep=0); /** \brief Set isClosed to given boolean. false - The link between the last control point the first point will be removed. true - The last control point will be linked with the first point. */ virtual void SetIsClosed(bool isClosed, int timestep=0); /** \brief Returns the number of vertices at a given timestep. \param timestep - default = 0 */ int GetNumberOfVertices( int timestep=0) const; /** \brief Returns whether the contour model is empty at a given timestep. \pararm timestep - default = 0 */ - bool IsEmpty( int timestep=0); + virtual bool IsEmpty( int timestep) const; + + /** \brief Returns whether the contour model is empty. + */ + virtual bool IsEmpty() const; /** \brief Returns the vertex at the index position within the container. */ virtual const VertexType* GetVertexAt(int index, int timestep=0) const; + /** \brief Remove a vertex at given timestep within the container. + + \return index of vertex. -1 if not found. + */ + int GetIndex(const VertexType* vertex, int timestep=0); + /** \brief Check if there isn't something at this timestep. */ - virtual bool IsEmptyTimeStep( int t) const; + virtual bool IsEmptyTimeStep(unsigned int t) const; /** \brief Check if mouse cursor is near the contour. */ virtual bool IsNearContour(mitk::Point3D &point, float eps, int timestep); /** \brief Mark a vertex at an index in the container as selected. */ bool SelectVertexAt(int index, int timestep=0); /** \brief Mark a vertex at an index in the container as control point. */ bool SetControlVertexAt(int index, int timestep=0); /** \brief Mark a vertex at a given position in 3D space. \param point - query point in 3D space \param eps - radius for nearest neighbour search (error bound). \param timestep - search at this timestep @return true = vertex found; false = no vertex found */ bool SelectVertexAt(mitk::Point3D &point, float eps, int timestep=0); /* \pararm point - query point in 3D space \pararm eps - radius for nearest neighbour search (error bound). \pararm timestep - search at this timestep @return true = vertex found; false = no vertex found */ bool SetControlVertexAt(mitk::Point3D &point, float eps, int timestep=0); /** \brief Remove a vertex at given index within the container. @return true = the vertex was successfuly removed; false = wrong index. */ bool RemoveVertexAt(int index, int timestep=0); /** \brief Remove a vertex at given timestep within the container. @return true = the vertex was successfuly removed. */ - bool RemoveVertex(VertexType* vertex, int timestep=0); + bool RemoveVertex(const VertexType* vertex, int timestep=0); /** \brief Remove a vertex at a query position in 3D space. The vertex to be removed will be search by nearest neighbour search. Note that possibly no vertex at this position and eps is stored inside the contour. @return true = the vertex was successfuly removed; false = no vertex found. */ bool RemoveVertexAt(mitk::Point3D &point, float eps, int timestep=0); /** \brief Shift the currently selected vertex by a translation vector. \param translate - the translation vector. */ void ShiftSelectedVertex(mitk::Vector3D &translate); /** \brief Shift the whole contour by a translation vector at given timestep. \param translate - the translation vector. \param timestep - at this timestep the contour will be shifted. */ void ShiftContour(mitk::Vector3D &translate, int timestep=0); /** \brief Clear the storage container at given timestep. All control points are removed at timestep. */ virtual void Clear(int timestep); /** \brief Initialize all data objects */ virtual void Initialize(); /** \brief Initialize object with specs of other contour. Note: No data will be copied. */ void Initialize(mitk::ContourModel &other); /*++++++++++++++++++ method inherit from base data +++++++++++++++++++++++++++*/ /** \brief Inherit from base data - no region support available for contourModel objects. */ virtual void SetRequestedRegionToLargestPossibleRegion (); /** \brief Inherit from base data - no region support available for contourModel objects. */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion (); /** \brief Inherit from base data - no region support available for contourModel objects. */ virtual bool VerifyRequestedRegion (); /** \brief Get the updated geometry with recomputed bounds. */ virtual const mitk::Geometry3D* GetUpdatedGeometry (int t=0); /** \brief Get the Geometry3D for timestep t. */ virtual mitk::Geometry3D* GetGeometry (int t=0) const; /** \brief Inherit from base data - no region support available for contourModel objects. */ virtual void SetRequestedRegion( const itk::DataObject *data); /** \brief Expand the timebounds of the TimeSlicedGeometry to given number of timesteps. */ - virtual void Expand( int timeSteps ); + virtual void Expand( unsigned int timeSteps ); /** \brief Update the OutputInformation of a ContourModel object The BoundingBox of the contour will be updated, if necessary. */ virtual void UpdateOutputInformation(); /** \brief Clear the storage container. The object is set to initial state. All control points are removed and the number of timesteps are set to 1. */ virtual void Clear(); /** \brief overwrite if the Data can be called by an Interactor (StateMachine). */ void ExecuteOperation(Operation* operation); /** \brief Redistributes ontrol vertices with a given period (as number of vertices) \param period - the number of vertices between control points. \param timestep - at this timestep all lines will be rebuilt. */ virtual void RedistributeControlVertices(int period, int timestep); protected: ContourModel(); ContourModel(const mitk::ContourModel &other); virtual ~ContourModel(); //inherit from BaseData. called by Clear() virtual void ClearData(); //inherit from BaseData. Initial state of a contour with no vertices and a single timestep. virtual void InitializeEmpty(); //Shift a vertex void ShiftVertex(VertexType* vertex, mitk::Vector3D &vector); //Storage with time resolved support. ContourModelSeries m_ContourSeries; //The currently selected vertex. VertexType* m_SelectedVertex; //The interpolation of the line segment between control points. LineSegmentInterpolation m_lineInterpolation; //only update the bounding geometry if necessary bool m_UpdateBoundingBox; }; itkEventMacro( ContourModelEvent, itk::AnyEvent ); itkEventMacro( ContourModelShiftEvent, ContourModelEvent ); itkEventMacro( ContourModelSizeChangeEvent, ContourModelEvent ); itkEventMacro( ContourModelAddEvent, ContourModelSizeChangeEvent ); itkEventMacro( ContourModelRemoveEvent, ContourModelSizeChangeEvent ); itkEventMacro( ContourModelExpandTimeBoundsEvent, ContourModelEvent ); itkEventMacro( ContourModelClosedEvent, ContourModelEvent ); } #endif diff --git a/Modules/ContourModel/Testing/mitkContourModelTest.cpp b/Modules/ContourModel/Testing/mitkContourModelTest.cpp index 908d9d7509..6764fc41db 100644 --- a/Modules/ContourModel/Testing/mitkContourModelTest.cpp +++ b/Modules/ContourModel/Testing/mitkContourModelTest.cpp @@ -1,375 +1,460 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include //Add a vertex to the contour and see if size changed static void TestAddVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); MITK_TEST_CONDITION(contour->GetNumberOfVertices() > 0, "Add a Vertex, size increased"); } //Select a vertex by index. successful if the selected vertex member of the contour is no longer set to null static void TestSelectVertexAtIndex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->SelectVertexAt(0); MITK_TEST_CONDITION(contour->GetSelectedVertex() != NULL, "Vertex was selected at index"); } //Select a vertex by worldposition. successful if the selected vertex member of the contour is no longer set to null static void TestSelectVertexAtWorldposition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); //same point is used here so the epsilon can be chosen very small contour->SelectVertexAt(p, 0.01); MITK_TEST_CONDITION(contour->GetSelectedVertex() != NULL, "Vertex was selected at position"); } //Move a vertex by a translation vector static void TestMoveSelectedVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); //Same point is used here so the epsilon can be chosen very small contour->SelectVertexAt(p, 0.01); mitk::Vector3D v; v[0] = 1; v[1] = 3; v[2] = -1; contour->ShiftSelectedVertex(v); const mitk::ContourModel::VertexType* vertex = contour->GetSelectedVertex(); bool correctlyMoved = false; correctlyMoved = (vertex->Coordinates)[0] == (v[0]) && (vertex->Coordinates)[1] == (v[1]) && (vertex->Coordinates)[2] == (v[2]); MITK_TEST_CONDITION(correctlyMoved, "Vertex has been moved"); } //Test to move the whole contour static void TestMoveContour() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 0; contour->AddVertex(p2); mitk::Vector3D v; v[0] = 1; v[1] = 3; v[2] = -1; contour->ShiftContour(v); mitk::ContourModel::VertexIterator it = contour->IteratorBegin(); mitk::ContourModel::VertexIterator end = contour->IteratorEnd(); bool correctlyMoved = false; while(it != end) { correctlyMoved &= (*it)->Coordinates[0] == (v[0]) && (*it)->Coordinates[1] == (v[1]) && (*it)->Coordinates[2] == (v[2]); } MITK_TEST_CONDITION(correctlyMoved, "Contour has been moved"); } //Remove a vertex by index static void TestRemoveVertexAtIndex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->RemoveVertexAt(0); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "removed vertex"); } //Remove a vertex by position static void TestRemoveVertexAtWorldPosition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); contour->RemoveVertexAt(p, 0.01); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "removed vertex"); } //Check closeable contour static void TestIsclosed() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); contour->Close(); MITK_TEST_CONDITION(contour->IsClosed(), "closed contour"); //no vertices should be added to a closed contour int oldNumberOfVertices = contour->GetNumberOfVertices(); mitk::Point3D p3; p3[0] = p3[1] = p3[2] = 4; contour->AddVertex(p3); int newNumberOfVertices = contour->GetNumberOfVertices(); MITK_TEST_CONDITION(oldNumberOfVertices != newNumberOfVertices, "vertices added to closed contour"); } //Test concatenating two contours static void TestConcatenate() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); mitk::Point3D p3; p3[0] = -2; p3[1] = 10; p3[2] = 0; contour2->AddVertex(p3); mitk::Point3D p4; p4[0] = -3; p4[1] = 6; p4[2] = -5; contour2->AddVertex(p4); contour->Concatenate(contour2); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 4, "two contours were concatenated"); } //Try to select a vertex at position (within a epsilon of course) where no vertex is. //So the selected verted member should be null. static void TestSelectVertexAtWrongPosition() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); - MITK_TEST_CONDITION_REQUIRED(contour->GetSelectedVertex() == NULL, "slected vertex is NULL"); + MITK_TEST_CONDITION_REQUIRED(contour->GetSelectedVertex() == NULL, "selected vertex is NULL"); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 2; contour->SelectVertexAt(p2, 0.1); MITK_TEST_CONDITION(contour->GetSelectedVertex() == NULL, "Vertex was not selected"); } static void TestInsertVertex() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); mitk::Point3D pointToInsert; pointToInsert[0] = pointToInsert[1] = pointToInsert[2] = 10; contour->InsertVertexAtIndex(pointToInsert, 1); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 3, "test insert vertex"); MITK_TEST_CONDITION(contour->GetVertexAt(1)->Coordinates == pointToInsert, "compare inserted vertex"); } //try to access an invalid timestep static void TestInvalidTimeStep() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); mitk::Point3D p; p[0] = p[1] = p[2] = 0; contour->AddVertex(p); mitk::Point3D p2; p2[0] = p2[1] = p2[2] = 1; contour->AddVertex(p2); int invalidTimeStep = 42; MITK_TEST_CONDITION_REQUIRED(contour->IsEmptyTimeStep(invalidTimeStep), "invalid timestep required"); MITK_TEST_FOR_EXCEPTION(std::exception, contour->IteratorBegin(-1)); contour->Close(invalidTimeStep); MITK_TEST_CONDITION(contour->IsClosed() == false, "test close for timestep 0"); MITK_TEST_CONDITION(contour->IsClosed(invalidTimeStep) == false, "test close at invalid timestep"); contour->SetIsClosed(true, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test number of vertices at invalid timestep"); contour->AddVertex(p2, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test add vertex at invalid timestep"); contour->InsertVertexAtIndex(p2, 0, false, invalidTimeStep); MITK_TEST_CONDITION(contour->GetNumberOfVertices(invalidTimeStep) == -1, "test insert vertex at invalid timestep"); MITK_TEST_CONDITION(contour->SelectVertexAt(0, invalidTimeStep) == NULL, "test select vertex at invalid timestep"); MITK_TEST_CONDITION(contour->RemoveVertexAt(0, invalidTimeStep) == false, "test remove vertex at invalid timestep"); } static void TestEmptyContour() { mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); MITK_TEST_CONDITION(contour->IteratorBegin() == contour->IteratorEnd(), "test iterator of emtpy contour"); MITK_TEST_CONDITION(contour->GetNumberOfVertices() == 0, "test numberof vertices of empty contour"); } +static void TestSetVertices() +{ + mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); + + mitk::Point3D p; + p[0] = p[1] = p[2] = 0; + + contour->AddVertex(p); + + mitk::Point3D newCoordinates; + + newCoordinates[0] = newCoordinates[1] = newCoordinates[2] = 1; + + contour->SetVertexAt(0, newCoordinates ); + + MITK_TEST_EQUAL(contour->GetVertexAt(0)->Coordinates, newCoordinates, "set coordinates" ); + + mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); + + mitk::Point3D p3; + p3[0] = -2; + p3[1] = 10; + p3[2] = 0; + + contour2->AddVertex(p3); + + + mitk::Point3D p4; + p4[0] = -3; + p4[1] = 6; + p4[2] = -5; + + contour2->AddVertex(p4); + + contour->AddVertex(p); + + contour->SetVertexAt(1, contour2->GetVertexAt(1)); + + MITK_TEST_EQUAL(contour->GetVertexAt(1)->Coordinates, contour2->GetVertexAt(1)->Coordinates, "Use setter and getter combination"); +} -int mitkContourModelTest(int argc, char* argv[]) + +static void TestContourModelAPI() +{ + mitk::ContourModel::Pointer contour1 = mitk::ContourModel::New(); + + mitk::Point3D p1; + p1[0] = -2; + p1[1] = 10; + p1[2] = 0; + + contour1->AddVertex(p1); + + //adding vertices should always copy the content and not store pointers or references. + MITK_TEST_CONDITION( &p1 != &(contour1->GetVertexAt(0)->Coordinates), "copied point" ); + + + mitk::Point3D p2; + p2[0] = -3; + p2[1] = 6; + p2[2] = -5; + + contour1->AddVertex(p2); + + //test use of setter and getter with const and non-const pointers + const mitk::ContourModel::VertexType* vertex = contour1->GetVertexAt(1); + + MITK_TEST_CONDITION(contour1->GetIndex(vertex) == 1, "Get index"); + + mitk::ContourModel::VertexType* nonConstVertex = const_cast(vertex); + + MITK_TEST_CONDITION(contour1->GetIndex(nonConstVertex) == 1, "Get index non-const"); + + + mitk::ContourModel::Pointer contour2 = mitk::ContourModel::New(); + + mitk::Point3D p3; + p3[0] = p3[1] = p3[2] = 3; + + contour2->AddVertex(p3); + + contour1->AddVertex(contour2->GetVertexAt(0)); +} + + +int mitkContourModelTest(int itkNotUsed(argc), char** itkNotUsed(argv)) { MITK_TEST_BEGIN("mitkContourModelTest") TestAddVertex(); TestSelectVertexAtIndex(); TestSelectVertexAtWorldposition(); TestMoveSelectedVertex(); TestRemoveVertexAtIndex(); TestRemoveVertexAtWorldPosition(); TestIsclosed(); TestConcatenate(); TestInvalidTimeStep(); TestInsertVertex(); TestEmptyContour(); - + TestSetVertices(); TestSelectVertexAtWrongPosition(); + TestContourModelAPI(); MITK_TEST_END() }