textord/underlin.cpp

Go to the documentation of this file.
00001 
00020 #include          "mfcpch.h"
00021 #ifdef __UNIX__
00022 #include          <assert.h>
00023 #endif
00024 #include          "underlin.h"
00025 
00027 #define PROJECTION_MARGIN 10
00028 #define EXTERN
00029 
00032 EXTERN double_VAR (textord_underline_offset, 0.1, "Fraction of x to ignore");
00033 EXTERN BOOL_VAR (textord_restore_underlines, TRUE,
00034 "Chop underlines & put back");
00042 void restore_underlined_blobs(                 //get chop points
00043                               TO_BLOCK *block  //block to do
00044                              ) {
00045   INT16 chop_coord;              //chop boundary
00046   BOX blob_box;                  //of underline
00047   BLOBNBOX *u_line;              //underline bit
00048   TO_ROW *row;                   //best row for blob
00049   ICOORDELT_LIST chop_cells;     //blobs to cut out
00050                                  //real underlines
00051   BLOBNBOX_LIST residual_underlines;
00052   OUTLINE_LIST left_outlines;    //in current blob
00053   OUTLINE_LIST right_outlines;   //for next blob
00054   C_OUTLINE_LIST left_coutlines;
00055   C_OUTLINE_LIST right_coutlines;
00056   ICOORDELT_IT cell_it = &chop_cells;
00057                                  //under lines
00058   BLOBNBOX_IT under_it = &block->underlines;
00059   BLOBNBOX_IT ru_it = &residual_underlines;
00060 
00061   if (block->get_rows()->empty())
00062     return;  // Don't crash if there are no rows.
00063   for (under_it.mark_cycle_pt (); !under_it.cycled_list ();
00064   under_it.forward ()) {
00065     u_line = under_it.extract ();
00066     blob_box = u_line->bounding_box ();
00067     row = most_overlapping_row (block->get_rows (), u_line);
00068     find_underlined_blobs (u_line, &row->baseline, row->xheight,
00069       row->xheight * textord_underline_offset,
00070       &chop_cells);
00071     cell_it.set_to_list (&chop_cells);
00072     for (cell_it.mark_cycle_pt (); !cell_it.cycled_list ();
00073     cell_it.forward ()) {
00074       chop_coord = cell_it.data ()->x ();
00075       if (cell_it.data ()->y () - chop_coord > textord_fp_chop_error + 1) {
00076         split_to_blob (u_line, chop_coord,
00077           textord_fp_chop_error + 0.5,
00078           &left_outlines, &left_coutlines,
00079           &right_outlines, &right_coutlines);
00080         if (!left_outlines.empty ())
00081           ru_it.
00082             add_after_then_move (new
00083             BLOBNBOX (new PBLOB (&left_outlines)));
00084         else if (!left_coutlines.empty ())
00085           ru_it.
00086               add_after_then_move (new
00087               BLOBNBOX (new
00088               C_BLOB (&left_coutlines)));
00089                                  //right edge of lbob
00090         chop_coord = cell_it.data ()->y ();
00091         split_to_blob (NULL, chop_coord,
00092           textord_fp_chop_error + 0.5,
00093           &left_outlines, &left_coutlines,
00094           &right_outlines, &right_coutlines);
00095         if (!left_outlines.empty ())
00096           row->insert_blob (new BLOBNBOX (new PBLOB (&left_outlines)));
00097         else if (!left_coutlines.empty ())
00098           row->
00099               insert_blob (new BLOBNBOX (new C_BLOB (&left_coutlines)));
00100         else {
00101           ASSERT_HOST(FALSE);
00102           fprintf (stderr,
00103             "Error:no outlines after chopping from %d to %d from (%d,%d)->(%d,%d)\n",
00104             cell_it.data ()->x (), cell_it.data ()->y (),
00105             blob_box.left (), blob_box.bottom (),
00106             blob_box.right (), blob_box.top ());
00107         }
00108         u_line = NULL;           //no more blobs to add
00109       }
00110       delete cell_it.extract ();
00111     }
00112     if (!right_outlines.empty () || !right_coutlines.empty ()) {
00113       split_to_blob (NULL, blob_box.right (),
00114         textord_fp_chop_error + 0.5,
00115         &left_outlines, &left_coutlines,
00116         &right_outlines, &right_coutlines);
00117       if (!left_outlines.empty ())
00118         ru_it.
00119           add_after_then_move (new BLOBNBOX (new PBLOB (&left_outlines)));
00120       else if (!left_coutlines.empty ())
00121         ru_it.
00122             add_after_then_move (new
00123             BLOBNBOX (new C_BLOB (&left_coutlines)));
00124     }
00125     if (u_line != NULL) {
00126       if (u_line->blob() != NULL)
00127         delete u_line->blob();
00128       if (u_line->cblob() != NULL)
00129         delete u_line->cblob();
00130       delete u_line;
00131     }
00132   }
00133   if (!ru_it.empty ()) {
00134     ru_it.move_to_first ();
00135     for (ru_it.mark_cycle_pt (); !ru_it.cycled_list (); ru_it.forward ()) {
00136       under_it.add_after_then_move (ru_it.extract ());
00137     }
00138   }
00139 }
00140 
00141 
00147 TO_ROW *most_overlapping_row(                    //find best row
00148                              TO_ROW_LIST *rows,  //list of rows
00149                              BLOBNBOX *blob      //blob to place
00150                             ) {
00151   INT16 x = (blob->bounding_box ().left ()
00152     + blob->bounding_box ().right ()) / 2;
00153   TO_ROW_IT row_it = rows;       //row iterator
00154   TO_ROW *row;                   //current row
00155   TO_ROW *best_row;              //output row
00156   float overlap;                 //of blob & row
00157   float bestover;                //best overlap
00158 
00159   best_row = NULL;
00160   bestover = (float) -MAX_INT32;
00161   if (row_it.empty ())
00162     return NULL;
00163   row = row_it.data ();
00164   row_it.mark_cycle_pt ();
00165   while (row->baseline.y (x) + row->descdrop > blob->bounding_box ().top ()
00166   && !row_it.cycled_list ()) {
00167     best_row = row;
00168     bestover =
00169       blob->bounding_box ().top () - row->baseline.y (x) + row->descdrop;
00170     row_it.forward ();
00171     row = row_it.data ();
00172   }
00173   while (row->baseline.y (x) + row->xheight + row->ascrise
00174   >= blob->bounding_box ().bottom () && !row_it.cycled_list ()) {
00175     overlap = row->baseline.y (x) + row->xheight + row->ascrise;
00176     if (blob->bounding_box ().top () < overlap)
00177       overlap = blob->bounding_box ().top ();
00178     if (blob->bounding_box ().bottom () >
00179       row->baseline.y (x) + row->descdrop)
00180       overlap -= blob->bounding_box ().bottom ();
00181     else
00182       overlap -= row->baseline.y (x) + row->descdrop;
00183     if (overlap > bestover) {
00184       bestover = overlap;
00185       best_row = row;
00186     }
00187     row_it.forward ();
00188     row = row_it.data ();
00189   }
00190   if (bestover < 0
00191     && row->baseline.y (x) + row->xheight + row->ascrise
00192     - blob->bounding_box ().bottom () > bestover)
00193     best_row = row;
00194   return best_row;
00195 }
00196 
00197 
00203 void find_underlined_blobs(                            //get chop points
00204                            BLOBNBOX *u_line,           //underlined unit
00205                            QSPLINE *baseline,          //actual baseline
00206                            float xheight,              //height of line
00207                            float baseline_offset,      //amount to shrinke it
00208                            ICOORDELT_LIST *chop_cells  //places to chop
00209                           ) {
00210   INT16 x, y;                    //sides of blob
00211   ICOORD blob_chop;              //sides of blob
00212   BOX blob_box = u_line->bounding_box ();
00213                                  //cell iterator
00214   ICOORDELT_IT cell_it = chop_cells;
00215   STATS upper_proj (blob_box.left (), blob_box.right () + 1);
00216   STATS middle_proj (blob_box.left (), blob_box.right () + 1);
00217   STATS lower_proj (blob_box.left (), blob_box.right () + 1);
00218   C_OUTLINE_IT out_it;           //outlines of blob
00219 
00220   ASSERT_HOST (u_line->cblob () != NULL);
00221 
00222   out_it.set_to_list (u_line->cblob ()->out_list ());
00223   for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
00224     vertical_cunderline_projection (out_it.data (),
00225       baseline, xheight, baseline_offset,
00226       &lower_proj, &middle_proj, &upper_proj);
00227   }
00228 
00229   for (x = blob_box.left (); x < blob_box.right (); x++) {
00230     if (middle_proj.pile_count (x) > 0) {
00231       for (y = x + 1;
00232         y < blob_box.right () && middle_proj.pile_count (y) > 0; y++);
00233       blob_chop = ICOORD (x, y);
00234       cell_it.add_after_then_move (new ICOORDELT (blob_chop));
00235       x = y;
00236     }
00237   }
00238 }
00239 
00240 
00247 void vertical_cunderline_projection(
00248                           C_OUTLINE *outline,     //outline to project
00249                           QSPLINE *baseline,      //actual baseline
00250                           float xheight,          //height of line
00251                           float baseline_offset,  //amount to shrinke it
00252                           STATS *lower_proj,      //below baseline
00253                           STATS *middle_proj,     //centre region
00254                           STATS *upper_proj       //top region
00255                          ) {
00256   ICOORD pos;                    //current point
00257   ICOORD step;                   //edge step
00258   INT16 lower_y, upper_y;        //region limits
00259   INT32 length;                  //of outline
00260   INT16 stepindex;               //current step
00261   C_OUTLINE_IT out_it = outline->child ();
00262 
00263   pos = outline->start_pos ();
00264   length = outline->pathlength ();
00265   for (stepindex = 0; stepindex < length; stepindex++) {
00266     step = outline->step (stepindex);
00267     if (step.x () > 0) {
00268       lower_y =
00269         (INT16) floor (baseline->y (pos.x ()) + baseline_offset + 0.5);
00270       upper_y =
00271         (INT16) floor (baseline->y (pos.x ()) + baseline_offset +
00272         xheight + 0.5);
00273       if (pos.y () >= lower_y) {
00274         lower_proj->add (pos.x (), -lower_y);
00275         if (pos.y () >= upper_y) {
00276           middle_proj->add (pos.x (), lower_y - upper_y);
00277           upper_proj->add (pos.x (), upper_y - pos.y ());
00278         }
00279         else
00280           middle_proj->add (pos.x (), lower_y - pos.y ());
00281       }
00282       else
00283         lower_proj->add (pos.x (), -pos.y ());
00284     }
00285     else if (step.x () < 0) {
00286       lower_y =
00287         (INT16) floor (baseline->y (pos.x () - 1) + baseline_offset +
00288         0.5);
00289       upper_y =
00290         (INT16) floor (baseline->y (pos.x () - 1) + baseline_offset +
00291         xheight + 0.5);
00292       if (pos.y () >= lower_y) {
00293         lower_proj->add (pos.x () - 1, lower_y);
00294         if (pos.y () >= upper_y) {
00295           middle_proj->add (pos.x () - 1, upper_y - lower_y);
00296           upper_proj->add (pos.x () - 1, pos.y () - upper_y);
00297         }
00298         else
00299           middle_proj->add (pos.x () - 1, pos.y () - lower_y);
00300       }
00301       else
00302         lower_proj->add (pos.x () - 1, pos.y ());
00303     }
00304     pos += step;
00305   }
00306 
00307   for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
00308     vertical_cunderline_projection (out_it.data (),
00309       baseline, xheight, baseline_offset,
00310       lower_proj, middle_proj, upper_proj);
00311   }
00312 }

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