diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index 264a7973af..1f2657ed1b 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,757 +1,774 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigure.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" #include #include "algorithm" mitk::PlanarFigure::PolyLineElement::PolyLineElement(Point2D point, int index) : Point(point), Index(index) { } mitk::PlanarFigure::PolyLineElement::PolyLineElement(const Point2D& point) : Point(point), Index(-1) { } +mitk::PlanarFigure::PolyLineElement::PolyLineElement(const PolyLineElement &other) + : Point(other.Point), + Index(other.Index) +{ +} + +mitk::PlanarFigure::PolyLineElement& mitk::PlanarFigure::PolyLineElement::operator=(const PolyLineElement &other) +{ + if (this != &other) + { + Point = other.Point; + Index = other.Index; + } + + return *this; +} + mitk::PlanarFigure::PolyLineElement::operator mitk::Point2D&() { return Point; } mitk::PlanarFigure::PolyLineElement::operator const mitk::Point2D&() const { return Point; } mitk::PlanarFigure::PlanarFigure() : m_SelectedControlPoint( -1 ), m_PreviewControlPointVisible( false ), m_FigurePlaced( false ), m_Geometry2D( NULL ), m_PolyLineUpToDate(false), m_HelperLinesUpToDate(false), m_FeaturesUpToDate(false), m_FeaturesMTime( 0 ) { m_HelperPolyLinesToBePainted = BoolContainerType::New(); m_DisplaySize.first = 0.0; m_DisplaySize.second = 0; this->SetProperty( "closed", mitk::BoolProperty::New( false ) ); // Currently only single-time-step geometries are supported this->InitializeTimeGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } mitk::PlanarFigure::PlanarFigure(const Self& other) : BaseData(other), m_ControlPoints(other.m_ControlPoints), m_NumberOfControlPoints(other.m_NumberOfControlPoints), m_SelectedControlPoint(other.m_SelectedControlPoint), m_PolyLines(other.m_PolyLines), m_HelperPolyLines(other.m_HelperPolyLines), m_HelperPolyLinesToBePainted(other.m_HelperPolyLinesToBePainted->Clone()), m_PreviewControlPoint(other.m_PreviewControlPoint), m_PreviewControlPointVisible(other.m_PreviewControlPointVisible), m_FigurePlaced(other.m_FigurePlaced), m_Geometry2D(other.m_Geometry2D), // do not clone since SetGeometry2D() doesn't clone either m_PolyLineUpToDate(other.m_PolyLineUpToDate), m_HelperLinesUpToDate(other.m_HelperLinesUpToDate), m_FeaturesUpToDate(other.m_FeaturesUpToDate), m_Features(other.m_Features), m_FeaturesMTime(other.m_FeaturesMTime), m_DisplaySize(other.m_DisplaySize) { } void mitk::PlanarFigure::SetGeometry2D( mitk::Geometry2D *geometry ) { this->SetGeometry( geometry ); m_Geometry2D = dynamic_cast(GetGeometry(0));//geometry; } const mitk::Geometry2D *mitk::PlanarFigure::GetGeometry2D() const { return m_Geometry2D; } bool mitk::PlanarFigure::IsClosed() const { mitk::BoolProperty* closed = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "closed" ).GetPointer() ); if ( closed != NULL ) { return closed->GetValue(); } return false; } void mitk::PlanarFigure::PlaceFigure( const mitk::Point2D& point ) { for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( i, point ) ); } m_FigurePlaced = true; m_SelectedControlPoint = 1; } bool mitk::PlanarFigure::AddControlPoint( const mitk::Point2D& point, int position ) { // if we already have the maximum number of control points, do nothing if ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() ) { // if position has not been defined or position would be the last control point, just append the new one // we also append a new point if we click onto the line between the first two control-points if the second control-point is selected // -> special case for PlanarCross if ( position == -1 || position > (int)m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) ) { if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 ) { // get rid of deprecated control points in the list. This is necessary // as ::ResetNumberOfControlPoints() only sets the member, does not resize the list! m_ControlPoints.resize( this->GetNumberOfControlPoints() ); } m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { // insert the point at the given position and set it as selected point ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) ); for( unsigned int i = 0; i < m_ControlPoints.size(); ++i ) { if( point == m_ControlPoints.at(i) ) { m_SelectedControlPoint = i; } } } // polylines & helperpolylines need to be repainted m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; // one control point more ++m_NumberOfControlPoints; return true; } else { return false; } } bool mitk::PlanarFigure::SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist ) { bool controlPointSetCorrectly = false; if (createIfDoesNotExist) { if ( m_NumberOfControlPoints <= index ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( index, point ) ); m_NumberOfControlPoints++; } else { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); } controlPointSetCorrectly = true; } else if ( index < m_NumberOfControlPoints ) { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); controlPointSetCorrectly = true; } else { return false; } if ( controlPointSetCorrectly ) { m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; } return controlPointSetCorrectly; } bool mitk::PlanarFigure::SetCurrentControlPoint( const Point2D& point ) { if ( (m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints) ) { return false; } return this->SetControlPoint(m_SelectedControlPoint, point, false); } unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const { return m_NumberOfControlPoints; } bool mitk::PlanarFigure::SelectControlPoint( unsigned int index ) { if ( index < this->GetNumberOfControlPoints() ) { m_SelectedControlPoint = index; return true; } else { return false; } } bool mitk::PlanarFigure::DeselectControlPoint() { bool wasSelected = ( m_SelectedControlPoint != -1); m_SelectedControlPoint = -1; return wasSelected; } void mitk::PlanarFigure::SetPreviewControlPoint( const Point2D& point ) { m_PreviewControlPoint = point; m_PreviewControlPointVisible = true; } void mitk::PlanarFigure::ResetPreviewContolPoint() { m_PreviewControlPointVisible = false; } mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint() { return m_PreviewControlPoint; } bool mitk::PlanarFigure::IsPreviewControlPointVisible() { return m_PreviewControlPointVisible; } mitk::Point2D mitk::PlanarFigure::GetControlPoint( unsigned int index ) const { if ( index < m_NumberOfControlPoints ) { return m_ControlPoints.at( index ); } itkExceptionMacro( << "GetControlPoint(): Invalid index!" ); } mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint( unsigned int index ) const { Point3D point3D; if ( (m_Geometry2D != NULL) && (index < m_NumberOfControlPoints) ) { m_Geometry2D->Map( m_ControlPoints.at( index ), point3D ); return point3D; } itkExceptionMacro( << "GetWorldControlPoint(): Invalid index!" ); } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) { mitk::PlanarFigure::PolyLineType polyLine; if ( index > m_PolyLines.size() || !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.at( index );; } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) const { return m_PolyLines.at( index ); } void mitk::PlanarFigure::ClearPolyLines() { for ( std::vector::size_type i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight); m_HelperLinesUpToDate = true; // store these parameters to be able to check next time if somebody zoomed in or out m_DisplaySize.first = mmPerDisplayUnit; m_DisplaySize.second = displayHeight; } helperPolyLine = m_HelperPolyLines.at(index); } return helperPolyLine; } void mitk::PlanarFigure::ClearHelperPolyLines() { for ( std::vector::size_type i=0; iGeneratePolyLine(); } this->EvaluateFeaturesInternal(); m_FeaturesUpToDate = true; } } void mitk::PlanarFigure::UpdateOutputInformation() { // Bounds are NOT calculated here, since the Geometry2D defines a fixed // frame (= bounds) for the planar figure. Superclass::UpdateOutputInformation(); this->GetTimeGeometry()->Update(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion(const itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { // DO NOT resize the list here, will cause crash!! m_NumberOfControlPoints = numberOfControlPoints; } mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ) { if ( m_Geometry2D == NULL ) { return point; } Point2D indexPoint; m_Geometry2D->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = m_Geometry2D->GetBounds(); if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; } if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; } if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; } if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; } Point2D constrainedPoint; m_Geometry2D->IndexToWorld( indexPoint, constrainedPoint ); return constrainedPoint; } unsigned int mitk::PlanarFigure::AddFeature( const char *featureName, const char *unitName ) { unsigned int index = m_Features.size(); Feature newFeature( featureName, unitName ); m_Features.push_back( newFeature ); return index; } void mitk::PlanarFigure::SetFeatureName( unsigned int index, const char *featureName ) { if ( index < m_Features.size() ) { m_Features[index].Name = featureName; } } void mitk::PlanarFigure::SetFeatureUnit( unsigned int index, const char *unitName ) { if ( index < m_Features.size() ) { m_Features[index].Unit = unitName; } } void mitk::PlanarFigure::SetQuantity( unsigned int index, double quantity ) { if ( index < m_Features.size() ) { m_Features[index].Quantity = quantity; } } void mitk::PlanarFigure::ActivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = true; } } void mitk::PlanarFigure::DeactivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = false; } } void mitk::PlanarFigure::InitializeTimeGeometry( unsigned int timeSteps ) { mitk::Geometry2D::Pointer geometry2D = mitk::Geometry2D::New(); geometry2D->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; geometry2D->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to all time steps, // if EvenlyTimed is true... ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(geometry2D, timeSteps); SetTimeGeometry(timeGeometry); } void mitk::PlanarFigure::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << this->GetNameOfClass() << ":\n"; if (this->IsClosed()) os << indent << "This figure is closed\n"; else os << indent << "This figure is not closed\n"; os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl; os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl; os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl; os << indent << "Control points:" << std::endl; for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { //os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl; os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at( i ) << std::endl; } os << indent << "Geometry:\n"; this->GetGeometry2D()->Print(os, indent.GetNextIndent()); } unsigned short mitk::PlanarFigure::GetPolyLinesSize() { if ( !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.size(); } unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize() { return m_HelperPolyLines.size(); } bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index) { return m_HelperPolyLinesToBePainted->GetElement( index ); } bool mitk::PlanarFigure::ResetOnPointSelect() { return false; } void mitk::PlanarFigure::RemoveControlPoint( unsigned int index ) { if ( index > m_ControlPoints.size() ) return; if ( (m_ControlPoints.size() -1) < this->GetMinimumNumberOfControlPoints() ) return; ControlPointListType::iterator iter; iter = m_ControlPoints.begin() + index; m_ControlPoints.erase( iter ); m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; --m_NumberOfControlPoints; } void mitk::PlanarFigure::RemoveLastControlPoint() { RemoveControlPoint( m_ControlPoints.size()-1 ); } void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure) { //DeepCopy only same types of planar figures //Notice to get typeid polymorph you have to use the *operator if(typeid(*oldFigure) != typeid(*this)) { itkExceptionMacro( << "DeepCopy(): Inconsistent type of source (" << typeid(*oldFigure).name() << ") and destination figure (" << typeid(*this).name() << ")!" ); return; } m_ControlPoints.clear(); this->ClearPolyLines(); this->ClearHelperPolyLines(); // clone base data members SetPropertyList(oldFigure->GetPropertyList()->Clone()); /// deep copy members m_FigurePlaced = oldFigure->m_FigurePlaced; m_SelectedControlPoint = oldFigure->m_SelectedControlPoint; m_FeaturesMTime = oldFigure->m_FeaturesMTime; m_Features = oldFigure->m_Features; m_NumberOfControlPoints = oldFigure->m_NumberOfControlPoints; //copy geometry 2D of planar figure Geometry2D::Pointer affineGeometry = oldFigure->m_Geometry2D->Clone(); SetGeometry2D(affineGeometry.GetPointer()); for(unsigned long index=0; index < oldFigure->GetNumberOfControlPoints(); index++) { m_ControlPoints.push_back( oldFigure->GetControlPoint( index )); } //After setting the control points we can generate the polylines this->GeneratePolyLine(); } void mitk::PlanarFigure::SetNumberOfPolyLines( unsigned int numberOfPolyLines ) { m_PolyLines.resize(numberOfPolyLines); } void mitk::PlanarFigure::SetNumberOfHelperPolyLines( unsigned int numberOfHerlperPolyLines ) { m_HelperPolyLines.resize(numberOfHerlperPolyLines); } void mitk::PlanarFigure::AppendPointToPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_PolyLines.size() ) { if(element.Index == -1) element.Index = m_PolyLines[index].size(); m_PolyLines[index].push_back(element); m_PolyLineUpToDate = false; } else { MITK_ERROR << "Tried to add point to PolyLine " << index+1 << ", although only " << m_PolyLines.size() << " exists"; } } void mitk::PlanarFigure::AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_HelperPolyLines.size() ) { if(element.Index == -1) element.Index = m_HelperPolyLines[index].size(); m_HelperPolyLines[index].push_back(element); m_HelperLinesUpToDate = false; } else { MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h index 7caa75e3b2..6078ce0061 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.h @@ -1,423 +1,426 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_FIGURE_H_ #define _MITK_PLANAR_FIGURE_H_ #include #include "mitkBaseData.h" #include "mitkCommon.h" #include namespace mitk { class Geometry2D; /** * \brief Base-class for geometric planar (2D) figures, such as * lines, circles, rectangles, polygons, etc. * * \warning Currently does not support time-resolved data handling * * Behavior and appearance of PlanarFigures are controlled by various properties; for a detailed * list of appearance properties see mitk::PlanarFigureMapper2D * * The following properties control general PlanarFigure behavior: * *
    *
  • "selected": true if the planar figure is selected *
  • "planarfigure.ishovering": true if the mouse "hovers" over the planar figure *
  • "planarfigure.iseditable": true if the planar figure can be edited (otherwise, * it can only be picked/selected, but its control points cannot be edited); default is true *
  • "planarfigure.isextendable": true if new control points can be inserted into the list of control points; * default is false *
* * * TODO: Implement local 2D transform (including center of rotation...) * */ class MitkPlanarFigure_EXPORT PlanarFigure : public BaseData { public: mitkClassMacro( PlanarFigure, BaseData ) itkCloneMacro( Self ) /** \brief Treat as Point2D by implicitly using conversion operators. * * \deprecatedSince{2014_06} "struct PolyLineElement {...};" will be changed to "typedef Point2D PolyLineElement;". */ struct MitkPlanarFigure_EXPORT PolyLineElement { DEPRECATED(PolyLineElement(Point2D point, int index)); PolyLineElement(const Point2D& point); + PolyLineElement(const PolyLineElement &other); + PolyLineElement& operator=(const PolyLineElement &other); + operator Point2D&(); operator const Point2D&() const; DEPRECATED(Point2D Point); DEPRECATED(int Index); }; typedef itk::VectorContainer< unsigned long, bool> BoolContainerType; typedef std::deque< Point2D > ControlPointListType; typedef std::vector< PolyLineElement > PolyLineType; /** \brief Sets the 2D geometry on which this figure will be placed. * * In most cases, this is a Geometry already owned by another object, e.g. * describing the slice of the image on which measurements will be * performed. */ virtual void SetGeometry2D( mitk::Geometry2D *geometry ); /** \brief Returns (previously set) 2D geometry of this figure. */ virtual const Geometry2D *GetGeometry2D() const; /** \brief True if the planar figure is closed. * * Default is false. The "closed" boolean property must be set in sub-classes. */ virtual bool IsClosed() const; /** \brief True if the planar figure has been placed (and can be * displayed/interacted with). */ virtual bool IsPlaced() const { return m_FigurePlaced; }; /** \brief Place figure at the given point (in 2D index coordinates) onto * the given 2D geometry. * * By default, the first two control points of the figure are set to the * passed point. Further points can be set via AddControlPoint(), if the * current number of control points is below the maximum number of control * points. * * Can be re-implemented in sub-classes as needed. */ virtual void PlaceFigure( const Point2D& point ); /** * \brief Adds / inserts new control-points * * This method adds a new control-point with the coordinates defined by point at the given index. * If 'index' == -1 or index is greater than the number of control-points the new point is appended * to the back of the list of control points. * If a control-point already exists for 'index', an additional point is inserted at that position. * It is not possible to add more points if the maximum number of control-points (GetMaximumNumberOfControlPoints()) * has been reached. */ virtual bool AddControlPoint( const Point2D& point, int index = -1 ); virtual bool SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist = false); virtual bool SetCurrentControlPoint( const Point2D& point ); /** \brief Returns the current number of 2D control points defining this figure. */ unsigned int GetNumberOfControlPoints() const; /** \brief Returns the minimum number of control points needed to represent * this figure. * * Must be implemented in sub-classes. */ virtual unsigned int GetMinimumNumberOfControlPoints() const = 0; /** \brief Returns the maximum number of control points allowed for * this figure (e.g. 3 for triangles). * * Must be implemented in sub-classes. */ virtual unsigned int GetMaximumNumberOfControlPoints() const = 0; /** \brief Selects currently active control points. */ virtual bool SelectControlPoint( unsigned int index ); /** \brief Deselect control point; no control point active. */ virtual bool DeselectControlPoint(); /** \brief Return currently selected control point. */ virtual int GetSelectedControlPoint() const { return m_SelectedControlPoint; } /** \brief Returns specified control point in 2D world coordinates. */ Point2D GetControlPoint( unsigned int index ) const; /** \brief Returns specified control point in world coordinates. */ Point3D GetWorldControlPoint( unsigned int index ) const; /** \brief Returns the polyline representing the planar figure * (for rendering, measurements, etc.). */ const PolyLineType GetPolyLine(unsigned int index); /** \brief Returns the polyline representing the planar figure * (for rendering, measurments, etc.). */ const PolyLineType GetPolyLine(unsigned int index) const; /** \brief Returns the polyline that should be drawn the same size at every scale * (for text, angles, etc.). */ const PolyLineType GetHelperPolyLine( unsigned int index, double mmPerDisplayUnit, unsigned int displayHeight ); /** \brief Sets the position of the PreviewControlPoint. Automatically sets it visible.*/ void SetPreviewControlPoint( const Point2D& point ); /** \brief Marks the PreviewControlPoint as invisible.*/ void ResetPreviewContolPoint(); /** \brief Returns whether or not the PreviewControlPoint is visible.*/ bool IsPreviewControlPointVisible(); /** \brief Returns the coordinates of the PreviewControlPoint. */ Point2D GetPreviewControlPoint(); /** \brief Returns the number of features available for this PlanarFigure * (such as, radius, area, ...). */ virtual unsigned int GetNumberOfFeatures() const; /** \brief Returns the name (identifier) of the specified features. */ const char *GetFeatureName( unsigned int index ) const; /** \brief Returns the physical unit of the specified features. */ const char *GetFeatureUnit( unsigned int index ) const; /** Returns quantity of the specified feature (e.g., length, radius, * area, ... ) */ double GetQuantity( unsigned int index ) const; /** \brief Returns true if the feature with the specified index exists and * is active (an inactive feature may e.g. be the area of a non-closed * polygon. */ bool IsFeatureActive( unsigned int index ) const; /** \brief Returns true if the feature with the specified index exists and is set visible */ bool IsFeatureVisible( unsigned int index ) const; /** \brief Defines if the feature with the specified index will be shown as an * overlay in the RenderWindow */ void SetFeatureVisible( unsigned int index, bool visible ); /** \brief Calculates quantities of all features of this planar figure. */ virtual void EvaluateFeatures(); /** \brief Intherited from parent */ virtual void UpdateOutputInformation(); /** \brief Intherited from parent */ virtual void SetRequestedRegionToLargestPossibleRegion(); /** \brief Intherited from parent */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); /** \brief Intherited from parent */ virtual bool VerifyRequestedRegion(); /** \brief Intherited from parent */ virtual void SetRequestedRegion( const itk::DataObject *data); /** \brief Returns the current number of polylines */ virtual unsigned short GetPolyLinesSize(); /** \brief Returns the current number of helperpolylines */ virtual unsigned short GetHelperPolyLinesSize(); /** \brief Returns whether a helper polyline should be painted or not */ virtual bool IsHelperToBePainted(unsigned int index); /** \brief Returns true if the planar figure is reset to "add points" mode * when a point is selected. * * Default return value is false. Subclasses can overwrite this method and * execute any reset / initialization statements required. */ virtual bool ResetOnPointSelect(); /** \brief removes the point with the given index from the list of controlpoints. */ virtual void RemoveControlPoint( unsigned int index ); /** \brief Removes last control point */ virtual void RemoveLastControlPoint(); /** \brief Copies contents and state of a figre provided as parameter to the current object. * * Requires a matching type of both figures. * * \note Deprecated, use Clone() instead. */ DEPRECATED(void DeepCopy(Self::Pointer oldFigure)); /** \brief Allow sub-classes to apply constraints on control points. * * Sub-classes can define spatial constraints to certain control points by * overwriting this method and returning a constrained point. By default, * the points are constrained by the image bounds. */ virtual Point2D ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ); protected: PlanarFigure(); virtual ~PlanarFigure(); PlanarFigure(const Self& other); /** \brief Set the initial number of control points of the planar figure */ void ResetNumberOfControlPoints( int numberOfControlPoints ); /** Adds feature (e.g., circumference, radius, angle, ...) to feature vector * of a planar figure object and returns integer ID for the feature element. * Should be called in sub-class constructors. */ virtual unsigned int AddFeature( const char *featureName, const char *unitName ); /** Sets the name of the specified feature. INTERNAL METHOD. */ void SetFeatureName( unsigned int index, const char *featureName ); /** Sets the physical unit of the specified feature. INTERNAL METHOD. */ void SetFeatureUnit( unsigned int index, const char *unitName ); /** Sets quantity of the specified feature. INTERNAL METHOD. */ void SetQuantity( unsigned int index, double quantity ); /** Sets the specified feature as active. INTERAL METHOD. */ void ActivateFeature( unsigned int index ); /** Sets the specified feature as active. INTERAL METHOD. */ void DeactivateFeature( unsigned int index ); /** \brief Generates the poly-line representation of the planar figure. * Must be implemented in sub-classes. */ virtual void GeneratePolyLine() = 0; /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom. * Must be implemented in sub-classes. */ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) = 0; /** \brief Calculates quantities of all features of this planar figure. * Must be implemented in sub-classes. */ virtual void EvaluateFeaturesInternal() = 0; /** \brief Initializes the TimeGeometry describing the (time-resolved) * geometry of this figure. Note that each time step holds one Geometry2D. */ virtual void InitializeTimeGeometry( unsigned int timeSteps = 1 ); /** \brief defines the number of PolyLines that will be available */ void SetNumberOfPolyLines( unsigned int numberOfPolyLines ); /** \brief Append a point to the PolyLine # index */ void AppendPointToPolyLine( unsigned int index, PolyLineElement element ); /** \brief clears the list of PolyLines. Call before re-calculating a new Polyline. */ void ClearPolyLines(); /** \brief defines the number of HelperPolyLines that will be available */ void SetNumberOfHelperPolyLines( unsigned int numberOfHelperPolyLines ); /** \brief Append a point to the HelperPolyLine # index */ void AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ); /** \brief clears the list of HelperPolyLines. Call before re-calculating a new HelperPolyline. */ void ClearHelperPolyLines(); virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; ControlPointListType m_ControlPoints; unsigned int m_NumberOfControlPoints; // Currently selected control point; -1 means no point selected int m_SelectedControlPoint; std::vector m_PolyLines; std::vector m_HelperPolyLines; BoolContainerType::Pointer m_HelperPolyLinesToBePainted; // this point is used to store the coordiantes an additional 'ControlPoint' that is rendered // when the mouse cursor is above the figure (and not a control-point) and when the // property 'planarfigure.isextendable' is set to true Point2D m_PreviewControlPoint; bool m_PreviewControlPointVisible; bool m_FigurePlaced; private: // not implemented to prevent PlanarFigure::New() calls which would create an itk::Object. static Pointer New(); struct Feature { Feature( const char *name, const char *unit ) : Name( name ), Unit( unit ), Quantity( 0.0 ), Active( true ), Visible( true ) { } std::string Name; std::string Unit; double Quantity; bool Active; bool Visible; }; virtual itk::LightObject::Pointer InternalClone() const = 0; Geometry2D *m_Geometry2D; bool m_PolyLineUpToDate; bool m_HelperLinesUpToDate; bool m_FeaturesUpToDate; // Vector of features available for this geometric figure typedef std::vector< Feature > FeatureVectorType; FeatureVectorType m_Features; unsigned long m_FeaturesMTime; // this pair is used to store the mmInDisplayUnits (m_DisplaySize.first) and the displayHeight (m_DisplaySize.second) // that the helperPolyLines have been calculated for. // It's used to determine whether or not GetHelperPolyLine() needs to recalculate the HelperPolyLines. std::pair m_DisplaySize; }; } // namespace mitk #endif //_MITK_PLANAR_FIGURE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp index d206ab6fb3..be81602ce0 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp @@ -1,274 +1,274 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarPolygon.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" // stl related includes #include mitk::PlanarPolygon::PlanarPolygon() : FEATURE_ID_CIRCUMFERENCE( this->AddFeature( "Circumference", "mm" ) ), FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) ) { // Polygon has at least two control points this->ResetNumberOfControlPoints( 2 ); this->SetNumberOfPolyLines( 1 ); // Polygon is closed by default this->SetProperty( "closed", mitk::BoolProperty::New( true ) ); this->SetProperty( "subdivision", mitk::BoolProperty::New( false ) ); } mitk::PlanarPolygon::~PlanarPolygon() { } void mitk::PlanarPolygon::SetClosed( bool closed ) { this->SetProperty( "closed", mitk::BoolProperty::New( closed ) ); if ( !closed ) { // For non-closed polygons: use "Length" as feature name; disable area this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Length" ); this->DeactivateFeature( FEATURE_ID_AREA ); } else { // For closed polygons: use "Circumference" as feature name; enable area this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Circumference" ); this->ActivateFeature( FEATURE_ID_AREA ); } this->Modified(); } void mitk::PlanarPolygon::GeneratePolyLine() { this->ClearPolyLines(); for (ControlPointListType::size_type i = 0; i < m_ControlPoints.size(); ++i) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); } void mitk::PlanarPolygon::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A polygon does not require helper objects } void mitk::PlanarPolygon::EvaluateFeaturesInternal() { // Calculate circumference double circumference = 0.0; unsigned int i,j; PolyLineType polyLine = m_PolyLines[0]; if(polyLine.empty()) return; for ( i = 0; i <(polyLine.size()-1); ++i ) { circumference += static_cast(polyLine[i]).EuclideanDistanceTo( static_cast(polyLine[i + 1]) ); } if ( this->IsClosed() ) { circumference += static_cast(polyLine[i]).EuclideanDistanceTo( static_cast(polyLine.front()) ); } this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference ); // Calculate polygon area (if closed) double area = 0.0; bool intersection = false; if ( this->IsClosed() && (this->GetGeometry2D() != NULL) ) { // does PlanarPolygon overlap/intersect itself? unsigned int numberOfPoints = polyLine.size(); if( numberOfPoints >= 4) { for ( i = 0; i < (numberOfPoints - 1); ++i ) { // line 1 Point2D p0 = polyLine[i]; Point2D p1 = polyLine[i + 1]; // check for intersection with all other lines for (j = i+1; j < (numberOfPoints - 1); ++j ) { Point2D p2 = polyLine[j]; Point2D p3 = polyLine[j + 1]; intersection = CheckForLineIntersection(p0,p1,p2,p3); if (intersection) break; } if (intersection) break; // only because the inner loop might have changed "intersection" // last line from p_x to p_0 Point2D p2 = polyLine.front(); Point2D p3 = polyLine.back(); intersection = CheckForLineIntersection(p0,p1,p2,p3); if (intersection) break; } } // calculate area for ( i = 0; i < polyLine.size(); ++i ) { Point2D p0 = polyLine[i]; Point2D p1 = polyLine[ (i + 1) % polyLine.size() ]; area += p0[0] * p1[1] - p1[0] * p0[1]; } area /= 2.0; } // set area if appropiate (i.e. closed and not intersected) if(this->IsClosed() && !intersection) { SetQuantity( FEATURE_ID_AREA, fabs( area ) ); this->ActivateFeature( FEATURE_ID_AREA ); } else { SetQuantity( FEATURE_ID_AREA, 0 ); this->DeactivateFeature( FEATURE_ID_AREA ); } } void mitk::PlanarPolygon::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); if (this->IsClosed()) os << indent << "Polygon is closed\n"; else os << indent << "Polygon is not closed\n"; } // based on // http://flassari.is/2008/11/line-line-intersection-in-cplusplus/ bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4, Point2D& intersection ) const { // do not check for intersections with control points if(p1 == p2 || p1 == p3 || p1 == p4 || p2 == p3 || p2 == p4 || p3 == p4) return false; // Store the values for fast access and easy // equations-to-code conversion double x1 = p1[0], x2 = p2[0], x3 = p3[0], x4 = p4[0]; double y1 = p1[1], y2 = p2[1], y3 = p3[1], y4 = p4[1]; double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); // If d is zero, there is no intersection //if (d < mitk::eps) return false; if (d == 0) return false; // Get the x and y double pre = (x1*y2 - y1*x2); double post = (x3*y4 - y3*x4); double x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d; double y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d; double tolerance = 0.001; // Check if the x coordinates are within both lines, including tolerance if ( x < ( std::min(x1, x2) - tolerance ) || x > ( std::max(x1, x2) + tolerance ) || x < ( std::min(x3, x4) - tolerance ) || x > ( std::max(x3, x4) + tolerance ) ) { return false; } // Check if the y coordinates are within both lines, including tolerance if ( y < ( std::min(y1, y2) - tolerance ) || y > ( std::max(y1, y2) + tolerance ) || y < ( std::min(y3, y4) - tolerance ) || y > ( std::max(y3, y4) + tolerance ) ) { return false; } // point of intersection Point2D ret; ret[0] = x; ret[1] = y; intersection = ret; return true; } bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4 ) const { mitk::Point2D intersection; return mitk::PlanarPolygon::CheckForLineIntersection( p1, p2, p3, p4, intersection ); } std::vector mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2 ) const { std::vector intersectionList; ControlPointListType polyLinePoints; PolyLineType tempList = m_PolyLines[0]; PolyLineType::iterator iter; for( iter = tempList.begin(); iter != tempList.end(); ++iter ) { - polyLinePoints.push_back((*iter).Point); + polyLinePoints.push_back(*iter); } for ( ControlPointListType::size_type i=0; iIsClosed() ) { mitk::Point2D intersection, lastControlPoint, firstControlPoint; lastControlPoint = polyLinePoints.back(); firstControlPoint = polyLinePoints.front(); if ( mitk::PlanarPolygon::CheckForLineIntersection( lastControlPoint, firstControlPoint, p1, p2, intersection ) ) { intersectionList.push_back( intersection ); } } return intersectionList; } diff --git a/Modules/PlanarFigure/Testing/mitkPlanarArrowTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarArrowTest.cpp index 12df1bf73e..2b4cd73969 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarArrowTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarArrowTest.cpp @@ -1,95 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPlanarArrow.h" #include "mitkPlaneGeometry.h" class mitkPlanarArrowTestClass { public: static void TestPlanarArrowPlacement( mitk::PlanarArrow::Pointer PlanarArrow ) { // Test for correct minimum number of control points in cross-mode MITK_TEST_CONDITION( PlanarArrow->GetMinimumNumberOfControlPoints() == 2, "Minimum number of control points" ); // Test for correct maximum number of control points in cross-mode MITK_TEST_CONDITION( PlanarArrow->GetMaximumNumberOfControlPoints() == 2, "Maximum number of control points" ); // Initial placement of PlanarArrow mitk::Point2D p0; p0[0] = 00.0; p0[1] = 0.0; PlanarArrow->PlaceFigure( p0 ); // Add second control point mitk::Point2D p1; p1[0] = 50.0; p1[1] = 00.0; PlanarArrow->SetControlPoint(1, p1 ); // Test for number of control points MITK_TEST_CONDITION( PlanarArrow->GetNumberOfControlPoints() == 2, "Number of control points after placement" ); // Test for number of polylines const mitk::PlanarFigure::PolyLineType polyLine0 = PlanarArrow->GetPolyLine( 0 ); mitk::PlanarFigure::PolyLineType::const_iterator iter = polyLine0.begin(); MITK_TEST_CONDITION( PlanarArrow->GetPolyLinesSize() == 1, "Number of polylines after placement" ); // Get polylines and check if the generated coordinates are OK - const mitk::Point2D& pp0 = iter->Point; + const mitk::Point2D& pp0 = *iter; iter++; - const mitk::Point2D& pp1 = iter->Point; + const mitk::Point2D& pp1 = *iter; MITK_TEST_CONDITION( (pp0 == p0) && (pp1 == p1), "Correct polyline 1" ); // Test for number of measurement features // none yet } }; /** * mitkPlanarArrowTest tests the methods and behavior of mitk::PlanarArrow with sub-tests: * * 1. Instantiation and basic tests * */ int mitkPlanarArrowTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("PlanarArrow") // create PlaneGeometry on which to place the PlanarArrow mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( 100.0, 100.0 ); // ************************************************************************** // 1. Instantiation and basic tests mitk::PlanarArrow::Pointer PlanarArrow = mitk::PlanarArrow::New(); PlanarArrow->SetGeometry2D( planeGeometry ); // first test: did this work? MITK_TEST_CONDITION_REQUIRED( PlanarArrow.IsNotNull(), "Testing instantiation" ); // Test placement of PlanarArrow by control points mitkPlanarArrowTestClass::TestPlanarArrowPlacement( PlanarArrow ); // always end with this! MITK_TEST_END(); } diff --git a/Modules/PlanarFigure/Testing/mitkPlanarCrossTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarCrossTest.cpp index 1a5360da74..c9da5e9d1c 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarCrossTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarCrossTest.cpp @@ -1,417 +1,417 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPlanarCross.h" #include "mitkPlaneGeometry.h" class mitkPlanarCrossTestClass { public: static void TestPlanarCrossPlacement( mitk::PlanarCross::Pointer planarCross ) { // Test for correct minimum number of control points in cross-mode MITK_TEST_CONDITION( planarCross->GetMinimumNumberOfControlPoints() == 4, "Minimum number of control points" ); // Test for correct maximum number of control points in cross-mode MITK_TEST_CONDITION( planarCross->GetMaximumNumberOfControlPoints() == 4, "Maximum number of control points" ); // Initial placement of PlanarCross mitk::Point2D p0; p0[0] = 20.0; p0[1] = 20.0; planarCross->PlaceFigure( p0 ); // Add second control point mitk::Point2D p1; p1[0] = 80.0; p1[1] = 80.0; planarCross->SetCurrentControlPoint( p1 ); // Add third control point mitk::Point2D p2; p2[0] = 90.0; p2[1] = 10.0; planarCross->AddControlPoint( p2 ); // Test if helper polyline is generated const mitk::PlanarFigure::PolyLineType helperPolyLine = planarCross->GetHelperPolyLine( 0, 1.0, 100 ); MITK_TEST_CONDITION( planarCross->GetHelperPolyLinesSize() == 1, "Number of helper polylines after placing 3 points" ); // Test if helper polyline is marked as "to be painted" MITK_TEST_CONDITION( planarCross->IsHelperToBePainted( 0 ), "Helper line to be painted after placing 3 points" ); // Test if helper polyline is orthogonal to first line mitk::Vector2D v0 = p1 - p0; v0.Normalize(); // TODO: make it work again //mitk::Vector2D hv = helperPolyLine->ElementAt( 1 ) - helperPolyLine->ElementAt( 0 ); //hv.Normalize(); //MITK_TEST_CONDITION( fabs(v0 * hv) < mitk::eps, "Helper line is orthogonal to first line" ); //// Test if helper polyline is placed correctly //mitk::Vector2D hv1 = helperPolyLine->ElementAt( 1 ) - p2; //hv1.Normalize(); //MITK_TEST_CONDITION( fabs(hv * hv1 - 1.0) < mitk::eps, "Helper line is aligned to third point" ); // Add fourth control point mitk::Point2D p3; p3[0] = 10.0; p3[1] = 90.0; planarCross->AddControlPoint( p3 ); // Test for number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 4, "Number of control points after placement" ); // Test if PlanarFigure is closed MITK_TEST_CONDITION( !planarCross->IsClosed(), "Is PlanarFigure closed?" ); // Test if helper polyline is no longer marked as "to be painted" MITK_TEST_CONDITION( planarCross->IsHelperToBePainted( 0 ), "Helper line no longer to be painted after placement of all 4 points" ); // Test for number of polylines const mitk::PlanarFigure::PolyLineType polyLine0 = planarCross->GetPolyLine( 0 ); const mitk::PlanarFigure::PolyLineType polyLine1 = planarCross->GetPolyLine( 1 ); MITK_TEST_CONDITION( planarCross->GetPolyLinesSize() == 2, "Number of polylines after placement" ); mitk::PlanarFigure::PolyLineType::const_iterator iter0 = polyLine0.begin(); mitk::PlanarFigure::PolyLineType::const_iterator iter1 = polyLine1.begin(); // Get polylines and check if the generated coordinates are OK - const mitk::Point2D& pp0 = iter0->Point; + const mitk::Point2D& pp0 = *iter0; iter0++; - const mitk::Point2D& pp1 = iter0->Point; + const mitk::Point2D& pp1 = *iter0; MITK_TEST_CONDITION( ((pp0 == p0) && (pp1 == p1)) || ((pp0 == p1) && (pp1 == p0)), "Correct polyline 1" ); - const mitk::Point2D& pp2 = iter1->Point; + const mitk::Point2D& pp2 = *iter1; iter1++; - const mitk::Point2D& pp3 = iter1->Point; + const mitk::Point2D& pp3 = *iter1; MITK_TEST_CONDITION( ((pp2 == p2) && (pp3 == p3)) || ((pp2 == p3) && (pp3 == p2)), "Correct polyline 2" ); // Test for number of measurement features planarCross->EvaluateFeatures(); MITK_TEST_CONDITION( planarCross->GetNumberOfFeatures() == 2, "Number of measurement features" ); // Test for correct feature evaluation double length0 = sqrt( 80.0 * 80.0 * 2.0 ); MITK_TEST_CONDITION( fabs( planarCross->GetQuantity( 0 ) - length0) < mitk::eps, "Size of longest diameter" ); double length1 = sqrt( 60.0 * 60.0 * 2.0 ); MITK_TEST_CONDITION( fabs( planarCross->GetQuantity( 1 ) - length1) < mitk::eps, "Size of short axis diameter" ); } static void TestPlanarCrossPlacementSingleLine(mitk::PlanarCross::Pointer planarCross) { // Test for correct minimum number of control points in cross-mode MITK_TEST_CONDITION( planarCross->GetMinimumNumberOfControlPoints() == 2, "Minimum number of control points" ); // Test for correct maximum number of control points in cross-mode MITK_TEST_CONDITION( planarCross->GetMaximumNumberOfControlPoints() == 2, "Maximum number of control points" ); // Initial placement of PlanarCross mitk::Point2D p0; p0[0] = 25.0; p0[1] = 10.0; planarCross->PlaceFigure( p0 ); // Add second control point mitk::Point2D p1; p1[0] = 30.0; p1[1] = 60.0; planarCross->SetCurrentControlPoint( p1 ); // Verify that no helper line is drawn MITK_TEST_CONDITION( planarCross->IsHelperToBePainted( 0 ) == false, "No helper line to be painted in single-line mode" ); // Test for number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 2, "Number of control points after placement" ); // Test if PlanarFigure is closed MITK_TEST_CONDITION( !planarCross->IsClosed(), "Is PlanarFigure closed?" ); // Test for number of polylines const mitk::PlanarFigure::PolyLineType polyLine0 = planarCross->GetPolyLine( 0 ); mitk::PlanarFigure::PolyLineType::const_iterator iter = polyLine0.begin(); MITK_TEST_CONDITION( planarCross->GetPolyLinesSize() == 1, "Number of polylines after placement" ); // Get polylines and check if the generated coordinates are OK - const mitk::Point2D& pp0 = iter->Point; + const mitk::Point2D& pp0 = *iter; iter++; - const mitk::Point2D& pp1 = iter->Point; + const mitk::Point2D& pp1 = *iter; MITK_TEST_CONDITION( ((pp0 == p0) && (pp1 == p1)) || ((pp0 == p1) && (pp1 == p0)), "Correct polyline 1" ); // Test for number of measurement features planarCross->EvaluateFeatures(); MITK_TEST_CONDITION( planarCross->GetNumberOfFeatures() == 1, "Number of measurement features" ); // Test for correct feature evaluation double length0 = sqrt( 5.0 * 5.0 + 50.0 * 50.0 ); MITK_TEST_CONDITION( fabs( planarCross->GetQuantity( 0 ) - length0) < mitk::eps, "Size of diameter" ); // Test if reset called on single-line PlanarCross returns false (nothing to reset) MITK_TEST_CONDITION( planarCross->ResetOnPointSelect() == false, "Single-line PlanarCross should not be reset on point edit" ); } static void TestPlanarCrossPlacementConstrained(mitk::PlanarCross::Pointer planarCross) { // ************************************************************************** // Place first control point out of bounds (to the left of the image bounds) mitk::Point2D p0; p0[0] = -20.0; p0[1] = 20.0; planarCross->PlaceFigure( p0 ); // Test if constraint has been applied correctly mitk::Point2D cp0 = planarCross->GetControlPoint( 0 ); MITK_TEST_CONDITION( (fabs(cp0[0]) < mitk::eps) && (fabs(cp0[1] - 20.0) < mitk::eps), "Point1 placed and constrained correctly" ); // ************************************************************************** // Add second control point out of bounds (to the top of the image bounds) mitk::Point2D p1; p1[0] = 80.0; p1[1] = 120.0; planarCross->SetCurrentControlPoint( p1 ); // Test if constraint has been applied correctly mitk::Point2D cp1 = planarCross->GetControlPoint( 1 ); MITK_TEST_CONDITION( (fabs(cp1[0] - 80.0) < mitk::eps) && (fabs(cp1[1] - 100.0) < mitk::eps), "Point2 placed and constrained correctly" ); // ************************************************************************** // Add third control point out of bounds (outside of channel defined by first line) mitk::Point2D p2; p2[0] = 100.0; p2[1] = 100.0; planarCross->AddControlPoint( p2 ); // Test if constraint has been applied correctly (100.0, 100.0) must be projected to (90.0, 90.0) mitk::Point2D cp2 = planarCross->GetControlPoint( 2 ); MITK_TEST_CONDITION( (fabs(cp2[0] - 90.0) < mitk::eps) && (fabs(cp2[1] - 90.0) < mitk::eps), "Point3 placed and constrained correctly" ); // Move third control point (within channel defined by first line) p2[0] = 40.0; p2[1] = 20.0; planarCross->SetControlPoint( 2, p2 ); // Test if point is still at this position (no constrained should be applied) cp2 = planarCross->GetControlPoint( 2 ); MITK_TEST_CONDITION( (fabs(cp2[0] - 40.0) < mitk::eps) && (fabs(cp2[1] - 20.0) < mitk::eps), "Point3 moved correctly" ); // ************************************************************************** // Add fourth control point out of bounds (outside of line defined by first line and third point) mitk::Point2D p3; p3[0] = 20.0; p3[1] = 60.0; planarCross->AddControlPoint( p3 ); // Test if constraint has been applied correctly (20.0, 60.0) must be projected to (10.0, 50.0) mitk::Point2D cp3 = planarCross->GetControlPoint( 3 ); MITK_TEST_CONDITION( (fabs(cp3[0] - 10.0) < mitk::eps) && (fabs(cp3[1] - 50.0) < mitk::eps), "Point4 placed and constrained correctly" ); // Move fourth control point (to a position which would result in two non-intersecting line // without the constraint that lines have to intersect) p3[0] = 40.0; p3[1] = 30.0; planarCross->SetControlPoint( 3, p3 ); // Test if constrained point is on the projected intersection point of both lines (20.0/40.0) cp3 = planarCross->GetControlPoint( 3 ); MITK_TEST_CONDITION( (fabs(cp3[0] - 20.0) < mitk::eps) && (fabs(cp3[1] - 40.0) < mitk::eps), "Point4 placed and constrained correctly" ); } static void TestPlanarCrossEdit(mitk::PlanarCross::Pointer planarCross) { // * point move (different points) // --> reset // --> test which point is where / evaluation mitk::Point2D p0 = planarCross->GetControlPoint( 0 ); mitk::Point2D p1 = planarCross->GetControlPoint( 1 ); mitk::Point2D p2 = planarCross->GetControlPoint( 2 ); mitk::Point2D p3 = planarCross->GetControlPoint( 3 ); // ************************************************************************** // Edit control point 0 planarCross->SelectControlPoint( 0 ); // Request reset and check if it is done MITK_TEST_CONDITION( planarCross->ResetOnPointSelect(), "Editing control point 0: Double-line PlanarCross should be reset" ); // Check number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 2, "Two control points are left" ); // Check if correct control points have been left MITK_TEST_CONDITION( (planarCross->GetControlPoint( 0 ).EuclideanDistanceTo( p1 ) < mitk::eps) && (planarCross->GetControlPoint( 1 ).EuclideanDistanceTo( p0 ) < mitk::eps), "Reset to expected control points (p1, p0)" ); // Reset planar cross to original values ResetPlanarCross( planarCross, p0, p1, p2, p3 ); // ************************************************************************** // Edit control point 1 planarCross->SelectControlPoint( 1 ); // Request reset and check if it is done MITK_TEST_CONDITION( planarCross->ResetOnPointSelect(), "Editing control point 1: Double-line PlanarCross should be reset" ); // Check number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 2, "Two control points are left" ); // Check if correct control points have been left MITK_TEST_CONDITION( (planarCross->GetControlPoint( 0 ).EuclideanDistanceTo( p0 ) < mitk::eps) && (planarCross->GetControlPoint( 1 ).EuclideanDistanceTo( p1 ) < mitk::eps), "Reset to expected control points (p0, p1)" ); // Reset planar cross to original values ResetPlanarCross( planarCross, p0, p1, p2, p3 ); // ************************************************************************** // Edit control point 2 planarCross->SelectControlPoint( 2 ); // Request reset and check if it is done MITK_TEST_CONDITION( planarCross->ResetOnPointSelect(), "Editing control point 2: Double-line PlanarCross should be reset" ); // Check number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 2, "Two control points are left" ); // Check if correct control points have been left MITK_TEST_CONDITION( (planarCross->GetControlPoint( 0 ).EuclideanDistanceTo( p3 ) < mitk::eps) && (planarCross->GetControlPoint( 1 ).EuclideanDistanceTo( p2 ) < mitk::eps), "Reset to expected control points (p3, p2)" ); // Reset planar cross to original values ResetPlanarCross( planarCross, p0, p1, p2, p3 ); // ************************************************************************** // Edit control point 3 planarCross->SelectControlPoint( 3 ); // Request reset and check if it is done MITK_TEST_CONDITION( planarCross->ResetOnPointSelect(), "Editing control point 3: Double-line PlanarCross should be reset" ); // Check number of control points MITK_TEST_CONDITION( planarCross->GetNumberOfControlPoints() == 2, "Two control points are left" ); // Check if correct control points have been left MITK_TEST_CONDITION( (planarCross->GetControlPoint( 0 ).EuclideanDistanceTo( p2 ) < mitk::eps) && (planarCross->GetControlPoint( 1 ).EuclideanDistanceTo( p3 ) < mitk::eps), "Reset to expected control points (p2, p3)" ); } static void ResetPlanarCross( mitk::PlanarCross::Pointer planarCross, mitk::Point2D p0, mitk::Point2D p1, mitk::Point2D p2, mitk::Point2D p3 ) { planarCross->SetControlPoint( 0, p0, true ); planarCross->SetControlPoint( 1, p1, true ); planarCross->SetControlPoint( 2, p2, true ); planarCross->SetControlPoint( 3, p3, true ); } }; /** * mitkPlanarCrossTest tests the methods and behavior of mitk::PlanarCross with four sub-tests: * * 1. Double-line mode instantiation and basic tests * 2. Single-line mode instantiation and basic tests * 3. Tests of application of spatial constraints for double-line mode * 4. Tests if editing of PlanarCross works as intended * */ int mitkPlanarCrossTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("PlanarCross") // create PlaneGeometry on which to place the PlanarCross mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( 100.0, 100.0 ); // ************************************************************************** // 1. Double-line mode instantiation and basic tests mitk::PlanarCross::Pointer planarCross = mitk::PlanarCross::New(); planarCross->SetGeometry2D( planeGeometry ); // first test: did this work? MITK_TEST_CONDITION_REQUIRED( planarCross.IsNotNull(), "Testing instantiation" ); // test: default cross-mode (not single-line-mode)? MITK_TEST_CONDITION_REQUIRED( !planarCross->GetSingleLineMode(), "Testing default cross mode" ); // Test placement of PlanarCross by control points mitkPlanarCrossTestClass::TestPlanarCrossPlacement( planarCross ); // ************************************************************************** // 2. Single-line mode instantiation and basic tests planarCross = mitk::PlanarCross::New(); planarCross->SingleLineModeOn(); planarCross->SetGeometry2D( planeGeometry ); // test: single-line mode? MITK_TEST_CONDITION_REQUIRED( planarCross->GetSingleLineMode(), "Testing activation of single-line mode" ); // Test placement of single-line PlanarCross by control points mitkPlanarCrossTestClass::TestPlanarCrossPlacementSingleLine( planarCross ); // ************************************************************************** // 3. Tests of application of spatial constraints for double-line mode planarCross = mitk::PlanarCross::New(); planarCross->SetGeometry2D( planeGeometry ); // Test placement with various out-of-bounds control points (automatic application of // constraints expected) mitkPlanarCrossTestClass::TestPlanarCrossPlacementConstrained( planarCross ); // ************************************************************************** // 4. Tests if editing of PlanarCross works as intended mitkPlanarCrossTestClass::TestPlanarCrossEdit( planarCross ); // always end with this! MITK_TEST_END() } diff --git a/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp index e0c41dd6fd..3515933f39 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp @@ -1,151 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPlanarPolygon.h" #include "mitkPlaneGeometry.h" class mitkPlanarPolygonTestClass { public: static void TestPlanarPolygonPlacement( mitk::PlanarPolygon::Pointer planarPolygon ) { // Test for correct minimum number of control points in cross-mode MITK_TEST_CONDITION( planarPolygon->GetMinimumNumberOfControlPoints() == 3, "Minimum number of control points" ); // Test for correct maximum number of control points in cross-mode MITK_TEST_CONDITION( planarPolygon->GetMaximumNumberOfControlPoints() == 1000, "Maximum number of control points" ); // Initial placement of PlanarPolygon mitk::Point2D p0; p0[0] = 00.0; p0[1] = 0.0; planarPolygon->PlaceFigure( p0 ); // Add second control point mitk::Point2D p1; p1[0] = 50.0; p1[1] = 00.0; planarPolygon->SetControlPoint(1, p1 ); // Add third control point mitk::Point2D p2; p2[0] = 50.0; p2[1] = 50.0; planarPolygon->AddControlPoint( p2 ); // Add fourth control point mitk::Point2D p3; p3[0] = 0.0; p3[1] = 50.0; planarPolygon->AddControlPoint( p3 ); // Test for number of control points MITK_TEST_CONDITION( planarPolygon->GetNumberOfControlPoints() == 4, "Number of control points after placement" ); // Test if PlanarFigure is closed MITK_TEST_CONDITION( planarPolygon->IsClosed(), "planar polygon should not be closed, yet, right?" ); planarPolygon->SetClosed(true); MITK_TEST_CONDITION( planarPolygon->IsClosed(), "planar polygon should be closed after function call, right?" ); // Test for number of polylines const mitk::PlanarFigure::PolyLineType polyLine0 = planarPolygon->GetPolyLine( 0 ); mitk::PlanarFigure::PolyLineType::const_iterator iter = polyLine0.begin(); MITK_TEST_CONDITION( planarPolygon->GetPolyLinesSize() == 1, "Number of polylines after placement" ); // Get polylines and check if the generated coordinates are OK - const mitk::Point2D& pp0 = iter->Point; + const mitk::Point2D& pp0 = *iter; ++iter; - const mitk::Point2D& pp1 = iter->Point; + const mitk::Point2D& pp1 = *iter; MITK_TEST_CONDITION( ((pp0 == p0) && (pp1 == p1)) || ((pp0 == p1) && (pp1 == p0)), "Correct polyline 1" ); // Test for number of measurement features planarPolygon->EvaluateFeatures(); MITK_TEST_CONDITION( planarPolygon->GetNumberOfFeatures() == 2, "Number of measurement features" ); // Test for correct feature evaluation double length0 = 4 * 50.0; // circumference MITK_TEST_CONDITION( fabs( planarPolygon->GetQuantity( 0 ) - length0) < mitk::eps, "Size of longest diameter" ); double length1 = 50.0 * 50.0 ; // area MITK_TEST_CONDITION( fabs( planarPolygon->GetQuantity( 1 ) - length1) < mitk::eps, "Size of short axis diameter" ); } static void TestPlanarPolygonEditing( mitk::PlanarPolygon::Pointer planarPolygon ) { unsigned int initialNumberOfControlPoints = planarPolygon->GetNumberOfControlPoints(); mitk::Point2D pnt; pnt[0] = 75.0; pnt[1] = 25.0; planarPolygon->AddControlPoint( pnt); MITK_TEST_CONDITION( planarPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints+1, "A new control-point shall be added" ); MITK_TEST_CONDITION( planarPolygon->GetControlPoint( planarPolygon->GetNumberOfControlPoints()-1 ) == pnt, "Control-point shall be added at the end." ); planarPolygon->RemoveControlPoint( 3 ); MITK_TEST_CONDITION( planarPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints, "A control-point has been removed" ); MITK_TEST_CONDITION( planarPolygon->GetControlPoint( 3 ) == pnt, "It shall be possible to remove any control-point." ); planarPolygon->RemoveControlPoint( 0 ); planarPolygon->RemoveControlPoint( 0 ); planarPolygon->RemoveControlPoint( 0 ); MITK_TEST_CONDITION( planarPolygon->GetNumberOfControlPoints() == 3, "Control-points cannot be removed if only three points remain." ); mitk::Point2D pnt1; pnt1[0] = 33.0; pnt1[1] = 33.0; planarPolygon->AddControlPoint( pnt1, 0 ); MITK_TEST_CONDITION( planarPolygon->GetNumberOfControlPoints() == 4, "A control-point has been added" ); MITK_TEST_CONDITION( planarPolygon->GetControlPoint( 0 ) == pnt1, "It shall be possible to insert a control-point at any position." ); } }; /** * mitkplanarPolygonTest tests the methods and behavior of mitk::PlanarPolygon with sub-tests: * * 1. Instantiation and basic tests, including feature evaluation * */ int mitkPlanarPolygonTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("planarPolygon") // create PlaneGeometry on which to place the planarPolygon mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( 100.0, 100.0 ); // ************************************************************************** // 1. Instantiation and basic tests, including feature evaluation mitk::PlanarPolygon::Pointer planarPolygon = mitk::PlanarPolygon::New(); planarPolygon->SetGeometry2D( planeGeometry ); // first test: did this work? MITK_TEST_CONDITION_REQUIRED( planarPolygon.IsNotNull(), "Testing instantiation" ); // Test placement of planarPolygon by control points mitkPlanarPolygonTestClass::TestPlanarPolygonPlacement( planarPolygon ); mitkPlanarPolygonTestClass::TestPlanarPolygonEditing( planarPolygon ); // always end with this! MITK_TEST_END(); } diff --git a/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp index 8b549a5b66..5c14e89c3e 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp @@ -1,195 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPlanarSubdivisionPolygon.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" class mitkPlanarSubdivisionPolygonTestClass { public: static void TestPlanarSubdivisionPolygonPlacement( mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon ) { // Test for correct minimum number of control points in cross-mode MITK_TEST_CONDITION( planarSubdivisionPolygon->GetMinimumNumberOfControlPoints() == 3, "Minimum number of control points" ); // Test for correct maximum number of control points in cross-mode MITK_TEST_CONDITION( planarSubdivisionPolygon->GetMaximumNumberOfControlPoints() == 1000, "Maximum number of control points" ); // Test for correct rounds of subdivisionPoints MITK_TEST_CONDITION( planarSubdivisionPolygon->GetSubdivisionRounds() == 5, "Subdivision point generation depth" ); // Test for correct tension parameter MITK_TEST_CONDITION( planarSubdivisionPolygon->GetTensionParameter() == 0.0625, "Tension parameter" ); planarSubdivisionPolygon->SetProperty( "initiallyplaced", mitk::BoolProperty::New( true ) ); // Initial placement of planarSubdivisionPolygon mitk::Point2D p0; p0[0] = 25.0; p0[1] = 25.0; planarSubdivisionPolygon->PlaceFigure( p0 ); // Add second control point mitk::Point2D p1; p1[0] = 75.0; p1[1] = 25.0; planarSubdivisionPolygon->SetControlPoint(1, p1 ); // Add third control point mitk::Point2D p2; p2[0] = 75.0; p2[1] = 75.0; planarSubdivisionPolygon->AddControlPoint( p2 ); // Add fourth control point mitk::Point2D p3; p3[0] = 25.0; p3[1] = 75.0; planarSubdivisionPolygon->AddControlPoint( p3 ); // Test for number of control points MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 4, "Number of control points after placement" ); // Test if PlanarFigure is closed MITK_TEST_CONDITION( planarSubdivisionPolygon->IsClosed(), "Test if property 'closed' is set by default" ); // Test for number of polylines const mitk::PlanarFigure::PolyLineType polyLine0 = planarSubdivisionPolygon->GetPolyLine( 0 ); mitk::PlanarFigure::PolyLineType::const_iterator iter = polyLine0.begin(); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetPolyLinesSize() == 1, "Number of polylines after placement" ); // Test if subdivision point count is correct MITK_TEST_CONDITION( polyLine0.size() == 128, "correct number of subdivision points for this depth level" ); // Test if control points are in correct order between subdivision points bool correctPoint = true; iter = polyLine0.begin(); - if( iter->Point != p0 ){ correctPoint = false; } + if( static_cast(*iter) != p0 ){ correctPoint = false; } advance(iter, 32); - if( iter->Point != p1 ){ correctPoint = false; } + if( static_cast(*iter) != p1 ){ correctPoint = false; } advance(iter, 32); - if( iter->Point != p2 ){ correctPoint = false; } + if( static_cast(*iter) != p2 ){ correctPoint = false; } advance(iter, 32); - if( iter->Point != p3 ){ correctPoint = false; } + if( static_cast(*iter) != p3 ){ correctPoint = false; } MITK_TEST_CONDITION( correctPoint, "Test if control points are in correct order in polyline" ); // Test if a picked point has the correct coordinates correctPoint = true; mitk::Point2D testPoint; testPoint[0] = 81.25; testPoint[1] = 48.243; iter = polyLine0.begin(); advance(iter, 47); mitk::ScalarType testEps = 1E-5; - if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > testEps ){ correctPoint = false; } + if( (static_cast(*iter)[0] - testPoint[0]) + (static_cast(*iter)[1] - testPoint[1]) > testEps ){ correctPoint = false; } testPoint[0] = 39.624; testPoint[1] = 19.3268; iter = polyLine0.begin(); advance(iter, 10); - if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > testEps ){ correctPoint = false; } + if( (static_cast(*iter)[0] - testPoint[0]) + (static_cast(*iter)[1] - testPoint[1]) > testEps ){ correctPoint = false; } testPoint[0] = 71.2887; testPoint[1] = 77.5248; iter = polyLine0.begin(); advance(iter, 67); - if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > testEps ){ correctPoint = false; } + if( (static_cast(*iter)[0] - testPoint[0]) + (static_cast(*iter)[1] - testPoint[1]) > testEps ){ correctPoint = false; } MITK_TEST_CONDITION( correctPoint, "Test if subdivision points are calculated correctly" ) // Test for number of measurement features /* Does not work yet planarSubdivisionPolygon->EvaluateFeatures(); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfFeatures() == 2, "Number of measurement features" ); // Test for correct feature evaluation double length0 = 4 * 50.0; // circumference MITK_TEST_CONDITION( fabs( planarSubdivisionPolygon->GetQuantity( 0 ) - length0) < mitk::eps, "Size of longest diameter" ); double length1 = 50.0 * 50.0 ; // area MITK_TEST_CONDITION( fabs( planarSubdivisionPolygon->GetQuantity( 1 ) - length1) < mitk::eps, "Size of short axis diameter" ); */ } static void TestPlanarSubdivisionPolygonEditing( mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon ) { unsigned int initialNumberOfControlPoints = planarSubdivisionPolygon->GetNumberOfControlPoints(); mitk::Point2D pnt; pnt[0] = 75.0; pnt[1] = 25.0; planarSubdivisionPolygon->AddControlPoint( pnt); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints+1, "A new control-point shall be added" ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( planarSubdivisionPolygon->GetNumberOfControlPoints()-1 ) == pnt, "Control-point shall be added at the end." ); planarSubdivisionPolygon->RemoveControlPoint( 3 ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints, "A control-point has been removed" ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( 3 ) == pnt, "It shall be possible to remove any control-point." ); planarSubdivisionPolygon->RemoveControlPoint( 0 ); planarSubdivisionPolygon->RemoveControlPoint( 0 ); planarSubdivisionPolygon->RemoveControlPoint( 0 ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 3, "Control-points cannot be removed if only three points remain." ); mitk::Point2D pnt1; pnt1[0] = 33.0; pnt1[1] = 33.0; planarSubdivisionPolygon->AddControlPoint( pnt1, 0 ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 4, "A control-point has been added" ); MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( 0 ) == pnt1, "It shall be possible to insert a control-point at any position." ); } }; /** * mitkplanarSubdivisionPolygonTest tests the methods and behavior of mitk::planarSubdivisionPolygon with sub-tests: * * 1. Instantiation and basic tests, including feature evaluation * */ int mitkPlanarSubdivisionPolygonTest(int /* argc */, char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("planarSubdivisionPolygon") // create PlaneGeometry on which to place the planarSubdivisionPolygon mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane( 100.0, 100.0 ); // ************************************************************************** // 1. Instantiation and basic tests, including feature evaluation mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon = mitk::PlanarSubdivisionPolygon::New(); planarSubdivisionPolygon->SetGeometry2D( planeGeometry ); // first test: did this work? MITK_TEST_CONDITION_REQUIRED( planarSubdivisionPolygon.IsNotNull(), "Testing instantiation" ); // Test placement of planarSubdivisionPolygon by control points mitkPlanarSubdivisionPolygonTestClass::TestPlanarSubdivisionPolygonPlacement( planarSubdivisionPolygon ); mitkPlanarSubdivisionPolygonTestClass::TestPlanarSubdivisionPolygonEditing( planarSubdivisionPolygon ); // always end with this! MITK_TEST_END(); }