tesseract 4.1.1
Loading...
Searching...
No Matches
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 *
6 * (C) Copyright 1991, Hewlett-Packard Ltd.
7 ** Licensed under the Apache License, Version 2.0 (the "License");
8 ** you may not use this file except in compliance with the License.
9 ** You may obtain a copy of the License at
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 *
17 **********************************************************************/
18
19#include "allheaders.h"
20#include "pdblock.h"
21#include <cstdlib>
22#include <memory> // std::unique_ptr
23#include <cinttypes> // for PRId32
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
32constexpr ERRCODE BADBLOCKLINE("Y coordinate in block out of bounds");
33constexpr ERRCODE LOSTBLOCKLINE("Can't find rectangle for line");
34
36/**********************************************************************
37 * PDBLK::PDBLK
38 *
39 * Constructor for a simple rectangular block.
40 **********************************************************************/
41PDBLK::PDBLK ( //rectangular block
42int16_t xmin, //bottom left
43int16_t ymin, int16_t xmax, //top right
44int16_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
67void 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
89bool 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
113void 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.
131Pix* 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 auto *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
180void 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
242const 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
264PDBLK * 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
280void 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
297void 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
316void 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
347int16_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}
constexpr ERRCODE BADBLOCKLINE("Y coordinate in block out of bounds")
#define BLOCK_LABEL_HEIGHT
Definition: pdblock.cpp:30
constexpr ERRCODE LOSTBLOCKLINE("Can't find rectangle for line")
#define CLISTIZE(CLASSNAME)
Definition: clst.h:891
@ ABORT
Definition: errcode.h:29
page block
Definition: pdblock.h:31
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
POLY_BLOCK * hand_poly
weird as well
Definition: pdblock.h:95
Pix * render_mask(const FCOORD &rerotation, TBOX *mask_box)
Definition: pdblock.cpp:131
bool contains(ICOORD pt)
is pt inside block
Definition: pdblock.cpp:89
void move(const ICOORD vec)
reposition block
Definition: pdblock.cpp:113
void plot(ScrollView *window, int32_t serial, ScrollView::Color colour)
Definition: pdblock.cpp:180
ICOORDELT_LIST rightside
right side vertices
Definition: pdblock.h:97
void set_sides(ICOORDELT_LIST *left, ICOORDELT_LIST *right)
Definition: pdblock.cpp:67
PDBLK & operator=(const PDBLK &source)
Definition: pdblock.cpp:241
TBOX box
bounding box
Definition: pdblock.h:98
ICOORDELT_LIST leftside
left side vertices
Definition: pdblock.h:96
BLOCK_RECT_IT(PDBLK *blkptr)
Definition: pdblock.cpp:262
void bounding_box(ICOORD &bleft, ICOORD &tright)
Definition: pdblock.h:127
void set_to_block(PDBLK *blkptr)
start (new) block
Definition: pdblock.cpp:280
void start_block()
start iteration
Definition: pdblock.cpp:297
bool cycled_rects()
test end
Definition: pdblock.h:120
void forward()
next rectangle
Definition: pdblock.cpp:316
int16_t get_line(int16_t y, int16_t &xext)
Definition: pdblock.cpp:347
integer coordinate
Definition: points.h:32
int16_t y() const
access_function
Definition: points.h:56
int16_t x() const
access function
Definition: points.h:52
static ICOORDELT * deep_copy(const ICOORDELT *src)
Definition: points.h:179
Definition: points.h:189
ICOORDELT_LIST * points()
Definition: polyblk.h:39
PolyBlockType isA() const
Definition: polyblk.h:45
void rotate(FCOORD rotation)
Definition: polyblk.cpp:184
void plot(ScrollView *window, int32_t num)
Definition: polyblk.cpp:244
Definition: rect.h:34
void rotate(const FCOORD &vec)
Definition: rect.h:197
int16_t top() const
Definition: rect.h:58
void move(const ICOORD vec)
Definition: rect.h:157
int16_t width() const
Definition: rect.h:115
int16_t height() const
Definition: rect.h:108
int16_t left() const
Definition: rect.h:72
int16_t bottom() const
Definition: rect.h:65
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:35
void DrawTo(int x, int y)
Definition: scrollview.cpp:525
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:635
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:652
void SetCursor(int x, int y)
Definition: scrollview.cpp:519
void Pen(Color color)
Definition: scrollview.cpp:719