textord/fpchop.cpp

Go to the documentation of this file.
00001 
00020 #include          "mfcpch.h"
00021 #ifdef __UNIX__
00022 #include          <assert.h>
00023 #endif
00024 #include          "stderr.h"
00025 #include          "blobbox.h"
00026 #include          "lmedsq.h"
00027 #include          "statistc.h"
00028 #include          "drawtord.h"
00029 #include          "tovars.h"
00030 #include          "topitch.h"
00031 #include          "fpchop.h"
00032 #include          "notdll.h"
00033 
00034 #define EXTERN
00035 
00038 EXTERN INT_VAR (textord_fp_chop_error, 2,
00039 "Max allowed bending of chop cells");
00040 EXTERN double_VAR (textord_fp_chop_snap, 0.5,
00041 "Max distance of chop pt from vertex");
00044 ELISTIZE (OUTLINE_FRAG) ELISTIZE (C_OUTLINE_FRAG)
00045 //#undef ASSERT_HOST
00046 //#define ASSERT_HOST(x) if (!(x)) AfxMessageBox(#x);
00047 
00048 /* ================ */
00054 ROW *fixed_pitch_words(                 //find lines
00055                        TO_ROW *row,     //row to do
00056                        FCOORD rotation  //for drawing
00057                       ) {
00058   BOOL8 bol;                     //start of line
00059   UINT8 blanks;                  //in front of word
00060   UINT8 new_blanks;              //blanks in empty cell
00061   INT16 chop_coord;              //chop boundary
00062   INT16 prev_chop_coord;         //start of cell
00063   INT16 rep_left;                //left edge of rep word
00064   ROW *real_row;                 //output row
00065   OUTLINE_LIST left_outlines;    //in current blob
00066   OUTLINE_LIST right_outlines;   //for next blob
00067   C_OUTLINE_LIST left_coutlines;
00068   C_OUTLINE_LIST right_coutlines;
00069   PBLOB_LIST blobs;              //blobs in word
00070   C_BLOB_LIST cblobs;
00071   PBLOB_IT blob_it = &blobs;     //iterator
00072   C_BLOB_IT cblob_it = &cblobs;
00073   WERD_LIST words;
00074   WERD_IT word_it = &words;      //new words
00075                                  //repeated blobs
00076   WERD_IT rep_it = &row->rep_words;
00077   WERD *word;                    //new word
00078   INT32 xstarts[2];              //row ends
00079   double coeffs[3];              //quadratic
00080   INT32 prev_x;                  //end of prev blob
00081                                  //iterator
00082   BLOBNBOX_IT box_it = row->blob_list ();
00083                                  //boundaries
00084   ICOORDELT_IT cell_it = &row->char_cells;
00085 
00086 #ifndef GRAPHICS_DISABLED
00087   if (textord_show_page_cuts && to_win != NO_WINDOW) {
00088     plot_row_cells (to_win, RED, row, 0, &row->char_cells);
00089   }
00090 #endif
00091 
00092   prev_x = -MAX_INT16;
00093   bol = TRUE;
00094   blanks = 0;
00095   if (rep_it.empty ())
00096     rep_left = MAX_INT16;
00097   else
00098     rep_left = rep_it.data ()->bounding_box ().left ();
00099   if (box_it.empty ())
00100     return NULL;                 //empty row
00101   xstarts[0] = box_it.data ()->bounding_box ().left ();
00102   if (rep_left < xstarts[0]) {
00103     xstarts[0] = rep_left;
00104   }
00105   if (cell_it.empty () || row->char_cells.singleton ()) {
00106     tprintf ("Row without enough char cells!\n");
00107     tprintf ("Leftmost blob is at (%d,%d)\n",
00108       box_it.data ()->bounding_box ().left (),
00109       box_it.data ()->bounding_box ().bottom ());
00110     return NULL;
00111   }
00112   ASSERT_HOST (!cell_it.empty () && !row->char_cells.singleton ());
00113   prev_chop_coord = cell_it.data ()->x ();
00114   word = NULL;
00115   while (rep_left < cell_it.data ()->x ()) {
00116     word = add_repeated_word (&rep_it, rep_left, prev_chop_coord,
00117       blanks, row->fixed_pitch, &word_it);
00118   }
00119   cell_it.mark_cycle_pt ();
00120   if (prev_chop_coord >= cell_it.data ()->x ())
00121     cell_it.forward ();
00122   for (; !cell_it.cycled_list (); cell_it.forward ()) {
00123     chop_coord = cell_it.data ()->x ();
00124     while (!box_it.empty ()
00125     && box_it.data ()->bounding_box ().left () <= chop_coord) {
00126       if (box_it.data ()->bounding_box ().right () > prev_x)
00127         prev_x = box_it.data ()->bounding_box ().right ();
00128       split_to_blob (box_it.extract (), chop_coord,
00129         textord_fp_chop_error + 0.5f,
00130         &left_outlines, &left_coutlines,
00131         &right_outlines, &right_coutlines);
00132       box_it.forward ();
00133       while (!box_it.empty ()
00134         && box_it.data ()->blob () == NULL
00135       && box_it.data ()->cblob () == NULL) {
00136         delete box_it.extract ();
00137         box_it.forward ();
00138       }
00139     }
00140     if ((!right_outlines.empty () || !right_coutlines.empty ())
00141       && left_outlines.empty () && left_coutlines.empty ())
00142       split_to_blob (NULL, chop_coord,
00143         textord_fp_chop_error + 0.5f,
00144         &left_outlines, &left_coutlines,
00145         &right_outlines, &right_coutlines);
00146     if (!left_outlines.empty ())
00147       blob_it.add_after_then_move (new PBLOB (&left_outlines));
00148     else if (!left_coutlines.empty ())
00149       cblob_it.add_after_then_move (new C_BLOB (&left_coutlines));
00150     else {
00151       if (rep_left < chop_coord) {
00152         if (rep_left > prev_chop_coord)
00153           new_blanks = (UINT8) floor ((rep_left - prev_chop_coord)
00154             / row->fixed_pitch + 0.5);
00155         else
00156           new_blanks = 0;
00157       }
00158       else {
00159         if (chop_coord > prev_chop_coord)
00160           new_blanks = (UINT8) floor ((chop_coord - prev_chop_coord)
00161             / row->fixed_pitch + 0.5);
00162         else
00163           new_blanks = 0;
00164       }
00165       if (!blob_it.empty () || !cblob_it.empty ()) {
00166         if (blanks < 1 && word != NULL && !word->flag (W_REP_CHAR))
00167           blanks = 1;
00168         if (!blob_it.empty ()) {
00169                                  //make real word
00170           word = new WERD (&blobs, blanks, NULL);
00171           blob_it.set_to_list (&blobs);
00172         }
00173         else {
00174           word = new WERD (&cblobs, blanks, NULL);
00175           cblob_it.set_to_list (&cblobs);
00176         }
00177         word->set_flag (W_DONT_CHOP, TRUE);
00178         word_it.add_after_then_move (word);
00179         if (bol) {
00180           word->set_flag (W_BOL, TRUE);
00181           bol = FALSE;
00182         }
00183         blanks = new_blanks;
00184       }
00185       else
00186         blanks += new_blanks;
00187       while (rep_left < chop_coord) {
00188         word = add_repeated_word (&rep_it, rep_left, prev_chop_coord,
00189           blanks, row->fixed_pitch, &word_it);
00190       }
00191     }
00192     if (prev_chop_coord < chop_coord)
00193       prev_chop_coord = chop_coord;
00194   }
00195   if (!blob_it.empty () || !cblob_it.empty ()) {
00196     if (!blob_it.empty ())
00197                                  //last word on line
00198       word = new WERD (&blobs, blanks, NULL);
00199     else
00200       word = new WERD (&cblobs, blanks, NULL);
00201     word->set_flag (W_DONT_CHOP, TRUE);
00202     word_it.add_after_then_move (word);
00203     if (bol)
00204       word->set_flag (W_BOL, TRUE);
00205   }
00206   ASSERT_HOST (word != NULL);
00207   while (!rep_it.empty ()) {
00208     add_repeated_word (&rep_it, rep_left, prev_chop_coord,
00209       blanks, row->fixed_pitch, &word_it);
00210   }
00211                                  //at end of line
00212   word_it.data ()->set_flag (W_EOL, TRUE);
00213   if (prev_chop_coord > prev_x)
00214     prev_x = prev_chop_coord;
00215   xstarts[1] = prev_x + 1;
00216   coeffs[0] = 0;
00217   coeffs[1] = row->line_m ();
00218   coeffs[2] = row->line_c ();
00219   real_row = new ROW (row, (INT16) row->kern_size, (INT16) row->space_size);
00220   word_it.set_to_list (real_row->word_list ());
00221                                  //put words in row
00222   word_it.add_list_after (&words);
00223   real_row->recalc_bounding_box ();
00224   return real_row;
00225 }
00226 
00227 
00228 /* ================ */
00234 WERD *add_repeated_word(                         //move repeated word
00235                         WERD_IT *rep_it,         //repeated words
00236                         INT16 &rep_left,         //left edge of word
00237                         INT16 &prev_chop_coord,  //previous word end
00238                         UINT8 &blanks,           //no of blanks
00239                         float pitch,             //char cell size
00240                         WERD_IT *word_it         //list of words
00241                        ) {
00242   WERD *word;                    //word to move
00243   INT16 new_blanks;              //extra blanks
00244 
00245   if (rep_left > prev_chop_coord) {
00246     new_blanks = (UINT8) floor ((rep_left - prev_chop_coord) / pitch + 0.5);
00247     blanks += new_blanks;
00248   }
00249   word = rep_it->extract ();
00250   prev_chop_coord = word->bounding_box ().right ();
00251   word_it->add_after_then_move (word);
00252   word->set_blanks (blanks);
00253   rep_it->forward ();
00254   if (rep_it->empty ())
00255     rep_left = MAX_INT16;
00256   else
00257     rep_left = rep_it->data ()->bounding_box ().left ();
00258   blanks = 0;
00259   return word;
00260 }
00261 
00262 
00263 /* ================ */
00270 void split_to_blob(                                 //split the blob
00271                    BLOBNBOX *blob,                  //blob to split
00272                    INT16 chop_coord,                //place to chop
00273                    float pitch_error,               //allowed deviation
00274                    OUTLINE_LIST *left_outlines,     //left half of chop
00275                    C_OUTLINE_LIST *left_coutlines,  //for cblobs
00276                    OUTLINE_LIST *right_outlines,    //right half of chop
00277                    C_OUTLINE_LIST *right_coutlines) {
00278   PBLOB *real_blob;              //blob to chop
00279   C_BLOB *real_cblob;            //cblob to chop
00280 
00281   if (blob != NULL) {
00282     real_blob = blob->blob ();
00283     real_cblob = blob->cblob ();
00284   }
00285   else {
00286     real_blob = NULL;
00287     real_cblob = NULL;
00288   }
00289   if (!right_outlines->empty () || real_blob != NULL)
00290     fixed_chop_blob(real_blob,
00291                     chop_coord,
00292                     pitch_error,
00293                     left_outlines,
00294                     right_outlines);
00295   else if (!right_coutlines->empty () || real_cblob != NULL)
00296     fixed_chop_cblob(real_cblob,
00297                      chop_coord,
00298                      pitch_error,
00299                      left_coutlines,
00300                      right_coutlines);
00301   if (blob != NULL)
00302     delete blob;                 //free it
00303 }
00304 
00305 
00306 /* ================ */
00313 void fixed_chop_blob(                              //split the blob
00314                      PBLOB *blob,                  //blob to split
00315                      INT16 chop_coord,             //place to chop
00316                      float pitch_error,            //allowed deviation
00317                      OUTLINE_LIST *left_outlines,  //left half of chop
00318                      OUTLINE_LIST *right_outlines  //right half of chop
00319                     ) {
00320   OUTLINE *old_right;            //already there
00321   OUTLINE_LIST new_outlines;     //new right ones
00322                                  //ouput iterator
00323   OUTLINE_IT left_it = left_outlines;
00324                                  //in/out iterator
00325   OUTLINE_IT right_it = right_outlines;
00326   OUTLINE_IT new_it = &new_outlines;
00327   OUTLINE_IT blob_it;            //outlines in blob
00328 
00329   if (!right_it.empty ()) {
00330     while (!right_it.empty ()) {
00331       old_right = right_it.extract ();
00332       right_it.forward ();
00333       fixed_split_outline(old_right,
00334                           chop_coord,
00335                           pitch_error,
00336                           &left_it,
00337                           &new_it);
00338     }
00339     right_it.add_list_before (&new_outlines);
00340   }
00341   if (blob != NULL) {
00342     blob_it.set_to_list (blob->out_list ());
00343     for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
00344       blob_it.forward ())
00345     fixed_split_outline (blob_it.extract (), chop_coord, pitch_error,
00346         &left_it, &right_it);
00347     delete blob;
00348   }
00349 }
00350 
00351 
00352 /* ================ */
00359 void fixed_split_outline(                      //chop the outline
00360                          OUTLINE *srcline,     //source outline
00361                          INT16 chop_coord,     //place to chop
00362                          float pitch_error,    //allowed deviation
00363                          OUTLINE_IT *left_it,  //left half of chop
00364                          OUTLINE_IT *right_it  //right half of chop
00365                         ) {
00366   OUTLINE *child;                //child outline
00367   BOX srcbox;                    //box of outline
00368   OUTLINE_LIST left_ch;          //left children
00369   OUTLINE_LIST right_ch;         //right children
00370   OUTLINE_FRAG_LIST left_frags;  //chopped fragments
00371   OUTLINE_FRAG_LIST right_frags;;
00372   OUTLINE_IT left_ch_it = &left_ch;
00373                                  //for whole children
00374   OUTLINE_IT right_ch_it = &right_ch;
00375                                  //for holes
00376   OUTLINE_IT child_it = srcline->child ();
00377 
00378   srcbox = srcline->bounding_box ();
00379                                  //left of line
00380   if (srcbox.left () + srcbox.right () <= chop_coord * 2
00381                                  //and not far over
00382     && srcbox.right () < chop_coord + pitch_error)
00383                                  //stick whole in left
00384     left_it->add_after_then_move (srcline);
00385   else if (srcbox.left () + srcbox.right () > chop_coord * 2
00386     && srcbox.left () > chop_coord - pitch_error)
00387                                  //stick whole in right
00388     right_it->add_before_stay_put (srcline);
00389   else {
00390                                  //needs real chopping
00391     if (fixed_chop_outline (srcline, chop_coord, pitch_error,
00392     &left_frags, &right_frags)) {
00393       for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00394       child_it.forward ()) {
00395         child = child_it.extract ();
00396         srcbox = child->bounding_box ();
00397         if (srcbox.right () < chop_coord)
00398           left_ch_it.add_after_then_move (child);
00399         else if (srcbox.left () > chop_coord)
00400           right_ch_it.add_after_then_move (child);
00401         else {
00402           if (fixed_chop_outline (child, chop_coord, pitch_error,
00403             &left_frags, &right_frags))
00404             delete child;
00405           else {
00406             if (srcbox.left () + srcbox.right () <= chop_coord * 2)
00407               left_ch_it.add_after_then_move (child);
00408             else
00409               right_ch_it.add_after_then_move (child);
00410           }
00411         }
00412       }
00413       close_chopped_fragments(&left_frags, &left_ch, left_it); 
00414       close_chopped_fragments(&right_frags, &right_ch, right_it); 
00415       ASSERT_HOST (left_ch.empty () && right_ch.empty ());
00416       //no children left
00417       delete srcline;            //smashed up
00418     }
00419     else {
00420       if (srcbox.left () + srcbox.right () <= chop_coord * 2)
00421                                  //stick whole in left
00422         left_it->add_after_then_move (srcline);
00423       else
00424         right_it->add_before_stay_put (srcline);
00425     }
00426   }
00427 }
00428 
00429 
00430 /* ================ */
00439 BOOL8 fixed_chop_outline(                                //chop the outline
00440                          OUTLINE *srcline,               //source outline
00441                          INT16 chop_coord,               //place to chop
00442                          float pitch_error,              //allowed deviation
00443                          OUTLINE_FRAG_LIST *left_frags,  //left half of chop
00444                          OUTLINE_FRAG_LIST *right_frags  //right half of chop
00445                         ) {
00446   BOOL8 not_first;               //fragment
00447   BOOL8 test_valid;              //test pt valid
00448   float left_edge;               //of outline
00449   FCOORD chop_pos;               //coords of chop
00450   float chop_starty;             //test chop pt
00451   POLYPT *startpt;               //in first fragment
00452                                  //general iterator
00453   POLYPT_IT poly_it = srcline->polypts ();
00454   POLYPT_IT head_it;             //head of fragment
00455   POLYPT_IT tail_it;             //tail of fragment
00456   POLYPT_IT test_tail;           //possible chop pt
00457 
00458   left_edge = poly_it.data ()->pos.x ();
00459   tail_it = poly_it;
00460   for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) {
00461     if (poly_it.data ()->pos.x () < left_edge) {
00462       left_edge = poly_it.data ()->pos.x ();
00463       tail_it = poly_it;         //find leftmost pt
00464     }
00465   }
00466   if (left_edge >= chop_coord - pitch_error)
00467     return FALSE;                //not worth it
00468 
00469   startpt = tail_it.data ();
00470   not_first = FALSE;
00471   head_it = tail_it;
00472   chop_starty = tail_it.data ()->pos.y ();
00473   do {
00474     test_valid = FALSE;
00475     do {
00476       tail_it.forward ();
00477       if (test_valid
00478         && tail_it.data ()->pos.x () >= chop_coord
00479         && tail_it.data ()->pos.x () + tail_it.data ()->vec.x () <=
00480       chop_coord) {
00481         chop_pos = find_chop_coords (&tail_it, chop_coord);
00482         if (chop_pos.y () >= chop_starty)
00483           test_valid = FALSE;
00484         else {
00485           tail_it = test_tail;
00486           break;                 //must chop there
00487         }
00488       }
00489       if (tail_it.data ()->pos.x () <= chop_coord
00490         && tail_it.data ()->pos.x () + tail_it.data ()->vec.x () >=
00491       chop_coord) {
00492         chop_pos = find_chop_coords (&tail_it, chop_coord);
00493         chop_starty = chop_pos.y ();
00494         test_tail = tail_it;     //save possible chop pt
00495         test_valid = TRUE;
00496         if (tail_it.data ()->vec.x () == 0
00497           && tail_it.data ()->vec.y () < 0)
00498           break;                 //must chop here
00499       }
00500     }
00501     while (tail_it.data () != startpt
00502       && tail_it.data ()->pos.x () < chop_coord + pitch_error);
00503                                  //back to start
00504     if (tail_it.data () == startpt) {
00505       if (not_first)
00506         break;
00507       else
00508         return FALSE;            //doesn't cross line
00509     }
00510     while (tail_it.data ()->pos.x () > chop_coord)
00511       tail_it.backward ();
00512     if (head_it.data () == tail_it.data ())
00513       insert_extra_pt(&tail_it); 
00514     insert_chop_pt(&tail_it, chop_coord); 
00515     if (not_first) {
00516       save_chop_fragment(&head_it, &tail_it, left_frags); 
00517     }
00518     else {
00519       tail_it.forward ();
00520       head_it = tail_it;
00521     }
00522     test_valid = FALSE;
00523     do {
00524       tail_it.forward ();
00525       if (test_valid
00526         && tail_it.data ()->pos.x () <= chop_coord
00527         && tail_it.data ()->pos.x () + tail_it.data ()->vec.x () >=
00528       chop_coord) {
00529         chop_pos = find_chop_coords (&tail_it, chop_coord);
00530         if (chop_pos.y () <= chop_starty)
00531           test_valid = FALSE;
00532         else {
00533           tail_it = test_tail;
00534           break;                 //must chop there
00535         }
00536       }
00537       if (tail_it.data ()->pos.x () >= chop_coord
00538         && tail_it.data ()->pos.x () + tail_it.data ()->vec.x () <=
00539       chop_coord) {
00540         chop_pos = find_chop_coords (&tail_it, chop_coord);
00541         chop_starty = chop_pos.y ();
00542         test_tail = tail_it;
00543         test_valid = TRUE;       //save possible chop pt
00544         if (tail_it.data ()->vec.x () == 0
00545           && tail_it.data ()->vec.y () > 0)
00546           break;                 //must chop here
00547       }
00548     }
00549     while (tail_it.data () != startpt
00550       && tail_it.data ()->pos.x () > chop_coord - pitch_error);
00551     while (tail_it.data ()->pos.x () < chop_coord)
00552       tail_it.backward ();
00553     if (head_it.data () == tail_it.data ())
00554       insert_extra_pt(&tail_it); 
00555     insert_chop_pt(&tail_it, chop_coord); 
00556     save_chop_fragment(&head_it, &tail_it, right_frags); 
00557     not_first = TRUE;
00558   }
00559   while (tail_it.data () != startpt);
00560   startpt = head_it.data_relative (-1);
00561   while (tail_it.data () != startpt)
00562     tail_it.forward ();
00563   save_chop_fragment(&head_it, &tail_it, left_frags); 
00564   return TRUE;                   //did some chopping
00565 }
00566 
00567 
00568 /* ================ */
00574 void save_chop_fragment(                          //chop the outline
00575                         POLYPT_IT *head_it,       //head of fragment
00576                         POLYPT_IT *tail_it,       //tail of fragment
00577                         OUTLINE_FRAG_LIST *frags  //fragment list
00578                        ) {
00579   OUTLINE_FRAG *head;            //head of fragment
00580   OUTLINE_FRAG *tail;            //tail of fragment
00581   float tail_y;                  //ycoord of tail
00582 
00583   tail_y = tail_it->data ()->pos.y ();
00584   head = new OUTLINE_FRAG (head_it, tail_it);
00585   tail = new OUTLINE_FRAG (head, tail_y);
00586   head->other_end = tail;
00587   add_frag_to_list(head, frags); 
00588   add_frag_to_list(tail, frags); 
00589   head_it->forward ();
00590   tail_it->forward ();
00591 }
00592 
00593 
00594 /* ================ */
00600 OUTLINE_FRAG::OUTLINE_FRAG(                     //record fragment
00601                            POLYPT_IT *head_it,  //head of fragment
00602                            POLYPT_IT *tail_it   //tail of fragment
00603                           ) {
00604   ycoord = head_it->data ()->pos.y ();
00605   other_end = NULL;
00606   polypts.assign_to_sublist (head_it, tail_it);
00607 }
00608 
00609 
00610 OUTLINE_FRAG::OUTLINE_FRAG(                     //record fragment
00611                            OUTLINE_FRAG *head,  //other end
00612                            float tail_y) {
00613   ycoord = tail_y;
00614   other_end = head;
00615 }
00616 
00617 
00618 /* ================ */
00625 void add_frag_to_list(                          //ordered add
00626                       OUTLINE_FRAG *frag,       //fragment to add
00627                       OUTLINE_FRAG_LIST *frags  //fragment list
00628                      ) {
00629                                  //output list
00630   OUTLINE_FRAG_IT frag_it = frags;
00631 
00632   if (!frags->empty ()) {
00633     for (frag_it.mark_cycle_pt (); !frag_it.cycled_list ();
00634     frag_it.forward ()) {
00635       if (frag_it.data ()->ycoord >= frag->ycoord) {
00636         frag_it.add_before_then_move (frag);
00637         return;
00638       }
00639     }
00640   }
00641   frag_it.add_to_end (frag);
00642 }
00643 
00644 
00645 /* ================ */
00653 void insert_chop_pt(                  //make chop
00654                     POLYPT_IT *it,    //iterator
00655                     INT16 chop_coord  //required chop pt
00656                    ) {
00657   POLYPT *prev_pt;               //point befor chop
00658   POLYPT *chop_pt;               //new vertex
00659   FCOORD chop_pos;               //coords of chop
00660   FCOORD chop_vec;               //vector to next
00661 
00662   prev_pt = it->data ();
00663   if (prev_pt->pos.x () + textord_fp_chop_snap >= chop_coord
00664   && prev_pt->pos.x () - textord_fp_chop_snap <= chop_coord) {
00665     chop_pt = new POLYPT (prev_pt->pos, prev_pt->vec);
00666   }
00667   else {
00668     chop_pos = FCOORD (chop_coord, prev_pt->pos.y ()
00669       + prev_pt->vec.y () * (chop_coord -
00670       prev_pt->pos.x ()) /
00671       prev_pt->vec.x ());
00672     chop_vec = it->data_relative (1)->pos - chop_pos;
00673     chop_pt = new POLYPT (chop_pos, chop_vec);
00674     it->add_after_then_move (chop_pt);
00675     chop_pt = new POLYPT (chop_pos, chop_vec);
00676   }
00677   it->add_after_stay_put (chop_pt);
00678 }
00679 
00680 
00681 /* ================ */
00689 FCOORD find_chop_coords(                  //make chop
00690                         POLYPT_IT *it,    //iterator
00691                         INT16 chop_coord  //required chop pt
00692                        ) {
00693   POLYPT *prev_pt;               //point befor chop
00694   FCOORD chop_pos;               //coords of chop
00695 
00696   prev_pt = it->data ();
00697   if (prev_pt->pos.x () + textord_fp_chop_snap >= chop_coord
00698   && prev_pt->pos.x () - textord_fp_chop_snap <= chop_coord) {
00699     chop_pos = prev_pt->pos;
00700   }
00701   else {
00702     chop_pos = FCOORD (chop_coord, prev_pt->pos.y ()
00703       + prev_pt->vec.y () * (chop_coord -
00704       prev_pt->pos.x ()) /
00705       prev_pt->vec.x ());
00706   }
00707   return chop_pos;
00708 }
00709 
00710 
00711 /* ================ */
00717 void insert_extra_pt(               //make extra
00718                      POLYPT_IT *it  //iterator
00719                     ) {
00720   POLYPT *prev_pt;               //point befor chop
00721   POLYPT *chop_pt;               //new vertex
00722   FCOORD chop_pos;               //coords of chop
00723   FCOORD chop_vec;               //vector to next
00724 
00725   prev_pt = it->data ();
00726   if (it->data_relative (1)->pos.y () > it->data_relative (-1)->pos.y ()) {
00727     chop_pos = prev_pt->pos + FCOORD (0.0f,
00728                                       static_cast<float>(textord_fp_chop_snap));
00729   }
00730   else {
00731     chop_pos = prev_pt->pos - FCOORD (0.0f,
00732                                       static_cast<float>(textord_fp_chop_snap));
00733   }
00734   chop_vec = it->data_relative (1)->pos - chop_pos;
00735   prev_pt->vec = chop_pos - prev_pt->pos;
00736   chop_pt = new POLYPT (chop_pos, chop_vec);
00737   it->add_after_then_move (chop_pt);
00738 }
00739 
00740 
00741 /* ================ */
00748 void close_chopped_fragments(                           //chop the outline
00749                              OUTLINE_FRAG_LIST *frags,  //list to clear
00750                              OUTLINE_LIST *children,    //potential children
00751                              OUTLINE_IT *dest_it        //output list
00752                             ) {
00753                                  //iterator
00754   OUTLINE_FRAG_IT frag_it = frags;
00755   OUTLINE_FRAG *bottom_frag;     //bottom of cut
00756   OUTLINE_FRAG *top_frag;        //top of cut
00757   OUTLINE *outline;              //new outline
00758   OUTLINE *child;                //current child
00759   OUTLINE_IT child_it = children;
00760   OUTLINE_IT olchild_it;         //children of outline
00761   POLYPT_IT poly_it;             //iterator for constr
00762 
00763   while (!frag_it.empty ()) {
00764     frag_it.move_to_first ();
00765                                  //get bottom one
00766     bottom_frag = frag_it.extract ();
00767     frag_it.forward ();
00768                                  //and one above it
00769     top_frag = frag_it.extract ();
00770     while (top_frag->other_end != bottom_frag) {
00771       do {
00772         frag_it.forward ();
00773       }
00774                                  //find other end
00775       while (frag_it.data () != top_frag->other_end);
00776       join_chopped_fragments(bottom_frag, top_frag); 
00777       delete top_frag;
00778       delete frag_it.extract (); //remove middle section
00779       frag_it.forward ();
00780       top_frag = frag_it.extract ();
00781     }
00782     join_chopped_fragments(bottom_frag, top_frag); 
00783     if (bottom_frag->polypts.empty ())
00784       poly_it.set_to_list (&top_frag->polypts);
00785     else
00786       poly_it.set_to_list (&bottom_frag->polypts);
00787     outline = new OUTLINE (&poly_it);
00788     olchild_it.set_to_list (outline->child ());
00789     for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00790     child_it.forward ()) {
00791       child = child_it.data ();
00792       if (*child < *outline)
00793         olchild_it.add_to_end (child_it.extract ());
00794     }
00795     dest_it->add_after_then_move (outline);
00796   }
00797   while (!child_it.empty ()) {
00798     dest_it->add_after_then_move (child_it.extract ());
00799     child_it.forward ();
00800   }
00801 }
00802 
00803 
00804 /* ================ */
00811 void join_chopped_fragments(                       //join pieces
00812                             OUTLINE_FRAG *bottom,  //bottom of cut
00813                             OUTLINE_FRAG *top      //top of cut
00814                            ) {
00815   POLYPT_IT master_it;           //dest list
00816   POLYPT_IT slave_it;            //src list
00817   POLYPT *cutpt;                 //vectors to change
00818   POLYPT *nextpt;                //other end of cut
00819 
00820   if (bottom->polypts.empty ()) {
00821     master_it.set_to_list (&bottom->other_end->polypts);
00822     cutpt = master_it.data_relative (-1);
00823     ASSERT_HOST (!top->polypts.empty ());
00824     slave_it.set_to_list (&top->polypts);
00825     nextpt = slave_it.data ();
00826     if (bottom->other_end != top) {
00827       master_it.move_to_last ();
00828       master_it.add_list_after (&top->polypts);
00829     }
00830   }
00831   else {
00832     master_it.set_to_list (&bottom->polypts);
00833     ASSERT_HOST (top->polypts.empty ());
00834     slave_it.set_to_list (&top->other_end->polypts);
00835     cutpt = slave_it.data_relative (-1);
00836     nextpt = master_it.data ();
00837     if (bottom->other_end != top)
00838       master_it.add_list_before (&top->other_end->polypts);
00839   }
00840   cutpt->vec = nextpt->pos - cutpt->pos;
00841 }
00842 
00843 
00844 /* ================ */
00851 void fixed_chop_cblob(                                //split the blob
00852                       C_BLOB *blob,                   //blob to split
00853                       INT16 chop_coord,               //place to chop
00854                       float pitch_error,              //allowed deviation
00855                       C_OUTLINE_LIST *left_outlines,  //left half of chop
00856                       C_OUTLINE_LIST *right_outlines  //right half of chop
00857                      ) {
00858   C_OUTLINE *old_right;          //already there
00859   C_OUTLINE_LIST new_outlines;   //new right ones
00860                                  //ouput iterator
00861   C_OUTLINE_IT left_it = left_outlines;
00862                                  //in/out iterator
00863   C_OUTLINE_IT right_it = right_outlines;
00864   C_OUTLINE_IT new_it = &new_outlines;
00865   C_OUTLINE_IT blob_it;          //outlines in blob
00866 
00867   if (!right_it.empty ()) {
00868     while (!right_it.empty ()) {
00869       old_right = right_it.extract ();
00870       right_it.forward ();
00871       fixed_split_coutline(old_right,
00872                            chop_coord,
00873                            pitch_error,
00874                            &left_it,
00875                            &new_it);
00876     }
00877     right_it.add_list_before (&new_outlines);
00878   }
00879   if (blob != NULL) {
00880     blob_it.set_to_list (blob->out_list ());
00881     for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
00882       blob_it.forward ())
00883     fixed_split_coutline (blob_it.extract (), chop_coord, pitch_error,
00884         &left_it, &right_it);
00885     delete blob;
00886   }
00887 }
00888 
00889 
00890 /* ================ */
00897 void fixed_split_coutline(                        //chop the outline
00898                           C_OUTLINE *srcline,     //source outline
00899                           INT16 chop_coord,       //place to chop
00900                           float pitch_error,      //allowed deviation
00901                           C_OUTLINE_IT *left_it,  //left half of chop
00902                           C_OUTLINE_IT *right_it  //right half of chop
00903                          ) {
00904   C_OUTLINE *child;              //child outline
00905   BOX srcbox;                    //box of outline
00906   C_OUTLINE_LIST left_ch;        //left children
00907   C_OUTLINE_LIST right_ch;       //right children
00908   C_OUTLINE_FRAG_LIST left_frags;//chopped fragments
00909   C_OUTLINE_FRAG_LIST right_frags;;
00910   C_OUTLINE_IT left_ch_it = &left_ch;
00911                                  //for whole children
00912   C_OUTLINE_IT right_ch_it = &right_ch;
00913                                  //for holes
00914   C_OUTLINE_IT child_it = srcline->child ();
00915 
00916   srcbox = srcline->bounding_box ();
00917                                  //left of line
00918   if (srcbox.left () + srcbox.right () <= chop_coord * 2
00919                                  //and not far over
00920     && srcbox.right () < chop_coord + pitch_error)
00921                                  //stick whole in left
00922     left_it->add_after_then_move (srcline);
00923   else if (srcbox.left () + srcbox.right () > chop_coord * 2
00924     && srcbox.left () > chop_coord - pitch_error)
00925                                  //stick whole in right
00926     right_it->add_before_stay_put (srcline);
00927   else {
00928                                  //needs real chopping
00929     if (fixed_chop_coutline (srcline, chop_coord, pitch_error,
00930     &left_frags, &right_frags)) {
00931       for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00932       child_it.forward ()) {
00933         child = child_it.extract ();
00934         srcbox = child->bounding_box ();
00935         if (srcbox.right () < chop_coord)
00936           left_ch_it.add_after_then_move (child);
00937         else if (srcbox.left () > chop_coord)
00938           right_ch_it.add_after_then_move (child);
00939         else {
00940           if (fixed_chop_coutline (child, chop_coord, pitch_error,
00941             &left_frags, &right_frags))
00942             delete child;
00943           else {
00944             if (srcbox.left () + srcbox.right () <= chop_coord * 2)
00945               left_ch_it.add_after_then_move (child);
00946             else
00947               right_ch_it.add_after_then_move (child);
00948           }
00949         }
00950       }
00951       close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it); 
00952       close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it); 
00953       ASSERT_HOST (left_ch.empty () && right_ch.empty ());
00954       //no children left
00955       delete srcline;            //smashed up
00956     }
00957     else {
00958       if (srcbox.left () + srcbox.right () <= chop_coord * 2)
00959                                  //stick whole in left
00960         left_it->add_after_then_move (srcline);
00961       else
00962         right_it->add_before_stay_put (srcline);
00963     }
00964   }
00965 }
00966 
00967 
00968 /* ================ */
00980 BOOL8 fixed_chop_coutline(
00981                           C_OUTLINE *srcline,
00982                           INT16 chop_coord,
00983                           float pitch_error,
00984                           C_OUTLINE_FRAG_LIST *left_frags,
00985                           C_OUTLINE_FRAG_LIST *right_frags
00986                          ) {
00987   BOOL8 first_frag;              //fragment
00988   BOOL8 anticlock;               //direction of loop
00989   INT16 left_edge;               //of outline
00990   INT16 startindex;              //in first fragment
00991   INT32 length;                  //of outline
00992   INT16 stepindex;               //into outline
00993   INT16 head_index;              //start of fragment
00994   ICOORD head_pos;               //start of fragment
00995   INT16 tail_index;              //end of fragment
00996   ICOORD tail_pos;               //end of fragment
00997   ICOORD pos;                    //current point
00998   INT16 first_index = 0;         //first tail
00999   ICOORD first_pos;              //first tail
01000 
01001   length = srcline->pathlength ();
01002   pos = srcline->start_pos ();
01003   anticlock = srcline->turn_direction () > 0;
01004   left_edge = pos.x ();
01005   tail_index = 0;
01006   tail_pos = pos;
01007   for (stepindex = 0; stepindex < length; stepindex++) {
01008     if (pos.x () < left_edge) {
01009       left_edge = pos.x ();
01010       tail_index = stepindex;
01011       tail_pos = pos;
01012     }
01013     pos += srcline->step (stepindex);
01014   }
01015   if (left_edge >= chop_coord - pitch_error)
01016     return FALSE;                //not worth it
01017 
01018   startindex = tail_index;
01019   first_frag = TRUE;
01020   head_index = tail_index;
01021   head_pos = tail_pos;
01022   do {
01023     do {
01024       tail_pos += srcline->step (tail_index);
01025       tail_index++;
01026       if (tail_index == length)
01027         tail_index = 0;
01028     }
01029     while (tail_pos.x () != chop_coord && tail_index != startindex);
01030     if (tail_index == startindex) {
01031       if (first_frag)
01032         return FALSE;            //doesn't cross line
01033       else
01034         break;
01035     }
01036     //#ifdef __UNIX__
01037     ASSERT_HOST (head_index != tail_index);
01038     //#endif
01039     if (!first_frag) {
01040       save_chop_cfragment(head_index,
01041                           head_pos,
01042                           tail_index,
01043                           tail_pos,
01044                           srcline,
01045                           left_frags);
01046     }
01047     else {
01048       first_index = tail_index;
01049       first_pos = tail_pos;
01050       first_frag = FALSE;
01051     }
01052     while (srcline->step (tail_index).x () == 0) {
01053       tail_pos += srcline->step (tail_index);
01054       tail_index++;
01055       if (tail_index == length)
01056         tail_index = 0;
01057     }
01058     head_index = tail_index;
01059     head_pos = tail_pos;
01060     while (srcline->step (tail_index).x () > 0) {
01061       do {
01062         tail_pos += srcline->step (tail_index);
01063         tail_index++;
01064         if (tail_index == length)
01065           tail_index = 0;
01066       }
01067       while (tail_pos.x () != chop_coord);
01068       //#ifdef __UNIX__
01069       ASSERT_HOST (head_index != tail_index);
01070       //#endif
01071       save_chop_cfragment(head_index,
01072                           head_pos,
01073                           tail_index,
01074                           tail_pos,
01075                           srcline,
01076                           right_frags);
01077       while (srcline->step (tail_index).x () == 0) {
01078         tail_pos += srcline->step (tail_index);
01079         tail_index++;
01080         if (tail_index == length)
01081           tail_index = 0;
01082       }
01083       head_index = tail_index;
01084       head_pos = tail_pos;
01085     }
01086   }
01087   while (tail_index != startindex);
01088   save_chop_cfragment(head_index,
01089                       head_pos,
01090                       first_index,
01091                       first_pos,
01092                       srcline,
01093                       left_frags);
01094   return TRUE;                   //did some chopping
01095 }
01096 
01097 
01098 /* ================ */
01105 INT16 next_anti_left_seg(                     //chop the outline
01106                          C_OUTLINE *srcline,  //source outline
01107                          INT16 tail_index,    //of tailpos
01108                          INT16 startindex,    //end of search
01109                          INT32 length,        //of outline
01110                          INT16 chop_coord,    //place to chop
01111                          float pitch_error,   //allowed deviation
01112                          ICOORD *tail_pos     //current position
01113                         ) {
01114   BOOL8 test_valid;              //test pt valid
01115   INT16 chop_starty;             //test chop pt
01116   INT16 test_index;              //possible chop pt
01117   ICOORD test_pos;               //possible chop pt
01118   ICOORD prev_step;              //in x to tail pos
01119 
01120   test_valid = FALSE;
01121   chop_starty = -MAX_INT16;
01122   test_index = tail_index;       //stop warnings
01123   do {
01124     *tail_pos += srcline->step (tail_index);
01125     prev_step = srcline->step (tail_index);
01126     tail_index++;
01127     if (tail_index >= length)
01128       tail_index = 0;
01129     if (test_valid && tail_pos->x () == chop_coord && prev_step.x () < 0) {
01130       if (tail_pos->y () >= chop_starty) {
01131         chop_starty = -MAX_INT16;
01132         test_valid = FALSE;
01133       }
01134       else {
01135         *tail_pos = test_pos;
01136         tail_index = test_index;
01137         break;                   //must chop there
01138       }
01139     }
01140     if (tail_pos->x () == chop_coord
01141       && srcline->step (tail_index).x () > 0
01142     && tail_pos->y () > chop_starty) {
01143       chop_starty = tail_pos->y ();
01144       test_index = tail_index;
01145       test_pos = *tail_pos;
01146       test_valid = TRUE;
01147     }
01148     else if (tail_pos->x () == chop_coord
01149       && srcline->step (tail_index).y () < 0
01150       && prev_step.x () > 0 && tail_pos->y () > chop_starty)
01151       break;                     //must chop here
01152   }
01153   while (tail_index != startindex
01154     && tail_pos->x () < chop_coord + pitch_error);
01155   return tail_index;
01156 }
01157 
01158 
01159 /* ================ */
01166 INT16 next_anti_right_seg(                     //chop the outline
01167                           C_OUTLINE *srcline,  //source outline
01168                           INT16 tail_index,    //of tailpos
01169                           INT16 startindex,    //end of search
01170                           INT32 length,        //of outline
01171                           INT16 chop_coord,    //place to chop
01172                           float pitch_error,   //allowed deviation
01173                           ICOORD *tail_pos     //current position
01174                          ) {
01175   BOOL8 test_valid;              //test pt valid
01176   INT16 chop_starty;             //test chop pt
01177   INT16 test_index;              //possible chop pt
01178   ICOORD test_pos;               //possible chop pt
01179   ICOORD prev_step;              //in x to tail pos
01180 
01181   test_valid = FALSE;
01182   chop_starty = MAX_INT16;
01183   test_index = tail_index;       //stop warnings
01184   do {
01185                                  //move forward
01186     *tail_pos += srcline->step (tail_index);
01187     prev_step = srcline->step (tail_index);
01188     tail_index++;
01189     if (tail_index >= length)
01190       tail_index = 0;
01191     if (test_valid && tail_pos->x () == chop_coord && prev_step.x () > 0) {
01192       if (tail_pos->y () <= chop_starty) {
01193         chop_starty = MAX_INT16;
01194         test_valid = FALSE;
01195       }
01196       else {
01197         *tail_pos = test_pos;
01198         tail_index = test_index;
01199         break;                   //must chop there
01200       }
01201     }
01202     if (tail_pos->x () == chop_coord
01203       && srcline->step (tail_index).x () < 0
01204     && tail_pos->y () < chop_starty) {
01205       chop_starty = tail_pos->y ();
01206       test_index = tail_index;
01207       test_pos = *tail_pos;
01208       test_valid = TRUE;         //save possible chop pt
01209     }
01210     else if (tail_pos->x () == chop_coord
01211       && srcline->step (tail_index).y () > 0
01212       && prev_step.x () < 0 && tail_pos->y () < chop_starty)
01213       break;                     //must chop here
01214   }
01215   while (tail_index != startindex
01216     && tail_pos->x () > chop_coord - pitch_error);
01217   return tail_index;
01218 }
01219 
01220 
01221 /* ================ */
01228 INT16 next_clock_left_seg(                     //chop the outline
01229                           C_OUTLINE *srcline,  //source outline
01230                           INT16 tail_index,    //of tailpos
01231                           INT16 startindex,    //end of search
01232                           INT32 length,        //of outline
01233                           INT16 chop_coord,    //place to chop
01234                           float pitch_error,   //allowed deviation
01235                           ICOORD *tail_pos     //current position
01236                          ) {
01237   BOOL8 test_valid;              //test pt valid
01238   INT16 chop_starty;             //test chop pt
01239   INT16 test_index;              //possible chop pt
01240   ICOORD test_pos;               //possible chop pt
01241   ICOORD prev_step;              //in x to tail pos
01242 
01243   test_valid = FALSE;
01244   chop_starty = MAX_INT16;
01245   test_index = tail_index;       //stop warnings
01246   do {
01247     *tail_pos += srcline->step (tail_index);
01248     prev_step = srcline->step (tail_index);
01249     tail_index++;
01250     if (tail_index >= length)
01251       tail_index = 0;
01252     if (test_valid && tail_pos->x () == chop_coord && prev_step.x () < 0) {
01253       if (tail_pos->y () <= chop_starty) {
01254         chop_starty = MAX_INT16;
01255         test_valid = FALSE;
01256       }
01257       else {
01258         *tail_pos = test_pos;
01259         tail_index = test_index;
01260         break;                   //must chop there
01261       }
01262     }
01263     if (tail_pos->x () == chop_coord
01264       && srcline->step (tail_index).x () > 0
01265     && tail_pos->y () < chop_starty) {
01266       chop_starty = tail_pos->y ();
01267       test_index = tail_index;
01268       test_pos = *tail_pos;
01269       test_valid = TRUE;
01270     }
01271     else if (tail_pos->x () == chop_coord
01272       && srcline->step (tail_index).y () > 0
01273       && prev_step.x () > 0 && tail_pos->y () < chop_starty)
01274       break;                     //must chop here
01275   }
01276   while (tail_index != startindex
01277     && tail_pos->x () < chop_coord + pitch_error);
01278   return tail_index;
01279 }
01280 
01281 
01282 /* ================ */
01289 INT16 next_clock_right_seg(                     //chop the outline
01290                            C_OUTLINE *srcline,  //source outline
01291                            INT16 tail_index,    //of tailpos
01292                            INT16 startindex,    //end of search
01293                            INT32 length,        //of outline
01294                            INT16 chop_coord,    //place to chop
01295                            float pitch_error,   //allowed deviation
01296                            ICOORD *tail_pos     //current position
01297                           ) {
01298   BOOL8 test_valid;              //test pt valid
01299   INT16 chop_starty;             //test chop pt
01300   INT16 test_index;              //possible chop pt
01301   ICOORD test_pos;               //possible chop pt
01302   ICOORD prev_step;              //in x to tail pos
01303 
01304   test_valid = FALSE;
01305   chop_starty = MAX_INT16;
01306   test_index = tail_index;       //stop warnings
01307   do {
01308                                  //move forward
01309     *tail_pos += srcline->step (tail_index);
01310     prev_step = srcline->step (tail_index);
01311     tail_index++;
01312     if (tail_index >= length)
01313       tail_index = 0;
01314     if (test_valid && tail_pos->x () == chop_coord && prev_step.x () > 0) {
01315       if (tail_pos->y () >= chop_starty) {
01316         chop_starty = MAX_INT16;
01317         test_valid = FALSE;
01318       }
01319       else {
01320         *tail_pos = test_pos;
01321         tail_index = test_index;
01322         break;                   //must chop there
01323       }
01324     }
01325     if (tail_pos->x () == chop_coord
01326       && srcline->step (tail_index).x () < 0
01327     && tail_pos->y () > chop_starty) {
01328       chop_starty = tail_pos->y ();
01329       test_index = tail_index;
01330       test_pos = *tail_pos;
01331       test_valid = TRUE;         //save possible chop pt
01332     }
01333     else if (tail_pos->x () == chop_coord
01334       && srcline->step (tail_index).y () < 0
01335       && prev_step.x () < 0 && tail_pos->y () > chop_starty)
01336       break;                     //must chop here
01337   }
01338   while (tail_index != startindex
01339     && tail_pos->x () > chop_coord - pitch_error);
01340   return tail_index;
01341 }
01342 
01343 
01344 /* ================ */
01350 void save_chop_cfragment(                            //chop the outline
01351                          INT16 head_index,           //head of fragment
01352                          ICOORD head_pos,            //head of fragment
01353                          INT16 tail_index,           //tail of fragment
01354                          ICOORD tail_pos,            //tail of fragment
01355                          C_OUTLINE *srcline,         //source of edgesteps
01356                          C_OUTLINE_FRAG_LIST *frags  //fragment list
01357                         ) {
01358   INT16 jump;                    //gap across end
01359   INT16 stepcount;               //total steps
01360   C_OUTLINE_FRAG *head;          //head of fragment
01361   C_OUTLINE_FRAG *tail;          //tail of fragment
01362   INT16 tail_y;                  //ycoord of tail
01363 
01364   ASSERT_HOST (tail_pos.x () == head_pos.x ());
01365   ASSERT_HOST (tail_index != head_index);
01366   stepcount = tail_index - head_index;
01367   if (stepcount < 0)
01368     stepcount += srcline->pathlength ();
01369   jump = tail_pos.y () - head_pos.y ();
01370   if (jump < 0)
01371     jump = -jump;
01372   if (jump == stepcount)
01373     return;                      //its a nop
01374   tail_y = tail_pos.y ();
01375   head = new C_OUTLINE_FRAG (head_pos, tail_pos, srcline,
01376     head_index, tail_index);
01377   tail = new C_OUTLINE_FRAG (head, tail_y);
01378   head->other_end = tail;
01379   add_frag_to_list(head, frags); 
01380   add_frag_to_list(tail, frags); 
01381 }
01382 
01383 
01384 /* ================ */
01390 C_OUTLINE_FRAG::C_OUTLINE_FRAG(                     //record fragment
01391                                ICOORD start_pt,     //start coord
01392                                ICOORD end_pt,       //end coord
01393                                C_OUTLINE *outline,  //source of steps
01394                                INT16 start_index,
01395                                INT16 end_index) {
01396   start = start_pt;
01397   end = end_pt;
01398   ycoord = start_pt.y ();
01399   stepcount = end_index - start_index;
01400   if (stepcount < 0)
01401     stepcount += outline->pathlength ();
01402   ASSERT_HOST (stepcount > 0);
01403   steps = new DIR128[stepcount];
01404   if (end_index > start_index) {
01405     for (int i = start_index; i < end_index; ++i)
01406       steps[i - start_index] = outline->step_dir(i);
01407   }
01408   else {
01409     int len = outline->pathlength();
01410     int i = start_index;
01411     for (; i < len; ++i)
01412       steps[i - start_index] = outline->step_dir(i);
01413     if (end_index > 0)
01414       for (; i < end_index + len; ++i)
01415         steps[i - start_index] = outline->step_dir(i - len);
01416   }
01417   other_end = NULL;
01418   delete close(); 
01419 }
01420 
01421 
01422 /* ================ */
01426 C_OUTLINE_FRAG::C_OUTLINE_FRAG(                       //record fragment
01427                                C_OUTLINE_FRAG *head,  //other end
01428                                INT16 tail_y) {
01429   ycoord = tail_y;
01430   other_end = head;
01431   start = head->start;
01432   end = head->end;
01433   steps = NULL;
01434   stepcount = 0;
01435 }
01436 
01437 
01438 /* ================ */
01445 void add_frag_to_list(                            //ordered add
01446                       C_OUTLINE_FRAG *frag,       //fragment to add
01447                       C_OUTLINE_FRAG_LIST *frags  //fragment list
01448                      ) {
01449                                  //output list
01450   C_OUTLINE_FRAG_IT frag_it = frags;
01451 
01452   if (!frags->empty ()) {
01453     for (frag_it.mark_cycle_pt (); !frag_it.cycled_list ();
01454     frag_it.forward ()) {
01455       if (frag_it.data ()->ycoord > frag->ycoord
01456         || frag_it.data ()->ycoord == frag->ycoord
01457       && frag->other_end->ycoord < frag->ycoord) {
01458         frag_it.add_before_then_move (frag);
01459         return;
01460       }
01461     }
01462   }
01463   frag_it.add_to_end (frag);
01464 }
01465 
01466 
01467 /* ================ */
01474 void close_chopped_cfragments(                             //chop the outline
01475                               C_OUTLINE_FRAG_LIST *frags,  //list to clear
01476                               C_OUTLINE_LIST *children,    //potential children
01477                               float pitch_error,           //allowed shrinkage
01478                               C_OUTLINE_IT *dest_it        //output list
01479                              ) {
01480                                  //iterator
01481   C_OUTLINE_FRAG_IT frag_it = frags;
01482   C_OUTLINE_FRAG *bottom_frag;   //bottom of cut
01483   C_OUTLINE_FRAG *top_frag;      //top of cut
01484   C_OUTLINE *outline;            //new outline
01485   C_OUTLINE *child;              //current child
01486   C_OUTLINE_IT child_it = children;
01487   C_OUTLINE_IT olchild_it;       //children of outline
01488 
01489   while (!frag_it.empty ()) {
01490     frag_it.move_to_first ();
01491                                  //get bottom one
01492     bottom_frag = frag_it.extract ();
01493     frag_it.forward ();
01494     top_frag = frag_it.data ();  //look at next
01495     if (bottom_frag->steps == 0 && top_frag->steps == 0
01496     || bottom_frag->steps != 0 && top_frag->steps != 0) {
01497       if (frag_it.data_relative (1)->ycoord == top_frag->ycoord)
01498         frag_it.forward ();
01499     }
01500     top_frag = frag_it.extract ();
01501     if (top_frag->other_end != bottom_frag) {
01502       outline = join_chopped_fragments (bottom_frag, top_frag);
01503       ASSERT_HOST (outline == NULL);
01504     }
01505     else {
01506       outline = join_chopped_fragments (bottom_frag, top_frag);
01507       ASSERT_HOST (outline != NULL);
01508       olchild_it.set_to_list (outline->child ());
01509       for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
01510       child_it.forward ()) {
01511         child = child_it.data ();
01512         if (*child < *outline)
01513           olchild_it.add_to_end (child_it.extract ());
01514       }
01515       if (outline->bounding_box ().width () > pitch_error)
01516         dest_it->add_after_then_move (outline);
01517       else
01518         delete outline;          //make it disappear
01519     }
01520   }
01521   while (!child_it.empty ()) {
01522     dest_it->add_after_then_move (child_it.extract ());
01523     child_it.forward ();
01524   }
01525 }
01526 
01527 
01528 /* ================ */
01535 C_OUTLINE *join_chopped_fragments(                         //join pieces
01536                                   C_OUTLINE_FRAG *bottom,  //bottom of cut
01537                                   C_OUTLINE_FRAG *top      //top of cut
01538                                  ) {
01539   C_OUTLINE *outline;            //closed loop
01540 
01541   if (bottom->other_end == top) {
01542     if (bottom->steps == 0)
01543       outline = top->close ();   //turn to outline
01544     else
01545       outline = bottom->close ();
01546     delete top;
01547     delete bottom;
01548     return outline;
01549   }
01550   if (bottom->steps == 0) {
01551     ASSERT_HOST (top->steps != 0);
01552     join_segments (bottom->other_end, top);
01553   }
01554   else {
01555     ASSERT_HOST (top->steps == 0);
01556     join_segments (top->other_end, bottom);
01557   }
01558   top->other_end->other_end = bottom->other_end;
01559   bottom->other_end->other_end = top->other_end;
01560   delete bottom;
01561   delete top;
01562   return NULL;
01563 }
01564 
01565 
01566 /* ================ */
01573 void join_segments(                         //join pieces
01574                    C_OUTLINE_FRAG *bottom,  //bottom of cut
01575                    C_OUTLINE_FRAG *top      //top of cut
01576                   ) {
01577   DIR128 *steps;                  //new steps
01578   INT32 stepcount;               //no of steps
01579   INT16 fake_count;              //fake steps
01580   DIR128 fake_step;               //step entry
01581 
01582   ASSERT_HOST (bottom->end.x () == top->start.x ());
01583   fake_count = top->start.y () - bottom->end.y ();
01584   if (fake_count < 0) {
01585     fake_count = -fake_count;
01586     fake_step = 32;
01587   }
01588   else
01589     fake_step = 96;
01590 
01591   stepcount = bottom->stepcount + fake_count + top->stepcount;
01592   steps = new DIR128[stepcount];
01593   memmove (steps, bottom->steps, bottom->stepcount);
01594   memset (steps + bottom->stepcount, fake_step.get_dir(), fake_count);
01595   memmove (steps + bottom->stepcount + fake_count, top->steps,
01596     top->stepcount);
01597   delete [] bottom->steps;
01598   bottom->steps = steps;
01599   bottom->stepcount = stepcount;
01600   bottom->end = top->end;
01601   bottom->other_end->end = top->end;
01602 }
01603 
01604 
01605 /* ================ */
01611 C_OUTLINE *C_OUTLINE_FRAG::close() {  //join pieces
01612   DIR128 *new_steps;              //new steps
01613   INT32 new_stepcount;           //no of steps
01614   INT16 fake_count;              //fake steps
01615   DIR128 fake_step;               //step entry
01616 
01617   ASSERT_HOST (start.x () == end.x ());
01618   fake_count = start.y () - end.y ();
01619   if (fake_count < 0) {
01620     fake_count = -fake_count;
01621     fake_step = 32;
01622   }
01623   else
01624     fake_step = 96;
01625 
01626   new_stepcount = stepcount + fake_count;
01627   new_steps = new DIR128[new_stepcount];
01628   memmove(new_steps, steps, stepcount); 
01629   memset (new_steps + stepcount, fake_step.get_dir(), fake_count);
01630   C_OUTLINE* result = new C_OUTLINE (start, new_steps, new_stepcount);
01631   delete [] new_steps;
01632   return result;
01633 }
01634 
01635 
01636 /* ================ */
01642 C_OUTLINE_FRAG & C_OUTLINE_FRAG::operator= ( //join pieces
01643 const C_OUTLINE_FRAG & src       //fragment to copy
01644 ) {
01645   if (steps != NULL)
01646     delete [] steps; 
01647 
01648   stepcount = src.stepcount;
01649   steps = new DIR128[stepcount];
01650   memmove (steps, src.steps, stepcount);
01651   start = src.start;
01652   end = src.end;
01653   ycoord = src.ycoord;
01654   return *this;
01655 }

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