tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/textord/pithsync.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        pithsync.cpp  (Formerly pitsync2.c)
00003  * Description: Code to find the optimum fixed pitch segmentation of some blobs.
00004  * Author:              Ray Smith
00005  * Created:             Thu Nov 19 11:48:05 GMT 1992
00006  *
00007  * (C) Copyright 1992, Hewlett-Packard Ltd.
00008  ** Licensed under the Apache License, Version 2.0 (the "License");
00009  ** you may not use this file except in compliance with the License.
00010  ** You may obtain a copy of the License at
00011  ** http://www.apache.org/licenses/LICENSE-2.0
00012  ** Unless required by applicable law or agreed to in writing, software
00013  ** distributed under the License is distributed on an "AS IS" BASIS,
00014  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  ** See the License for the specific language governing permissions and
00016  ** limitations under the License.
00017  *
00018  **********************************************************************/
00019 
00020 #ifdef __UNIX__
00021 #include          <assert.h>
00022 #endif
00023 #include          <math.h>
00024 #include          "memry.h"
00025 #include          "makerow.h"
00026 #include          "pitsync1.h"
00027 #include          "topitch.h"
00028 #include          "pithsync.h"
00029 #include          "tprintf.h"
00030 
00031 #define PROJECTION_MARGIN 10     //arbitrary
00032 
00033 #define EXTERN
00034 
00035 /**********************************************************************
00036  * FPCUTPT::setup
00037  *
00038  * Constructor to make a new FPCUTPT.
00039  **********************************************************************/
00040 
00041 void FPCUTPT::setup(                     //constructor
00042                     FPCUTPT *cutpts,     //predecessors
00043                     inT16 array_origin,  //start coord
00044                     STATS *projection,   //vertical occupation
00045                     inT16 zero_count,    //official zero
00046                     inT16 pitch,         //proposed pitch
00047                     inT16 x,             //position
00048                     inT16 offset         //dist to gap
00049                    ) {
00050                                  //half of pitch
00051   inT16 half_pitch = pitch / 2 - 1;
00052   uinT32 lead_flag;              //new flag
00053   inT32 ind;                     //current position
00054 
00055   if (half_pitch > 31)
00056     half_pitch = 31;
00057   else if (half_pitch < 0)
00058     half_pitch = 0;
00059   lead_flag = 1 << half_pitch;
00060 
00061   pred = NULL;
00062   mean_sum = 0;
00063   sq_sum = offset * offset;
00064   cost = sq_sum;
00065   faked = FALSE;
00066   terminal = FALSE;
00067   fake_count = 0;
00068   xpos = x;
00069   region_index = 0;
00070   mid_cuts = 0;
00071   if (x == array_origin) {
00072     back_balance = 0;
00073     fwd_balance = 0;
00074     for (ind = 0; ind <= half_pitch; ind++) {
00075       fwd_balance >>= 1;
00076       if (projection->pile_count (ind) > zero_count)
00077         fwd_balance |= lead_flag;
00078     }
00079   }
00080   else {
00081     back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
00082     back_balance &= lead_flag + lead_flag - 1;
00083     if (projection->pile_count (x) > zero_count)
00084       back_balance |= 1;
00085     fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
00086     if (projection->pile_count (x + half_pitch) > zero_count)
00087       fwd_balance |= lead_flag;
00088   }
00089 }
00090 
00091 
00092 /**********************************************************************
00093  * FPCUTPT::assign
00094  *
00095  * Constructor to make a new FPCUTPT.
00096  **********************************************************************/
00097 
00098 void FPCUTPT::assign(                         //constructor
00099                      FPCUTPT *cutpts,         //predecessors
00100                      inT16 array_origin,      //start coord
00101                      inT16 x,                 //position
00102                      BOOL8 faking,            //faking this one
00103                      BOOL8 mid_cut,           //cheap cut.
00104                      inT16 offset,            //dist to gap
00105                      STATS *projection,       //vertical occupation
00106                      float projection_scale,  //scaling
00107                      inT16 zero_count,        //official zero
00108                      inT16 pitch,             //proposed pitch
00109                      inT16 pitch_error        //allowed tolerance
00110                     ) {
00111   int index;                     //test index
00112   int balance_index;             //for balance factor
00113   inT16 balance_count;           //ding factor
00114   inT16 r_index;                 //test cut number
00115   FPCUTPT *segpt;                //segment point
00116   inT32 dist;                    //from prev segment
00117   double sq_dist;                //squared distance
00118   double mean;                   //mean pitch
00119   double total;                  //total dists
00120   double factor;                 //cost function
00121                                  //half of pitch
00122   inT16 half_pitch = pitch / 2 - 1;
00123   uinT32 lead_flag;              //new flag
00124 
00125   if (half_pitch > 31)
00126     half_pitch = 31;
00127   else if (half_pitch < 0)
00128     half_pitch = 0;
00129   lead_flag = 1 << half_pitch;
00130 
00131   back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
00132   back_balance &= lead_flag + lead_flag - 1;
00133   if (projection->pile_count (x) > zero_count)
00134     back_balance |= 1;
00135   fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
00136   if (projection->pile_count (x + half_pitch) > zero_count)
00137     fwd_balance |= lead_flag;
00138 
00139   xpos = x;
00140   cost = MAX_FLOAT32;
00141   pred = NULL;
00142   faked = faking;
00143   terminal = FALSE;
00144   region_index = 0;
00145   fake_count = MAX_INT16;
00146   for (index = x - pitch - pitch_error; index <= x - pitch + pitch_error;
00147   index++) {
00148     if (index >= array_origin) {
00149       segpt = &cutpts[index - array_origin];
00150       dist = x - segpt->xpos;
00151       if (!segpt->terminal && segpt->fake_count < MAX_INT16) {
00152         balance_count = 0;
00153         if (textord_balance_factor > 0) {
00154           if (textord_fast_pitch_test) {
00155             lead_flag = back_balance ^ segpt->fwd_balance;
00156             balance_count = 0;
00157             while (lead_flag != 0) {
00158               balance_count++;
00159               lead_flag &= lead_flag - 1;
00160             }
00161           }
00162           else {
00163             for (balance_index = 0;
00164               index + balance_index < x - balance_index;
00165               balance_index++)
00166             balance_count +=
00167                 (projection->pile_count (index + balance_index) <=
00168                 zero_count) ^ (projection->pile_count (x -
00169                 balance_index)
00170                 <= zero_count);
00171           }
00172           balance_count =
00173             (inT16) (balance_count * textord_balance_factor /
00174             projection_scale);
00175         }
00176         r_index = segpt->region_index + 1;
00177         total = segpt->mean_sum + dist;
00178         balance_count += offset;
00179         sq_dist =
00180           dist * dist + segpt->sq_sum + balance_count * balance_count;
00181         mean = total / r_index;
00182         factor = mean - pitch;
00183         factor *= factor;
00184         factor += sq_dist / (r_index) - mean * mean;
00185         if (factor < cost && segpt->fake_count + faked <= fake_count) {
00186           cost = factor;         //find least cost
00187           pred = segpt;          //save path
00188           mean_sum = total;
00189           sq_sum = sq_dist;
00190           fake_count = segpt->fake_count + faked;
00191           mid_cuts = segpt->mid_cuts + mid_cut;
00192           region_index = r_index;
00193         }
00194       }
00195     }
00196   }
00197 }
00198 
00199 
00200 /**********************************************************************
00201  * FPCUTPT::assign_cheap
00202  *
00203  * Constructor to make a new FPCUTPT on the cheap.
00204  **********************************************************************/
00205 
00206 void FPCUTPT::assign_cheap(                         //constructor
00207                            FPCUTPT *cutpts,         //predecessors
00208                            inT16 array_origin,      //start coord
00209                            inT16 x,                 //position
00210                            BOOL8 faking,            //faking this one
00211                            BOOL8 mid_cut,           //cheap cut.
00212                            inT16 offset,            //dist to gap
00213                            STATS *projection,       //vertical occupation
00214                            float projection_scale,  //scaling
00215                            inT16 zero_count,        //official zero
00216                            inT16 pitch,             //proposed pitch
00217                            inT16 pitch_error        //allowed tolerance
00218                           ) {
00219   int index;                     //test index
00220   inT16 balance_count;           //ding factor
00221   inT16 r_index;                 //test cut number
00222   FPCUTPT *segpt;                //segment point
00223   inT32 dist;                    //from prev segment
00224   double sq_dist;                //squared distance
00225   double mean;                   //mean pitch
00226   double total;                  //total dists
00227   double factor;                 //cost function
00228                                  //half of pitch
00229   inT16 half_pitch = pitch / 2 - 1;
00230   uinT32 lead_flag;              //new flag
00231 
00232   if (half_pitch > 31)
00233     half_pitch = 31;
00234   else if (half_pitch < 0)
00235     half_pitch = 0;
00236   lead_flag = 1 << half_pitch;
00237 
00238   back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
00239   back_balance &= lead_flag + lead_flag - 1;
00240   if (projection->pile_count (x) > zero_count)
00241     back_balance |= 1;
00242   fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
00243   if (projection->pile_count (x + half_pitch) > zero_count)
00244     fwd_balance |= lead_flag;
00245 
00246   xpos = x;
00247   cost = MAX_FLOAT32;
00248   pred = NULL;
00249   faked = faking;
00250   terminal = FALSE;
00251   region_index = 0;
00252   fake_count = MAX_INT16;
00253   index = x - pitch;
00254   if (index >= array_origin) {
00255     segpt = &cutpts[index - array_origin];
00256     dist = x - segpt->xpos;
00257     if (!segpt->terminal && segpt->fake_count < MAX_INT16) {
00258       balance_count = 0;
00259       if (textord_balance_factor > 0) {
00260         lead_flag = back_balance ^ segpt->fwd_balance;
00261         balance_count = 0;
00262         while (lead_flag != 0) {
00263           balance_count++;
00264           lead_flag &= lead_flag - 1;
00265         }
00266         balance_count = (inT16) (balance_count * textord_balance_factor
00267           / projection_scale);
00268       }
00269       r_index = segpt->region_index + 1;
00270       total = segpt->mean_sum + dist;
00271       balance_count += offset;
00272       sq_dist =
00273         dist * dist + segpt->sq_sum + balance_count * balance_count;
00274       mean = total / r_index;
00275       factor = mean - pitch;
00276       factor *= factor;
00277       factor += sq_dist / (r_index) - mean * mean;
00278       cost = factor;             //find least cost
00279       pred = segpt;              //save path
00280       mean_sum = total;
00281       sq_sum = sq_dist;
00282       fake_count = segpt->fake_count + faked;
00283       mid_cuts = segpt->mid_cuts + mid_cut;
00284       region_index = r_index;
00285     }
00286   }
00287 }
00288 
00289 
00290 /**********************************************************************
00291  * check_pitch_sync
00292  *
00293  * Construct the lattice of possible segmentation points and choose the
00294  * optimal path. Return the optimal path only.
00295  * The return value is a measure of goodness of the sync.
00296  **********************************************************************/
00297 
00298 double check_pitch_sync2(                          //find segmentation
00299                          BLOBNBOX_IT *blob_it,     //blobs to do
00300                          inT16 blob_count,         //no of blobs
00301                          inT16 pitch,              //pitch estimate
00302                          inT16 pitch_error,        //tolerance
00303                          STATS *projection,        //vertical
00304                          inT16 projection_left,    //edges //scale factor
00305                          inT16 projection_right,
00306                          float projection_scale,
00307                          inT16 &occupation_count,  //no of occupied cells
00308                          FPSEGPT_LIST *seg_list,   //output list
00309                          inT16 start,              //start of good range
00310                          inT16 end                 //end of good range
00311                         ) {
00312   BOOL8 faking;                  //illegal cut pt
00313   BOOL8 mid_cut;                 //cheap cut pt.
00314   inT16 x;                       //current coord
00315   inT16 blob_index;              //blob number
00316   inT16 left_edge;               //of word
00317   inT16 right_edge;              //of word
00318   inT16 array_origin;            //x coord of array
00319   inT16 offset;                  //dist to legal area
00320   inT16 zero_count;              //projection zero
00321   inT16 best_left_x = 0;         //for equals
00322   inT16 best_right_x = 0;        //right edge
00323   TBOX this_box;                  //bounding box
00324   TBOX next_box;                  //box of next blob
00325   FPSEGPT *segpt;                //segment point
00326   FPCUTPT *cutpts;               //array of points
00327   double best_cost;              //best path
00328   double mean_sum;               //computes result
00329   FPCUTPT *best_end;             //end of best path
00330   inT16 best_fake;               //best fake level
00331   inT16 best_count;              //no of cuts
00332   BLOBNBOX_IT this_it;           //copy iterator
00333   FPSEGPT_IT seg_it = seg_list;  //output iterator
00334 
00335   //      tprintf("Computing sync on word of %d blobs with pitch %d\n",
00336   //              blob_count, pitch);
00337   //      if (blob_count==8 && pitch==27)
00338   //              projection->print(stdout,TRUE);
00339   zero_count = 0;
00340   if (pitch < 3)
00341     pitch = 3;                   //nothing ludicrous
00342   if ((pitch - 3) / 2 < pitch_error)
00343     pitch_error = (pitch - 3) / 2;
00344   this_it = *blob_it;
00345   this_box = box_next (&this_it);//get box
00346   //      left_edge=this_box.left();                                              //left of word
00347   //      right_edge=this_box.right();
00348   //      for (blob_index=1;blob_index<blob_count;blob_index++)
00349   //      {
00350   //              this_box=box_next(&this_it);
00351   //              if (this_box.right()>right_edge)
00352   //                      right_edge=this_box.right();
00353   //      }
00354   for (left_edge = projection_left; projection->pile_count (left_edge) == 0
00355     && left_edge < projection_right; left_edge++);
00356   for (right_edge = projection_right; projection->pile_count (right_edge) == 0
00357     && right_edge > left_edge; right_edge--);
00358   ASSERT_HOST (right_edge >= left_edge);
00359   if (pitsync_linear_version >= 4)
00360     return check_pitch_sync3 (projection_left, projection_right, zero_count,
00361       pitch, pitch_error, projection,
00362       projection_scale, occupation_count, seg_list,
00363       start, end);
00364   array_origin = left_edge - pitch;
00365   cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1)
00366     * sizeof (FPCUTPT));
00367   for (x = array_origin; x < left_edge; x++)
00368                                  //free cuts
00369     cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0);
00370   for (offset = 0; offset <= pitch_error; offset++, x++)
00371                                  //not quite free
00372     cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset);
00373 
00374   this_it = *blob_it;
00375   best_cost = MAX_FLOAT32;
00376   best_end = NULL;
00377   this_box = box_next (&this_it);//first box
00378   next_box = box_next (&this_it);//second box
00379   blob_index = 1;
00380   while (x < right_edge - pitch_error) {
00381     if (x > this_box.right () + pitch_error && blob_index < blob_count) {
00382       this_box = next_box;
00383       next_box = box_next (&this_it);
00384       blob_index++;
00385     }
00386     faking = FALSE;
00387     mid_cut = FALSE;
00388     if (x <= this_box.left ())
00389       offset = 0;
00390     else if (x <= this_box.left () + pitch_error)
00391       offset = x - this_box.left ();
00392     else if (x >= this_box.right ())
00393       offset = 0;
00394     else if (x >= next_box.left () && blob_index < blob_count) {
00395       offset = x - next_box.left ();
00396       if (this_box.right () - x < offset)
00397         offset = this_box.right () - x;
00398     }
00399     else if (x >= this_box.right () - pitch_error)
00400       offset = this_box.right () - x;
00401     else if (x - this_box.left () > pitch * pitsync_joined_edge
00402     && this_box.right () - x > pitch * pitsync_joined_edge) {
00403       mid_cut = TRUE;
00404       offset = 0;
00405     }
00406     else {
00407       faking = TRUE;
00408       offset = projection->pile_count (x);
00409     }
00410     cutpts[x - array_origin].assign (cutpts, array_origin, x,
00411       faking, mid_cut, offset, projection,
00412       projection_scale, zero_count, pitch,
00413       pitch_error);
00414     x++;
00415   }
00416 
00417   best_fake = MAX_INT16;
00418   best_cost = MAX_INT32;
00419   best_count = MAX_INT16;
00420   while (x < right_edge + pitch) {
00421     offset = x < right_edge ? right_edge - x : 0;
00422     cutpts[x - array_origin].assign (cutpts, array_origin, x,
00423       FALSE, FALSE, offset, projection,
00424       projection_scale, zero_count, pitch,
00425       pitch_error);
00426     cutpts[x - array_origin].terminal = TRUE;
00427     if (cutpts[x - array_origin].index () +
00428     cutpts[x - array_origin].fake_count <= best_count + best_fake) {
00429       if (cutpts[x - array_origin].fake_count < best_fake
00430         || (cutpts[x - array_origin].fake_count == best_fake
00431       && cutpts[x - array_origin].cost_function () < best_cost)) {
00432         best_fake = cutpts[x - array_origin].fake_count;
00433         best_cost = cutpts[x - array_origin].cost_function ();
00434         best_left_x = x;
00435         best_right_x = x;
00436         best_count = cutpts[x - array_origin].index ();
00437       }
00438       else if (cutpts[x - array_origin].fake_count == best_fake
00439         && x == best_right_x + 1
00440       && cutpts[x - array_origin].cost_function () == best_cost) {
00441       //exactly equal
00442         best_right_x = x;
00443       }
00444     }
00445     x++;
00446   }
00447   ASSERT_HOST (best_fake < MAX_INT16);
00448 
00449   best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
00450   if (this_box.right () == textord_test_x
00451   && this_box.top () == textord_test_y) {
00452     for (x = left_edge - pitch; x < right_edge + pitch; x++) {
00453       tprintf ("x=%d, C=%g, s=%g, sq=%g, prev=%d\n",
00454         x, cutpts[x - array_origin].cost_function (),
00455         cutpts[x - array_origin].sum (),
00456         cutpts[x - array_origin].squares (),
00457         cutpts[x - array_origin].previous ()->position ());
00458     }
00459   }
00460   occupation_count = -1;
00461   do {
00462     for (x = best_end->position () - pitch + pitch_error;
00463       x < best_end->position () - pitch_error
00464       && projection->pile_count (x) == 0; x++);
00465     if (x < best_end->position () - pitch_error)
00466       occupation_count++;
00467                                  //copy it
00468     segpt = new FPSEGPT (best_end);
00469     seg_it.add_before_then_move (segpt);
00470     best_end = best_end->previous ();
00471   }
00472   while (best_end != NULL);
00473   seg_it.move_to_last ();
00474   mean_sum = seg_it.data ()->sum ();
00475   mean_sum = mean_sum * mean_sum / best_count;
00476   if (seg_it.data ()->squares () - mean_sum < 0)
00477     tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n",
00478       seg_it.data ()->squares (), seg_it.data ()->sum (), best_count);
00479   free_mem(cutpts);
00480   //      tprintf("blob_count=%d, pitch=%d, sync=%g, occ=%d\n",
00481   //              blob_count,pitch,seg_it.data()->squares()-mean_sum,
00482   //              occupation_count);
00483   return seg_it.data ()->squares () - mean_sum;
00484 }
00485 
00486 
00487 /**********************************************************************
00488  * check_pitch_sync
00489  *
00490  * Construct the lattice of possible segmentation points and choose the
00491  * optimal path. Return the optimal path only.
00492  * The return value is a measure of goodness of the sync.
00493  **********************************************************************/
00494 
00495 double check_pitch_sync3(                          //find segmentation
00496                          inT16 projection_left,    //edges //to be considered 0
00497                          inT16 projection_right,
00498                          inT16 zero_count,
00499                          inT16 pitch,              //pitch estimate
00500                          inT16 pitch_error,        //tolerance
00501                          STATS *projection,        //vertical
00502                          float projection_scale,   //scale factor
00503                          inT16 &occupation_count,  //no of occupied cells
00504                          FPSEGPT_LIST *seg_list,   //output list
00505                          inT16 start,              //start of good range
00506                          inT16 end                 //end of good range
00507                         ) {
00508   BOOL8 faking;                  //illegal cut pt
00509   BOOL8 mid_cut;                 //cheap cut pt.
00510   inT16 left_edge;               //of word
00511   inT16 right_edge;              //of word
00512   inT16 x;                       //current coord
00513   inT16 array_origin;            //x coord of array
00514   inT16 offset;                  //dist to legal area
00515   inT16 projection_offset;       //from scaled projection
00516   inT16 prev_zero;               //previous zero dist
00517   inT16 next_zero;               //next zero dist
00518   inT16 zero_offset;             //scan window
00519   inT16 best_left_x = 0;         //for equals
00520   inT16 best_right_x = 0;        //right edge
00521   FPSEGPT *segpt;                //segment point
00522   FPCUTPT *cutpts;               //array of points
00523   BOOL8 *mins;                   //local min results
00524   int minindex;                  //next input position
00525   int test_index;                //index to mins
00526   double best_cost;              //best path
00527   double mean_sum;               //computes result
00528   FPCUTPT *best_end;             //end of best path
00529   inT16 best_fake;               //best fake level
00530   inT16 best_count;              //no of cuts
00531   FPSEGPT_IT seg_it = seg_list;  //output iterator
00532 
00533   end = (end - start) % pitch;
00534   if (pitch < 3)
00535     pitch = 3;                   //nothing ludicrous
00536   if ((pitch - 3) / 2 < pitch_error)
00537     pitch_error = (pitch - 3) / 2;
00538                                  //min dist of zero
00539   zero_offset = (inT16) (pitch * pitsync_joined_edge);
00540   for (left_edge = projection_left; projection->pile_count (left_edge) == 0
00541     && left_edge < projection_right; left_edge++);
00542   for (right_edge = projection_right; projection->pile_count (right_edge) == 0
00543     && right_edge > left_edge; right_edge--);
00544   array_origin = left_edge - pitch;
00545   cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1)
00546     * sizeof (FPCUTPT));
00547   mins = (BOOL8 *) alloc_mem ((pitch_error * 2 + 1) * sizeof (BOOL8));
00548   for (x = array_origin; x < left_edge; x++)
00549                                  //free cuts
00550     cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0);
00551   prev_zero = left_edge - 1;
00552   for (offset = 0; offset <= pitch_error; offset++, x++)
00553                                  //not quite free
00554     cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset);
00555 
00556   best_cost = MAX_FLOAT32;
00557   best_end = NULL;
00558   for (offset = -pitch_error, minindex = 0; offset < pitch_error;
00559     offset++, minindex++)
00560   mins[minindex] = projection->local_min (x + offset);
00561   next_zero = x + zero_offset + 1;
00562   for (offset = next_zero - 1; offset >= x; offset--) {
00563     if (projection->pile_count (offset) <= zero_count) {
00564       next_zero = offset;
00565       break;
00566     }
00567   }
00568   while (x < right_edge - pitch_error) {
00569     mins[minindex] = projection->local_min (x + pitch_error);
00570     minindex++;
00571     if (minindex > pitch_error * 2)
00572       minindex = 0;
00573     faking = FALSE;
00574     mid_cut = FALSE;
00575     offset = 0;
00576     if (projection->pile_count (x) <= zero_count) {
00577       prev_zero = x;
00578     }
00579     else {
00580       for (offset = 1; offset <= pitch_error; offset++)
00581         if (projection->pile_count (x + offset) <= zero_count
00582         || projection->pile_count (x - offset) <= zero_count)
00583           break;
00584     }
00585     if (offset > pitch_error) {
00586       if (x - prev_zero > zero_offset && next_zero - x > zero_offset) {
00587         for (offset = 0; offset <= pitch_error; offset++) {
00588           test_index = minindex + pitch_error + offset;
00589           if (test_index > pitch_error * 2)
00590             test_index -= pitch_error * 2 + 1;
00591           if (mins[test_index])
00592             break;
00593           test_index = minindex + pitch_error - offset;
00594           if (test_index > pitch_error * 2)
00595             test_index -= pitch_error * 2 + 1;
00596           if (mins[test_index])
00597             break;
00598         }
00599       }
00600       if (offset > pitch_error) {
00601         offset = projection->pile_count (x);
00602         faking = TRUE;
00603       }
00604       else {
00605         projection_offset =
00606           (inT16) (projection->pile_count (x) / projection_scale);
00607         if (projection_offset > offset)
00608           offset = projection_offset;
00609         mid_cut = TRUE;
00610       }
00611     }
00612     if ((start == 0 && end == 0)
00613       || !textord_fast_pitch_test
00614       || (x - projection_left - start) % pitch <= end)
00615       cutpts[x - array_origin].assign (cutpts, array_origin, x,
00616         faking, mid_cut, offset, projection,
00617         projection_scale, zero_count, pitch,
00618         pitch_error);
00619     else
00620       cutpts[x - array_origin].assign_cheap (cutpts, array_origin, x,
00621         faking, mid_cut, offset,
00622         projection, projection_scale,
00623         zero_count, pitch,
00624         pitch_error);
00625     x++;
00626     if (next_zero < x || next_zero == x + zero_offset)
00627       next_zero = x + zero_offset + 1;
00628     if (projection->pile_count (x + zero_offset) <= zero_count)
00629       next_zero = x + zero_offset;
00630   }
00631 
00632   best_fake = MAX_INT16;
00633   best_cost = MAX_INT32;
00634   best_count = MAX_INT16;
00635   while (x < right_edge + pitch) {
00636     offset = x < right_edge ? right_edge - x : 0;
00637     cutpts[x - array_origin].assign (cutpts, array_origin, x,
00638       FALSE, FALSE, offset, projection,
00639       projection_scale, zero_count, pitch,
00640       pitch_error);
00641     cutpts[x - array_origin].terminal = TRUE;
00642     if (cutpts[x - array_origin].index () +
00643     cutpts[x - array_origin].fake_count <= best_count + best_fake) {
00644       if (cutpts[x - array_origin].fake_count < best_fake
00645         || (cutpts[x - array_origin].fake_count == best_fake
00646       && cutpts[x - array_origin].cost_function () < best_cost)) {
00647         best_fake = cutpts[x - array_origin].fake_count;
00648         best_cost = cutpts[x - array_origin].cost_function ();
00649         best_left_x = x;
00650         best_right_x = x;
00651         best_count = cutpts[x - array_origin].index ();
00652       }
00653       else if (cutpts[x - array_origin].fake_count == best_fake
00654         && x == best_right_x + 1
00655       && cutpts[x - array_origin].cost_function () == best_cost) {
00656       //exactly equal
00657         best_right_x = x;
00658       }
00659     }
00660     x++;
00661   }
00662   ASSERT_HOST (best_fake < MAX_INT16);
00663 
00664   best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
00665   //      for (x=left_edge-pitch;x<right_edge+pitch;x++)
00666   //      {
00667   //              tprintf("x=%d, C=%g, s=%g, sq=%g, prev=%d\n",
00668   //                      x,cutpts[x-array_origin].cost_function(),
00669   //                      cutpts[x-array_origin].sum(),
00670   //                      cutpts[x-array_origin].squares(),
00671   //                      cutpts[x-array_origin].previous()->position());
00672   //      }
00673   occupation_count = -1;
00674   do {
00675     for (x = best_end->position () - pitch + pitch_error;
00676       x < best_end->position () - pitch_error
00677       && projection->pile_count (x) == 0; x++);
00678     if (x < best_end->position () - pitch_error)
00679       occupation_count++;
00680                                  //copy it
00681     segpt = new FPSEGPT (best_end);
00682     seg_it.add_before_then_move (segpt);
00683     best_end = best_end->previous ();
00684   }
00685   while (best_end != NULL);
00686   seg_it.move_to_last ();
00687   mean_sum = seg_it.data ()->sum ();
00688   mean_sum = mean_sum * mean_sum / best_count;
00689   if (seg_it.data ()->squares () - mean_sum < 0)
00690     tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n",
00691       seg_it.data ()->squares (), seg_it.data ()->sum (), best_count);
00692   free_mem(mins);
00693   free_mem(cutpts);
00694   return seg_it.data ()->squares () - mean_sum;
00695 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines