ccstruct/linlsq.cpp

Go to the documentation of this file.
00001 
00020 #include "mfcpch.h"
00021 #include          <stdio.h>
00022 #include          <math.h>
00023 #include          "errcode.h"
00024 #include          "linlsq.h"
00025 
00026 #ifndef __UNIX__
00027 #define M_PI        3.14159265359
00028 #endif
00029 
00030 const ERRCODE EMPTY_LLSQ = "Can't delete from an empty LLSQ";
00031 
00032 #define EXTERN
00033 
00036 EXTERN double_VAR (pdlsq_posdir_ratio, 4e-6, "Mult of dir to cf pos");
00037 EXTERN double_VAR (pdlsq_threshold_angleavg, 0.1666666,
00038 "Frac of pi for simple fit");
00044 void LLSQ::clear() {  //initialize
00045   n = 0;                         //no elements
00046   sigx = 0;                      //update accumulators
00047   sigy = 0;
00048   sigxx = 0;
00049   sigxy = 0;
00050   sigyy = 0;
00051 }
00052 
00053 
00057 void LLSQ::add(           //add an element
00058                double x,  //xcoord
00059                double y   //ycoord
00060               ) {
00061   n++;                           //count elements
00062   sigx += x;                     //update accumulators
00063   sigy += y;
00064   sigxx += x * x;
00065   sigxy += x * y;
00066   sigyy += y * y;
00067 }
00068 
00069 
00073 void LLSQ::remove(           //delete an element
00074                   double x,  //xcoord
00075                   double y   //ycoord
00076                  ) {
00077   if (n <= 0)
00078                                  //illegal
00079     EMPTY_LLSQ.error ("LLSQ::remove", ABORT, NULL);
00080   n--;                           //count elements
00081   sigx -= x;                     //update accumulators
00082   sigy -= y;
00083   sigxx -= x * x;
00084   sigxy -= x * y;
00085   sigyy -= y * y;
00086 }
00087 
00088 
00094 double LLSQ::m() {  //get gradient
00095   if (n > 1)
00096     return (sigxy - sigx * sigy / n) / (sigxx - sigx * sigx / n);
00097   else
00098     return 0;                    //too little
00099 }
00100 
00101 
00107 double LLSQ::c(          //get constant
00108                double m  //gradient to fit with
00109               ) {
00110   if (n > 0)
00111     return (sigy - m * sigx) / n;
00112   else
00113     return 0;                    //too little
00114 }
00115 
00116 
00122 double LLSQ::rms(           //get error
00123                  double m,  //gradient to fit with
00124                  double c   //constant to fit with
00125                 ) {
00126   double error;                  //total error
00127 
00128   if (n > 0) {
00129     error =
00130       sigyy + m * (m * sigxx + 2 * (c * sigx - sigxy)) + c * (n * c -
00131       2 * sigy);
00132     if (error >= 0)
00133       error = sqrt (error / n);  //sqrt of mean
00134     else
00135       error = 0;
00136   }
00137   else
00138     error = 0;                   //too little
00139   return error;
00140 }
00141 
00142 
00148 double LLSQ::spearman() {  //get error
00149   double error;                  //total error
00150 
00151   if (n > 1) {
00152     error = (sigxx - sigx * sigx / n) * (sigyy - sigy * sigy / n);
00153     if (error > 0) {
00154       error = (sigxy - sigx * sigy / n) / sqrt (error);
00155     }
00156     else
00157       error = 1;
00158   }
00159   else
00160     error = 1;                   //too little
00161   return error;
00162 }
00163 
00164 
00169 float PDLSQ::fit(                 //get fit
00170                  DIR128 &ang,     //output angle
00171                  float &sin_ang,  //r,theta parameterisation
00172                  float &cos_ang,
00173                  float &r) {
00174   double a, b;                   //itermediates
00175   double angle;                  //resulting angle
00176   double avg_angle;              //simple average
00177   double error;                  //total error
00178   double sinx, cosx;             //return values
00179 
00180   if (pos.n > 0) {
00181     a = pos.sigxy - pos.sigx * pos.sigy / pos.n
00182       + pdlsq_posdir_ratio * dir.sigxy;
00183     b =
00184       pos.sigxx - pos.sigyy + (pos.sigy * pos.sigy -
00185       pos.sigx * pos.sigx) / pos.n +
00186       pdlsq_posdir_ratio * (dir.sigxx - dir.sigyy);
00187     if (dir.sigy != 0 || dir.sigx != 0)
00188       avg_angle = atan2 (dir.sigy, dir.sigx);
00189     else
00190       avg_angle = 0;
00191     if ((a != 0 || b != 0) && pos.n > 1)
00192       angle = atan2 (2 * a, b) / 2;
00193     else
00194       angle = avg_angle;
00195     error = avg_angle - angle;
00196     if (error > M_PI / 2) {
00197       error -= M_PI;
00198       angle += M_PI;
00199     }
00200     if (error < -M_PI / 2) {
00201       error += M_PI;
00202       angle -= M_PI;
00203     }
00204     if (error > M_PI * pdlsq_threshold_angleavg
00205       || error < -M_PI * pdlsq_threshold_angleavg)
00206       angle = avg_angle;         //go simple
00207                                  //convert direction
00208     ang = (INT16) (angle * MODULUS / (2 * M_PI));
00209     sinx = sin (angle);
00210     cosx = cos (angle);
00211     r = (sinx * pos.sigx - cosx * pos.sigy) / pos.n;
00212     //              tprintf("x=%g, y=%g, xx=%g, xy=%g, yy=%g, a=%g, b=%g, ang=%g, r=%g\n",
00213     //                      pos.sigx,pos.sigy,pos.sigxx,pos.sigxy,pos.sigyy,
00214     //                      a,b,angle,r);
00215     error = dir.sigxx * sinx * sinx + dir.sigyy * cosx * cosx
00216       - 2 * dir.sigxy * sinx * cosx;
00217     error *= pdlsq_posdir_ratio;
00218     error += sinx * sinx * pos.sigxx + cosx * cosx * pos.sigyy
00219       - 2 * sinx * cosx * pos.sigxy
00220       - 2 * r * (sinx * pos.sigx - cosx * pos.sigy) + r * r * pos.n;
00221     if (error >= 0)
00222                                  //rms value
00223         error = sqrt (error / pos.n);
00224     else
00225       error = 0;                 //-0
00226     sin_ang = sinx;
00227     cos_ang = cosx;
00228   }
00229   else {
00230     sin_ang = 0.0f;
00231     cos_ang = 0.0f;
00232     ang = 0;
00233     error = 0;                   //too little
00234   }
00235   return error;
00236 }

Generated on Wed Feb 28 19:49:08 2007 for Tesseract by  doxygen 1.5.1