contrib/oxl/osl/internals/osl_reorder_chain.cxx
Go to the documentation of this file.
00001 // This is oxl/osl/internals/osl_reorder_chain.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "osl_reorder_chain.h"
00010 
00011 #include <vcl_vector.h>
00012 #include <vnl/vnl_math.h>
00013 #include <osl/osl_edgel_chain.h>
00014 #include <osl/osl_OrthogRegress.h>
00015 
00016 //:
00017 // Takes a DigitalCurve that is assumed to form a closed loop and finds the
00018 // largest corner in the chain. This point is then used as the starting point for
00019 // the chain and the rest of the points are reordered. Doing this improves the
00020 // segmentation for osl_edgel_chains composed of many straight lines.
00021 //
00022 void osl_reorder_chain(osl_edgel_chain *dc)
00023 {
00024   int i,j,start=-1;
00025   int npts=5;
00026   int mid=npts/2;
00027   int size=dc->size();
00028 
00029   // The corner detection process involves fitting straight lines to npts
00030   // and computing the difference in orientation between between the current
00031   // and last fit. The largest change in slope is recorded and this point used
00032   // as the new start point.
00033 
00034   // Need at least npts+1 points to do anything (though may as well have more!)
00035   if ( size < npts+1 )
00036     return;
00037 
00038   osl_OrthogRegress data;
00039   double a0,b0,a1,b1,dot,diff,max=0.0;
00040   double MPIby2 = vnl_math::pi/2.0;
00041 
00042   // Add the first npts to the data set and fit.
00043   for (i=0; i<npts; ++i)
00044     data.IncrByXY(dc->GetX(i),dc->GetY(i));
00045   data.Fit();
00046   a0 = data.GetA();  b0 = data.GetB();
00047 
00048   // Now redo the fits up to the end of the data set
00049   //FIXME: should this say "j<size", not "i<size"? -- fsm
00050   for (j=0; i<size; i++,j++)  {
00051     data.DecrByXY(dc->GetX(j),dc->GetY(j));
00052     data.IncrByXY(dc->GetX(i),dc->GetY(i));
00053     data.Fit();
00054     a1 = data.GetA();  b1 = data.GetB();
00055 
00056     // Compute the angle between this and the last fit. Store if this is
00057     // the new maximum. Note that the fits are normalised so that a^2+b^2=1.
00058     dot = a0*a1+b0*b1;
00059     if ( dot > 1.0 )
00060       dot = 1.0;
00061     if ( dot < -1.0 )
00062       dot = -1.0;
00063     diff = vcl_acos(dot);
00064     if ( diff > MPIby2)
00065       diff = vnl_math::pi - diff;
00066     if ( diff > max ) {
00067       max = diff;
00068       start = j+mid;
00069     }
00070 
00071     a0 = a1;  b0 = b1;
00072   }
00073 
00074   // Simple error check
00075   if ( start < 0 )
00076     return;
00077 
00078   // The curve should now begin at start - shuffle the points around.
00079   // Buffer the points first, then move.
00080   vcl_vector<float> x(size);
00081   vcl_vector<float> y(size);
00082   vcl_vector<float> grad(size);
00083   vcl_vector<float> theta(size);
00084 
00085   for (i=0; i<size; ++i)  {
00086     x[i] = dc->GetX(i);
00087     y[i] = dc->GetY(i);
00088     grad[i] = dc->GetGrad(i);
00089     theta[i] = dc->GetTheta(i);
00090   }
00091 
00092   for (i=0,j=start; i<size; i++,j++)  {
00093     if ( j == size )
00094       j = 0;
00095     dc->SetX(x[j],i);
00096     dc->SetY(y[j],i);
00097     dc->SetGrad(grad[j],i);
00098     dc->SetTheta(theta[j],i);
00099   }
00100 }