diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp index 32c7f81ad1..71702c0e04 100755 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp @@ -1,238 +1,238 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include mitk::ContourModelUtils::ContourModelUtils() { } mitk::ContourModelUtils::~ContourModelUtils() { } mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice( - Image *slice, ContourModel *contourIn3D, bool, bool) + const Image *slice, const ContourModel *contourIn3D, bool, bool) { if (nullptr == slice || nullptr == contourIn3D) return nullptr; auto projectedContour = ContourModel::New(); projectedContour->Initialize(*contourIn3D); auto sliceGeometry = slice->GetGeometry(); auto numberOfTimesteps = static_cast(contourIn3D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn3D->Begin(t); auto end = contourIn3D->End(t); while (iter != end) { const auto ¤tPointIn3D = (*iter)->Coordinates; Point3D projectedPointIn2D; projectedPointIn2D.Fill(0.0); sliceGeometry->WorldToIndex(currentPointIn3D, projectedPointIn2D); projectedContour->AddVertex(projectedPointIn2D, t); ++iter; } } return projectedContour; } mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice( - const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool) + const BaseGeometry *sliceGeometry, const ContourModel *contourIn2D, bool) { if (nullptr == sliceGeometry || nullptr == contourIn2D) return nullptr; auto worldContour = ContourModel::New(); worldContour->Initialize(*contourIn2D); auto numberOfTimesteps = static_cast(contourIn2D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn2D->Begin(t); auto end = contourIn2D->End(t); while (iter != end) { const auto ¤tPointIn2D = (*iter)->Coordinates; Point3D worldPointIn3D; worldPointIn3D.Fill(0.0); sliceGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D); worldContour->AddVertex(worldPointIn3D, t); ++iter; } } return worldContour; } void mitk::ContourModelUtils::FillContourInSlice( const ContourModel *projectedContour, Image *sliceImage, const Image* workingImage, int paintingPixelValue) { FillContourInSlice(projectedContour, 0, sliceImage, workingImage, paintingPixelValue); } void mitk::ContourModelUtils::FillContourInSlice( const ContourModel *projectedContour, unsigned int contourTimeStep, Image *sliceImage, const Image* workingImage, int paintingPixelValue) { if (nullptr == projectedContour) { mitkThrow() << "Cannot fill contour in slice. Passed contour is invalid"; } if (nullptr == sliceImage) { mitkThrow() << "Cannot fill contour in slice. Passed slice is invalid"; } auto contourModelFilter = mitk::ContourModelToSurfaceFilter::New(); contourModelFilter->SetInput(projectedContour); contourModelFilter->Update(); auto surface = mitk::Surface::New(); surface = contourModelFilter->GetOutput(); if (nullptr == surface->GetVtkPolyData(contourTimeStep)) { MITK_WARN << "Could not create surface from contour model."; return; } auto surface2D = vtkSmartPointer::New(); surface2D->SetPoints(surface->GetVtkPolyData(contourTimeStep)->GetPoints()); surface2D->SetLines(surface->GetVtkPolyData(contourTimeStep)->GetLines()); auto image = vtkSmartPointer::New(); image->DeepCopy(sliceImage->GetVtkImageData()); const double FOREGROUND_VALUE = 255.0; const double BACKGROUND_VALUE = 0.0; vtkIdType count = image->GetNumberOfPoints(); for (decltype(count) i = 0; i < count; ++i) image->GetPointData()->GetScalars()->SetTuple1(i, FOREGROUND_VALUE); auto polyDataToImageStencil = vtkSmartPointer::New(); // Set a minimal tolerance, so that clipped pixels will be added to contour as well. polyDataToImageStencil->SetTolerance(mitk::eps); polyDataToImageStencil->SetInputData(surface2D); polyDataToImageStencil->Update(); auto imageStencil = vtkSmartPointer::New(); imageStencil->SetInputData(image); imageStencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort()); imageStencil->ReverseStencilOff(); imageStencil->SetBackgroundValue(BACKGROUND_VALUE); imageStencil->Update(); vtkSmartPointer filledImage = imageStencil->GetOutput(); vtkSmartPointer resultImage = sliceImage->GetVtkImageData(); FillSliceInSlice(filledImage, resultImage, workingImage, paintingPixelValue); sliceImage->SetVolume(resultImage->GetScalarPointer()); } void mitk::ContourModelUtils::FillSliceInSlice( vtkSmartPointer filledImage, vtkSmartPointer resultImage, const Image* image, int paintingPixelValue) { auto labelImage = dynamic_cast(image); auto numberOfPoints = filledImage->GetNumberOfPoints(); if (nullptr == labelImage) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } else { auto backgroundValue = labelImage->GetExteriorLabel()->GetValue(); if (paintingPixelValue != backgroundValue) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { auto existingValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i); if (!labelImage->GetLabel(existingValue, labelImage->GetActiveLayer())->GetLocked()) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } else { auto activePixelValue = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue(); for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { if (resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } } } mitk::ContourModel::Pointer mitk::ContourModelUtils::MoveZerothContourTimeStep(const ContourModel *contour, unsigned int t) { if (nullptr == contour) return nullptr; auto resultContour = ContourModel::New(); resultContour->Expand(t + 1); std::for_each(contour->Begin(), contour->End(), [&resultContour, t](ContourElement::VertexType *vertex) { resultContour->AddVertex(vertex, t); }); return resultContour; } int mitk::ContourModelUtils::GetActivePixelValue(const Image* workingImage) { auto* labelSetImage = dynamic_cast(workingImage); int activePixelValue = 1; if (nullptr != labelSetImage) { activePixelValue = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue(); } return activePixelValue; } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h index dec716cbc6..a7d8a98a4d 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h @@ -1,113 +1,113 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkContourModelUtils_h #define mitkContourModelUtils_h #include #include #include #include namespace mitk { /** * \brief Helpful methods for working with contours and images * * */ class MITKCONTOURMODEL_EXPORT ContourModelUtils : public itk::Object { public: mitkClassMacroItkParent(ContourModelUtils, itk::Object); /** \brief Projects a contour onto an image point by point. Converts from world to index coordinates. \param slice \param contourIn3D \param correctionForIpSegmentation adds 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) \param constrainToInside */ - static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, - ContourModel *contourIn3D, + static ContourModel::Pointer ProjectContourTo2DSlice(const Image *slice, + const ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside); /** \brief Projects a slice index coordinates of a contour back into world coordinates. \param sliceGeometry \param contourIn2D \param correctionForIpSegmentation subtracts 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) */ static ContourModel::Pointer BackProjectContourFrom2DSlice(const BaseGeometry *sliceGeometry, - ContourModel *contourIn2D, + const ContourModel *contourIn2D, bool correctionForIpSegmentation = false); /** \brief Fill a contour in a 2D slice with a specified pixel value. This version always uses the contour of time step 0 and fills the image. \pre sliceImage points to a valid instance \pre projectedContour points to a valid instance */ static void FillContourInSlice(const ContourModel *projectedContour, Image *sliceImage, const Image* workingImage, int paintingPixelValue = 1); /** \brief Fill a contour in a 2D slice with a specified pixel value. This overloaded version uses the contour at the passed contourTimeStep to file the passed image slice. \pre sliceImage points to a valid instance \pre projectedContour points to a valid instance */ static void FillContourInSlice(const ContourModel *projectedContour, unsigned int contourTimeStep, Image *sliceImage, const Image* workingImage, int paintingPixelValue = 1); /** \brief Fills a image (filledImage) into another image (resultImage) by incorporating the rules of LabelSet-Images */ static void FillSliceInSlice(vtkSmartPointer filledImage, vtkSmartPointer resultImage, const Image* image, int paintingPixelValue); /** \brief Move the contour in time step 0 to to a new contour model at the given time step. */ static ContourModel::Pointer MoveZerothContourTimeStep(const ContourModel *contour, unsigned int timeStep); /** \brief Retrieves the active pixel value of a (labelset) image. If the image is basic image, the pixel value 1 (one) will be returned. If the image is actually a labelset image, the pixel value of the active label of the active layer will be returned. \param workingImage The (labelset) image to retrieve the active pixel value of. */ static int GetActivePixelValue(const Image* workingImage); protected: ContourModelUtils(); ~ContourModelUtils() override; }; } #endif diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.cpp b/Modules/ContourModel/DataManagement/mitkContourElement.cpp index fd14eacedb..1542d5a74d 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourElement.cpp @@ -1,471 +1,471 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include mitk::ContourElement::ContourElement() { this->m_Vertices = new VertexListType(); this->m_IsClosed = false; } mitk::ContourElement::ContourElement(const mitk::ContourElement &other) : itk::LightObject(), 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) +void mitk::ContourElement::AddVertex(const 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) +void mitk::ContourElement::AddVertexAtFront(const 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) +void mitk::ContourElement::InsertVertexAtIndex(const mitk::Point3D &vertex, bool isControlPoint, int index) { if (index >= 0 && this->GetSize() > index) { auto _where = this->m_Vertices->begin(); _where += index; this->m_Vertices->insert(_where, new VertexType(vertex, isControlPoint)); } } void mitk::ContourElement::SetVertexAt(int pointId, const Point3D &point) { if (pointId >= 0 && this->GetSize() > pointId) { this->m_Vertices->at(pointId)->Coordinates = point; } } void mitk::ContourElement::SetVertexAt(int pointId, const VertexType *vertex) { if (pointId >= 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 nullptr; } mitk::ContourElement::VertexType *mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, float eps) { if (eps > 0) { std::deque> nearestlist; ConstVertexIterator it = this->m_Vertices->begin(); ConstVertexIterator end = this->m_Vertices->end(); while (it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; double distance = currentPoint.EuclideanDistanceTo(point); if (distance < eps) { // if list is emtpy, add point to list if (nearestlist.size() < 1) { nearestlist.push_front(std::pair((*it)->Coordinates.EuclideanDistanceTo(point), (*it))); } // found an approximate point - check if current is closer then first in nearestlist else if (distance < nearestlist.front().first) { // found even closer vertex nearestlist.push_front(std::pair((*it)->Coordinates.EuclideanDistanceTo(point), (*it))); } } // if distance > eps it++; } // while if (nearestlist.size() > 0) { /*++++++++++++++++++++ return the nearest active point if one was found++++++++++++++++++*/ auto it = nearestlist.begin(); auto end = nearestlist.end(); while (it != end) { if ((*it).second->IsControlPoint) { return (*it).second; } it++; } /*---------------------------------------------------------------------------------------*/ // return closest point return nearestlist.front().second; } } return nullptr; } /*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 = nullptr; try { ret = this->m_Vertices->at(indexArray[0]); } catch(std::out_of_range ex) { //ret stays nullptr return ret; } //clean up ANN delete [] indexArray; delete [] distanceArray; delete kdTree; annClose(); return ret; } return nullptr; } */ 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::SetClosed(bool isClosed) { isClosed ? this->Close() : this->Open(); } mitk::ContourElement::VertexListType *mitk::ContourElement::GetControlVertices() { auto newVertices = new VertexListType(); auto it = this->m_Vertices->begin(); auto 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(const VertexType *vertex) { auto it = this->m_Vertices->begin(); auto 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) { auto it = this->m_Vertices->begin(); auto 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 && static_cast(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) { auto it = this->m_Vertices->begin(); auto 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; auto _where = this->m_Vertices->begin(); if (selected != nullptr) { while (_where != this->m_Vertices->end()) { if ((*_where) == selected) { break; } _where++; } } auto _iter = _where; while (_iter != this->m_Vertices->end()) { div_t divresult; divresult = div(counter, period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter++; } _iter = _where; counter = 0; while (_iter != this->m_Vertices->begin()) { div_t divresult; divresult = div(counter, period); (*_iter)->IsControlPoint = (divresult.rem == 0); counter++; _iter--; } } diff --git a/Modules/ContourModel/DataManagement/mitkContourElement.h b/Modules/ContourModel/DataManagement/mitkContourElement.h index ea18abc41d..b9d6c1d3d9 100644 --- a/Modules/ContourModel/DataManagement/mitkContourElement.h +++ b/Modules/ContourModel/DataManagement/mitkContourElement.h @@ -1,231 +1,231 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _mitkContourElement_H_ #define _mitkContourElement_H_ #include "mitkCommon.h" #include #include //#include #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 MITKCONTOURMODEL_EXPORT ContourElement : public itk::LightObject { public: mitkClassMacroItkParent(ContourElement, itk::LightObject); itkFactorylessNewMacro(Self); itkCloneMacro(Self); // Data container representing vertices /** \brief Represents a single vertex of contour. */ struct ContourModelVertex { - ContourModelVertex(mitk::Point3D &point, bool active = false) : IsControlPoint(active), Coordinates(point) {} + ContourModelVertex(const mitk::Point3D &point, bool active = false) : IsControlPoint(active), Coordinates(point) {} ContourModelVertex(const ContourModelVertex &other) : IsControlPoint(other.IsControlPoint), Coordinates(other.Coordinates) { } /** \brief Treat point special. */ bool IsControlPoint; /** \brief Coordinates in 3D space. */ mitk::Point3D Coordinates; }; // 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); + virtual void AddVertex(const 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); + virtual void AddVertexAtFront(const 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); + virtual void InsertVertexAtIndex(const 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, const 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 SetClosed(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(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); 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: mitkCloneMacro(Self); ContourElement(); ContourElement(const mitk::ContourElement &other); ~ContourElement() override; 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 6d88174b43..fc5c9e78f9 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.cpp +++ b/Modules/ContourModel/DataManagement/mitkContourModel.cpp @@ -1,635 +1,635 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include mitk::ContourModel::ContourModel() : m_UpdateBoundingBox(true) { // set to initial state this->InitializeEmpty(); } mitk::ContourModel::ContourModel(const mitk::ContourModel &other) : mitk::BaseData(other), m_ContourSeries(other.m_ContourSeries), m_lineInterpolation(other.m_lineInterpolation) { m_SelectedVertex = nullptr; } mitk::ContourModel::~ContourModel() { m_SelectedVertex = nullptr; this->m_ContourSeries.clear(); // TODO check destruction } -void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, int timestep) +void mitk::ContourModel::AddVertex(const 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) +void mitk::ContourModel::AddVertex(const 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 != nullptr) { this->m_ContourSeries[timestep]->AddVertex(*const_cast(vertex)); } } 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; } } 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; } } bool mitk::ContourModel::SetVertexAt(int pointId, const Point3D &point, unsigned int timestep) { if (!this->IsEmptyTimeStep(timestep)) { if (pointId >= 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 == nullptr) return false; if (!this->IsEmptyTimeStep(timestep)) { if (pointId >= 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; } } } 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 nullptr; } 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::SetClosed(bool isClosed, int timestep) { if (!this->IsEmptyTimeStep(timestep)) { this->m_ContourSeries[timestep]->SetClosed(isClosed); this->InvokeEvent(ContourModelClosedEvent()); this->Modified(); this->m_UpdateBoundingBox = true; } } bool mitk::ContourModel::IsEmptyTimeStep(unsigned int t) const { return (this->m_ContourSeries.size() <= t); } bool mitk::ContourModel::IsNearContour(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) const { return this->IteratorBegin(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorBegin(int timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorBegin(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } mitk::ContourModel::VertexIterator mitk::ContourModel::End(int timestep) const { return this->IteratorEnd(timestep); } mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorEnd(int timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IteratorEnd(); } else { mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available."; } } bool mitk::ContourModel::IsClosed(int timestep) const { if (!this->IsEmptyTimeStep(timestep)) { return this->m_ContourSeries[timestep]->IsClosed(); } return false; } bool mitk::ContourModel::SelectVertexAt(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 != nullptr; } 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 != nullptr) { 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 != nullptr) { vertex->IsControlPoint = true; return true; } } return false; } 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(); auto it = vList->begin(); auto 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(unsigned int timeSteps) { std::size_t oldSize = this->m_ContourSeries.size(); if (static_cast(timeSteps) > oldSize) { Superclass::Expand(timeSteps); // insert contours for each new timestep for (std::size_t i = oldSize; i < static_cast(timeSteps); i++) { m_ContourSeries.push_back(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::BaseGeometry *mitk::ContourModel::GetUpdatedGeometry(int t) { return Superclass::GetUpdatedGeometry(t); } mitk::BaseGeometry *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) +void mitk::ContourModel::Initialize(const mitk::ContourModel &other) { mitk::TimeStepType numberOfTimesteps = other.GetTimeGeometry()->CountTimeSteps(); this->InitializeTimeGeometry(numberOfTimesteps); for (mitk::TimeStepType currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { this->m_ContourSeries.push_back(mitk::ContourElement::New()); this->SetClosed(other.IsClosed(currentTimestep), currentTimestep); } m_SelectedVertex = nullptr; this->m_lineInterpolation = other.m_lineInterpolation; this->Modified(); this->m_UpdateBoundingBox = true; } void mitk::ContourModel::InitializeEmpty() { // clear data at timesteps this->m_ContourSeries.resize(0); this->m_ContourSeries.push_back(mitk::ContourElement::New()); // set number of timesteps to one this->InitializeTimeGeometry(1); m_SelectedVertex = nullptr; this->m_lineInterpolation = ContourModel::LINEAR; } void mitk::ContourModel::UpdateOutputInformation() { if (this->GetSource()) { this->GetSource()->UpdateOutputInformation(); } if (this->m_UpdateBoundingBox) { // update the bounds of the geometry according to the stored vertices ScalarType mitkBounds[6]; // calculate the boundingbox at each timestep typedef itk::BoundingBox BoundingBoxType; typedef BoundingBoxType::PointsContainer PointsContainer; int timesteps = this->GetTimeSteps(); // iterate over the timesteps for (int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++) { if (dynamic_cast(this->GetGeometry(currenTimeStep))) { // do not update bounds for 2D geometries, as they are unfortunately defined with min bounds 0! return; } else { // we have a 3D geometry -> let's update bounds // only update bounds if the contour was modified if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime()) { mitkBounds[0] = 0.0; mitkBounds[1] = 0.0; mitkBounds[2] = 0.0; mitkBounds[3] = 0.0; mitkBounds[4] = 0.0; mitkBounds[5] = 0.0; BoundingBoxType::Pointer boundingBox = BoundingBoxType::New(); PointsContainer::Pointer points = PointsContainer::New(); auto it = this->IteratorBegin(currenTimeStep); auto end = this->IteratorEnd(currenTimeStep); // fill the boundingbox with the points while (it != end) { Point3D currentP = (*it)->Coordinates; BoundingBoxType::PointType p; p.CastFrom(currentP); points->InsertElement(points->Size(), p); it++; } // construct the new boundingBox boundingBox->SetPoints(points); boundingBox->ComputeBoundingBox(); BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds(); mitkBounds[0] = tmp[0]; mitkBounds[1] = tmp[1]; mitkBounds[2] = tmp[2]; mitkBounds[3] = tmp[3]; mitkBounds[4] = tmp[4]; mitkBounds[5] = tmp[5]; // set boundingBox at current timestep BaseGeometry *geometry3d = this->GetGeometry(currenTimeStep); geometry3d->SetBounds(mitkBounds); } } } this->m_UpdateBoundingBox = false; } GetTimeGeometry()->Update(); } void mitk::ContourModel::ExecuteOperation(mitk::Operation * /*operation*/) { // not supported yet } diff --git a/Modules/ContourModel/DataManagement/mitkContourModel.h b/Modules/ContourModel/DataManagement/mitkContourModel.h index 45aae9bcda..a61fc06d60 100644 --- a/Modules/ContourModel/DataManagement/mitkContourModel.h +++ b/Modules/ContourModel/DataManagement/mitkContourModel.h @@ -1,453 +1,453 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_CONTOURMODEL_H_ #define _MITK_CONTOURMODEL_H_ #include "mitkBaseData.h" #include "mitkCommon.h" #include #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 MITKCONTOURMODEL_EXPORT ContourModel : public BaseData { public: mitkClassMacro(ContourModel, BaseData); itkFactorylessNewMacro(Self); itkCloneMacro(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 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 = nullptr; } /** \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 TimeGeometry will not be expanded. */ - void AddVertex(mitk::Point3D &vertex, int timestep = 0); + void AddVertex(const 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 TimeGeometry 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 TimeGeometry will not be expanded. */ - void AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep = 0); + void AddVertex(const 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 TimeGeometry 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 TimeGeometry 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 TimeGeometry 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, const 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) const; /** \brief Concatenate two contours. The starting control point of the other will be added at the end of the contour. \param other \param timestep - the timestep at which the vertex will be add ( default 0) \param 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) const; /** \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) const; /** \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) const; /** \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) const; /** \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 closed property 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 SetClosed(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. \param timestep - default = 0 */ virtual bool IsEmpty(int timestep) const; /** \brief Returns whether the contour model is empty. */ bool IsEmpty() const override; /** \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. */ bool IsEmptyTimeStep(unsigned int t) const override; /** \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(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 */ void Initialize() override; /** \brief Initialize object with specs of other contour. Note: No data will be copied. */ - void Initialize(mitk::ContourModel &other); + void Initialize(const mitk::ContourModel &other); /*++++++++++++++++++ method inherit from base data +++++++++++++++++++++++++++*/ /** \brief Inherit from base data - no region support available for contourModel objects. */ void SetRequestedRegionToLargestPossibleRegion() override; /** \brief Inherit from base data - no region support available for contourModel objects. */ bool RequestedRegionIsOutsideOfTheBufferedRegion() override; /** \brief Inherit from base data - no region support available for contourModel objects. */ bool VerifyRequestedRegion() override; /** \brief Get the updated geometry with recomputed bounds. */ virtual const mitk::BaseGeometry *GetUpdatedGeometry(int t = 0); /** \brief Get the BaseGeometry for timestep t. */ virtual mitk::BaseGeometry *GetGeometry(int t = 0) const; /** \brief Inherit from base data - no region support available for contourModel objects. */ void SetRequestedRegion(const itk::DataObject *data) override; /** \brief Expand the timebounds of the TimeGeometry to given number of timesteps. */ void Expand(unsigned int timeSteps) override; /** \brief Update the OutputInformation of a ContourModel object The BoundingBox of the contour will be updated, if necessary. */ void UpdateOutputInformation() override; /** \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. */ void Clear() override; /** \brief overwrite if the Data can be called by an Interactor (StateMachine). */ void ExecuteOperation(Operation *operation) override; /** \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: mitkCloneMacro(Self); ContourModel(); ContourModel(const mitk::ContourModel &other); ~ContourModel() override; // inherit from BaseData. called by Clear() void ClearData() override; // inherit from BaseData. Initial state of a contour with no vertices and a single timestep. void InitializeEmpty() override; // 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