diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h index c8a7049c76..5010e6a3fa 100644 --- a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h +++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h @@ -1,164 +1,164 @@ /*=================================================================== 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 _mitkImageLiveWireContourModelFilter_h__ #define _mitkImageLiveWireContourModelFilter_h__ #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkContourModel.h" #include "mitkContourModelSource.h" #include #include #include #include #include namespace mitk { /** \brief Calculates a LiveWire contour between two points in an image. For defining costs between two pixels specific features are extraced from the image and tranformed into a single cost value. \sa ShortestPathCostFunctionLiveWire The filter is able to create dynamic cost tranfer map and thus use on the fly training. \Note On the fly training will only be used for next update. The computation uses the last calculated segment to map cost according to features in the area of the segment. For time resolved purposes use ImageLiveWireContourModelFilter::SetTimestep( unsigned int ) to create the LiveWire contour at a specific timestep. \ingroup ContourModelFilters \ingroup Process */ class Segmentation_EXPORT ImageLiveWireContourModelFilter : public ContourModelSource { public: mitkClassMacro(ImageLiveWireContourModelFilter, ContourModelSource); itkNewMacro(Self); typedef ContourModel OutputType; typedef OutputType::Pointer OutputTypePointer; typedef mitk::Image InputType; typedef itk::Image< float, 2 > InternalImageType; typedef itk::ShortestPathImageFilter< InternalImageType, InternalImageType > ShortestPathImageFilterType; typedef itk::ShortestPathCostFunctionLiveWire< InternalImageType > CostFunctionType; - typedef std::vector< InternalImageType::IndexType > ShortestPathType; + typedef std::vector< itk::Index<2> > ShortestPathType; /** \brief start point in world coordinates*/ itkSetMacro(StartPoint, mitk::Point3D); itkGetMacro(StartPoint, mitk::Point3D); /** \brief end point in woorld coordinates*/ itkSetMacro(EndPoint, mitk::Point3D); itkGetMacro(EndPoint, mitk::Point3D); /** \brief Create dynamic cost tranfer map - use on the fly training. \Note On the fly training will be used for next update only. The computation uses the last calculated segment to map cost according to features in the area of the segment. */ itkSetMacro(UseDynamicCostMap, bool); itkGetMacro(UseDynamicCostMap, bool); /** \brief Actual time step */ itkSetMacro(TimeStep, unsigned int); itkGetMacro(TimeStep, unsigned int); /** \brief Clear all repulsive points used in the cost function */ void ClearRepulsivePoints(); /** \brief Set a vector with repulsive points to use in the cost function */ void SetRepulsivePoints(const ShortestPathType& points); - /** \brief Add a single repulsive point + /** \brief Add a single repulsive point to use in the cost function */ - void AddRepulsivePoint( const InternalImageType::IndexType& idx ); + void AddRepulsivePoint( const itk::Index<2>& idx ); virtual void SetInput( const InputType *input); virtual void SetInput( unsigned int idx, const InputType * input); const InputType* GetInput(void); const InputType* GetInput(unsigned int idx); virtual OutputType* GetOutput(); /** \brief Create dynamic cost tranfer map - on the fly training*/ bool CreateDynamicCostMap(mitk::ContourModel* path=NULL); protected: ImageLiveWireContourModelFilter(); virtual ~ImageLiveWireContourModelFilter(); void GenerateOutputInformation() {}; void GenerateData(); void UpdateLiveWire(); /** \brief start point in worldcoordinates*/ mitk::Point3D m_StartPoint; /** \brief end point in woorldcoordinates*/ mitk::Point3D m_EndPoint; /** \brief Start point in index*/ mitk::Point3D m_StartPointInIndex; /** \brief End point in index*/ mitk::Point3D m_EndPointInIndex; /** \brief The cost function to compute costs between two pixels*/ CostFunctionType::Pointer m_CostFunction; /** \brief Shortest path filter according to cost function m_CostFunction*/ ShortestPathImageFilterType::Pointer m_ShortestPathFilter; /** \brief Flag to use a dynmic cost map or not*/ bool m_UseDynamicCostMap; /** \brief Flag to decide whether to run image pre-processing*/ bool m_ImageModified; unsigned int m_TimeStep; template void ItkPreProcessImage (itk::Image* inputImage); template void CreateDynamicCostMapByITK(itk::Image* inputImage, mitk::ContourModel* path=NULL); InternalImageType::Pointer m_InternalImage; }; } #endif diff --git a/Modules/Segmentation/DataManagement/mitkContourElement.cpp b/Modules/Segmentation/DataManagement/mitkContourElement.cpp index 87f6a07a00..f70b092c84 100644 --- a/Modules/Segmentation/DataManagement/mitkContourElement.cpp +++ b/Modules/Segmentation/DataManagement/mitkContourElement.cpp @@ -1,717 +1,717 @@ /*=================================================================== 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)); } } mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(int index) { return this->m_Vertices->at(index); } 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) { if( other->GetSize() > 0) { ConstVertexIterator it = other->m_Vertices->begin(); ConstVertexIterator end = other->m_Vertices->end(); //add all vertices of other after last vertex while(it != end) { this->m_Vertices->push_back(*it); it++; } } } std::pair mitk::ContourElement::FindFirstIntersection(mitk::ContourElement* other) { VertexIterator thisIt = this->m_Vertices->begin(); VertexIterator thisEnd = this->m_Vertices->end(); VertexIterator otherEnd = other->m_Vertices->end(); std::pair match(thisEnd,otherEnd); while (thisIt != thisEnd) { VertexIterator otherIt = other->m_Vertices->begin(); while (otherIt != otherEnd) { if ( (*thisIt)->Coordinates == (*otherIt)->Coordinates ) { match.first = thisIt; match.second = otherIt; return match; } otherIt++; } thisIt++; } return match; } void mitk::ContourElement::RemoveIntersections(mitk::ContourElement* other) { if( other->GetSize() > 0) { // VertexIterator _where = this->FindFirstIntersection(other); std::pair match = this->FindFirstIntersection(other); this->m_Vertices->erase(match.first, this->m_Vertices->end()); other->m_Vertices->erase(other->m_Vertices->begin(), match.second ); } } bool mitk::ContourElement::RemoveVertex(mitk::ContourElement::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; } 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::Interpolate() { VertexListType* newVertices = new VertexListType(); int nverts = this->m_Vertices->size(); for (int i=0; (i+1)DoBezierInterpolation(i, i+1, newVertices); } if ( this->IsClosed() ) { this->DoBezierInterpolation(nverts-1, 0, newVertices); } delete this->m_Vertices; this->m_Vertices = newVertices; } //---------------------------------------------------------------------- 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--; } } //---------------------------------------------------------------------- void mitk::ContourElement::DoBezierInterpolation( int idx1, int idx2, VertexListType* vertices ) { mitk::Point3D mp1; mp1 = this->m_Vertices->at(idx1)->Coordinates; mitk::Point3D mp2; mp2 = this->m_Vertices->at(idx2)->Coordinates; // this->RemoveIntermediateVerticesAt(idx1); // this->AddIntermediateVertex(mp1, idx1); vertices->push_back(new VertexType(mp1, this->m_Vertices->at(idx1)->IsControlPoint)); int maxRecursion = 0; int tmp = 3; const int MaximumCurveLineSegments = 100; const double MaximumCurveError = 0.005; while ( 2*tmp < MaximumCurveLineSegments ) { tmp *= 2; maxRecursion++; } // There are four control points with 3 components each, plus one // value for the recursion depth of this point double *controlPointsStack = new double[(3*4+1)*(maxRecursion+1)]; int stackCount = 0; double slope1[3]; double slope2[3]; this->GetNthNodeSlope( idx1, slope1 ); this->GetNthNodeSlope( idx2, slope2 ); controlPointsStack[0] = 0; double *p1 = controlPointsStack+1; double *p2 = controlPointsStack+4; double *p3 = controlPointsStack+7; double *p4 = controlPointsStack+10; const VertexType* vertex1 = this->m_Vertices->at(idx1); p1[0] = vertex1->Coordinates[0]; p1[1] = vertex1->Coordinates[1]; p1[2] = vertex1->Coordinates[2]; const VertexType* vertex2 = this->m_Vertices->at(idx2); p4[0] = vertex2->Coordinates[0]; p4[1] = vertex2->Coordinates[1]; p4[2] = vertex2->Coordinates[2]; double distance = sqrt( vtkMath::Distance2BetweenPoints( p1, p4 ) ); p2[0] = p1[0] + .333*distance*slope1[0]; p2[1] = p1[1] + .333*distance*slope1[1]; p2[2] = p1[2] + .333*distance*slope1[2]; p3[0] = p4[0] - .333*distance*slope2[0]; p3[1] = p4[1] - .333*distance*slope2[1]; p3[2] = p4[2] - .333*distance*slope2[2]; stackCount++; while ( stackCount ) { //process last point on stack int recursionLevel = static_cast(controlPointsStack[13*(stackCount-1)]); p1 = controlPointsStack + 13*(stackCount-1)+1; p2 = controlPointsStack + 13*(stackCount-1)+4; p3 = controlPointsStack + 13*(stackCount-1)+7; p4 = controlPointsStack + 13*(stackCount-1)+10; double totalDist = 0; totalDist += sqrt(vtkMath::Distance2BetweenPoints(p1,p2)); totalDist += sqrt(vtkMath::Distance2BetweenPoints(p2,p3)); totalDist += sqrt(vtkMath::Distance2BetweenPoints(p3,p4)); distance = sqrt(vtkMath::Distance2BetweenPoints(p1,p4)); if ( recursionLevel >= maxRecursion || distance == 0 || (totalDist - distance)/distance < MaximumCurveError ) { mitk::Point3D mp2; mp2[0] = p2[0]; mp2[1] = p2[1]; mp2[2] = p2[2]; //this->InsertVertexAtIndex(mp2, false, idx1); vertices->push_back(new VertexType(mp2, false)); mitk::Point3D mp3; mp3[0] = p3[0]; mp3[1] = p3[1]; mp3[2] = p3[2]; //this->InsertVertexAtIndex(mp3, false, idx1); vertices->push_back(new VertexType(mp3, false)); if ( stackCount > 1 ) { mitk::Point3D mp4; mp4[0] = p4[0]; mp4[1] = p4[1]; mp4[2] = p4[2]; //this->InsertVertexAtIndex(mp4, false, idx1); vertices->push_back(new VertexType(mp4, false)); } stackCount--; } else { double p12[3], p23[3], p34[3], p123[3], p234[3], p1234[3]; this->ComputeMidpoint( p1, p2, p12 ); this->ComputeMidpoint( p2, p3, p23 ); this->ComputeMidpoint( p3, p4, p34 ); this->ComputeMidpoint( p12, p23, p123 ); this->ComputeMidpoint( p23, p34, p234 ); this->ComputeMidpoint( p123, p234, p1234 ); // add these two points to the stack controlPointsStack[13*(stackCount-1)] = recursionLevel+1; controlPointsStack[13*(stackCount)] = recursionLevel+1; double *newp1 = controlPointsStack + 13*(stackCount)+1; double *newp2 = controlPointsStack + 13*(stackCount)+4; double *newp3 = controlPointsStack + 13*(stackCount)+7; double *newp4 = controlPointsStack + 13*(stackCount)+10; newp1[0] = p1[0]; newp1[1] = p1[1]; newp1[2] = p1[2]; newp2[0] = p12[0]; newp2[1] = p12[1]; newp2[2] = p12[2]; newp3[0] = p123[0]; newp3[1] = p123[1]; newp3[2] = p123[2]; newp4[0] = p1234[0]; newp4[1] = p1234[1]; newp4[2] = p1234[2]; p1[0] = p1234[0]; p1[1] = p1234[1]; p1[2] = p1234[2]; p2[0] = p234[0]; p2[1] = p234[1]; p2[2] = p234[2]; p3[0] = p34[0]; p3[1] = p34[1]; p3[2] = p34[2]; stackCount++; } } delete [] controlPointsStack; } //---------------------------------------------------------------------- -int mitk::ContourElement::GetNthNodeSlope( int n, double slope[3]) +bool mitk::ContourElement::GetNthNodeSlope( int index, double slope[3]) { - if ( n < 0 || - static_cast(n) >= this->m_Vertices->size() ) + if ( index < 0 || + static_cast(index) >= this->m_Vertices->size() ) { - return 0; + return false; } int idx1, idx2; - if ( n == 0 && !this->IsClosed() ) + if ( index == 0 && !this->IsClosed() ) { idx1 = 0; idx2 = 1; } - else if ( n == this->m_Vertices->size()-1 && !this->IsClosed() ) + else if ( index == this->m_Vertices->size()-1 && !this->IsClosed() ) { idx1 = this->m_Vertices->size()-2; idx2 = idx1+1; } else { - idx1 = n - 1; - idx2 = n + 1; + idx1 = index - 1; + idx2 = index + 1; if ( idx1 < 0 ) { idx1 += this->m_Vertices->size(); } if ( idx2 >= this->m_Vertices->size() ) { idx2 -= this->m_Vertices->size(); } } slope[0] = this->m_Vertices->at(idx2)->Coordinates[0] - this->m_Vertices->at(idx1)->Coordinates[0]; slope[1] = this->m_Vertices->at(idx2)->Coordinates[1] - this->m_Vertices->at(idx1)->Coordinates[1]; slope[2] = this->m_Vertices->at(idx2)->Coordinates[2] - this->m_Vertices->at(idx1)->Coordinates[2]; vtkMath::Normalize( slope ); - return 1; + return true; } diff --git a/Modules/Segmentation/DataManagement/mitkContourElement.h b/Modules/Segmentation/DataManagement/mitkContourElement.h index cf96aee8f9..2f4cafb578 100644 --- a/Modules/Segmentation/DataManagement/mitkContourElement.h +++ b/Modules/Segmentation/DataManagement/mitkContourElement.h @@ -1,259 +1,277 @@ /*=================================================================== 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_ContourElement_H_ -#define _MITK_ContourElement_H_ +#ifndef _mitkContourElement_H_ +#define _mitkContourElement_H_ #include "mitkCommon.h" #include "SegmentationExports.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 Segmentation_EXPORT ContourElement : public itk::LightObject { public: mitkClassMacro(ContourElement, itk::LightObject); itkNewMacro(Self); mitkCloneMacro(Self); -/*+++++++++++++++++++++ Data container representing vertices +++++++++++++++++*/ - +// Data container representing vertices /** \brief Represents a single vertex of contour. */ struct ContourModelVertex { ContourModelVertex(mitk::Point3D &point, bool active=false) : Coordinates(point), IsControlPoint(active) { }; /** \brief Treat point special. */ bool IsControlPoint; /** \brief Coordinates in 3D space. */ mitk::Point3D Coordinates; }; -/*+++++++++++++++++++++ END Data container representing vertices ++++++++++++++*/ - +// END Data container representing vertices -/*+++++++++++++++ typedefs +++++++++++++++++++++++++++++++*/ typedef ContourModelVertex VertexType; typedef std::deque VertexListType; typedef VertexListType::iterator VertexIterator; typedef VertexListType::const_iterator ConstVertexIterator; -/*+++++++++++++++ END typedefs ++++++++++++++++++++++++++++*/ - - -/*++++++++++++++++ inline methods +++++++++++++++++++++++*/ + // start of inline methods - /** \brief Return a const iterator a the front. */ + /** \brief Return a const iterator a the front. + */ virtual ConstVertexIterator ConstIteratorBegin() { return this->m_Vertices->begin(); } - /** \brief Return a const iterator a the end. */ + /** \brief Return a const iterator a the end. + */ virtual ConstVertexIterator ConstIteratorEnd() { return this->m_Vertices->end(); } - /** \brief Return an iterator a the front. */ + /** \brief Return an iterator a the front. + */ virtual VertexIterator IteratorBegin() { return this->m_Vertices->begin(); } - /** \brief Return an iterator a the end. */ + /** \brief Return an iterator a the end. + */ virtual VertexIterator IteratorEnd() { return this->m_Vertices->end(); } - /** \brief Returns the number of contained vertices. */ + /** \brief Returns the number of contained vertices. + */ virtual int GetSize() { return this->m_Vertices->size(); } -/*++++++++++++++++ END inline methods +++++++++++++++++++++++*/ - - + // end of inline methods /** \brief Add a vertex at the end of the contour - \param vertex - coordinates in 3D space. - \param isControlPoint - is the vertex a special control point.*/ - virtual void AddVertex(mitk::Point3D &vertex, bool isControlPoint); + \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 ContourModelVertex. + \param vertex - a contour element vertex. */ virtual void AddVertex(VertexType &vertex); /** \brief Add a vertex at the front of the contour - \param vertex - coordinates in 3D space. - \param isControlPoint - is the vertex a special control point.*/ - virtual void AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint); + \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 ContourModelVertex. + \param vertex - a contour element vertex. */ virtual void AddVertexAtFront(VertexType &vertex); /** \brief Add a vertex at a given index of the contour - \param vertex - coordinates in 3D space. + \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 &vertex, bool isControlPoint, int index); + virtual void InsertVertexAtIndex(mitk::Point3D &point, bool isControlPoint, int index); /** \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 container of the vertices. */ VertexListType* GetVertexList(); /** \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. + /** \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 add after last vertex. */ void Concatenate(mitk::ContourElement* other); - std::pair - FindFirstIntersection(mitk::ContourElement* other); - + /** \brief Removes intersected vertices between two contour elements + \param other - a given contour element. + */ void RemoveIntersections(mitk::ContourElement* other); /** \brief Remove the given vertex from the container if exists. \param vertex - the vertex to be removed. */ virtual bool RemoveVertex(VertexType* vertex); /** \brief Remove a vertex at given index within the container if exists. \param index - the index to be removed at. */ 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); + /** \brief Generate and interpolated version of the contour element based on the + active interpolation method + */ void Interpolate(); VertexListType* GetControlVertices(); + /** \brief Uniformly redistribute control points with a given period (in number of vertices) + \param period - number of vertices between control points. + */ void RedistributeControlVertices(const VertexType* selected, int period); protected: ContourElement(); ContourElement(const mitk::ContourElement &other); virtual ~ContourElement(); - /** \brief Finds the 4th order bezier curve between given indexes. + /** \brief Finds the 4-th order bezier curve between given indexes. Adapted from vtkBezierContourLineInterpolator \param idx1 - first index \param idx2 - second index */ void DoBezierInterpolation( int idx1, int idx2, VertexListType* vertices ); - int GetNthNodeSlope( int n, double slope[3]); + /** \brief Returns a pair with two iterators pointing to the vertices where + the contour element intersects (i.e. has the same coordinates) with another given contour element + \param other - a given contour element. + */ + std::pair + FindFirstIntersection(mitk::ContourElement* other); + + /** \brief Calculates the slope at a given index + \param index - the index to get the slope at. + \param slope - splope at given index. + */ + bool GetNthNodeSlope( int index, double slope[3]); void ComputeMidpoint( double p1[3], double p2[3], double mid[3] ) { mid[0] = (p1[0] + p2[0])/2; mid[1] = (p1[1] + p2[1])/2; mid[2] = (p1[2] + p2[2])/2; } VertexListType* m_Vertices; //double ended queue with vertices bool m_IsClosed; }; -} +} // namespace mitk -#endif +#endif // _mitkContourElement_H_ diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp index 243afd4d99..2a2a88eda5 100644 --- a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp +++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp @@ -1,398 +1,397 @@ /*=================================================================== 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 "mitkContourModelLiveWireInteractor.h" #include "mitkToolManager.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include #include #include mitk::ContourModelLiveWireInteractor::ContourModelLiveWireInteractor(DataNode* dataNode) :ContourModelInteractor(dataNode) { m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New(); m_NextActiveVertexDown.Fill(0); m_NextActiveVertexUp.Fill(0); } mitk::ContourModelLiveWireInteractor::~ContourModelLiveWireInteractor() { } bool mitk::ContourModelLiveWireInteractor::OnCheckPointClick( Action* action, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) { this->HandleEvent( new mitk::StateEvent(EIDNO, stateEvent->GetEvent()) ); - MITK_WARN << "Could not get position event"; return false; } mitk::StateEvent* newStateEvent = NULL; int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); if (!contour) { this->HandleEvent( new mitk::StateEvent(EIDNO, stateEvent->GetEvent()) ); - MITK_WARN << "Could not get working contour"; return false; } contour->Deselect(); // Check distance to any vertex. // Transition YES if click close to a vertex mitk::Point3D click = positionEvent->GetWorldPosition(); if (contour->SelectVertexAt(click, 1.5, timestep) ) { contour->SetSelectedVertexAsControlPoint(false); m_lastMousePosition = click; m_ContourLeft = mitk::ContourModel::New(); //get coordinates of next active vertex downwards from selected vertex int downIndex = this->SplitContourFromSelectedVertex( contour, m_ContourLeft, false, timestep); - mitk::ContourModel::VertexIterator itDown = contour->IteratorBegin() + downIndex; - m_NextActiveVertexDown = (*itDown)->Coordinates; + m_NextActiveVertexDownIter = contour->IteratorBegin() + downIndex; + m_NextActiveVertexDown = (*m_NextActiveVertexDownIter)->Coordinates; m_ContourRight = mitk::ContourModel::New(); //get coordinates of next active vertex upwards from selected vertex int upIndex = this->SplitContourFromSelectedVertex( contour, m_ContourRight, true, timestep); - mitk::ContourModel::VertexIterator itUp = contour->IteratorBegin() + upIndex; - m_NextActiveVertexUp = (*itUp)->Coordinates; + m_NextActiveVertexUpIter = contour->IteratorBegin() + upIndex; + m_NextActiveVertexUp = (*m_NextActiveVertexUpIter)->Coordinates; newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent()); } else { newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); } this->HandleEvent( newStateEvent ); contour->SetSelectedVertexAsControlPoint(true); assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } bool mitk::ContourModelLiveWireInteractor::OnDeletePoint( Action* action, const StateEvent* stateEvent) { int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); - if (!contour) - { - MITK_WARN << "Could not get working contour"; - return false; - } + assert ( contour ); if (contour->GetSelectedVertex()) { mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); newContour->Expand(contour->GetTimeSteps()); newContour->Concatenate( m_ContourLeft, timestep ); //recompute contour between neighbored two active control points - this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown ); - this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp ); + this->m_LiveWireFilter->SetStartPoint( this->m_NextActiveVertexDown ); + this->m_LiveWireFilter->SetEndPoint( this->m_NextActiveVertexUp ); this->m_LiveWireFilter->ClearRepulsivePoints(); this->m_LiveWireFilter->Update(); mitk::ContourModel *liveWireContour = this->m_LiveWireFilter->GetOutput(); - - if (!liveWireContour) - { - MITK_WARN << "could not retrieve liveWireContour"; - return false; - } + assert ( liveWireContour ); liveWireContour->RemoveVertexAt( 0, timestep); liveWireContour->RemoveVertexAt( liveWireContour->GetNumberOfVertices(timestep) - 1, timestep); //insert new live wire computed points newContour->Concatenate( liveWireContour, timestep ); // insert right side of original contour - newContour->Concatenate( m_ContourRight, timestep ); + newContour->Concatenate( this->m_ContourRight, timestep ); newContour->SetIsClosed(contour->IsClosed(timestep), timestep); m_DataNode->SetData(newContour); assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); return true; } return false; } bool mitk::ContourModelLiveWireInteractor::OnMovePoint( Action* action, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); mitk::Point3D currentPosition = positionEvent->GetWorldPosition(); + mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); + assert ( contour ); + //recompute contour between previous active vertex and selected vertex - this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown ); + this->m_LiveWireFilter->SetStartPoint( this->m_NextActiveVertexDown ); this->m_LiveWireFilter->SetEndPoint( currentPosition ); this->m_LiveWireFilter->ClearRepulsivePoints(); this->m_LiveWireFilter->Update(); mitk::ContourModel::Pointer leftLiveWire = this->m_LiveWireFilter->GetOutput(); - if (!leftLiveWire) - { - MITK_WARN << "There is no left live wire contour"; - return false; - } + assert ( leftLiveWire ); leftLiveWire->RemoveVertexAt(0, timestep); //recompute contour between selected vertex and next active vertex this->m_LiveWireFilter->SetStartPoint( currentPosition ); this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp ); this->m_LiveWireFilter->ClearRepulsivePoints(); +/* + mitk::ContourModel::VertexIterator iter = contour->IteratorBegin(timestep); + for (;iter != m_NextActiveVertexDownIter; iter++) + { + itk::Index<2> idx; + this->m_WorkingImage->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx); + this->m_LiveWireFilter->AddRepulsivePoint( idx ); + } - // TODO: try using all contour points - typedef mitk::ImageLiveWireContourModelFilter::InternalImageType::IndexType IndexType; - mitk::ContourModel::ConstVertexIterator iter = leftLiveWire->IteratorBegin(timestep); + iter = m_NextActiveVertexUpIter; + for (;iter != contour->IteratorEnd(timestep); iter++) + { + itk::Index<2> idx; + this->m_WorkingImage->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx); + this->m_LiveWireFilter->AddRepulsivePoint( idx ); + } +*/ + // add points from already calculated left live wire + mitk::ContourModel::VertexIterator iter = leftLiveWire->IteratorBegin(timestep); for (;iter != leftLiveWire->IteratorEnd(timestep); iter++) { - IndexType idx; + itk::Index<2> idx; this->m_WorkingImage->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx); this->m_LiveWireFilter->AddRepulsivePoint( idx ); } this->m_LiveWireFilter->Update(); mitk::ContourModel::Pointer rightLiveWire = this->m_LiveWireFilter->GetOutput(); - - if (!rightLiveWire) - { - MITK_WARN << "There is no right live wire contour"; - return false; - } + assert ( rightLiveWire ); rightLiveWire->RemoveVertexAt(0, timestep); leftLiveWire->SetControlVertexAt(leftLiveWire->GetNumberOfVertices()-1, timestep); //leftLiveWire->SelectVertexAt(leftLiveWire->GetNumberOfVertices()-1, timestep); // set corrected left live wire to its node m_LeftLiveWireContourNode->SetData(leftLiveWire); // set corrected right live wire to its node m_RightLiveWireContourNode->SetData(rightLiveWire); - mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); + mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); newContour->Expand(contour->GetTimeSteps()); // concatenate left original contour newContour->Concatenate( this->m_ContourLeft, timestep ); newContour->Deselect(); // concatenate left live wire newContour->Concatenate( leftLiveWire, timestep ); + // set last inserted vertex as selected newContour->SelectVertexAt(newContour->GetNumberOfVertices()-1, timestep); // concatenate right live wire newContour->Concatenate( rightLiveWire, timestep ); // concatenate right original contour newContour->Concatenate( this->m_ContourRight, timestep ); newContour->SetIsClosed(contour->IsClosed(timestep), timestep); m_DataNode->SetData(newContour); this->m_lastMousePosition = positionEvent->GetWorldPosition(); assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } -int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour, +int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* srcContour, mitk::ContourModel* destContour, bool fromSelectedUpwards, int timestep) { - mitk::ContourModel::VertexIterator end = sourceContour->IteratorEnd(); - mitk::ContourModel::VertexIterator begin = sourceContour->IteratorBegin(); + mitk::ContourModel::VertexIterator end = srcContour->IteratorEnd(); + mitk::ContourModel::VertexIterator begin = srcContour->IteratorBegin(); //search next active control point to left and rigth and set as start and end point for filter mitk::ContourModel::VertexIterator itSelected = begin; // move iterator to position - while ((*itSelected) != sourceContour->GetSelectedVertex()) + while ((*itSelected) != srcContour->GetSelectedVertex()) { itSelected++; } // CASE search upwards for next control point if(fromSelectedUpwards) { mitk::ContourModel::VertexIterator itUp = itSelected; if(itUp != end) { itUp++;//step once up otherwise the loop breaks immediately } while( itUp != end && !((*itUp)->IsControlPoint)) { itUp++; } mitk::ContourModel::VertexIterator it = itUp; if (itSelected != begin) { //copy the rest of the original contour while (it != end) { destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); it++; } } //else do not copy the contour //return the offset of iterator at one before next-vertex-upwards if(itUp != begin) { return std::distance( begin, itUp) - 1; } else { return std::distance( begin, itUp); } } else //CASE search downwards for next control point { mitk::ContourModel::VertexIterator itDown = itSelected; - mitk::ContourModel::VertexIterator it = sourceContour->IteratorBegin(); + mitk::ContourModel::VertexIterator it = srcContour->IteratorBegin(); if( itSelected != begin ) { if(itDown != begin) { itDown--;//step once down otherwise the the loop breaks immediately } while( itDown != begin && !((*itDown)->IsControlPoint)){ itDown--; } if(it != end)//if not empty { //always add the first vertex destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); it++; } //copy from begin to itDown while(it <= itDown) { destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); it++; } } else { //if selected vertex is the first element search from end of contour downwards itDown = end; itDown--; while(!((*itDown)->IsControlPoint)){itDown--;} //move one forward as we don't want the first control point it++; //move iterator to second control point while( (it!=end) && !((*it)->IsControlPoint) ){it++;} //copy from begin to itDown while(it <= itDown) { //copy the contour from second control point to itDown destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); it++; } } - +/* //add vertex at itDown - it's not considered during while loop if( it != begin && it != end) { //destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); } - +*/ //return the offset of iterator at one after next-vertex-downwards if( itDown != end) { return std::distance( begin, itDown);// + 1;//index of next vertex } else { return std::distance( begin, itDown) - 1; } } } bool mitk::ContourModelLiveWireInteractor::OnFinishEditing( Action* action, const StateEvent* stateEvent) { int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); mitk::ContourModel *leftLiveWire = dynamic_cast( this->m_LeftLiveWireContourNode->GetData() ); + assert ( leftLiveWire ); - if (leftLiveWire) - leftLiveWire->Clear(timestep); + leftLiveWire->Clear(timestep); mitk::ContourModel *rightLiveWire = dynamic_cast( this->m_RightLiveWireContourNode->GetData() ); + assert ( rightLiveWire ); - if (rightLiveWire) - rightLiveWire->Clear(timestep); + rightLiveWire->Clear(timestep); assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); return true; } diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h index 6fc2e99cb7..b98383c464 100644 --- a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h +++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h @@ -1,101 +1,105 @@ /*=================================================================== 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 mitkContourModelLiveWireInteractor_h_Included #define mitkContourModelLiveWireInteractor_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkContourModelInteractor.h" #include namespace mitk { /** \brief \sa Interactor \sa ContourModelInteractor \ingroup Interaction \warning Make sure the working image is properly set, otherwise the algorithm for computing livewire contour segments will not work! */ class Segmentation_EXPORT ContourModelLiveWireInteractor : public ContourModelInteractor { public: mitkClassMacro(ContourModelLiveWireInteractor, ContourModelInteractor); mitkNewMacro1Param(Self, DataNode*); virtual void SetLeftLiveWireContourModelNode (mitk::DataNode* _arg) { this->m_LeftLiveWireContourNode = _arg; this->Modified(); } virtual void SetRightLiveWireContourModelNode (mitk::DataNode* _arg) { this->m_RightLiveWireContourNode = _arg; this->Modified(); } virtual void SetWorkingImage (mitk::Image* _arg) { if (this->m_WorkingImage != _arg) { this->m_WorkingImage = _arg; this->m_LiveWireFilter->SetInput(this->m_WorkingImage); this->Modified(); } } protected: ContourModelLiveWireInteractor(DataNode* dataNode); virtual ~ContourModelLiveWireInteractor(); virtual bool OnDeletePoint(Action*, const StateEvent*); virtual bool OnMovePoint(Action*, const StateEvent*); virtual bool OnCheckPointClick( Action* action, const StateEvent* stateEvent); virtual bool OnFinishEditing( Action* action, const StateEvent* stateEvent); - int SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour, - mitk::ContourModel* destinationContour, - bool fromSelectedUpwards, - int timestep); + int SplitContourFromSelectedVertex(mitk::ContourModel* srcContour, + mitk::ContourModel* destContour, + bool fromSelectedUpwards, + int timestep); mitk::ImageLiveWireContourModelFilter::Pointer m_LiveWireFilter; mitk::Image::Pointer m_WorkingImage; mitk::Point3D m_NextActiveVertexDown; mitk::Point3D m_NextActiveVertexUp; + + mitk::ContourModel::VertexIterator m_NextActiveVertexDownIter; + mitk::ContourModel::VertexIterator m_NextActiveVertexUpIter; + mitk::DataNode::Pointer m_LeftLiveWireContourNode; mitk::DataNode::Pointer m_RightLiveWireContourNode; mitk::ContourModel::Pointer m_ContourLeft; mitk::ContourModel::Pointer m_ContourRight; }; -} // namespace +} // namespace mitk -#endif +#endif // mitkContourModelLiveWireInteractor_h_Included