Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "mitkPlanarCross.h"
00020 #include "mitkGeometry2D.h"
00021 #include "mitkProperties.h"
00022
00023
00024 mitk::PlanarCross::PlanarCross()
00025 : FEATURE_ID_LONGESTDIAMETER( this->AddFeature( "Longest Axis", "mm" ) ),
00026 FEATURE_ID_SHORTAXISDIAMETER( this->AddFeature( "Short Axis", "mm" ) )
00027 {
00028
00029 this->ResetNumberOfControlPoints( 2 );
00030
00031
00032 this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( false ) );
00033
00034
00035 m_HelperPolyLines->InsertElement( 0, VertexContainerType::New());
00036 m_HelperPolyLines->ElementAt( 0 )->Reserve( 2 );
00037 m_HelperPolyLinesToBePainted->InsertElement( 0, false );
00038 }
00039
00040
00041 mitk::PlanarCross::~PlanarCross()
00042 {
00043 }
00044
00045
00046 void mitk::PlanarCross::SetSingleLineMode( bool singleLineMode )
00047 {
00048 this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( singleLineMode ) );
00049 this->Modified();
00050 }
00051
00052
00053 bool mitk::PlanarCross::GetSingleLineMode() const
00054 {
00055 mitk::BoolProperty* singleLineMode = dynamic_cast< mitk::BoolProperty* >(
00056 this->GetProperty( "SingleLineMode" ).GetPointer() );
00057
00058 if ( singleLineMode != NULL )
00059 {
00060 return singleLineMode->GetValue();
00061 }
00062 return false;
00063 }
00064
00065
00066 bool mitk::PlanarCross::ResetOnPointSelect()
00067 {
00068 if ( this->GetSingleLineMode() )
00069 {
00070
00071 return false;
00072 }
00073
00074 switch ( m_SelectedControlPoint )
00075 {
00076 default:
00077
00078 return false;
00079
00080 case 0:
00081 {
00082
00083 Point2D tmpPoint = m_ControlPoints->ElementAt( 0 );
00084 m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 1 ) );
00085 m_ControlPoints->InsertElement( 1, tmpPoint );
00086
00087 }
00088
00089 case 1:
00090 {
00091
00092 this->ResetNumberOfControlPoints( 2 );
00093 this->SelectControlPoint( 1 );
00094 return true;
00095 }
00096
00097 case 2:
00098 {
00099
00100 m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 3 ) );
00101 m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 2 ) );
00102
00103
00104 this->ResetNumberOfControlPoints( 2 );
00105 this->SelectControlPoint( 1 );
00106 return true;
00107 }
00108
00109 case 3:
00110 {
00111
00112 m_ControlPoints->InsertElement( 0, m_ControlPoints->ElementAt( 2 ) );
00113 m_ControlPoints->InsertElement( 1, m_ControlPoints->ElementAt( 3 ) );
00114
00115
00116 this->ResetNumberOfControlPoints( 2 );
00117 this->SelectControlPoint( 1 );
00118 return true;
00119 }
00120 }
00121 }
00122
00123
00124 unsigned int mitk::PlanarCross::GetNumberOfFeatures() const
00125 {
00126 if ( this->GetSingleLineMode() || (this->GetNumberOfControlPoints() < 4) )
00127 {
00128 return 1;
00129 }
00130 else
00131 {
00132 return 2;
00133 }
00134 }
00135
00136
00137 mitk::Point2D mitk::PlanarCross::ApplyControlPointConstraints( unsigned int index, const Point2D& point )
00138 {
00139
00140
00141
00142
00143
00144
00145 unsigned int count = 0;
00146 Point2D confinedPoint = point;
00147 Point2D superclassConfinedPoint;
00148 do
00149 {
00150 superclassConfinedPoint = Superclass::ApplyControlPointConstraints( index, confinedPoint );
00151 confinedPoint = this->InternalApplyControlPointConstraints( index, superclassConfinedPoint );
00152 ++count;
00153 } while ( (confinedPoint.EuclideanDistanceTo( superclassConfinedPoint ) > mitk::eps)
00154 && (count < 32) );
00155
00156 return confinedPoint;
00157 }
00158
00159
00160 mitk::Point2D mitk::PlanarCross::InternalApplyControlPointConstraints( unsigned int index, const Point2D& point )
00161 {
00162
00163 switch ( index )
00164 {
00165 case 2:
00166 {
00167
00168
00169 const Point2D& p1 = m_ControlPoints->ElementAt( 0 );
00170 const Point2D& p2 = m_ControlPoints->ElementAt( 1 );
00171
00172 Vector2D n1 = p2 - p1;
00173 n1.Normalize();
00174
00175 Vector2D v1 = point - p1;
00176 double dotProduct = n1 * v1;
00177 Point2D crossPoint = p1 + n1 * dotProduct;;
00178 Vector2D crossVector = point - crossPoint;
00179
00180 if ( dotProduct < 0.0 )
00181 {
00182
00183 return (p1 + crossVector);
00184 }
00185 else if ( dotProduct > p2.EuclideanDistanceTo( p1 ) )
00186 {
00187
00188 return (p2 + crossVector);
00189 }
00190 else
00191 {
00192
00193 return point;
00194 }
00195 }
00196
00197 case 3:
00198 {
00199
00200
00201
00202
00203 const Point2D& p1 = m_ControlPoints->ElementAt( 0 );
00204 const Point2D& p2 = m_ControlPoints->ElementAt( 1 );
00205 const Point2D& p3 = m_ControlPoints->ElementAt( 2 );
00206
00207
00208
00209 Vector2D n1 = p2 - p1;
00210 n1.Normalize();
00211
00212 Vector2D v1 = point - p3;
00213 double dotProduct1 = n1 * v1;
00214
00215 Point2D pointOnLine = point - n1 * dotProduct1;
00216
00217
00218 Vector2D v2 = pointOnLine - p1;
00219 double dotProduct2 = n1 * v2;
00220
00221 Point2D crossingPoint = p1 + n1 * dotProduct2;
00222
00223
00224
00225 if ( (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > crossingPoint.SquaredEuclideanDistanceTo( p3 ))
00226 && (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > pointOnLine.SquaredEuclideanDistanceTo( crossingPoint )) )
00227 {
00228 return pointOnLine;
00229 }
00230 else
00231 {
00232 return crossingPoint;
00233 }
00234 }
00235
00236 default:
00237 return point;
00238 }
00239 }
00240
00241
00242 void mitk::PlanarCross::GeneratePolyLine()
00243 {
00244 m_PolyLines->Initialize();
00245
00246 m_PolyLines->InsertElement( 0, VertexContainerType::New() );
00247 m_PolyLines->ElementAt( 0 )->Reserve( 2 );
00248 if ( this->GetNumberOfControlPoints() > 2)
00249 {
00250 m_PolyLines->InsertElement( 1, VertexContainerType::New() );
00251 m_PolyLines->ElementAt( 1 )->Reserve( this->GetNumberOfControlPoints() - 2 );
00252 }
00253
00254 for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i )
00255 {
00256 if (i < 2)
00257 {
00258 m_PolyLines->ElementAt( 0 )->ElementAt( i ) = m_ControlPoints->ElementAt( i );
00259 }
00260 if (i > 1)
00261 {
00262 m_PolyLines->ElementAt( 1 )->ElementAt( i-2 ) = m_ControlPoints->ElementAt( i );
00263 }
00264 }
00265 }
00266
00267 void mitk::PlanarCross::GenerateHelperPolyLine(double , unsigned int )
00268 {
00269
00270
00271 if ( this->GetNumberOfControlPoints() != 3 )
00272 {
00273 m_HelperPolyLinesToBePainted->SetElement( 0, false );
00274 return;
00275 }
00276
00277 m_HelperPolyLinesToBePainted->SetElement( 0, true );
00278
00279
00280
00281 const Point2D& p1 = m_ControlPoints->ElementAt( 0 );
00282 const Point2D& p2 = m_ControlPoints->ElementAt( 1 );
00283 const Point2D& p3 = m_ControlPoints->ElementAt( 2 );
00284
00285 Vector2D n1 = p2 - p1;
00286 n1.Normalize();
00287
00288 Vector2D v1 = p3 - p1;
00289 Point2D crossPoint = p1 + n1 * (n1 * v1);
00290
00291 Vector2D v2 = crossPoint - p3;
00292 if ( v2.GetNorm() < 1.0 )
00293 {
00294
00295
00296 Vector2D v0;
00297 v0[0] = n1[1];
00298 v0[1] = -n1[0];
00299 m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3 - v0 * 10000.0;
00300 m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v0 * 10000.0;
00301 }
00302 else
00303 {
00304
00305
00306 m_HelperPolyLines->ElementAt( 0 )->ElementAt( 0 ) = p3;
00307 m_HelperPolyLines->ElementAt( 0 )->ElementAt( 1 ) = p3 + v2 * 10000.0;
00308 }
00309 }
00310
00311
00312 void mitk::PlanarCross::EvaluateFeaturesInternal()
00313 {
00314
00315 const Point3D &p0 = this->GetWorldControlPoint( 0 );
00316 const Point3D &p1 = this->GetWorldControlPoint( 1 );
00317 double l1 = p0.EuclideanDistanceTo( p1 );
00318
00319
00320 double l2 = 0.0;
00321 if ( !this->GetSingleLineMode() && (this->GetNumberOfControlPoints() > 3) )
00322 {
00323 const Point3D &p2 = this->GetWorldControlPoint( 2 );
00324 const Point3D &p3 = this->GetWorldControlPoint( 3 );
00325 l2 = p2.EuclideanDistanceTo( p3 );
00326 }
00327
00328 double longestDiameter;
00329 double shortAxisDiameter;
00330 if ( l1 > l2 )
00331 {
00332 longestDiameter = l1;
00333 shortAxisDiameter = l2;
00334 }
00335 else
00336 {
00337 longestDiameter = l2;
00338 shortAxisDiameter = l1;
00339 }
00340
00341
00342 this->SetQuantity( FEATURE_ID_LONGESTDIAMETER, longestDiameter );
00343 this->SetQuantity( FEATURE_ID_SHORTAXISDIAMETER, shortAxisDiameter );
00344 }
00345
00346
00347 void mitk::PlanarCross::PrintSelf( std::ostream& os, itk::Indent indent) const
00348 {
00349 Superclass::PrintSelf( os, indent );
00350 }