diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp index 53a172f81e..71b4539940 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp @@ -1,395 +1,354 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-02-17 23:03:29 +0100 (Mi, 17 Feb 2010) $ Version: $Revision: 18029 $ 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 "mitkPlanarCross.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" mitk::PlanarCross::PlanarCross() : FEATURE_ID_LONGESTDIAMETER( this->AddFeature( "Longest Axis", "mm" ) ), FEATURE_ID_SHORTAXISDIAMETER( this->AddFeature( "Short Axis", "mm" ) ) { // Cross has two control points at the beginning this->ResetNumberOfControlPoints( 2 ); // Create property for SingleLineMode (default: false) this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( false ) ); // Create helper polyline object (for drawing the orthogonal orientation line) this->SetNumberOfHelperPolyLines( 1 ); //m_HelperPolyLines->InsertElement( 0, VertexContainerType::New()); //m_HelperPolyLines->ElementAt( 0 )->Reserve( 2 ); m_HelperPolyLinesToBePainted->InsertElement( 0, false ); } mitk::PlanarCross::~PlanarCross() { } void mitk::PlanarCross::SetSingleLineMode( bool singleLineMode ) { this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( singleLineMode ) ); this->Modified(); } bool mitk::PlanarCross::GetSingleLineMode() const { mitk::BoolProperty* singleLineMode = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "SingleLineMode" ).GetPointer() ); if ( singleLineMode != NULL ) { return singleLineMode->GetValue(); } return false; } bool mitk::PlanarCross::ResetOnPointSelect() { if ( this->GetSingleLineMode() ) { // In single line mode --> nothing to reset return false; } switch ( m_SelectedControlPoint ) { default: // Nothing selected --> nothing to reset return false; case 0: { // Control point 0 selected: exchange points 0 and 1 Point2D tmpPoint = this->GetControlPoint( 0 ); //Point2D tmpPoint = m_ControlPoints->ElementAt( 0 ); this->SetControlPoint( 0, this->GetControlPoint( 1 ) ); this->SetControlPoint( 1, tmpPoint ); - //m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 1 ) ); - //m_ControlPoints->InsertElement( 1, tmpPoint ); // FALLS THROUGH! } case 1: { // Control point 0 or 1 selected: reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } case 2: { // Control point 2 selected: replace point 0 with point 3 and point 1 with point 2 this->SetControlPoint( 0, this->GetControlPoint( 3 ) ); this->SetControlPoint( 1, this->GetControlPoint( 2 ) ); - //m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 3 ) ); - //m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 2 ) ); - // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } case 3: { // Control point 3 selected: replace point 0 with point 2 and point 1 with point 3 this->SetControlPoint( 0, this->GetControlPoint( 2 ) ); this->SetControlPoint( 1, this->GetControlPoint( 3 ) ); - //m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 2 ) ); - //m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 3 ) ); - // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } } } unsigned int mitk::PlanarCross::GetNumberOfFeatures() const { if ( this->GetSingleLineMode() || (this->GetNumberOfControlPoints() < 4) ) { return 1; } else { return 2; } } mitk::Point2D mitk::PlanarCross::ApplyControlPointConstraints( unsigned int index, const Point2D& point ) { // Apply spatial constraints from superclass and from this class until the resulting constrained // point converges. Although not an optimal implementation, this iterative approach // helps to respect both constraints from the superclass and from this class. Without this, // situations may occur where control points are constrained by the superclass, but again // moved out of the superclass bounds by the subclass, or vice versa. unsigned int count = 0; // ensures stop of approach if point does not converge in reasonable time Point2D confinedPoint = point; Point2D superclassConfinedPoint; do { superclassConfinedPoint = Superclass::ApplyControlPointConstraints( index, confinedPoint ); confinedPoint = this->InternalApplyControlPointConstraints( index, superclassConfinedPoint ); ++count; } while ( (confinedPoint.EuclideanDistanceTo( superclassConfinedPoint ) > mitk::eps) && (count < 32) ); return confinedPoint; } mitk::Point2D mitk::PlanarCross::InternalApplyControlPointConstraints( unsigned int index, const Point2D& point ) { // Apply constraints depending on current interaction state switch ( index ) { case 2: { // Check if 3rd control point is outside of the range (2D area) defined by the first // line (via the first two control points); if it is outside, clip it to the bounds const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); - //const Point2D& p1 = m_ControlPoints->ElementAt( 0 ); - //const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); - Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = point - p1; double dotProduct = n1 * v1; Point2D crossPoint = p1 + n1 * dotProduct;; Vector2D crossVector = point - crossPoint; if ( dotProduct < 0.0 ) { // Out-of-bounds on the left: clip point to left boundary return (p1 + crossVector); } else if ( dotProduct > p2.EuclideanDistanceTo( p1 ) ) { // Out-of-bounds on the right: clip point to right boundary return (p2 + crossVector); } else { // Pass back original point return point; } } case 3: { // Constrain 4th control point so that with the 3rd control point it forms // a line orthogonal to the first line (constraint 1); the 4th control point // must lie on the opposite side of the line defined by the first two control // points than the 3rd control point (constraint 2) const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); const Point2D p3 = this->GetControlPoint( 2 ); - //const Point2D& p1 = m_ControlPoints->ElementAt( 0 ); - //const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); - //const Point2D& p3 = m_ControlPoints->ElementAt( 2 ); - // Calculate distance of original point from orthogonal line the corrected // point should lie on to project the point onto this line Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = point - p3; double dotProduct1 = n1 * v1; Point2D pointOnLine = point - n1 * dotProduct1; // Project new point onto line [p1, p2] Vector2D v2 = pointOnLine - p1; double dotProduct2 = n1 * v2; Point2D crossingPoint = p1 + n1 * dotProduct2; // Determine whether the projected point on the line, or the crossing point should be // used (according to the second constraint in the comment above) if ( (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > crossingPoint.SquaredEuclideanDistanceTo( p3 )) && (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > pointOnLine.SquaredEuclideanDistanceTo( crossingPoint )) ) { return pointOnLine; } else { return crossingPoint; } } default: return point; } } void mitk::PlanarCross::GeneratePolyLine() { this->SetNumberOfPolyLines( 1 ); this->ClearPolyLines(); - //m_PolyLines->Initialize(); - - //m_PolyLines->InsertElement( 0, VertexContainerType::New() ); - //m_PolyLines->ElementAt( 0 )->Reserve( 2 ); if ( this->GetNumberOfControlPoints() > 2) { this->SetNumberOfPolyLines( 2 ); - //m_PolyLines->InsertElement( 1, VertexContainerType::New() ); - //m_PolyLines->ElementAt( 1 )->Reserve( this->GetNumberOfControlPoints() - 2 ); } for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { if (i < 2) { this->AppendPointToPolyLine( 0, mitk::PlanarFigure::PolyLineElement( this->GetControlPoint( i ), i ) ); } if (i > 1) { this->AppendPointToPolyLine( 1, mitk::PlanarFigure::PolyLineElement( this->GetControlPoint( i ), i ) ); } - - - //if (i < 2) - //{ - // m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i ); - //} - //if (i > 1) - //{ - // m_PolyLines->ElementAt( 1 )->ElementAt( i-2 ) = m_ControlPoints->ElementAt( i ); - //} } } void mitk::PlanarCross::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // Generate helper polyline (orientation line orthogonal to first line) // if the third control point is currently being set if ( this->GetNumberOfControlPoints() != 3 ) { m_HelperPolyLinesToBePainted->SetElement( 0, false ); return; } m_HelperPolyLinesToBePainted->SetElement( 0, true ); this->ClearHelperPolyLines(); // Calculate cross point of first line (p1 to p2) and orthogonal line through // the third control point (p3) const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); const Point2D p3 = this->GetControlPoint( 2 ); - //const Point2D& p1 = m_ControlPoints->ElementAt( 0 ); - //const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); - //const Point2D& p3 = m_ControlPoints->ElementAt( 2 ); - Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = p3 - p1; Point2D crossPoint = p1 + n1 * (n1 * v1); Vector2D v2 = crossPoint - p3; if ( v2.GetNorm() < 1.0 ) { // If third point is on the first line, draw orthogonal "infinite" line // through cross point on line Vector2D v0; v0[0] = n1[1]; v0[1] = -n1[0]; this->AppendPointToHelperPolyLine( 0, mitk::PlanarFigure::PolyLineElement( p3 - v0 * 10000.0, 0 ) ) ; this->AppendPointToHelperPolyLine( 0, mitk::PlanarFigure::PolyLineElement( p3 + v0 * 10000.0, 0 ) ) ; - - //m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3 - v0 * 10000.0; - //m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v0 * 10000.0; } else { // Else, draw orthogonal line starting from third point and crossing the // first line, open-ended only on the other side this->AppendPointToHelperPolyLine( 0, mitk::PlanarFigure::PolyLineElement( p3, 0 ) ) ; this->AppendPointToHelperPolyLine( 0, mitk::PlanarFigure::PolyLineElement( p3 + v2 * 10000.0, 0 ) ) ; - - //m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3; - //m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v2 * 10000.0; } } void mitk::PlanarCross::EvaluateFeaturesInternal() { // Calculate length of first line const Point3D &p0 = this->GetWorldControlPoint( 0 ); const Point3D &p1 = this->GetWorldControlPoint( 1 ); double l1 = p0.EuclideanDistanceTo( p1 ); // Calculate length of second line double l2 = 0.0; if ( !this->GetSingleLineMode() && (this->GetNumberOfControlPoints() > 3) ) { const Point3D &p2 = this->GetWorldControlPoint( 2 ); const Point3D &p3 = this->GetWorldControlPoint( 3 ); l2 = p2.EuclideanDistanceTo( p3 ); } double longestDiameter; double shortAxisDiameter; if ( l1 > l2 ) { longestDiameter = l1; shortAxisDiameter = l2; } else { longestDiameter = l2; shortAxisDiameter = l1; } this->SetQuantity( FEATURE_ID_LONGESTDIAMETER, longestDiameter ); this->SetQuantity( FEATURE_ID_SHORTAXISDIAMETER, shortAxisDiameter ); } void mitk::PlanarCross::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index 4a0e215b21..b6a4d769f6 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,645 +1,640 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-07-08 11:04:08 +0200 (Mi, 08 Jul 2009) $ Version: $Revision: 18029 $ 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 "mitkPlanarFigure.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" #include "algorithm" mitk::PlanarFigure::PlanarFigure() : m_FigurePlaced( false ), m_PreviewControlPointVisible( false ), m_SelectedControlPoint( -1 ), m_Geometry2D( NULL ), m_PolyLineUpToDate(false), m_HelperLinesUpToDate(false), m_FeaturesUpToDate(false), m_FeaturesMTime( 0 ) { m_HelperPolyLinesToBePainted = BoolContainerType::New(); this->SetProperty( "closed", mitk::BoolProperty::New( false ) ); // Currently only single-time-step geometries are supported this->InitializeTimeSlicedGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } void mitk::PlanarFigure::SetGeometry2D( mitk::Geometry2D *geometry ) { this->SetGeometry( geometry ); m_Geometry2D = 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( point ); + 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 ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() ) { if ( position == -1 || position > m_NumberOfControlPoints-1 ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; ++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; } } void mitk::PlanarFigure::DeselectControlPoint() { m_SelectedControlPoint = -1; } 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 ( m_PolyLines.size() > index ) - { - if ( !m_PolyLineUpToDate ) + if ( m_PolyLines.size() > index || !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } - polyLine = m_PolyLines.at( index ); - } - - return polyLine; + 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 ( int i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight); m_HelperLinesUpToDate = true; } helperPolyLine = m_HelperPolyLines.at(index); } return helperPolyLine; } void mitk::PlanarFigure::ClearHelperPolyLines() { for ( int i=0; iEvaluateFeaturesInternal(); 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->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion( itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { 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::InitializeTimeSlicedGeometry( unsigned int timeSteps ) { mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); 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... timeGeometry->InitializeEvenlyTimed( geometry2D, timeSteps ); } 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; mitk::PlanarFigure::VertexContainerType::ConstIterator it; 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 and destination figure!" ); 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 SetGeometry2D((mitk::Geometry2D*)oldFigure->m_Geometry2D->Clone().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() ) m_PolyLines.at( index ).push_back( element ); 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() ) m_HelperPolyLines.at( index ).push_back( element ); else MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyline( int index ) const { return m_PolyLines.at( index ); } diff --git a/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp index 2c24144eab..8ebd1ae7a3 100644 --- a/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp +++ b/Modules/PlanarFigure/Testing/mitkPlanarPolygonTest.cpp @@ -1,120 +1,120 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-03-15 11:12:36 +0100 (Mo, 15 Mrz 2010) $ Version: $Revision: 21745 $ 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 "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() == 2, "Minimum number of control points" ); + 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; ++iter; const mitk::Point2D& pp1 = iter->Point; 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" ); } }; /** * 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 ); // always end with this! MITK_TEST_END(); }