diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp index 8b5bd88ed7..bfdaf01a28 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp @@ -1,196 +1,207 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ 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 "mitkPlanarAngle.h" #include "mitkGeometry2D.h" mitk::PlanarAngle::PlanarAngle() : FEATURE_ID_ANGLE( this->AddFeature( "Angle", "deg" ) ) { // Start with two control points this->ResetNumberOfControlPoints( 2 ); - m_PolyLines->InsertElement( 0, VertexContainerType::New()); - m_HelperPolyLines->InsertElement( 0, VertexContainerType::New()); + this->SetNumberOfPolyLines(1); + this->SetNumberOfHelperPolyLines(1); + + + //m_PolyLines->InsertElement( 0, VertexContainerType::New()); + //m_HelperPolyLines->InsertElement( 0, VertexContainerType::New()); m_HelperPolyLinesToBePainted->InsertElement( 0, false ); } mitk::PlanarAngle::~PlanarAngle() { } //void mitk::PlanarAngle::Initialize() //{ // // Default initialization of line control points // // mitk::Geometry2D *geometry2D = // dynamic_cast< mitk::Geometry2D * >( this->GetGeometry( 0 ) ); // // if ( geometry2D == NULL ) // { // MITK_ERROR << "Missing Geometry2D for PlanarLine"; // return; // } // // mitk::ScalarType width = geometry2D->GetBounds()[1]; // mitk::ScalarType height = geometry2D->GetBounds()[3]; // // mitk::Point2D &startPoint = m_ControlPoints->ElementAt( 0 ); // mitk::Point2D &endPoint = m_ControlPoints->ElementAt( 1 ); // // startPoint[0] = width / 2.0; // startPoint[1] = height / 2.0; // // endPoint[0] = startPoint[0] + 20.0; // endPoint[1] = startPoint[1] + 20.0; //} void mitk::PlanarAngle::GeneratePolyLine() { // Generate poly-line for angle - m_PolyLines->ElementAt( 0 )->Reserve( m_ControlPoints->Size() ); - - for ( unsigned int i = 0; i < m_ControlPoints->Size(); ++i ) + for ( int i=0; iGetNumberOfControlPoints(); i++ ) { - m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i ); + mitk::PlanarFigure::PolyLineElement element( this->GetControlPoint( i ), i ); + this->AppendPointToPolyLine( 0, element ); } + + //m_PolyLines->ElementAt( 0 )->Reserve( m_ControlPoints->Size() ); + + //for ( unsigned int i = 0; i < m_ControlPoints->Size(); ++i ) + //{ + // m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i ); + //} } void mitk::PlanarAngle::GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) { // Generate helper-poly-line for angle - if ( m_ControlPoints->Size() < 3) + if ( this->GetNumberOfControlPoints() < 3) { m_HelperPolyLinesToBePainted->SetElement(0, false); return; //We do not need to draw an angle as there are no two arms yet } + m_HelperPolyLines->ElementAt( 0 )->Reserve( 3 ); - const Point2D ¢erPoint = m_ControlPoints->ElementAt( 1 ); - const Point2D &boundaryPointOne = m_ControlPoints->ElementAt( 0 ); - const Point2D &boundaryPointTwo = m_ControlPoints->ElementAt( 2 ); + const Point2D centerPoint = this->GetControlPoint( 1 ); + const Point2D boundaryPointOne = this->GetControlPoint( 0 ); + const Point2D boundaryPointTwo = this->GetControlPoint( 2 ); double radius = centerPoint.EuclideanDistanceTo( boundaryPointOne ); if ( radius > centerPoint.EuclideanDistanceTo( boundaryPointTwo ) ) { radius = centerPoint.EuclideanDistanceTo( boundaryPointTwo ); } //Fixed size radius depending on screen size for the angle double nonScalingRadius = displayHeight * mmPerDisplayUnit * 0.05; if (nonScalingRadius > radius) { m_HelperPolyLinesToBePainted->SetElement(0, false); return; //if the arc has a radius that is longer than the shortest arm it should not be painted } m_HelperPolyLinesToBePainted->SetElement(0, true); radius = nonScalingRadius; double angle = this->GetQuantity( FEATURE_ID_ANGLE ); //Determine from which arm the angle should be drawn Vector2D v0 = boundaryPointOne - centerPoint; Vector2D v1 = boundaryPointTwo - centerPoint; Vector2D v2; v2[0] = 1.0; v2[1] = 0.0; v0[0] = v0[0] * cos( 0.001 ) - v0[1] * sin( 0.001 ); //rotate one arm a bit v0[1] = v0[0] * sin( 0.001 ) + v0[1] * cos( 0.001 ); v0.Normalize(); v1.Normalize(); double testAngle = acos( v0 * v1 ); //if the rotated arm is closer to the other arm than before it is the one from which we start drawing //else we start drawing from the other arm (we want to draw in the mathematically positive direction) if( angle > testAngle ) { v1[0] = v0[0] * cos( -0.001 ) - v0[1] * sin( -0.001 ); v1[1] = v0[0] * sin( -0.001 ) + v0[1] * cos( -0.001 ); //We determine if the arm is mathematically forward or backward //assuming we rotate between -pi and pi if ( acos( v0 * v2 ) > acos ( v1 * v2 )) { testAngle = acos( v1 * v2 ); } else { testAngle = -acos( v1 * v2 ); } } else { v0[0] = v1[0] * cos( -0.001 ) - v1[1] * sin( -0.001 ); v0[1] = v1[0] * sin( -0.001 ) + v1[1] * cos( -0.001 ); //We determine if the arm is mathematically forward or backward //assuming we rotate between -pi and pi if ( acos( v0 * v2 ) < acos ( v1 * v2 )) { testAngle = acos( v1 * v2 ); } else { testAngle = -acos( v1 * v2 ); } } // Generate poly-line with 16 segments m_HelperPolyLines->ElementAt( 0 )->Reserve( 16 ); for ( int t = 0; t < 16; ++t ) { double alpha = (double) t * angle / 15.0 + testAngle; m_HelperPolyLines->ElementAt( 0 )->ElementAt( t )[0] = centerPoint[0] + radius * cos( alpha ); m_HelperPolyLines->ElementAt( 0 )->ElementAt( t )[1] = centerPoint[1] + radius * sin( alpha ); } } void mitk::PlanarAngle::EvaluateFeaturesInternal() { if ( this->GetNumberOfControlPoints() < 3 ) { // Angle not yet complete. return; } // Calculate angle between lines const Point2D &p0 = this->GetControlPoint( 0 ); const Point2D &p1 = this->GetControlPoint( 1 ); const Point2D &p2 = this->GetControlPoint( 2 ); Vector2D v0 = p1 - p0; Vector2D v1 = p1 - p2; v0.Normalize(); v1.Normalize(); double angle = acos( v0 * v1 ); this->SetQuantity( FEATURE_ID_ANGLE, angle ); } void mitk::PlanarAngle::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp index d90c76665a..a4d345ffc3 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp @@ -1,350 +1,391 @@ /*========================================================================= 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) - m_HelperPolyLines->InsertElement( 0, VertexContainerType::New()); - m_HelperPolyLines->ElementAt( 0 )->Reserve( 2 ); + 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 = m_ControlPoints->ElementAt( 0 ); - m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 1 ) ); - m_ControlPoints->InsertElement( 1, tmpPoint ); + 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 - m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 3 ) ); - m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 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 - m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 2 ) ); - m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 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 = m_ControlPoints->ElementAt( 0 ); - const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); + 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 = m_ControlPoints->ElementAt( 0 ); - const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); - const Point2D& p3 = m_ControlPoints->ElementAt( 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() { - m_PolyLines->Initialize(); + this->SetNumberOfPolyLines( 1 ); + + //m_PolyLines->Initialize(); - m_PolyLines->InsertElement( 0, VertexContainerType::New() ); - m_PolyLines->ElementAt( 0 )->Reserve( 2 ); + //m_PolyLines->InsertElement( 0, VertexContainerType::New() ); + //m_PolyLines->ElementAt( 0 )->Reserve( 2 ); if ( this->GetNumberOfControlPoints() > 2) { - m_PolyLines->InsertElement( 1, VertexContainerType::New() ); - m_PolyLines->ElementAt( 1 )->Reserve( 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) { - m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i ); + this->AppendPointToPolyLine( 0, mitk::PlanarFigure::PolyLineElement( this->GetControlPoint( i ), i ) ); } if (i > 1) { - m_PolyLines->ElementAt( 1 )->ElementAt( i-2 ) = m_ControlPoints->ElementAt( i ); + 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 ); // Calculate cross point of first line (p1 to p2) and orthogonal line through // the third control point (p3) - const Point2D& p1 = m_ControlPoints->ElementAt( 0 ); - const Point2D& p2 = m_ControlPoints->ElementAt( 1 ); - const Point2D& p3 = m_ControlPoints->ElementAt( 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 ); 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]; - m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3 - v0 * 10000.0; - m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v0 * 10000.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 - m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3; - m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v2 * 10000.0; + 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/mitkPlanarLine.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp index 59a0789c8c..c0b2e9fec2 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp @@ -1,94 +1,72 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ 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 "mitkPlanarLine.h" #include "mitkGeometry2D.h" mitk::PlanarLine::PlanarLine() : FEATURE_ID_LENGTH( this->AddFeature( "Length", "mm" ) ) { // Line has two control points this->ResetNumberOfControlPoints( 2 ); - m_PolyLines->InsertElement( 0, VertexContainerType::New()); + this->SetNumberOfPolyLines( 1 ); + + //m_PolyLines->InsertElement( 0, VertexContainerType::New()); } mitk::PlanarLine::~PlanarLine() { } -//void mitk::PlanarLine::Initialize() -//{ -// // Default initialization of line control points -// -// mitk::Geometry2D *geometry2D = -// dynamic_cast< mitk::Geometry2D * >( this->GetGeometry( 0 ) ); -// -// if ( geometry2D == NULL ) -// { -// MITK_ERROR << "Missing Geometry2D for PlanarLine"; -// return; -// } -// -// mitk::ScalarType width = geometry2D->GetBounds()[1]; -// mitk::ScalarType height = geometry2D->GetBounds()[3]; -// -// mitk::Point2D &startPoint = m_ControlPoints->ElementAt( 0 ); -// mitk::Point2D &endPoint = m_ControlPoints->ElementAt( 1 ); -// -// startPoint[0] = width / 2.0; -// startPoint[1] = height / 2.0; -// -// endPoint[0] = startPoint[0] + 20.0; -// endPoint[1] = startPoint[1] + 20.0; -//} - - void mitk::PlanarLine::GeneratePolyLine() { // TODO: start line at specified start point... // Generate poly-line - m_PolyLines->ElementAt( 0 )->Reserve( 2 ); - m_PolyLines->ElementAt( 0 )->ElementAt( 0 ) = m_ControlPoints->ElementAt( 0 ); - m_PolyLines->ElementAt( 0 )->ElementAt( 1 ) = m_ControlPoints->ElementAt( 1 ); + this->AppendPointToPolyLine( 0 , mitk::PlanarFigure::PolyLineElement( this->GetControlPoint(0), 0) ); + this->AppendPointToPolyLine( 0 , mitk::PlanarFigure::PolyLineElement( this->GetControlPoint(1), 0) ); + + //m_PolyLines->ElementAt( 0 )->Reserve( 2 ); + //m_PolyLines->ElementAt( 0 )->ElementAt( 0 ) = m_ControlPoints->ElementAt( 0 ); + //m_PolyLines->ElementAt( 0 )->ElementAt( 1 ) = m_ControlPoints->ElementAt( 1 ); } void mitk::PlanarLine::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A line does not require a helper object } void mitk::PlanarLine::EvaluateFeaturesInternal() { // Calculate line length const Point3D &p0 = this->GetWorldControlPoint( 0 ); const Point3D &p1 = this->GetWorldControlPoint( 1 ); double length = p0.EuclideanDistanceTo( p1 ); this->SetQuantity( FEATURE_ID_LENGTH, length ); } void mitk::PlanarLine::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp index c3bd06d6ef..029ad62ea5 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp @@ -1,246 +1,256 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ 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 "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 ); // Polygon is closed by default this->SetProperty( "closed", mitk::BoolProperty::New( true ) ); m_PolyLines->InsertElement( 0, VertexContainerType::New()); + this->SetNumberOfPolyLines( 1 ); } 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::Initialize() //{ // // Default initialization of circle control points // // mitk::Geometry2D *geometry2D = // dynamic_cast< mitk::Geometry2D * >( this->GetGeometry( 0 ) ); // // if ( geometry2D == NULL ) // { // MITK_ERROR << "Missing Geometry2D for PlanarCircle"; // return; // } // // mitk::ScalarType width = geometry2D->GetBounds()[1]; // mitk::ScalarType height = geometry2D->GetBounds()[3]; // // mitk::Point2D ¢erPoint = m_ControlPoints->ElementAt( 0 ); // mitk::Point2D &boundaryPoint = m_ControlPoints->ElementAt( 1 ); // // centerPoint[0] = width / 2.0; // centerPoint[1] = height / 2.0; // // boundaryPoint[0] = centerPoint[0] + 20.0; // boundaryPoint[1] = centerPoint[1]; //} void mitk::PlanarPolygon::GeneratePolyLine() { - // if more elements are needed that have been reserved -> reserve - if ( m_PolyLines->ElementAt( 0 )->size() < this->GetNumberOfControlPoints() ) - { - m_PolyLines->ElementAt( 0 )->Reserve( this->GetNumberOfControlPoints() ); - } - // if more elements have been reserved/set before than are needed now -> clear vector - else if (m_PolyLines->ElementAt( 0 )->size() > this->GetNumberOfControlPoints()) + ControlPointListType::const_iterator iter = m_NewControlPoints.begin(); + + for ( int i=0; iElementAt( 0 )->clear(); + Point2D pnt = m_NewControlPoints.at( i ); + PolyLineElement elem(pnt,i); + this->AppendPointToPolyLine( 0, elem ); } + //// if more elements are needed that have been reserved -> reserve + //if ( m_PolyLines->ElementAt( 0 )->size() < this->GetNumberOfControlPoints() ) + //{ + // m_PolyLines->ElementAt( 0 )->Reserve( this->GetNumberOfControlPoints() ); + //} + //// if more elements have been reserved/set before than are needed now -> clear vector + //else if (m_PolyLines->ElementAt( 0 )->size() > this->GetNumberOfControlPoints()) + //{ + // m_PolyLines->ElementAt( 0 )->clear(); + //} + // TODO: start polygon at specified initalize point... - m_PolyLines->ElementAt( 0 )->Reserve( this->GetNumberOfControlPoints() ); - for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) - { - m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i ); - } + //m_PolyLines->ElementAt( 0 )->Reserve( this->GetNumberOfControlPoints() ); + //for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) + //{ + // m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( 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; for ( i = 0; i < this->GetNumberOfControlPoints() - 1; ++i ) { circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo( this->GetWorldControlPoint( i + 1 ) ); } if ( this->IsClosed() ) { circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo( this->GetWorldControlPoint( 0 ) ); } 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 = (unsigned int)GetNumberOfControlPoints(); if( numberOfPoints >= 4) { for ( i = 0; i < (numberOfPoints - 1); ++i ) { // line 1 Point2D p0 = this->GetControlPoint( i ); Point2D p1 = this->GetControlPoint(i + 1); // check for intersection with all other lines for (j = i+1; j < (numberOfPoints - 1); ++j ) { Point2D p2 = this->GetControlPoint(j); Point2D p3 = this->GetControlPoint(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 = this->GetControlPoint(0); Point2D p3 = this->GetControlPoint(numberOfPoints - 1); intersection = CheckForLineIntersection(p0,p1,p2,p3); if (intersection) break; } } // calculate area for ( i = 0; i < this->GetNumberOfControlPoints(); ++i ) { Point2D p0 = this->GetControlPoint( i ); Point2D p1 = this->GetControlPoint( (i + 1) % this->GetNumberOfControlPoints() ); 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(Point2D p1, Point2D p2, Point2D p3, Point2D p4) { // 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 float x1 = p1[0], x2 = p2[0], x3 = p3[0], x4 = p4[0]; float y1 = p1[1], y2 = p2[1], y3 = p3[1], y4 = p4[1]; float 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 float pre = (x1*y2 - y1*x2), post = (x3*y4 - y3*x4); float x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d; float y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d; // Check if the x and y coordinates are within both lines if ( x < std::min(x1, x2) || x > std::max(x1, x2) || x < std::min(x3, x4) || x > std::max(x3, x4) ) return false; if ( y < std::min(y1, y2) || y > std::max(y1, y2) || y < std::min(y3, y4) || y > std::max(y3, y4) ) return false; // point of intersection Point2D ret; ret[0] = x; ret[1] = y; return true; }