tesseract  4.00.00dev
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 <stdlib.h>
21 #include <memory> // std::unique_ptr
22 #include "allheaders.h"
23 #include "blckerr.h"
24 #include "pdblock.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(lines->get_line(y));
145  if (!segments->empty()) {
146  ICOORDELT_IT s_it(segments.get());
147  // Each element of segments is a start x and x size of the
148  // run of interior pixels.
149  for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
150  int start = s_it.data()->x();
151  int xext = s_it.data()->y();
152  // Set the run of pixels to 1.
153  pixRasterop(pix, start - rotated_box.left(),
154  rotated_box.height() - 1 - (y - rotated_box.bottom()),
155  xext, 1, PIX_SET, NULL, 0, 0);
156  }
157  }
158  }
159  delete lines;
160  } else {
161  // Just fill the whole block as there is only a bounding box.
162  pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(),
163  PIX_SET, NULL, 0, 0);
164  }
165  if (mask_box != NULL) *mask_box = rotated_box;
166  return pix;
167 }
168 
169 
170 /**********************************************************************
171  * PDBLK::plot
172  *
173  * Plot the outline of a block in the given colour.
174  **********************************************************************/
175 
176 #ifndef GRAPHICS_DISABLED
177 void PDBLK::plot( //draw outline
178  ScrollView* window, //window to draw in
179  inT32 serial, //serial number
180  ScrollView::Color colour //colour to draw in
181  ) {
182  ICOORD startpt; //start of outline
183  ICOORD endpt; //end of outline
184  ICOORD prevpt; //previous point
185  ICOORDELT_IT it = &leftside; //iterator
186 
187  //set the colour
188  window->Pen(colour);
189  window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);
190 
191  if (hand_poly != NULL) {
192  hand_poly->plot(window, serial);
193  } else if (!leftside.empty ()) {
194  startpt = *(it.data ()); //bottom left corner
195  // tprintf("Block %d bottom left is (%d,%d)\n",
196  // serial,startpt.x(),startpt.y());
197  char temp_buff[34];
198  #if defined(__UNIX__) || defined(MINGW)
199  sprintf(temp_buff, "%" PRId32, serial);
200  #else
201  ultoa (serial, temp_buff, 10);
202  #endif
203  window->Text(startpt.x (), startpt.y (), temp_buff);
204 
205  window->SetCursor(startpt.x (), startpt.y ());
206  do {
207  prevpt = *(it.data ()); //previous point
208  it.forward (); //move to next point
209  //draw round corner
210  window->DrawTo(prevpt.x (), it.data ()->y ());
211  window->DrawTo(it.data ()->x (), it.data ()->y ());
212  }
213  while (!it.at_last ()); //until end of list
214  endpt = *(it.data ()); //end point
215 
216  //other side of boundary
217  window->SetCursor(startpt.x (), startpt.y ());
218  it.set_to_list (&rightside);
219  prevpt = startpt;
220  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
221  //draw round corner
222  window->DrawTo(prevpt.x (), it.data ()->y ());
223  window->DrawTo(it.data ()->x (), it.data ()->y ());
224  prevpt = *(it.data ()); //previous point
225  }
226  //close boundary
227  window->DrawTo(endpt.x(), endpt.y());
228  }
229 }
230 #endif
231 
232 /**********************************************************************
233  * PDBLK::operator=
234  *
235  * Assignment - duplicate the block structure, but with an EMPTY row list.
236  **********************************************************************/
237 
238 PDBLK & PDBLK::operator= ( //assignment
239 const PDBLK & source //from this
240 ) {
241  // this->ELIST_LINK::operator=(source);
242  if (!leftside.empty ())
243  leftside.clear ();
244  if (!rightside.empty ())
245  rightside.clear ();
246  leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy);
247  rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy);
248  box = source.box;
249  return *this;
250 }
251 
252 
253 /**********************************************************************
254  * BLOCK_RECT_IT::BLOCK_RECT_IT
255  *
256  * Construct a block rectangle iterator.
257  **********************************************************************/
258 
260 //iterate rectangles
261 PDBLK * blkptr //from block
262 ):left_it (&blkptr->leftside), right_it (&blkptr->rightside) {
263  block = blkptr; //remember block
264  //non empty list
265  if (!blkptr->leftside.empty ()) {
266  start_block(); //ready for iteration
267  }
268 }
269 
270 
271 /**********************************************************************
272  * BLOCK_RECT_IT::set_to_block
273  *
274  * Start a new block.
275  **********************************************************************/
276 
277 void BLOCK_RECT_IT::set_to_block( //start (new) block
278  PDBLK *blkptr) { //block to start
279  block = blkptr; //remember block
280  //set iterators
281  left_it.set_to_list (&blkptr->leftside);
282  right_it.set_to_list (&blkptr->rightside);
283  if (!blkptr->leftside.empty ())
284  start_block(); //ready for iteration
285 }
286 
287 
288 /**********************************************************************
289  * BLOCK_RECT_IT::start_block
290  *
291  * Restart a block.
292  **********************************************************************/
293 
294 void BLOCK_RECT_IT::start_block() { //start (new) block
295  left_it.move_to_first ();
296  right_it.move_to_first ();
297  left_it.mark_cycle_pt ();
298  right_it.mark_cycle_pt ();
299  ymin = left_it.data ()->y (); //bottom of first box
300  ymax = left_it.data_relative (1)->y ();
301  if (right_it.data_relative (1)->y () < ymax)
302  //smallest step
303  ymax = right_it.data_relative (1)->y ();
304 }
305 
306 
307 /**********************************************************************
308  * BLOCK_RECT_IT::forward
309  *
310  * Move to the next rectangle in the block.
311  **********************************************************************/
312 
313 void BLOCK_RECT_IT::forward() { //next rectangle
314  if (!left_it.empty ()) { //non-empty list
315  if (left_it.data_relative (1)->y () == ymax)
316  left_it.forward (); //move to meet top
317  if (right_it.data_relative (1)->y () == ymax)
318  right_it.forward ();
319  //last is special
320  if (left_it.at_last () || right_it.at_last ()) {
321  left_it.move_to_first (); //restart
322  right_it.move_to_first ();
323  //now at bottom
324  ymin = left_it.data ()->y ();
325  }
326  else {
327  ymin = ymax; //new bottom
328  }
329  //next point
330  ymax = left_it.data_relative (1)->y ();
331  if (right_it.data_relative (1)->y () < ymax)
332  //least step forward
333  ymax = right_it.data_relative (1)->y ();
334  }
335 }
336 
337 
338 /**********************************************************************
339  * BLOCK_LINE_IT::get_line
340  *
341  * Get the the start and width of a line in the block.
342  **********************************************************************/
343 
345  inT16 y, //line to get
346  inT16 &xext //output extent
347  ) {
348  ICOORD bleft; //bounding box
349  ICOORD tright; //of block & rect
350 
351  //get block box
352  block->bounding_box (bleft, tright);
353  if (y < bleft.y () || y >= tright.y ()) {
354  // block->print(stderr,FALSE);
355  BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
356  }
357 
358  //get rectangle box
359  rect_it.bounding_box (bleft, tright);
360  //inside rectangle
361  if (y >= bleft.y () && y < tright.y ()) {
362  //width of line
363  xext = tright.x () - bleft.x ();
364  return bleft.x (); //start of line
365  }
366  for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
367  //get rectangle box
368  rect_it.bounding_box (bleft, tright);
369  //inside rectangle
370  if (y >= bleft.y () && y < tright.y ()) {
371  //width of line
372  xext = tright.x () - bleft.x ();
373  return bleft.x (); //start of line
374  }
375  }
376  LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
377  return 0; //dummy to stop warning
378 }
#define TRUE
Definition: capi.h:45
Definition: points.h:189
PDBLK & operator=(const PDBLK &source)
Definition: pdblock.cpp:238
int32_t inT32
Definition: host.h:38
ICOORDELT_LIST * points()
Definition: polyblk.h:42
void move(const ICOORD vec)
reposition block
Definition: pdblock.cpp:111
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
void rotate(FCOORD rotation)
Definition: polyblk.cpp:186
void plot(ScrollView *window, inT32 num)
Definition: polyblk.cpp:246
inT16 x() const
access function
Definition: points.h:52
void set_sides(ICOORDELT_LIST *left, ICOORDELT_LIST *right)
Definition: pdblock.cpp:65
const ERRCODE BADBLOCKLINE
Definition: blckerr.h:25
Pix * render_mask(const FCOORD &rerotation, TBOX *mask_box)
Definition: pdblock.cpp:129
int16_t inT16
Definition: host.h:36
void bounding_box(ICOORD &bleft, ICOORD &tright)
Definition: pdblock.h:127
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
inT16 left() const
Definition: rect.h:68
void set_to_block(PDBLK *blkptr)
start (new) block
Definition: pdblock.cpp:277
POLY_BLOCK * hand_poly
Definition: pdblock.h:95
ICOORDELT_LIST * get_line(inT16 y)
Definition: polyblk.cpp:343
BLOCK_RECT_IT(PDBLK *blkptr)
Definition: pdblock.cpp:259
unsigned char BOOL8
Definition: host.h:44
#define FALSE
Definition: capi.h:46
inT16 y() const
access_function
Definition: points.h:56
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
const ERRCODE LOSTBLOCKLINE
Definition: blckerr.h:26
inT16 top() const
Definition: rect.h:54
Definition: rect.h:30
BOOL8 cycled_rects()
test end
Definition: pdblock.h:120
inT16 height() const
Definition: rect.h:104
void plot(ScrollView *window, inT32 serial, ScrollView::Color colour)
Definition: pdblock.cpp:177
inT16 width() const
Definition: rect.h:111
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:658
PolyBlockType isA() const
Definition: polyblk.h:48
static ICOORDELT * deep_copy(const ICOORDELT *src)
Definition: points.h:180
inT16 bottom() const
Definition: rect.h:61
#define BLOCK_LABEL_HEIGHT
Definition: pdblock.cpp:31
void forward()
next rectangle
Definition: pdblock.cpp:313
void move(const ICOORD vec)
Definition: rect.h:153
Definition: errcode.h:30
ICOORDELT_LIST leftside
Definition: pdblock.h:96
inT16 get_line(inT16 y, inT16 &xext)
Definition: pdblock.cpp:344
void rotate(const FCOORD &vec)
Definition: rect.h:189
#define CLISTIZE(CLASSNAME)
Definition: clst.h:913
TBOX box
Definition: pdblock.h:98
ICOORDELT_LIST rightside
Definition: pdblock.h:97
void Pen(Color color)
Definition: scrollview.cpp:726
void start_block()
start iteration
Definition: pdblock.cpp:294
BOOL8 contains(ICOORD pt)
is pt inside block
Definition: pdblock.cpp:87
void DrawTo(int x, int y)
Definition: scrollview.cpp:531
integer coordinate
Definition: points.h:30
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:641
page block
Definition: pdblock.h:32