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