Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pdblock.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: pdblock.c (Formerly pdblk.c)
3  * Description: PDBLK member functions and iterator functions.
4  * Author: Ray Smith
5  * Created: Fri Mar 15 09:41:28 GMT 1991
6  *
7  * (C) Copyright 1991, Hewlett-Packard Ltd.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include "mfcpch.h"
21 #include <stdlib.h>
22 #include "allheaders.h"
23 #include "blckerr.h"
24 #include "pdblock.h"
25 #include "svshowim.h"
26 
27 // Include automatically generated configuration file if running autoconf.
28 #ifdef HAVE_CONFIG_H
29 #include "config_auto.h"
30 #endif
31 
32 #include "hpddef.h" //must be last (handpd.dll)
33 
34 #define BLOCK_LABEL_HEIGHT 150 //char height of block id
35 
37 /**********************************************************************
38  * PDBLK::PDBLK
39  *
40  * Constructor for a simple rectangular block.
41  **********************************************************************/
42 PDBLK::PDBLK ( //rectangular block
43 inT16 xmin, //bottom left
44 inT16 ymin, inT16 xmax, //top right
45 inT16 ymax): box (ICOORD (xmin, ymin), ICOORD (xmax, ymax)) {
46  //boundaries
47  ICOORDELT_IT left_it = &leftside;
48  ICOORDELT_IT right_it = &rightside;
49 
50  hand_poly = NULL;
51  left_it.set_to_list (&leftside);
52  right_it.set_to_list (&rightside);
53  //make default box
54  left_it.add_to_end (new ICOORDELT (xmin, ymin));
55  left_it.add_to_end (new ICOORDELT (xmin, ymax));
56  right_it.add_to_end (new ICOORDELT (xmax, ymin));
57  right_it.add_to_end (new ICOORDELT (xmax, ymax));
58  index_ = 0;
59 }
60 
61 
62 /**********************************************************************
63  * PDBLK::set_sides
64  *
65  * Sets left and right vertex lists
66  **********************************************************************/
67 
68 void PDBLK::set_sides( //set vertex lists
69  ICOORDELT_LIST *left, //left vertices
70  ICOORDELT_LIST *right //right vertices
71  ) {
72  //boundaries
73  ICOORDELT_IT left_it = &leftside;
74  ICOORDELT_IT right_it = &rightside;
75 
76  leftside.clear ();
77  left_it.move_to_first ();
78  left_it.add_list_before (left);
79  rightside.clear ();
80  right_it.move_to_first ();
81  right_it.add_list_before (right);
82 }
83 
84 
85 /**********************************************************************
86  * PDBLK::contains
87  *
88  * Return TRUE if the given point is within the block.
89  **********************************************************************/
90 
91 BOOL8 PDBLK::contains( //test containment
92  ICOORD pt //point to test
93  ) {
94  BLOCK_RECT_IT it = this; //rectangle iterator
95  ICOORD bleft, tright; //corners of rectangle
96 
97  for (it.start_block (); !it.cycled_rects (); it.forward ()) {
98  //get rectangle
99  it.bounding_box (bleft, tright);
100  //inside rect
101  if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
102  && pt.y () >= bleft.y () && pt.y () <= tright.y ())
103  return TRUE; //is inside
104  }
105  return FALSE; //not inside
106 }
107 
108 
109 /**********************************************************************
110  * PDBLK::move
111  *
112  * Reposition block
113  **********************************************************************/
114 
115 void PDBLK::move( // reposition block
116  const ICOORD vec // by vector
117  ) {
118  ICOORDELT_IT it(&leftside);
119 
120  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
121  *(it.data ()) += vec;
122 
123  it.set_to_list (&rightside);
124 
125  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
126  *(it.data ()) += vec;
127 
128  box.move (vec);
129 }
130 
131 // Returns a binary Pix mask with a 1 pixel for every pixel within the
132 // block. Rotates the coordinate system by rerotation prior to rendering.
133 Pix* PDBLK::render_mask(const FCOORD& rerotation) {
134  TBOX rotated_box(box);
135  rotated_box.rotate(rerotation);
136  Pix* pix = pixCreate(rotated_box.width(), rotated_box.height(), 1);
137  if (hand_poly != NULL) {
138  // We are going to rotate, so get a deep copy of the points and
139  // make a new POLY_BLOCK with it.
140  ICOORDELT_LIST polygon;
141  polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy);
142  POLY_BLOCK image_block(&polygon, hand_poly->isA());
143  image_block.rotate(rerotation);
144  // Block outline is a polygon, so use a PB_LINE_IT to get the
145  // rasterized interior. (Runs of interior pixels on a line.)
146  PB_LINE_IT *lines = new PB_LINE_IT(&image_block);
147  for (int y = box.bottom(); y < box.top(); ++y) {
148  ICOORDELT_LIST* segments = lines->get_line(y);
149  if (!segments->empty()) {
150  ICOORDELT_IT s_it(segments);
151  // Each element of segments is a start x and x size of the
152  // run of interior pixels.
153  for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
154  int start = s_it.data()->x();
155  int xext = s_it.data()->y();
156  // Set the run of pixels to 1.
157  pixRasterop(pix, start - rotated_box.left(),
158  rotated_box.height() - 1 - (y - rotated_box.bottom()),
159  xext, 1, PIX_SET, NULL, 0, 0);
160  }
161  }
162  delete segments;
163  }
164  delete lines;
165  } else {
166  // Just fill the whole block as there is only a bounding box.
167  pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(),
168  PIX_SET, NULL, 0, 0);
169  }
170  return pix;
171 }
172 
173 
174 /**********************************************************************
175  * PDBLK::plot
176  *
177  * Plot the outline of a block in the given colour.
178  **********************************************************************/
179 
180 #ifndef GRAPHICS_DISABLED
181 void PDBLK::plot( //draw outline
182  ScrollView* window, //window to draw in
183  inT32 serial, //serial number
184  ScrollView::Color colour //colour to draw in
185  ) {
186  ICOORD startpt; //start of outline
187  ICOORD endpt; //end of outline
188  ICOORD prevpt; //previous point
189  ICOORDELT_IT it = &leftside; //iterator
190 
191  //set the colour
192  window->Pen(colour);
193  window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);
194 
195  if (hand_poly != NULL) {
196  hand_poly->plot(window, serial);
197  } else if (!leftside.empty ()) {
198  startpt = *(it.data ()); //bottom left corner
199  // tprintf("Block %d bottom left is (%d,%d)\n",
200  // serial,startpt.x(),startpt.y());
201  char temp_buff[34];
202  #ifdef __UNIX__
203  sprintf(temp_buff, INT32FORMAT, serial);
204  #else
205  ultoa (serial, temp_buff, 10);
206  #endif
207  window->Text(startpt.x (), startpt.y (), temp_buff);
208 
209  window->SetCursor(startpt.x (), startpt.y ());
210  do {
211  prevpt = *(it.data ()); //previous point
212  it.forward (); //move to next point
213  //draw round corner
214  window->DrawTo(prevpt.x (), it.data ()->y ());
215  window->DrawTo(it.data ()->x (), it.data ()->y ());
216  }
217  while (!it.at_last ()); //until end of list
218  endpt = *(it.data ()); //end point
219 
220  //other side of boundary
221  window->SetCursor(startpt.x (), startpt.y ());
222  it.set_to_list (&rightside);
223  prevpt = startpt;
224  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
225  //draw round corner
226  window->DrawTo(prevpt.x (), it.data ()->y ());
227  window->DrawTo(it.data ()->x (), it.data ()->y ());
228  prevpt = *(it.data ()); //previous point
229  }
230  //close boundary
231  window->DrawTo(endpt.x(), endpt.y());
232  }
233 }
234 #endif
235 
236 
237 /**********************************************************************
238  * PDBLK::show
239  *
240  * Show the image corresponding to a block as its set of rectangles.
241  **********************************************************************/
242 
243 #ifndef GRAPHICS_DISABLED
244 void PDBLK::show( //show image block
245  IMAGE *image, //image to show
246  ScrollView* window //window to show in
247  ) {
248  BLOCK_RECT_IT it = this; //rectangle iterator
249  ICOORD bleft, tright; //corners of rectangle
250 
251  for (it.start_block (); !it.cycled_rects (); it.forward ()) {
252  //get rectangle
253  it.bounding_box (bleft, tright);
254  // tprintf("Drawing a block with a bottom left of (%d,%d)\n",
255  // bleft.x(),bleft.y());
256  //show it
257  sv_show_sub_image (image, bleft.x (), bleft.y (), tright.x () - bleft.x (), tright.y () - bleft.y (), window, bleft.x (), bleft.y ());
258  }
259 }
260 #endif
261 
262 
263 /**********************************************************************
264  * PDBLK::operator=
265  *
266  * Assignment - duplicate the block structure, but with an EMPTY row list.
267  **********************************************************************/
268 
269 PDBLK & PDBLK::operator= ( //assignment
270 const PDBLK & source //from this
271 ) {
272  // this->ELIST_LINK::operator=(source);
273  if (!leftside.empty ())
274  leftside.clear ();
275  if (!rightside.empty ())
276  rightside.clear ();
277  leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy);
278  rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy);
279  box = source.box;
280  return *this;
281 }
282 
283 
284 /**********************************************************************
285  * BLOCK_RECT_IT::BLOCK_RECT_IT
286  *
287  * Construct a block rectangle iterator.
288  **********************************************************************/
289 
291 //iterate rectangles
292 PDBLK * blkptr //from block
293 ):left_it (&blkptr->leftside), right_it (&blkptr->rightside) {
294  block = blkptr; //remember block
295  //non empty list
296  if (!blkptr->leftside.empty ()) {
297  start_block(); //ready for iteration
298  }
299 }
300 
301 
302 /**********************************************************************
303  * BLOCK_RECT_IT::set_to_block
304  *
305  * Start a new block.
306  **********************************************************************/
307 
308 void BLOCK_RECT_IT::set_to_block( //start (new) block
309  PDBLK *blkptr) { //block to start
310  block = blkptr; //remember block
311  //set iterators
312  left_it.set_to_list (&blkptr->leftside);
313  right_it.set_to_list (&blkptr->rightside);
314  if (!blkptr->leftside.empty ())
315  start_block(); //ready for iteration
316 }
317 
318 
319 /**********************************************************************
320  * BLOCK_RECT_IT::start_block
321  *
322  * Restart a block.
323  **********************************************************************/
324 
325 void BLOCK_RECT_IT::start_block() { //start (new) block
326  left_it.move_to_first ();
327  right_it.move_to_first ();
328  left_it.mark_cycle_pt ();
329  right_it.mark_cycle_pt ();
330  ymin = left_it.data ()->y (); //bottom of first box
331  ymax = left_it.data_relative (1)->y ();
332  if (right_it.data_relative (1)->y () < ymax)
333  //smallest step
334  ymax = right_it.data_relative (1)->y ();
335 }
336 
337 
338 /**********************************************************************
339  * BLOCK_RECT_IT::forward
340  *
341  * Move to the next rectangle in the block.
342  **********************************************************************/
343 
344 void BLOCK_RECT_IT::forward() { //next rectangle
345  if (!left_it.empty ()) { //non-empty list
346  if (left_it.data_relative (1)->y () == ymax)
347  left_it.forward (); //move to meet top
348  if (right_it.data_relative (1)->y () == ymax)
349  right_it.forward ();
350  //last is special
351  if (left_it.at_last () || right_it.at_last ()) {
352  left_it.move_to_first (); //restart
353  right_it.move_to_first ();
354  //now at bottom
355  ymin = left_it.data ()->y ();
356  }
357  else {
358  ymin = ymax; //new bottom
359  }
360  //next point
361  ymax = left_it.data_relative (1)->y ();
362  if (right_it.data_relative (1)->y () < ymax)
363  //least step forward
364  ymax = right_it.data_relative (1)->y ();
365  }
366 }
367 
368 
369 /**********************************************************************
370  * BLOCK_LINE_IT::get_line
371  *
372  * Get the the start and width of a line in the block.
373  **********************************************************************/
374 
376  inT16 y, //line to get
377  inT16 &xext //output extent
378  ) {
379  ICOORD bleft; //bounding box
380  ICOORD tright; //of block & rect
381 
382  //get block box
383  block->bounding_box (bleft, tright);
384  if (y < bleft.y () || y >= tright.y ()) {
385  // block->print(stderr,FALSE);
386  BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
387  }
388 
389  //get rectangle box
390  rect_it.bounding_box (bleft, tright);
391  //inside rectangle
392  if (y >= bleft.y () && y < tright.y ()) {
393  //width of line
394  xext = tright.x () - bleft.x ();
395  return bleft.x (); //start of line
396  }
397  for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
398  //get rectangle box
399  rect_it.bounding_box (bleft, tright);
400  //inside rectangle
401  if (y >= bleft.y () && y < tright.y ()) {
402  //width of line
403  xext = tright.x () - bleft.x ();
404  return bleft.x (); //start of line
405  }
406  }
407  LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
408  return 0; //dummy to stop warning
409 }