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