Tesseract
3.02
|
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 }