Tesseract  3.02
tesseract-ocr/ccstruct/stepblob.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        stepblob.cpp  (Formerly cblob.c)
00003  * Description: Code for C_BLOB class.
00004  * Author:              Ray Smith
00005  * Created:             Tue Oct 08 10:41:13 BST 1991
00006  *
00007  * (C) Copyright 1991, 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 #include "mfcpch.h"
00021 #include "stepblob.h"
00022 #include "allheaders.h"
00023 
00024 // Include automatically generated configuration file if running autoconf.
00025 #ifdef HAVE_CONFIG_H
00026 #include "config_auto.h"
00027 #endif
00028 
00029 ELISTIZE (C_BLOB)
00030 /**********************************************************************
00031  * position_outline
00032  *
00033  * Position the outline in the given list at the relevant place
00034  * according to its nesting.
00035  **********************************************************************/
00036 static void position_outline(                          //put in place
00037                              C_OUTLINE *outline,       //thing to place
00038                              C_OUTLINE_LIST *destlist  //desstination list
00039                             ) {
00040   C_OUTLINE *dest_outline;       //outline from dest list
00041   C_OUTLINE_IT it = destlist;    //iterator
00042                                  //iterator on children
00043   C_OUTLINE_IT child_it = outline->child ();
00044 
00045   if (!it.empty ()) {
00046     do {
00047       dest_outline = it.data (); //get destination
00048                                  //encloses dest
00049       if (*dest_outline < *outline) {
00050                                  //take off list
00051         dest_outline = it.extract ();
00052                                  //put this in place
00053         it.add_after_then_move (outline);
00054                                  //make it a child
00055         child_it.add_to_end (dest_outline);
00056         while (!it.at_last ()) {
00057           it.forward ();         //do rest of list
00058                                  //check for other children
00059           dest_outline = it.data ();
00060           if (*dest_outline < *outline) {
00061                                  //take off list
00062             dest_outline = it.extract ();
00063             child_it.add_to_end (dest_outline);
00064             //make it a child
00065             if (it.empty ())
00066               break;
00067           }
00068         }
00069         return;                  //finished
00070       }
00071                                  //enclosed by dest
00072       else if (*outline < *dest_outline) {
00073         position_outline (outline, dest_outline->child ());
00074         //place in child list
00075         return;                  //finished
00076       }
00077       it.forward ();
00078     }
00079     while (!it.at_first ());
00080   }
00081   it.add_to_end (outline);       //at outer level
00082 }
00083 
00084 
00085 /**********************************************************************
00086  * plot_outline_list
00087  *
00088  * Draw a list of outlines in the given colour and their children
00089  * in the child colour.
00090  **********************************************************************/
00091 
00092 #ifndef GRAPHICS_DISABLED
00093 static void plot_outline_list(                       //draw outlines
00094                               C_OUTLINE_LIST *list,  //outline to draw
00095                               ScrollView* window,         //window to draw in
00096                               ScrollView::Color colour,         //colour to use
00097                               ScrollView::Color child_colour    //colour of children
00098                              ) {
00099   C_OUTLINE *outline;            //current outline
00100   C_OUTLINE_IT it = list;        //iterator
00101 
00102   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00103     outline = it.data ();
00104                                  //draw it
00105     outline->plot (window, colour);
00106     if (!outline->child ()->empty ())
00107       plot_outline_list (outline->child (), window,
00108         child_colour, child_colour);
00109   }
00110 }
00111 #endif
00112 
00113 
00114 /**********************************************************************
00115  * reverse_outline_list
00116  *
00117  * Reverse a list of outlines and their children.
00118  **********************************************************************/
00119 
00120 static void reverse_outline_list(                      //reverse outlines
00121                                  C_OUTLINE_LIST *list  //outline to reverse
00122                                 ) {
00123   C_OUTLINE *outline;            //current outline
00124   C_OUTLINE_IT it = list;        //iterator
00125 
00126   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00127     outline = it.data ();
00128     outline->reverse ();         //reverse it
00129     if (!outline->child ()->empty ())
00130       reverse_outline_list (outline->child ());
00131   }
00132 }
00133 
00134 
00135 /**********************************************************************
00136  * C_BLOB::C_BLOB
00137  *
00138  * Constructor to build a C_BLOB from a list of C_OUTLINEs.
00139  * The C_OUTLINEs are not copied so the source list is emptied.
00140  * The C_OUTLINEs are nested correctly in the blob.
00141  **********************************************************************/
00142 
00143 C_BLOB::C_BLOB(                              //constructor
00144                C_OUTLINE_LIST *outline_list  //in random order
00145               ) {
00146   C_OUTLINE *outline;            //current outline
00147   C_OUTLINE_IT it = outline_list;//iterator
00148 
00149   while (!it.empty ()) {         //grab the list
00150     outline = it.extract ();     //get off the list
00151                                  //put it in place
00152     position_outline(outline, &outlines);
00153     if (!it.empty ())
00154       it.forward ();
00155   }
00156   it.set_to_list (&outlines);
00157   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00158     outline = it.data ();
00159     if (outline->turn_direction () < 0) {
00160       outline->reverse ();
00161       reverse_outline_list (outline->child ());
00162       outline->set_flag (COUT_INVERSE, TRUE);
00163     }
00164     else {
00165       outline->set_flag (COUT_INVERSE, FALSE);
00166     }
00167   }
00168 }
00169 
00170 // Simpler constructor to build a blob from a single outline that has
00171 // already been fully initialized.
00172 C_BLOB::C_BLOB(C_OUTLINE* outline) {
00173   C_OUTLINE_IT it(&outlines);
00174   it.add_to_end(outline);
00175 }
00176 
00177 
00178 // Build and return a fake blob containing a single fake outline with no
00179 // steps.
00180 C_BLOB* C_BLOB::FakeBlob(const TBOX& box) {
00181   C_OUTLINE_LIST outlines;
00182   C_OUTLINE::FakeOutline(box, &outlines);
00183   return new C_BLOB(&outlines);
00184 }
00185 
00186 /**********************************************************************
00187  * C_BLOB::bounding_box
00188  *
00189  * Return the bounding box of the blob.
00190  **********************************************************************/
00191 
00192 TBOX C_BLOB::bounding_box() {  //bounding box
00193   C_OUTLINE *outline;            //current outline
00194   C_OUTLINE_IT it = &outlines;   //outlines of blob
00195   TBOX box;                       //bounding box
00196 
00197   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00198     outline = it.data ();
00199     box += outline->bounding_box ();
00200   }
00201   return box;
00202 }
00203 
00204 
00205 /**********************************************************************
00206  * C_BLOB::area
00207  *
00208  * Return the area of the blob.
00209  **********************************************************************/
00210 
00211 inT32 C_BLOB::area() {  //area
00212   C_OUTLINE *outline;            //current outline
00213   C_OUTLINE_IT it = &outlines;   //outlines of blob
00214   inT32 total;                   //total area
00215 
00216   total = 0;
00217   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00218     outline = it.data ();
00219     total += outline->area ();
00220   }
00221   return total;
00222 }
00223 
00224 /**********************************************************************
00225  * C_BLOB::perimeter
00226  *
00227  * Return the perimeter of the top and 2nd level outlines.
00228  **********************************************************************/
00229 
00230 inT32 C_BLOB::perimeter() {
00231   C_OUTLINE *outline;            // current outline
00232   C_OUTLINE_IT it = &outlines;   // outlines of blob
00233   inT32 total;                   // total perimeter
00234 
00235   total = 0;
00236   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00237     outline = it.data();
00238     total += outline->perimeter();
00239   }
00240   return total;
00241 }
00242 
00243 
00244 /**********************************************************************
00245  * C_BLOB::outer_area
00246  *
00247  * Return the area of the blob.
00248  **********************************************************************/
00249 
00250 inT32 C_BLOB::outer_area() {  //area
00251   C_OUTLINE *outline;            //current outline
00252   C_OUTLINE_IT it = &outlines;   //outlines of blob
00253   inT32 total;                   //total area
00254 
00255   total = 0;
00256   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00257     outline = it.data ();
00258     total += outline->outer_area ();
00259   }
00260   return total;
00261 }
00262 
00263 
00264 /**********************************************************************
00265  * C_BLOB::count_transitions
00266  *
00267  * Return the total x and y maxes and mins in the blob.
00268  * Chlid outlines are not counted.
00269  **********************************************************************/
00270 
00271 inT32 C_BLOB::count_transitions(                 //area
00272                                 inT32 threshold  //on size
00273                                ) {
00274   C_OUTLINE *outline;            //current outline
00275   C_OUTLINE_IT it = &outlines;   //outlines of blob
00276   inT32 total;                   //total area
00277 
00278   total = 0;
00279   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00280     outline = it.data ();
00281     total += outline->count_transitions (threshold);
00282   }
00283   return total;
00284 }
00285 
00286 
00287 /**********************************************************************
00288  * C_BLOB::move
00289  *
00290  * Move C_BLOB by vector
00291  **********************************************************************/
00292 
00293 void C_BLOB::move(                  // reposition blob
00294                   const ICOORD vec  // by vector
00295                  ) {
00296   C_OUTLINE_IT it(&outlines);  // iterator
00297 
00298   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
00299     it.data ()->move (vec);      // move each outline
00300 }
00301 
00302 // Static helper for C_BLOB::rotate to allow recursion of child outlines.
00303 void RotateOutlineList(const FCOORD& rotation, C_OUTLINE_LIST* outlines) {
00304   C_OUTLINE_LIST new_outlines;
00305   C_OUTLINE_IT src_it(outlines);
00306   C_OUTLINE_IT dest_it(&new_outlines);
00307   while (!src_it.empty()) {
00308     C_OUTLINE* old_outline = src_it.extract();
00309     src_it.forward();
00310     C_OUTLINE* new_outline = new C_OUTLINE(old_outline, rotation);
00311     if (!old_outline->child()->empty()) {
00312       RotateOutlineList(rotation, old_outline->child());
00313       C_OUTLINE_IT child_it(new_outline->child());
00314       child_it.add_list_after(old_outline->child());
00315     }
00316     delete old_outline;
00317     dest_it.add_to_end(new_outline);
00318   }
00319   src_it.add_list_after(&new_outlines);
00320 }
00321 
00322 /**********************************************************************
00323  * C_BLOB::rotate
00324  *
00325  * Rotate C_BLOB by rotation.
00326  * Warning! has to rebuild all the C_OUTLINEs.
00327  **********************************************************************/
00328 void C_BLOB::rotate(const FCOORD& rotation) {
00329   RotateOutlineList(rotation, &outlines);
00330 }
00331 
00332 static void render_outline_list(C_OUTLINE_LIST *list,
00333                                 int left, int top, Pix* pix) {
00334   C_OUTLINE_IT it(list);
00335   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00336     C_OUTLINE* outline = it.data();
00337     outline->render(left, top, pix);
00338     if (!outline->child()->empty())
00339       render_outline_list(outline->child(), left, top, pix);
00340   }
00341 }
00342 
00343 static void render_outline_list_outline(C_OUTLINE_LIST *list,
00344                                         int left, int top, Pix* pix) {
00345   C_OUTLINE_IT it(list);
00346   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00347     C_OUTLINE* outline = it.data();
00348     outline->render_outline(left, top, pix);
00349   }
00350 }
00351 
00352 // Returns a Pix rendering of the blob. pixDestroy after use.
00353 Pix* C_BLOB::render() {
00354   TBOX box = bounding_box();
00355   Pix* pix = pixCreate(box.width(), box.height(), 1);
00356   render_outline_list(&outlines, box.left(), box.top(), pix);
00357   return pix;
00358 }
00359 
00360 // Returns a Pix rendering of the outline of the blob. (no fill).
00361 // pixDestroy after use.
00362 Pix* C_BLOB::render_outline() {
00363   TBOX box = bounding_box();
00364   Pix* pix = pixCreate(box.width(), box.height(), 1);
00365   render_outline_list_outline(&outlines, box.left(), box.top(), pix);
00366   return pix;
00367 }
00368 
00369 /**********************************************************************
00370  * C_BLOB::plot
00371  *
00372  * Draw the C_BLOB in the given colour.
00373  **********************************************************************/
00374 
00375 #ifndef GRAPHICS_DISABLED
00376 void C_BLOB::plot(                     //draw it
00377                   ScrollView* window,       //window to draw in
00378                   ScrollView::Color blob_colour,  //main colour
00379                   ScrollView::Color child_colour  //for holes
00380                  ) {
00381   plot_outline_list(&outlines, window, blob_colour, child_colour);
00382 }
00383 #endif