tesseract  4.00.00dev
pdblock.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: pdblock.cpp (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 "pdblock.h"
21 #include <stdlib.h>
22 #include <memory> // std::unique_ptr
23 #include "allheaders.h"
24 #include "blckerr.h"
25 
26 // Include automatically generated configuration file if running autoconf.
27 #ifdef HAVE_CONFIG_H
28 #include "config_auto.h"
29 #endif
30 
31 #define BLOCK_LABEL_HEIGHT 150 //char height of block id
32 
34 /**********************************************************************
35  * PDBLK::PDBLK
36  *
37  * Constructor for a simple rectangular block.
38  **********************************************************************/
39 PDBLK::PDBLK ( //rectangular block
40 inT16 xmin, //bottom left
41 inT16 ymin, inT16 xmax, //top right
42 inT16 ymax): box (ICOORD (xmin, ymin), ICOORD (xmax, ymax)) {
43  //boundaries
44  ICOORDELT_IT left_it = &leftside;
45  ICOORDELT_IT right_it = &rightside;
46 
47  hand_poly = NULL;
48  left_it.set_to_list (&leftside);
49  right_it.set_to_list (&rightside);
50  //make default box
51  left_it.add_to_end (new ICOORDELT (xmin, ymin));
52  left_it.add_to_end (new ICOORDELT (xmin, ymax));
53  right_it.add_to_end (new ICOORDELT (xmax, ymin));
54  right_it.add_to_end (new ICOORDELT (xmax, ymax));
55  index_ = 0;
56 }
57 
58 
59 /**********************************************************************
60  * PDBLK::set_sides
61  *
62  * Sets left and right vertex lists
63  **********************************************************************/
64 
65 void PDBLK::set_sides( //set vertex lists
66  ICOORDELT_LIST *left, //left vertices
67  ICOORDELT_LIST *right //right vertices
68  ) {
69  //boundaries
70  ICOORDELT_IT left_it = &leftside;
71  ICOORDELT_IT right_it = &rightside;
72 
73  leftside.clear ();
74  left_it.move_to_first ();
75  left_it.add_list_before (left);
76  rightside.clear ();
77  right_it.move_to_first ();
78  right_it.add_list_before (right);
79 }
80 
81 /**********************************************************************
82  * PDBLK::contains
83  *
84  * Return TRUE if the given point is within the block.
85  **********************************************************************/
86 
87 BOOL8 PDBLK::contains( //test containment
88  ICOORD pt //point to test
89  ) {
90  BLOCK_RECT_IT it = this; //rectangle iterator
91  ICOORD bleft, tright; //corners of rectangle
92 
93  for (it.start_block (); !it.cycled_rects (); it.forward ()) {
94  //get rectangle
95  it.bounding_box (bleft, tright);
96  //inside rect
97  if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
98  && pt.y () >= bleft.y () && pt.y () <= tright.y ())
99  return TRUE; //is inside
100  }
101  return FALSE; //not inside
102 }
103 
104 
105 /**********************************************************************
106  * PDBLK::move
107  *
108  * Reposition block
109  **********************************************************************/
110 
111 void PDBLK::move( // reposition block
112  const ICOORD vec // by vector
113  ) {
114  ICOORDELT_IT it(&leftside);
115 
116  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
117  *(it.data ()) += vec;
118 
119  it.set_to_list (&rightside);
120 
121  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
122  *(it.data ()) += vec;
123 
124  box.move (vec);
125 }
126 
127 // Returns a binary Pix mask with a 1 pixel for every pixel within the
128 // block. Rotates the coordinate system by rerotation prior to rendering.
129 Pix* PDBLK::render_mask(const FCOORD& rerotation, TBOX* mask_box) {
130  TBOX rotated_box(box);
131  rotated_box.rotate(rerotation);
132  Pix* pix = pixCreate(rotated_box.width(), rotated_box.height(), 1);
133  if (hand_poly != NULL) {
134  // We are going to rotate, so get a deep copy of the points and
135  // make a new POLY_BLOCK with it.
136  ICOORDELT_LIST polygon;
137  polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy);
138  POLY_BLOCK image_block(&polygon, hand_poly->isA());
139  image_block.rotate(rerotation);
140  // Block outline is a polygon, so use a PB_LINE_IT to get the
141  // rasterized interior. (Runs of interior pixels on a line.)
142  PB_LINE_IT *lines = new PB_LINE_IT(&image_block);
143  for (int y = box.bottom(); y < box.top(); ++y) {
144  const std::unique_ptr</*non-const*/ ICOORDELT_LIST> segments(
145  lines->get_line(y));
146  if (!segments->empty()) {
147  ICOORDELT_IT s_it(segments.get());
148  // Each element of segments is a start x and x size of the
149  // run of interior pixels.
150  for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
151  int start = s_it.data()->x();
152  int xext = s_it.data()->y();
153  // Set the run of pixels to 1.
154  pixRasterop(pix, start - rotated_box.left(),
155  rotated_box.height() - 1 - (y - rotated_box.bottom()),
156  xext, 1, PIX_SET, NULL, 0, 0);
157  }
158  }
159  }
160  delete lines;
161  } else {
162  // Just fill the whole block as there is only a bounding box.
163  pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(),
164  PIX_SET, NULL, 0, 0);
165  }
166  if (mask_box != NULL) *mask_box = rotated_box;
167  return pix;
168 }
169 
170 
171 /**********************************************************************
172  * PDBLK::plot
173  *
174  * Plot the outline of a block in the given colour.
175  **********************************************************************/
176 
177 #ifndef GRAPHICS_DISABLED
178 void PDBLK::plot( //draw outline
179  ScrollView* window, //window to draw in
180  inT32 serial, //serial number
181  ScrollView::Color colour //colour to draw in
182  ) {
183  ICOORD startpt; //start of outline
184  ICOORD endpt; //end of outline
185  ICOORD prevpt; //previous point
186  ICOORDELT_IT it = &leftside; //iterator
187 
188  //set the colour
189  window->Pen(colour);
190  window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);
191 
192  if (hand_poly != NULL) {
193  hand_poly->plot(window, serial);
194  } else if (!leftside.empty ()) {
195  startpt = *(it.data ()); //bottom left corner
196  // tprintf("Block %d bottom left is (%d,%d)\n",
197  // serial,startpt.x(),startpt.y());
198  char temp_buff[34];
199  #if defined(__UNIX__) || defined(MINGW)
200  snprintf(temp_buff, sizeof(temp_buff), "%" PRId32, serial);
201  #else
202  ultoa (serial, temp_buff, 10);
203  #endif
204  window->Text(startpt.x (), startpt.y (), temp_buff);
205 
206  window->SetCursor(startpt.x (), startpt.y ());
207  do {
208  prevpt = *(it.data ()); //previous point
209  it.forward (); //move to next point
210  //draw round corner
211  window->DrawTo(prevpt.x (), it.data ()->y ());
212  window->DrawTo(it.data ()->x (), it.data ()->y ());
213  }
214  while (!it.at_last ()); //until end of list
215  endpt = *(it.data ()); //end point
216 
217  //other side of boundary
218  window->SetCursor(startpt.x (), startpt.y ());
219  it.set_to_list (&rightside);
220  prevpt = startpt;
221  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
222  //draw round corner
223  window->DrawTo(prevpt.x (), it.data ()->y ());
224  window->DrawTo(it.data ()->x (), it.data ()->y ());
225  prevpt = *(it.data ()); //previous point
226  }
227  //close boundary
228  window->DrawTo(endpt.x(), endpt.y());
229  }
230 }
231 #endif
232 
233 /**********************************************************************
234  * PDBLK::operator=
235  *
236  * Assignment - duplicate the block structure, but with an EMPTY row list.
237  **********************************************************************/
238 
239 PDBLK & PDBLK::operator= ( //assignment
240 const PDBLK & source //from this
241 ) {
242  // this->ELIST_LINK::operator=(source);
243  if (!leftside.empty ())
244  leftside.clear ();
245  if (!rightside.empty ())
246  rightside.clear ();
247  leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy);
248  rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy);
249  box = source.box;
250  return *this;
251 }
252 
253 
254 /**********************************************************************
255  * BLOCK_RECT_IT::BLOCK_RECT_IT
256  *
257  * Construct a block rectangle iterator.
258  **********************************************************************/
259 
261 //iterate rectangles
262 PDBLK * blkptr //from block
263 ):left_it (&blkptr->leftside), right_it (&blkptr->rightside) {
264  block = blkptr; //remember block
265  //non empty list
266  if (!blkptr->leftside.empty ()) {
267  start_block(); //ready for iteration
268  }
269 }
270 
271 
272 /**********************************************************************
273  * BLOCK_RECT_IT::set_to_block
274  *
275  * Start a new block.
276  **********************************************************************/
277 
278 void BLOCK_RECT_IT::set_to_block( //start (new) block
279  PDBLK *blkptr) { //block to start
280  block = blkptr; //remember block
281  //set iterators
282  left_it.set_to_list (&blkptr->leftside);
283  right_it.set_to_list (&blkptr->rightside);
284  if (!blkptr->leftside.empty ())
285  start_block(); //ready for iteration
286 }
287 
288 
289 /**********************************************************************
290  * BLOCK_RECT_IT::start_block
291  *
292  * Restart a block.
293  **********************************************************************/
294 
295 void BLOCK_RECT_IT::start_block() { //start (new) block
296  left_it.move_to_first ();
297  right_it.move_to_first ();
298  left_it.mark_cycle_pt ();
299  right_it.mark_cycle_pt ();
300  ymin = left_it.data ()->y (); //bottom of first box
301  ymax = left_it.data_relative (1)->y ();
302  if (right_it.data_relative (1)->y () < ymax)
303  //smallest step
304  ymax = right_it.data_relative (1)->y ();
305 }
306 
307 
308 /**********************************************************************
309  * BLOCK_RECT_IT::forward
310  *
311  * Move to the next rectangle in the block.
312  **********************************************************************/
313 
314 void BLOCK_RECT_IT::forward() { //next rectangle
315  if (!left_it.empty ()) { //non-empty list
316  if (left_it.data_relative (1)->y () == ymax)
317  left_it.forward (); //move to meet top
318  if (right_it.data_relative (1)->y () == ymax)
319  right_it.forward ();
320  //last is special
321  if (left_it.at_last () || right_it.at_last ()) {
322  left_it.move_to_first (); //restart
323  right_it.move_to_first ();
324  //now at bottom
325  ymin = left_it.data ()->y ();
326  }
327  else {
328  ymin = ymax; //new bottom
329  }
330  //next point
331  ymax = left_it.data_relative (1)->y ();
332  if (right_it.data_relative (1)->y () < ymax)
333  //least step forward
334  ymax = right_it.data_relative (1)->y ();
335  }
336 }
337 
338 
339 /**********************************************************************
340  * BLOCK_LINE_IT::get_line
341  *
342  * Get the the start and width of a line in the block.
343  **********************************************************************/
344 
346  inT16 y, //line to get
347  inT16 &xext //output extent
348  ) {
349  ICOORD bleft; //bounding box
350  ICOORD tright; //of block & rect
351 
352  //get block box
353  block->bounding_box (bleft, tright);
354  if (y < bleft.y () || y >= tright.y ()) {
355  // block->print(stderr,FALSE);
356  BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
357  }
358 
359  //get rectangle box
360  rect_it.bounding_box (bleft, tright);
361  //inside rectangle
362  if (y >= bleft.y () && y < tright.y ()) {
363  //width of line
364  xext = tright.x () - bleft.x ();
365  return bleft.x (); //start of line
366  }
367  for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
368  //get rectangle box
369  rect_it.bounding_box (bleft, tright);
370  //inside rectangle
371  if (y >= bleft.y () && y < tright.y ()) {
372  //width of line
373  xext = tright.x () - bleft.x ();
374  return bleft.x (); //start of line
375  }
376  }
377  LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
378  return 0; //dummy to stop warning
379 }
Definition: points.h:189
Pix * render_mask(const FCOORD &rerotation, TBOX *mask_box)
Definition: pdblock.cpp:129
void plot(ScrollView *window, inT32 serial, ScrollView::Color colour)
Definition: pdblock.cpp:178
#define TRUE
Definition: capi.h:45
const ERRCODE BADBLOCKLINE
Definition: blckerr.h:25
BLOCK_RECT_IT(PDBLK *blkptr)
Definition: pdblock.cpp:260
void DrawTo(int x, int y)
Definition: scrollview.cpp:531
void bounding_box(ICOORD &bleft, ICOORD &tright)
Definition: pdblock.h:127
inT16 x() const
access function
Definition: points.h:52
int16_t inT16
Definition: host.h:36
inT16 get_line(inT16 y, inT16 &xext)
Definition: pdblock.cpp:345
void rotate(FCOORD rotation)
Definition: polyblk.cpp:186
BOOL8 cycled_rects()
test end
Definition: pdblock.h:120
POLY_BLOCK * hand_poly
Definition: pdblock.h:95
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
PolyBlockType isA() const
Definition: polyblk.h:48
const ERRCODE LOSTBLOCKLINE
Definition: blckerr.h:26
void Pen(Color color)
Definition: scrollview.cpp:726
inT16 top() const
Definition: rect.h:54
#define FALSE
Definition: capi.h:46
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:658
BOOL8 contains(ICOORD pt)
is pt inside block
Definition: pdblock.cpp:87
ICOORDELT_LIST * points()
Definition: polyblk.h:42
inT16 bottom() const
Definition: rect.h:61
Definition: errcode.h:30
int32_t inT32
Definition: host.h:38
inT16 height() const
Definition: rect.h:104
Definition: rect.h:30
void move(const ICOORD vec)
Definition: rect.h:153
inT16 left() const
Definition: rect.h:68
void forward()
next rectangle
Definition: pdblock.cpp:314
TBOX box
Definition: pdblock.h:98
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:641
static ICOORDELT * deep_copy(const ICOORDELT *src)
Definition: points.h:180
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
void move(const ICOORD vec)
reposition block
Definition: pdblock.cpp:111
void set_to_block(PDBLK *blkptr)
start (new) block
Definition: pdblock.cpp:278
unsigned char BOOL8
Definition: host.h:44
inT16 y() const
access_function
Definition: points.h:56
void rotate(const FCOORD &vec)
Definition: rect.h:189
ICOORDELT_LIST rightside
Definition: pdblock.h:97
integer coordinate
Definition: points.h:30
void start_block()
start iteration
Definition: pdblock.cpp:295
page block
Definition: pdblock.h:32
void set_sides(ICOORDELT_LIST *left, ICOORDELT_LIST *right)
Definition: pdblock.cpp:65
CLISTIZE(BLOCK_RES) ELISTIZE(ROW_RES) ELISTIZE(WERD_RES) static const double kStopperAmbiguityThresholdGain
ICOORDELT_LIST leftside
Definition: pdblock.h:96
#define BLOCK_LABEL_HEIGHT
Definition: pdblock.cpp:31
ICOORDELT_LIST * get_line(inT16 y)
Definition: polyblk.cpp:344
PDBLK & operator=(const PDBLK &source)
Definition: pdblock.cpp:239
void plot(ScrollView *window, inT32 num)
Definition: polyblk.cpp:246
inT16 width() const
Definition: rect.h:111