tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/pdblock.cpp
Go to the documentation of this file.
00001 /**********************************************************************
00002  * File:        pdblock.c  (Formerly pdblk.c)
00003  * Description: PDBLK member functions and iterator functions.
00004  * Author:                                      Ray Smith
00005  * Created:                                     Fri Mar 15 09:41:28 GMT 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          <stdlib.h>
00021 #include          "allheaders.h"
00022 #include          "blckerr.h"
00023 #include          "pdblock.h"
00024 
00025 // Include automatically generated configuration file if running autoconf.
00026 #ifdef HAVE_CONFIG_H
00027 #include "config_auto.h"
00028 #endif
00029 
00030 #define BLOCK_LABEL_HEIGHT  150  //char height of block id
00031 
00032 CLISTIZE (PDBLK)
00033 /**********************************************************************
00034  * PDBLK::PDBLK
00035  *
00036  * Constructor for a simple rectangular block.
00037  **********************************************************************/
00038 PDBLK::PDBLK (                   //rectangular block
00039 inT16 xmin,                      //bottom left
00040 inT16 ymin, inT16 xmax,          //top right
00041 inT16 ymax):    box (ICOORD (xmin, ymin), ICOORD (xmax, ymax)) {
00042                                  //boundaries
00043   ICOORDELT_IT left_it = &leftside;
00044   ICOORDELT_IT right_it = &rightside;
00045 
00046   hand_poly = NULL;
00047   left_it.set_to_list (&leftside);
00048   right_it.set_to_list (&rightside);
00049                                  //make default box
00050   left_it.add_to_end (new ICOORDELT (xmin, ymin));
00051   left_it.add_to_end (new ICOORDELT (xmin, ymax));
00052   right_it.add_to_end (new ICOORDELT (xmax, ymin));
00053   right_it.add_to_end (new ICOORDELT (xmax, ymax));
00054   index_ = 0;
00055 }
00056 
00057 
00058 /**********************************************************************
00059  * PDBLK::set_sides
00060  *
00061  * Sets left and right vertex lists
00062  **********************************************************************/
00063 
00064 void PDBLK::set_sides(                       //set vertex lists
00065                       ICOORDELT_LIST *left,  //left vertices
00066                       ICOORDELT_LIST *right  //right vertices
00067                      ) {
00068                                  //boundaries
00069   ICOORDELT_IT left_it = &leftside;
00070   ICOORDELT_IT right_it = &rightside;
00071 
00072   leftside.clear ();
00073   left_it.move_to_first ();
00074   left_it.add_list_before (left);
00075   rightside.clear ();
00076   right_it.move_to_first ();
00077   right_it.add_list_before (right);
00078 }
00079 
00080 
00081 /**********************************************************************
00082  * PDBLK::contains
00083  *
00084  * Return TRUE if the given point is within the block.
00085  **********************************************************************/
00086 
00087 BOOL8 PDBLK::contains(           //test containment
00088                       ICOORD pt  //point to test
00089                      ) {
00090   BLOCK_RECT_IT it = this;       //rectangle iterator
00091   ICOORD bleft, tright;          //corners of rectangle
00092 
00093   for (it.start_block (); !it.cycled_rects (); it.forward ()) {
00094                                  //get rectangle
00095     it.bounding_box (bleft, tright);
00096                                  //inside rect
00097     if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
00098       && pt.y () >= bleft.y () && pt.y () <= tright.y ())
00099       return TRUE;               //is inside
00100   }
00101   return FALSE;                  //not inside
00102 }
00103 
00104 
00105 /**********************************************************************
00106  * PDBLK::move
00107  *
00108  * Reposition block
00109  **********************************************************************/
00110 
00111 void PDBLK::move(                  // reposition block
00112                  const ICOORD vec  // by vector
00113                 ) {
00114   ICOORDELT_IT it(&leftside);
00115 
00116   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
00117     *(it.data ()) += vec;
00118 
00119   it.set_to_list (&rightside);
00120 
00121   for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
00122     *(it.data ()) += vec;
00123 
00124   box.move (vec);
00125 }
00126 
00127 // Returns a binary Pix mask with a 1 pixel for every pixel within the
00128 // block. Rotates the coordinate system by rerotation prior to rendering.
00129 Pix* PDBLK::render_mask(const FCOORD& rerotation) {
00130   TBOX rotated_box(box);
00131   rotated_box.rotate(rerotation);
00132   Pix* pix = pixCreate(rotated_box.width(), rotated_box.height(), 1);
00133   if (hand_poly != NULL) {
00134     // We are going to rotate, so get a deep copy of the points and
00135     // make a new POLY_BLOCK with it.
00136     ICOORDELT_LIST polygon;
00137     polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy);
00138     POLY_BLOCK image_block(&polygon, hand_poly->isA());
00139     image_block.rotate(rerotation);
00140     // Block outline is a polygon, so use a PB_LINE_IT to get the
00141     // rasterized interior. (Runs of interior pixels on a line.)
00142     PB_LINE_IT *lines = new PB_LINE_IT(&image_block);
00143     for (int y = box.bottom(); y < box.top(); ++y) {
00144       ICOORDELT_LIST* segments = lines->get_line(y);
00145       if (!segments->empty()) {
00146         ICOORDELT_IT s_it(segments);
00147         // Each element of segments is a start x and x size of the
00148         // run of interior pixels.
00149         for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
00150           int start = s_it.data()->x();
00151           int xext = s_it.data()->y();
00152           // Set the run of pixels to 1.
00153           pixRasterop(pix, start - rotated_box.left(),
00154                       rotated_box.height() - 1 - (y - rotated_box.bottom()),
00155                       xext, 1, PIX_SET, NULL, 0, 0);
00156         }
00157       }
00158       delete segments;
00159     }
00160     delete lines;
00161   } else {
00162     // Just fill the whole block as there is only a bounding box.
00163     pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(),
00164                 PIX_SET, NULL, 0, 0);
00165   }
00166   return pix;
00167 }
00168 
00169 
00170 /**********************************************************************
00171  * PDBLK::plot
00172  *
00173  * Plot the outline of a block in the given colour.
00174  **********************************************************************/
00175 
00176 #ifndef GRAPHICS_DISABLED
00177 void PDBLK::plot(                //draw outline
00178                  ScrollView* window,  //window to draw in
00179                  inT32 serial,   //serial number
00180                  ScrollView::Color colour   //colour to draw in
00181                 ) {
00182   ICOORD startpt;                //start of outline
00183   ICOORD endpt;                  //end of outline
00184   ICOORD prevpt;                 //previous point
00185   ICOORDELT_IT it = &leftside;   //iterator
00186 
00187                                  //set the colour
00188   window->Pen(colour);
00189   window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);
00190 
00191   if (hand_poly != NULL) {
00192     hand_poly->plot(window, serial);
00193   } else if (!leftside.empty ()) {
00194     startpt = *(it.data ());     //bottom left corner
00195     //              tprintf("Block %d bottom left is (%d,%d)\n",
00196     //                      serial,startpt.x(),startpt.y());
00197     char temp_buff[34];
00198     #if defined(__UNIX__) || defined(MINGW)
00199     sprintf(temp_buff, INT32FORMAT, serial);
00200     #else
00201     ultoa (serial, temp_buff, 10);
00202     #endif
00203     window->Text(startpt.x (), startpt.y (), temp_buff);
00204 
00205     window->SetCursor(startpt.x (), startpt.y ());
00206     do {
00207       prevpt = *(it.data ());    //previous point
00208       it.forward ();             //move to next point
00209                                  //draw round corner
00210     window->DrawTo(prevpt.x (), it.data ()->y ());
00211     window->DrawTo(it.data ()->x (), it.data ()->y ());
00212     }
00213     while (!it.at_last ());      //until end of list
00214     endpt = *(it.data ());       //end point
00215 
00216                                  //other side of boundary
00217     window->SetCursor(startpt.x (), startpt.y ());
00218     it.set_to_list (&rightside);
00219     prevpt = startpt;
00220     for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
00221                                  //draw round corner
00222     window->DrawTo(prevpt.x (), it.data ()->y ());
00223     window->DrawTo(it.data ()->x (), it.data ()->y ());
00224       prevpt = *(it.data ());    //previous point
00225     }
00226                                  //close boundary
00227     window->DrawTo(endpt.x(), endpt.y());
00228   }
00229 }
00230 #endif
00231 
00232 /**********************************************************************
00233  * PDBLK::operator=
00234  *
00235  * Assignment - duplicate the block structure, but with an EMPTY row list.
00236  **********************************************************************/
00237 
00238 PDBLK & PDBLK::operator= (       //assignment
00239 const PDBLK & source             //from this
00240 ) {
00241   //      this->ELIST_LINK::operator=(source);
00242   if (!leftside.empty ())
00243     leftside.clear ();
00244   if (!rightside.empty ())
00245     rightside.clear ();
00246   leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy);
00247   rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy);
00248   box = source.box;
00249   return *this;
00250 }
00251 
00252 
00253 /**********************************************************************
00254  * BLOCK_RECT_IT::BLOCK_RECT_IT
00255  *
00256  * Construct a block rectangle iterator.
00257  **********************************************************************/
00258 
00259 BLOCK_RECT_IT::BLOCK_RECT_IT (
00260 //iterate rectangles
00261 PDBLK * blkptr                   //from block
00262 ):left_it (&blkptr->leftside), right_it (&blkptr->rightside) {
00263   block = blkptr;                //remember block
00264                                  //non empty list
00265   if (!blkptr->leftside.empty ()) {
00266     start_block();  //ready for iteration
00267   }
00268 }
00269 
00270 
00271 /**********************************************************************
00272  * BLOCK_RECT_IT::set_to_block
00273  *
00274  * Start a new block.
00275  **********************************************************************/
00276 
00277 void BLOCK_RECT_IT::set_to_block(                  //start (new) block
00278                                  PDBLK *blkptr) {  //block to start
00279   block = blkptr;                //remember block
00280                                  //set iterators
00281   left_it.set_to_list (&blkptr->leftside);
00282   right_it.set_to_list (&blkptr->rightside);
00283   if (!blkptr->leftside.empty ())
00284     start_block();  //ready for iteration
00285 }
00286 
00287 
00288 /**********************************************************************
00289  * BLOCK_RECT_IT::start_block
00290  *
00291  * Restart a block.
00292  **********************************************************************/
00293 
00294 void BLOCK_RECT_IT::start_block() {  //start (new) block
00295   left_it.move_to_first ();
00296   right_it.move_to_first ();
00297   left_it.mark_cycle_pt ();
00298   right_it.mark_cycle_pt ();
00299   ymin = left_it.data ()->y ();  //bottom of first box
00300   ymax = left_it.data_relative (1)->y ();
00301   if (right_it.data_relative (1)->y () < ymax)
00302                                  //smallest step
00303     ymax = right_it.data_relative (1)->y ();
00304 }
00305 
00306 
00307 /**********************************************************************
00308  * BLOCK_RECT_IT::forward
00309  *
00310  * Move to the next rectangle in the block.
00311  **********************************************************************/
00312 
00313 void BLOCK_RECT_IT::forward() {  //next rectangle
00314   if (!left_it.empty ()) {       //non-empty list
00315     if (left_it.data_relative (1)->y () == ymax)
00316       left_it.forward ();        //move to meet top
00317     if (right_it.data_relative (1)->y () == ymax)
00318       right_it.forward ();
00319                                  //last is special
00320     if (left_it.at_last () || right_it.at_last ()) {
00321       left_it.move_to_first ();  //restart
00322       right_it.move_to_first ();
00323                                  //now at bottom
00324       ymin = left_it.data ()->y ();
00325     }
00326     else {
00327       ymin = ymax;               //new bottom
00328     }
00329                                  //next point
00330     ymax = left_it.data_relative (1)->y ();
00331     if (right_it.data_relative (1)->y () < ymax)
00332                                  //least step forward
00333       ymax = right_it.data_relative (1)->y ();
00334   }
00335 }
00336 
00337 
00338 /**********************************************************************
00339  * BLOCK_LINE_IT::get_line
00340  *
00341  * Get the the start and width of a line in the block.
00342  **********************************************************************/
00343 
00344 inT16 BLOCK_LINE_IT::get_line(             //get a line
00345                               inT16 y,     //line to get
00346                               inT16 &xext  //output extent
00347                              ) {
00348   ICOORD bleft;                  //bounding box
00349   ICOORD tright;                 //of block & rect
00350 
00351                                  //get block box
00352   block->bounding_box (bleft, tright);
00353   if (y < bleft.y () || y >= tright.y ()) {
00354     //              block->print(stderr,FALSE);
00355     BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
00356   }
00357 
00358                                  //get rectangle box
00359   rect_it.bounding_box (bleft, tright);
00360                                  //inside rectangle
00361   if (y >= bleft.y () && y < tright.y ()) {
00362                                  //width of line
00363     xext = tright.x () - bleft.x ();
00364     return bleft.x ();           //start of line
00365   }
00366   for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
00367                                  //get rectangle box
00368     rect_it.bounding_box (bleft, tright);
00369                                  //inside rectangle
00370     if (y >= bleft.y () && y < tright.y ()) {
00371                                  //width of line
00372       xext = tright.x () - bleft.x ();
00373       return bleft.x ();         //start of line
00374     }
00375   }
00376   LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
00377   return 0;                      //dummy to stop warning
00378 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines