ccstruct/quspline.cpp

Go to the documentation of this file.
00001 
00020 #include "mfcpch.h"
00021 #include          "memry.h"
00022 #include          "quadlsq.h"
00023 #include          "quspline.h"
00024 
00025 #define QSPLINE_PRECISION 16     //no of steps to draw
00026 
00030 QSPLINE::QSPLINE(                 //constructor
00031                  INT32 count,     //no of segments
00032                  INT32 *xstarts,  //start coords
00033                  double *coeffs   //coefficients
00034                 ) {
00035   INT32 index;                   //segment index
00036 
00037                                  //get memory
00038   xcoords = (INT32 *) alloc_mem ((count + 1) * sizeof (INT32));
00039   quadratics = (QUAD_COEFFS *) alloc_mem (count * sizeof (QUAD_COEFFS));
00040   segments = count;
00041   for (index = 0; index < segments; index++) {
00042                                  //copy them
00043     xcoords[index] = xstarts[index];
00044     quadratics[index] = QUAD_COEFFS (coeffs[index * 3],
00045       coeffs[index * 3 + 1],
00046       coeffs[index * 3 + 2]);
00047   }
00048                                  //right edge
00049   xcoords[index] = xstarts[index];
00050 }
00051 
00052 
00056 QSPLINE::QSPLINE (               //constructor
00057 int xstarts[],                   //spline boundaries
00058 int segcount,                    //no of segments
00059 int xpts[],                      //points to fit
00060 int ypts[], int pointcount,      //no of pts
00061 int degree                       //fit required
00062 ) {
00063   register int pointindex;       /*no along text line */
00064   register int segment;          /*segment no */
00065   INT32 *ptcounts;               //no in each segment
00066   QLSQ qlsq;                     /*accumulator */
00067 
00068   segments = segcount;
00069   xcoords = (INT32 *) alloc_mem ((segcount + 1) * sizeof (INT32));
00070   ptcounts = (INT32 *) alloc_mem ((segcount + 1) * sizeof (INT32));
00071   quadratics = (QUAD_COEFFS *) alloc_mem (segcount * sizeof (QUAD_COEFFS));
00072   memmove (xcoords, xstarts, (segcount + 1) * sizeof (INT32));
00073   ptcounts[0] = 0;               /*none in any yet */
00074   for (segment = 0, pointindex = 0; pointindex < pointcount; pointindex++) {
00075     while (segment < segcount && xpts[pointindex] >= xstarts[segment]) {
00076       segment++;                 /*try next segment */
00077                                  /*cumulative counts */
00078       ptcounts[segment] = ptcounts[segment - 1];
00079     }
00080     ptcounts[segment]++;         /*no in previous partition */
00081   }
00082   while (segment < segcount) {
00083     segment++;
00084                                  /*zero the rest */
00085     ptcounts[segment] = ptcounts[segment - 1];
00086   }
00087 
00088   for (segment = 0; segment < segcount; segment++) {
00089     qlsq.clear ();
00090                                  /*first blob */
00091     pointindex = ptcounts[segment];
00092     if (pointindex > 0
00093       && xpts[pointindex] != xpts[pointindex - 1]
00094       && xpts[pointindex] != xstarts[segment])
00095       qlsq.add (xstarts[segment],
00096         ypts[pointindex - 1]
00097         + (ypts[pointindex] - ypts[pointindex - 1])
00098         * (xstarts[segment] - xpts[pointindex - 1])
00099         / (xpts[pointindex] - xpts[pointindex - 1]));
00100     for (; pointindex < ptcounts[segment + 1]; pointindex++) {
00101       qlsq.add (xpts[pointindex], ypts[pointindex]);
00102     }
00103     if (pointindex > 0 && pointindex < pointcount
00104       && xpts[pointindex] != xstarts[segment + 1])
00105       qlsq.add (xstarts[segment + 1],
00106         ypts[pointindex - 1]
00107         + (ypts[pointindex] - ypts[pointindex - 1])
00108         * (xstarts[segment + 1] - xpts[pointindex - 1])
00109         / (xpts[pointindex] - xpts[pointindex - 1]));
00110     qlsq.fit (degree);
00111     quadratics[segment].a = qlsq.get_a ();
00112     quadratics[segment].b = qlsq.get_b ();
00113     quadratics[segment].c = qlsq.get_c ();
00114   }
00115   free_mem(ptcounts); 
00116 }
00117 
00118 
00122 QSPLINE::QSPLINE(  //constructor
00123                  const QSPLINE &src) {
00124   segments = 0;
00125   xcoords = NULL;
00126   quadratics = NULL;
00127   *this = src;
00128 }
00129 
00130 
00134 QSPLINE::~QSPLINE (              //constructor
00135 ) {
00136   if (xcoords != NULL) {
00137     free_mem(xcoords); 
00138     xcoords = NULL;
00139   }
00140   if (quadratics != NULL) {
00141     free_mem(quadratics); 
00142     quadratics = NULL;
00143   }
00144 }
00145 
00146 
00150 QSPLINE & QSPLINE::operator= (   //assignment
00151 const QSPLINE & source) {
00152   if (xcoords != NULL)
00153     free_mem(xcoords); 
00154   if (quadratics != NULL)
00155     free_mem(quadratics); 
00156 
00157   segments = source.segments;
00158   xcoords = (INT32 *) alloc_mem ((segments + 1) * sizeof (INT32));
00159   quadratics = (QUAD_COEFFS *) alloc_mem (segments * sizeof (QUAD_COEFFS));
00160   memmove (xcoords, source.xcoords, (segments + 1) * sizeof (INT32));
00161   memmove (quadratics, source.quadratics, segments * sizeof (QUAD_COEFFS));
00162   return *this;
00163 }
00164 
00165 
00169 double QSPLINE::step(            //find step functions
00170                      double x1,  //between coords
00171                      double x2) {
00172   int index1, index2;            //indices of coords
00173   double total;                  /*total steps */
00174 
00175   index1 = spline_index (x1);
00176   index2 = spline_index (x2);
00177   total = 0;
00178   while (index1 < index2) {
00179     total +=
00180       (double) quadratics[index1 + 1].y ((float) xcoords[index1 + 1]);
00181     total -= (double) quadratics[index1].y ((float) xcoords[index1 + 1]);
00182     index1++;                    /*next segment */
00183   }
00184   return total;                  /*total steps */
00185 }
00186 
00187 
00191 double QSPLINE::y(          //evaluate
00192                   double x  //coord to evaluate at
00193                  ) const {
00194   INT32 index;                   //segment index
00195 
00196   index = spline_index (x);
00197   return quadratics[index].y (x);//in correct segment
00198 }
00199 
00200 
00204 INT32 QSPLINE::spline_index(          //evaluate
00205                             double x  //coord to evaluate at
00206                            ) const {
00207   INT32 index;                   //segment index
00208   INT32 bottom;                  //bottom of range
00209   INT32 top;                     //top of range
00210 
00211   bottom = 0;
00212   top = segments;
00213   while (top - bottom > 1) {
00214     index = (top + bottom) / 2;  //centre of range
00215     if (x >= xcoords[index])
00216       bottom = index;            //new min
00217     else
00218       top = index;               //new max
00219   }
00220   return bottom;
00221 }
00222 
00223 
00227 void QSPLINE::move(            // reposition spline
00228                    ICOORD vec  // by vector
00229                   ) {
00230   INT32 segment;                 //index of segment
00231   INT16 x_shift = vec.x ();
00232 
00233   for (segment = 0; segment < segments; segment++) {
00234     xcoords[segment] += x_shift;
00235     quadratics[segment].move (vec);
00236   }
00237   xcoords[segment] += x_shift;
00238 }
00239 
00240 
00245 BOOL8 QSPLINE::overlap(                   //test overlap
00246                        QSPLINE *spline2,  //2 cannot be smaller
00247                        double fraction    //by more than this
00248                       ) {
00249   int leftlimit;                 /*common left limit */
00250   int rightlimit;                /*common right limit */
00251 
00252   leftlimit = xcoords[1];
00253   rightlimit = xcoords[segments - 1];
00254                                  /*or too non-overlap */
00255   if (spline2->segments < 3 || spline2->xcoords[1] > leftlimit + fraction * (rightlimit - leftlimit)
00256     || spline2->xcoords[spline2->segments - 1] < rightlimit
00257     - fraction * (rightlimit - leftlimit))
00258     return FALSE;
00259   else
00260     return TRUE;
00261 }
00262 
00263 
00268 void QSPLINE::extrapolate(                  //linear extrapolation
00269                           double gradient,  //gradient to use
00270                           int xmin,         //new left edge
00271                           int xmax          //new right edge
00272                          ) {
00273   register int segment;          /*current segment of spline */
00274   int dest_segment;              //dest index
00275   int *xstarts;                  //new boundaries
00276   QUAD_COEFFS *quads;            //new ones
00277   int increment;                 //in size
00278 
00279   increment = xmin < xcoords[0] ? 1 : 0;
00280   if (xmax > xcoords[segments])
00281     increment++;
00282   if (increment == 0)
00283     return;
00284   xstarts = (int *) alloc_mem ((segments + 1 + increment) * sizeof (int));
00285   quads =
00286     (QUAD_COEFFS *) alloc_mem ((segments + increment) * sizeof (QUAD_COEFFS));
00287   if (xmin < xcoords[0]) {
00288     xstarts[0] = xmin;
00289     quads[0].a = 0;
00290     quads[0].b = gradient;
00291     quads[0].c = y (xcoords[0]) - quads[0].b * xcoords[0];
00292     dest_segment = 1;
00293   }
00294   else
00295     dest_segment = 0;
00296   for (segment = 0; segment < segments; segment++) {
00297     xstarts[dest_segment] = xcoords[segment];
00298     quads[dest_segment] = quadratics[segment];
00299     dest_segment++;
00300   }
00301   xstarts[dest_segment] = xcoords[segment];
00302   if (xmax > xcoords[segments]) {
00303     quads[dest_segment].a = 0;
00304     quads[dest_segment].b = gradient;
00305     quads[dest_segment].c = y (xcoords[segments])
00306       - quads[dest_segment].b * xcoords[segments];
00307     dest_segment++;
00308     xstarts[dest_segment] = xmax + 1;
00309   }
00310   segments = dest_segment;
00311   free_mem(xcoords); 
00312   free_mem(quadratics); 
00313   xcoords = (INT32 *) xstarts;
00314   quadratics = quads;
00315 }
00316 
00317 
00321 #ifndef GRAPHICS_DISABLED
00322 void QSPLINE::plot(                //draw it
00323                    WINDOW window,  //window to draw in
00324                    COLOUR colour   //colour to draw in
00325                   ) const {
00326   INT32 segment;                 //index of segment
00327   INT16 step;                    //index of poly piece
00328   double increment;              //x increment
00329   double x;                      //x coord
00330 
00331   line_color_index(window, colour); 
00332   for (segment = 0; segment < segments; segment++) {
00333     increment =
00334       (double) (xcoords[segment + 1] -
00335       xcoords[segment]) / QSPLINE_PRECISION;
00336     x = xcoords[segment];
00337     for (step = 0; step <= QSPLINE_PRECISION; step++) {
00338       if (segment == 0 && step == 0)
00339         move2d (window, x, quadratics[segment].y (x));
00340       else
00341         draw2d (window, x, quadratics[segment].y (x));
00342       x += increment;
00343     }
00344   }
00345 }
00346 #endif

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