Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
36 CLISTIZE (PDBLK)
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
290 BLOCK_RECT_IT::BLOCK_RECT_IT (
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
375 inT16 BLOCK_LINE_IT::get_line( //get a line
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 }