diff --git a/Core/Code/DataManagement/mitkPointSet.cpp b/Core/Code/DataManagement/mitkPointSet.cpp index 7f51b9d4da..b8d4bf0bb7 100755 --- a/Core/Code/DataManagement/mitkPointSet.cpp +++ b/Core/Code/DataManagement/mitkPointSet.cpp @@ -1,709 +1,742 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkPointSet.h" #include "mitkPointOperation.h" #include "mitkInteractionConst.h" #include mitk::PointSet::PointSet() { this->InitializeEmpty(); } mitk::PointSet::~PointSet() { this->ClearData(); } void mitk::PointSet::ClearData() { m_PointSetSeries.clear(); Superclass::ClearData(); } void mitk::PointSet::InitializeEmpty() { m_PointSetSeries.resize( 1 ); m_PointSetSeries[0] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[0]->SetPointData( pointData ); m_CalculateBoundingBox = false; Superclass::InitializeTimeSlicedGeometry(1); m_Initialized = true; } bool mitk::PointSet::IsEmpty(unsigned int t) const { return IsInitialized() && (GetSize(t) == 0); } void mitk::PointSet::Expand( unsigned int timeSteps ) { // Check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient pre-initialized // elements. // // NOTE: This method will never REDUCE the vector size; it should only // be used to make sure that the vector has enough elements to include the // specified time step. unsigned int oldSize = m_PointSetSeries.size(); if ( timeSteps > oldSize ) { Superclass::Expand( timeSteps ); m_PointSetSeries.resize( timeSteps ); for ( unsigned int i = oldSize; i < timeSteps; ++i ) { m_PointSetSeries[i] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[i]->SetPointData( pointData ); } //if the size changes, then compute the bounding box m_CalculateBoundingBox = true; this->InvokeEvent( PointSetExtendTimeRangeEvent() ); } } unsigned int mitk::PointSet::GetPointSetSeriesSize() const { return m_PointSetSeries.size(); } int mitk::PointSet::GetSize( unsigned int t ) const { if ( t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetNumberOfPoints(); } else { return 0; } } mitk::PointSet::DataType::Pointer mitk::PointSet::GetPointSet( int t ) const { if ( t < (int)m_PointSetSeries.size() ) { return m_PointSetSeries[t]; } else { return NULL; } } int mitk::PointSet::SearchPoint( Point3D point, float distance, int t ) const { if ( t >= (int)m_PointSetSeries.size() ) { return -1; } // Out is the point which is checked to be the searched point PointType out; out.Fill( 0 ); PointType indexPoint; this->GetGeometry( t )->WorldToIndex(point, indexPoint); // Searching the first point in the Set, that is +- distance far away fro // the given point unsigned int i; PointsContainer::Iterator it, end; end = m_PointSetSeries[t]->GetPoints()->End(); int bestIndex = -1; distance = distance * distance; // To correct errors from converting index to world and world to index if (distance == 0.0) { distance = 0.000001; } ScalarType bestDist = distance; ScalarType dist, tmp; for ( it = m_PointSetSeries[t]->GetPoints()->Begin(), i = 0; it != end; ++it, ++i ) { bool ok = m_PointSetSeries[t]->GetPoints() ->GetElementIfIndexExists( it->Index(), &out ); if ( !ok ) { return -1; } else if ( indexPoint == out ) //if totally equal { return it->Index(); } //distance calculation tmp = out[0] - indexPoint[0]; dist = tmp * tmp; tmp = out[1] - indexPoint[1]; dist += tmp * tmp; tmp = out[2] - indexPoint[2]; dist += tmp * tmp; if ( dist < bestDist ) { bestIndex = it->Index(); bestDist = dist; } } return bestIndex; } mitk::PointSet::PointType mitk::PointSet::GetPoint( PointIdentifier id, int t ) const { PointType out; out.Fill(0); if ( (unsigned int) t >= m_PointSetSeries.size() ) { return out; } if ( m_PointSetSeries[t]->GetPoints()->IndexExists(id) ) { m_PointSetSeries[t]->GetPoint( id, &out ); this->GetGeometry(t)->IndexToWorld( out, out ); return out; } else { return out; } } bool mitk::PointSet ::GetPointIfExists( PointIdentifier id, PointType* point, int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return false; } if ( m_PointSetSeries[t]->GetPoints()->GetElementIfIndexExists(id, point) ) { this->GetGeometry( t )->IndexToWorld( *point, *point ); return true; } else { return false; } } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { LOG_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::Geometry3D* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { LOG_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } bool mitk::PointSet::SwapPointPosition( PointIdentifier id, bool moveUpwards, int t ) { if(IndexExists(id, t) ) { PointType point = GetPoint(id,t); if(moveUpwards) {//up if(IndexExists(id-1,t)) { InsertPoint(id, GetPoint(id - 1, t), t); InsertPoint(id-1,point,t); this->Modified(); return true; } } else {//down if(IndexExists(id+1,t)) { InsertPoint(id, GetPoint(id + 1, t), t); InsertPoint(id+1,point,t); this->Modified(); return true; } } } return false; } bool mitk::PointSet::IndexExists( int position, int t ) const { if ( (unsigned int) t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetPoints()->IndexExists( position ); } else { return false; } } bool mitk::PointSet::GetSelectInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.selected; } else { return false; } } void mitk::PointSet::SetSelectInfo( int position, bool selected, int t ) { if ( this->IndexExists( position, t ) ) { // timeStep to ms ScalarType timeInMS = this->GetTimeSlicedGeometry()->TimeStepToMS( t ); // point Point3D point = this->GetPoint( position, t ); PointOperation* op; if (selected) { op = new mitk::PointOperation(OpSELECTPOINT, timeInMS, point, position ); } else { op = new mitk::PointOperation(OpDESELECTPOINT, timeInMS, point, position ); } this->ExecuteOperation( op ); } } int mitk::PointSet::GetNumberOfSelected( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return 0; } int numberOfSelected = 0; PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if (it->Value().selected == true) { ++numberOfSelected; } } return numberOfSelected; } int mitk::PointSet::SearchSelectedPoint( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return -1; } PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if ( it->Value().selected == true ) { return it->Index(); } } return -1; } void mitk::PointSet::ExecuteOperation( Operation* operation ) { int timeStep = -1; mitkCheckOperationTypeMacro(PointOperation, operation, pointOp); if ( pointOp ) { timeStep = this->GetTimeSlicedGeometry() ->MSToTimeStep( pointOp->GetTimeInMS() ); } if ( timeStep < 0 ) { LOG_ERROR << "Time step (" << timeStep << ") outside of PointSet time bounds" << std::endl; return; } switch (operation->GetOperationType()) { case OpNOTHING: break; case OpINSERT://inserts the point at the given position and selects it. { int position = pointOp->GetIndex(); PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates mitk::Geometry3D* geometry = this->GetGeometry( timeStep ); if (geometry == NULL) { - LOG_INFO<<"mitkPointSet.cpp::L362: GetGeometry returned NULL!\n"; + LOG_INFO<<"GetGeometry returned NULL!\n"; return; } geometry->WorldToIndex(pt, pt); m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position, pt); PointDataType pointData = { pointOp->GetIndex(), pointOp->GetSelected(), pointOp->GetPointType() }; m_PointSetSeries[timeStep]->GetPointData() ->InsertElement(position, pointData); this->Modified(); //boundingbox has to be computed m_CalculateBoundingBox = true; this->InvokeEvent( PointSetAddEvent() ); this->OnPointSetChange(); } break; case OpMOVE://moves the point given by index { PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates this->GetGeometry( timeStep )->WorldToIndex(pt, pt); m_PointSetSeries[timeStep]->SetPoint(pointOp->GetIndex(), pt); this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetMoveEvent() ); } break; case OpREMOVE://removes the point at given by position { - m_PointSetSeries[timeStep]->GetPoints() - ->DeleteIndex((unsigned)pointOp->GetIndex()); - m_PointSetSeries[timeStep]->GetPointData() - ->DeleteIndex((unsigned)pointOp->GetIndex()); + m_PointSetSeries[timeStep]->GetPoints()->DeleteIndex((unsigned)pointOp->GetIndex()); + m_PointSetSeries[timeStep]->GetPointData()->DeleteIndex((unsigned)pointOp->GetIndex()); this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetRemoveEvent() ); } break; case OpSELECTPOINT://select the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = true; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpDESELECTPOINT://unselect the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = false; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpSETPOINTTYPE: { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.pointSpec = pointOp->GetPointType(); m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; - case OpMOVEPOINTUP: // move point position within the pointset + case OpMOVEPOINTUP: // swap content of point with ID pointOp->GetIndex() with the point preceding it in the container // move point position within the pointset { - int position = SearchPoint(pointOp->GetPoint(), 0.0, timeStep); - mitk::Point3D point1 = pointOp->GetPoint(); - - if(position >= 1) - { - mitk::Point3D point2 = m_PointSetSeries[timeStep]->GetPoints()->GetElement(position-1); - m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position-1,point1); - m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position,point2); + PointIdentifier currentID = pointOp->GetIndex(); + /* search for point with this id and point that precedes this one in the data container */ + PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); + PointsContainer::STLContainerType::iterator it = points.find(currentID); + if (it == points.end()) // ID not found + break; + if (it == points.begin()) // we are at the first element, there is no previous element + break; + + /* get and cache current point & pointdata and previous point & pointdata */ + --it; + PointIdentifier prevID = it->first; + if (this->SwapPointContents(prevID, currentID, timeStep) == true) this->Modified(); - } - } break; case OpMOVEPOINTDOWN: // move point position within the pointset { - int position = SearchPoint(pointOp->GetPoint(), 0.0, timeStep); - mitk::Point3D point1 = pointOp->GetPoint(); - - if(position >= 0 && GetSize(timeStep) > position) - { - mitk::Point3D point2 = m_PointSetSeries[timeStep]->GetPoints()->GetElement(position+1); - m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position+1,point1); - m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position,point2); + PointIdentifier currentID = pointOp->GetIndex(); + /* search for point with this id and point that succeeds this one in the data container */ + PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); + PointsContainer::STLContainerType::iterator it = points.find(currentID); + if (it == points.end()) // ID not found + break; + ++it; + if (it == points.end()) // ID is already the last element, there is no succeeding element + break; + + /* get and cache current point & pointdata and previous point & pointdata */ + PointIdentifier nextID = it->first; + if (this->SwapPointContents(nextID, currentID, timeStep) == true) this->Modified(); - } } break; default: itkWarningMacro("mitkPointSet could not understrand the operation. Please check!"); break; } - //to tell the mappers, that the data is modifierd and has to be updated + //to tell the mappers, that the data is modified and has to be updated //only call modified if anything is done, so call in cases //this->Modified(); mitk::OperationEndEvent endevent(operation); ((const itk::Object*)this)->InvokeEvent(endevent); //*todo has to be done here, cause of update-pipeline not working yet // As discussed lately, don't mess with the rendering from inside data structures //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PointSet::UpdateOutputInformation() { if ( this->GetSource( ) ) { this->GetSource( )->UpdateOutputInformation( ); } // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as PointSets are present // mitk::TimeSlicedGeometry* timeGeometry = GetTimeSlicedGeometry(); if ( timeGeometry->GetTimeSteps() != m_PointSetSeries.size() ) { itkExceptionMacro(<<"timeGeometry->GetTimeSteps() != m_PointSetSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // // Iterate over the PointSets and update the Geometry // information of each of the items. // if (m_CalculateBoundingBox) { for ( unsigned int i = 0 ; i < m_PointSetSeries.size() ; ++i ) { const DataType::BoundingBoxType *bb = m_PointSetSeries[i]->GetBoundingBox(); BoundingBox::BoundsArrayType itkBounds = bb->GetBounds(); // Ensure minimal bounds of 1.0 in each dimension for ( unsigned int j = 0; j < 3; ++j ) { if ( itkBounds[j*2+1] - itkBounds[j*2] < 1.0 ) { BoundingBox::CoordRepType center = (itkBounds[j*2] + itkBounds[j*2+1]) / 2.0; itkBounds[j*2] = center - 0.5; itkBounds[j*2+1] = center + 0.5; } } this->GetGeometry(i)->SetBounds(itkBounds); } m_CalculateBoundingBox = false; } this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PointSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PointSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PointSet::VerifyRequestedRegion() { return true; } void mitk::PointSet::SetRequestedRegion( itk::DataObject * ) { } void mitk::PointSet::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "Number timesteps: " << m_PointSetSeries.size() << "\n"; unsigned int i = 0; for (PointSetSeries::const_iterator it = m_PointSetSeries.begin(); it != m_PointSetSeries.end(); ++it) { os << indent << "Timestep " << i++ << ": \n"; MeshType::Pointer ps = *it; itk::Indent nextIndent = indent.GetNextIndent(); ps->Print(os, nextIndent); MeshType::PointsContainer* points = ps->GetPoints(); - for (MeshType::PointsContainer::iterator it2 = points->begin(); it2 != points->end(); ++it2) + MeshType::PointDataContainer* datas = ps->GetPointData(); + MeshType::PointDataContainer::Iterator dataIterator = datas->Begin(); + for (MeshType::PointsContainer::Iterator pointIterator = points->Begin(); + pointIterator != points->End(); + ++pointIterator, ++dataIterator) { - os << nextIndent << "Point " << it2->first << ": ["; - os << it2->second.GetElement(0); + os << nextIndent << "Point " << pointIterator->Index() << ": ["; + os << pointIterator->Value().GetElement(0); for (unsigned int i = 1; i < PointType::GetPointDimension(); ++i) { - os << ", " << it2->second.GetElement(i); + os << ", " << pointIterator->Value().GetElement(i); } - os << "]\n"; + os << "]"; + os << ", selected: " << dataIterator->Value().selected << ", point spec: " << dataIterator->Value().pointSpec << "\n"; } } } + +bool mitk::PointSet::SwapPointContents(PointIdentifier id1, PointIdentifier id2, int timeStep) +{ + /* search and cache contents */ + PointType p1; + if (m_PointSetSeries[timeStep]->GetPoint(id1, &p1) == false) + return false; + PointDataType data1; + if (m_PointSetSeries[timeStep]->GetPointData(id1, &data1) == false) + return false; + PointType p2; + if (m_PointSetSeries[timeStep]->GetPoint(id2, &p2) == false) + return false; + PointDataType data2; + if (m_PointSetSeries[timeStep]->GetPointData(id2, &data2) == false) + return false; + /* now swap contents */ + m_PointSetSeries[timeStep]->SetPoint(id1, p2); + m_PointSetSeries[timeStep]->SetPointData(id1, data2); + m_PointSetSeries[timeStep]->SetPoint(id2, p1); + m_PointSetSeries[timeStep]->SetPointData(id2, data1); + return true; +} \ No newline at end of file diff --git a/Core/Code/DataManagement/mitkPointSet.h b/Core/Code/DataManagement/mitkPointSet.h index 5ceb2a8e04..a522c298f3 100755 --- a/Core/Code/DataManagement/mitkPointSet.h +++ b/Core/Code/DataManagement/mitkPointSet.h @@ -1,269 +1,270 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKPointSet_H_HEADER_INCLUDED #define MITKPointSet_H_HEADER_INCLUDED #include "mitkBaseData.h" #include #include namespace mitk { /** * \brief Data structure which stores a set of points. Superclass of * mitk::Mesh. * * 3D points are grouped within a point set; for time resolved usage, one point * set is created and maintained per time step. A point entry consists of the * point coordinates and point data. * * The point data includes a point ID (unique identifier to address this point * within the point set), the selection state of the point and the type of * the point. * * For further information about different point types see * mitk::PointSpecificationType in mitkVector.h. * * Inserting a point is accompanied by an event, containing an index. The new * point is inserted into the list at the specified position. At the same time * an internal ID is generated and stored for the point. Points at specific time * steps are accessed by specifying the time step number (which defaults to 0). * * The points of itk::PointSet stores the points in a pointContainer * (MapContainer). The points are best accessed by using a ConstIterator (as * defined in MapContainer); avoid access via index. * * The class internally uses an itk::Mesh for each time step, because * mitk::Mesh is derived from mitk::PointSet and needs the itk::Mesh structure * which is also derived from itk::PointSet. Thus several typedefs which seem * to be in wrong place, are declared here (for example SelectedLinesType). * * \section mitkPointSetDisplayOptions * * The default mappers for this data structure are mitk::PointSetMapper2D and * mitk::PointSetVtkMapper3D. See these classes for display options which can * can be set via properties. * * \section Events * * PointSet issues the following events, for which observers can register * (the below events are grouped into a class hierarchy as indicated by * identation level; e.g. PointSetSizeChangeEvent comprises PointSetAddEvent * and PointSetRemoveEvent): * * * PointSetEvent subsumes all PointSet events * PointSetMoveEvent issued when a point of the PointSet is moved * PointSetSizeChangeEvent subsumes add and remove events * PointSetAddEvent issued when a point is added to the PointSet * PointSetRemoveEvent issued when a point is removed from the PointSet * * * \ingroup Data */ class MITK_CORE_EXPORT PointSet : public BaseData { public: mitkClassMacro(PointSet, BaseData); itkNewMacro(Self); typedef mitk::ScalarType CoordinateType; typedef mitk::ScalarType InterpolationWeightType; static const unsigned int PointDimension = 3; static const unsigned int MaxTopologicalDimension = 3; /** * \brief struct for data of a point */ struct PointDataType { unsigned int id; //to give the point a special ID bool selected; //information about if the point is selected mitk::PointSpecificationType pointSpec; //specifies the type of the point }; /** * \brief cellDataType, that stores all indexes of the lines, that are * selected e.g.: points A,B and C.Between A and B there is a line with * index 0. If vector of cellData contains 1 and 2, then the lines between * B and C and C and A is selected. */ typedef std::vector SelectedLinesType; typedef SelectedLinesType::iterator SelectedLinesIter; struct CellDataType { //used to set the whole cell on selected bool selected; //indexes of selected lines. 0 is between pointId 0 and 1 SelectedLinesType selectedLines; //is the polygon already finished and closed bool closed; }; typedef itk::DefaultDynamicMeshTraits< PointDataType, PointDimension, MaxTopologicalDimension, CoordinateType, InterpolationWeightType, CellDataType > MeshTraits; typedef itk::Mesh MeshType; typedef MeshType DataType; typedef DataType::PointType PointType; typedef DataType::PointIdentifier PointIdentifier; typedef DataType::PointsContainer PointsContainer; typedef DataType::PointsContainerIterator PointsIterator; typedef DataType::PointsContainer::ConstIterator PointsConstIterator; typedef DataType::PointDataContainer PointDataContainer; typedef DataType::PointDataContainerIterator PointDataIterator; virtual void Expand( unsigned int timeSteps ); /** \brief executes the given Operation */ virtual void ExecuteOperation(Operation* operation); /** \brief returns the current size of the point-list */ virtual int GetSize( unsigned int t = 0 ) const; virtual unsigned int GetPointSetSeriesSize() const; /** \brief returns the pointset */ virtual DataType::Pointer GetPointSet( int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * check if the ID exists. If it doesn't exist, then return 0,0,0 */ PointType GetPoint( PointIdentifier id, int t = 0 ) const; /** * \brief Get the point with ID id in world coordinates * * If a point exists for the ID id, the point is returned in the parameter point * and the method returns true. If the ID does not exist, the method returns false */ bool GetPointIfExists( PointIdentifier id, PointType* point, int t = 0 ) const; /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void SetPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with the given PointSpecificationType */ void SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t = 0 ); /** * \brief Set the given point in world coordinate system into the itkPointSet. */ void InsertPoint( PointIdentifier id, PointType point, int t = 0 ); /** * \brief Set the given point in world coordinate system with given PointSpecificationType */ void InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ); /** * \brief Swap a point at the given position (id) with the upper point (moveUpwards=true) or with the lower point (moveUpwards=false). * If upper or lower index does not exist false is returned, if swap was successful true. */ bool SwapPointPosition( PointIdentifier id, bool moveUpwards, int t = 0 ); /** * \brief searches a selected point and returns the id of that point. * If no point is found, then -1 is returned */ virtual int SearchSelectedPoint( int t = 0 ) const; /** \brief returns true if a point exists at this position */ virtual bool IndexExists( int position, int t = 0 ) const; /** \brief to get the state selected/unselected of the point on the * position */ virtual bool GetSelectInfo( int position, int t = 0 ) const; virtual void SetSelectInfo( int position, bool selected, int t = 0 ); /** \brief returns the number of selected points */ virtual int GetNumberOfSelected( int t = 0 ) const; /** * \brief searches a point in the list == point +/- distance * * \param point is in world coordinates. * \param distance is in mm. * returns -1 if no point is found * or the position in the list of the first match */ int SearchPoint( Point3D point, float distance, int t = 0 ) const; virtual bool IsEmpty(unsigned int t) const; //virtual methods, that need to be implemented virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(itk::DataObject *data); //Method for subclasses virtual void OnPointSetChange(){}; protected: PointSet(); virtual ~PointSet(); virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; ///< print content of the object to os virtual void ClearData(); virtual void InitializeEmpty(); + /** \brief swaps point coordinates and point data of the points with identifiers id1 and id2 */ + bool SwapPointContents(PointIdentifier id1, PointIdentifier id2, int t = 0 ); + typedef std::vector< DataType::Pointer > PointSetSeries; PointSetSeries m_PointSetSeries; /** * @brief flag to indicate the right time to call SetBounds **/ bool m_CalculateBoundingBox; - }; - itkEventMacro( PointSetEvent, itk::AnyEvent ); itkEventMacro( PointSetMoveEvent, PointSetEvent ); itkEventMacro( PointSetSizeChangeEvent, PointSetEvent ); itkEventMacro( PointSetAddEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetRemoveEvent, PointSetSizeChangeEvent ); itkEventMacro( PointSetExtendTimeRangeEvent, PointSetEvent ); } // namespace mitk #endif /* MITKPointSet_H_HEADER_INCLUDED */ diff --git a/Core/Code/Testing/mitkPointSetTest.cpp b/Core/Code/Testing/mitkPointSetTest.cpp index ad75da0b70..567c10c9c1 100644 --- a/Core/Code/Testing/mitkPointSetTest.cpp +++ b/Core/Code/Testing/mitkPointSetTest.cpp @@ -1,329 +1,418 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include #include #include #include int mitkPointSetTest(int /*argc*/, char* /*argv*/[]) { //Create PointSet mitk::PointSet::Pointer pointSet; pointSet = mitk::PointSet::New(); //try to get the itkPointSet std::cout << "try to get the itkPointSet from a newly created PointSet "; mitk::PointSet::DataType::Pointer itkdata = NULL; itkdata = pointSet->GetPointSet(); if (itkdata.IsNull()) { std::cout<<"[FAILED]"<GetSize() != 0) { std::cout<<"[FAILED]"<IsEmpty(0)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); //now check new condition! if ( (pointSet->GetSize()!=1) || - (!pointSet->IndexExists(position))) + (!pointSet->IndexExists(id))) { std::cout<<"[FAILED]"<GetPoint(position); + tempPoint = pointSet->GetPoint(id); if (tempPoint != point) { std::cout<<"[FAILED]"<GetPointSet()->GetPoints()->InsertElement(position, point); + ++id; + pointSet->GetPointSet()->GetPoints()->InsertElement(id, point); //now check new condition! if ( (pointSet->GetSize()!=2) || - (!pointSet->IndexExists(position))) + (!pointSet->IndexExists(id))) { std::cout<<"[FAILED]"<GetPoint(position); + tempPoint = pointSet->GetPoint(id); if (tempPoint != point) { std::cout<<"[FAILED]"<IsEmpty(0)) { std::cout<<"[FAILED]"<GetPoint(1); pointSet->SwapPointPosition(1, true); tempPoint = pointSet->GetPoint(0); if(point != tempPoint) { std::cout<<"[FAILED]"<SwapPointPosition(0, true)) { std::cout<<"[FAILED]"<GetPoint(0); pointSet->SwapPointPosition(0, false); tempPoint = pointSet->GetPoint(1); if(point != tempPoint) { std::cout<<"[FAILED]"<SwapPointPosition(1, false)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); - tempPoint = pointSet->GetPoint(position); + tempPoint = pointSet->GetPoint(id); if (tempPoint != point1) { std::cout<<"[FAILED]"<InsertPoint(2,point2); pointSet->InsertPoint(3,point3); pointSet->InsertPoint(4,point4); //check OpREMOVE ExecuteOperation std::cout << "check PointOperation OpREMOVE "; - position=0; - point = pointSet->GetPoint(position); + id=0; + point = pointSet->GetPoint(id); int size = pointSet->GetSize(); - doOp = new mitk::PointOperation(mitk::OpREMOVE, point, position); + doOp = new mitk::PointOperation(mitk::OpREMOVE, point, id); pointSet->ExecuteOperation(doOp); - tempPoint = pointSet->GetPoint(position); + tempPoint = pointSet->GetPoint(id); int tempSize = pointSet->GetSize(); - if(pointSet->IndexExists(position)) + if(pointSet->IndexExists(id)) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); if (!pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() != 1) { std::cout<<"[FAILED]"<SearchSelectedPoint() != 4) { std::cout<<"[FAILED]"<ExecuteOperation(doOp); if (pointSet->GetSelectInfo(4)) { std::cout<<"[FAILED]"<GetNumberOfSelected() != 0) { std::cout<<"[FAILED]"<GetPoint(position); - doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, point4, position); + id = 4; + point = pointSet->GetPoint(id); + doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, point4, id); pointSet->ExecuteOperation(doOp); - tempPoint = pointSet->GetPoint(position-1); + tempPoint = pointSet->GetPoint(id-1); if (tempPoint != point) { std::cout<<"[FAILED]"<GetPoint(position); - doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, point2, position); + id = 2; + point = pointSet->GetPoint(id); + doOp = new mitk::PointOperation(mitk::OpMOVEPOINTDOWN, point2, id); pointSet->ExecuteOperation(doOp); - tempPoint = pointSet->GetPoint(position+1); + tempPoint = pointSet->GetPoint(id+1); if (tempPoint != point) { std::cout<<"[FAILED]"<SetSelectInfo(2, true); if (!pointSet->GetSelectInfo(2)) { std::cout<<"[FAILED]"<SetPoint(5, point5, mitk::PTEDGE ); tempPoint = pointSet->GetPoint(5); if (tempPoint != point5) { std::cout<<"[FAILED]"<GetPointIfExists(5,&tmpPoint); + pointSet->GetPointIfExists(5, &tmpPoint); if (tmpPoint != point5) { std::cout<<"[FAILED]"<InsertPoint(10, p10); + pointSet->InsertPoint(11, p11); + pointSet->InsertPoint(12, p12); + if ((pointSet->IndexExists(10) == false) || (pointSet->IndexExists(11) == false) || (pointSet->IndexExists(12) == false)) + { + std::cout<<"[FAILED]"<ExecuteOperation(doOp); + if(pointSet->IndexExists(id)) + { + std::cout<<"[FAILED]"<ExecuteOperation(doOp); + delete doOp; + mitk::PointSet::PointType newP10 = pointSet->GetPoint(10); + mitk::PointSet::PointType newP12 = pointSet->GetPoint(12); + if (((newP10 == p12) && (newP12 == p10)) == false) + { + std::cout<<"[FAILED]"<ExecuteOperation(doOp); + delete doOp; + newP10 = pointSet->GetPoint(10); + newP12 = pointSet->GetPoint(12); + if (((newP10 == p10) && (newP12 == p12)) == false) + { + std::cout<<"[FAILED]"<ExecuteOperation(doOp); + delete doOp; + newP10 = pointSet->GetPoint(10); + newP12 = pointSet->GetPoint(12); + if (((newP10 == p10) && (newP12 == p12)) == false) + { + std::cout<<"[FAILED]"<GetPoint(1); + mitk::PointSet::PointType p2 = pointSet->GetPoint(2); + doOp = new mitk::PointOperation(mitk::OpMOVEPOINTUP, p1, 1); + pointSet->ExecuteOperation(doOp); + delete doOp; + mitk::PointSet::PointType newP1 = pointSet->GetPoint(1); + mitk::PointSet::PointType newP2 = pointSet->GetPoint(2); + if (((newP1 == p1) && (newP2 == p2)) == false) + { + std::cout<<"[FAILED]"<