tesseract
3.03
|
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 }