All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 <stdlib.h>
21 #include "allheaders.h"
22 #include "blckerr.h"
23 #include "pdblock.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 
33 /**********************************************************************
34  * PDBLK::PDBLK
35  *
36  * Constructor for a simple rectangular block.
37  **********************************************************************/
38 PDBLK::PDBLK ( //rectangular block
39 inT16 xmin, //bottom left
40 inT16 ymin, inT16 xmax, //top right
41 inT16 ymax): box (ICOORD (xmin, ymin), ICOORD (xmax, ymax)) {
42  //boundaries
43  ICOORDELT_IT left_it = &leftside;
44  ICOORDELT_IT right_it = &rightside;
45 
46  hand_poly = NULL;
47  left_it.set_to_list (&leftside);
48  right_it.set_to_list (&rightside);
49  //make default box
50  left_it.add_to_end (new ICOORDELT (xmin, ymin));
51  left_it.add_to_end (new ICOORDELT (xmin, ymax));
52  right_it.add_to_end (new ICOORDELT (xmax, ymin));
53  right_it.add_to_end (new ICOORDELT (xmax, ymax));
54  index_ = 0;
55 }
56 
57 
58 /**********************************************************************
59  * PDBLK::set_sides
60  *
61  * Sets left and right vertex lists
62  **********************************************************************/
63 
64 void PDBLK::set_sides( //set vertex lists
65  ICOORDELT_LIST *left, //left vertices
66  ICOORDELT_LIST *right //right vertices
67  ) {
68  //boundaries
69  ICOORDELT_IT left_it = &leftside;
70  ICOORDELT_IT right_it = &rightside;
71 
72  leftside.clear ();
73  left_it.move_to_first ();
74  left_it.add_list_before (left);
75  rightside.clear ();
76  right_it.move_to_first ();
77  right_it.add_list_before (right);
78 }
79 
80 /**********************************************************************
81  * PDBLK::contains
82  *
83  * Return TRUE if the given point is within the block.
84  **********************************************************************/
85 
86 BOOL8 PDBLK::contains( //test containment
87  ICOORD pt //point to test
88  ) {
89  BLOCK_RECT_IT it = this; //rectangle iterator
90  ICOORD bleft, tright; //corners of rectangle
91 
92  for (it.start_block (); !it.cycled_rects (); it.forward ()) {
93  //get rectangle
94  it.bounding_box (bleft, tright);
95  //inside rect
96  if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
97  && pt.y () >= bleft.y () && pt.y () <= tright.y ())
98  return TRUE; //is inside
99  }
100  return FALSE; //not inside
101 }
102 
103 
104 /**********************************************************************
105  * PDBLK::move
106  *
107  * Reposition block
108  **********************************************************************/
109 
110 void PDBLK::move( // reposition block
111  const ICOORD vec // by vector
112  ) {
113  ICOORDELT_IT it(&leftside);
114 
115  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
116  *(it.data ()) += vec;
117 
118  it.set_to_list (&rightside);
119 
120  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
121  *(it.data ()) += vec;
122 
123  box.move (vec);
124 }
125 
126 // Returns a binary Pix mask with a 1 pixel for every pixel within the
127 // block. Rotates the coordinate system by rerotation prior to rendering.
128 Pix* PDBLK::render_mask(const FCOORD& rerotation, TBOX* mask_box) {
129  TBOX rotated_box(box);
130  rotated_box.rotate(rerotation);
131  Pix* pix = pixCreate(rotated_box.width(), rotated_box.height(), 1);
132  if (hand_poly != NULL) {
133  // We are going to rotate, so get a deep copy of the points and
134  // make a new POLY_BLOCK with it.
135  ICOORDELT_LIST polygon;
136  polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy);
137  POLY_BLOCK image_block(&polygon, hand_poly->isA());
138  image_block.rotate(rerotation);
139  // Block outline is a polygon, so use a PB_LINE_IT to get the
140  // rasterized interior. (Runs of interior pixels on a line.)
141  PB_LINE_IT *lines = new PB_LINE_IT(&image_block);
142  for (int y = box.bottom(); y < box.top(); ++y) {
143  ICOORDELT_LIST* segments = lines->get_line(y);
144  if (!segments->empty()) {
145  ICOORDELT_IT s_it(segments);
146  // Each element of segments is a start x and x size of the
147  // run of interior pixels.
148  for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
149  int start = s_it.data()->x();
150  int xext = s_it.data()->y();
151  // Set the run of pixels to 1.
152  pixRasterop(pix, start - rotated_box.left(),
153  rotated_box.height() - 1 - (y - rotated_box.bottom()),
154  xext, 1, PIX_SET, NULL, 0, 0);
155  }
156  }
157  delete segments;
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, INT32FORMAT, 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 }
TBOX box
Definition: pdblock.h:114
void Pen(Color color)
Definition: scrollview.cpp:726
static ICOORDELT * deep_copy(const ICOORDELT *src)
Definition: points.h:180
void forward()
next rectangle
Definition: pdblock.cpp:313
void bounding_box(ICOORD &bleft, ICOORD &tright)
Definition: pdblock.h:143
POLY_BLOCK * hand_poly
Definition: pdblock.h:111
BOOL8 cycled_rects()
test end
Definition: pdblock.h:136
void plot(ScrollView *window, inT32 serial, ScrollView::Color colour)
Definition: pdblock.cpp:177
void rotate(FCOORD rotation)
Definition: polyblk.cpp:185
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:658
void DrawTo(int x, int y)
Definition: scrollview.cpp:531
void set_to_block(PDBLK *blkptr)
start (new) block
Definition: pdblock.cpp:277
BLOCK_RECT_IT(PDBLK *blkptr)
Definition: pdblock.cpp:259
#define INT32FORMAT
Definition: host.h:115
void TextAttributes(const char *font, int pixel_size, bool bold, bool italic, bool underlined)
Definition: scrollview.cpp:641
unsigned char BOOL8
Definition: host.h:113
void move(const ICOORD vec)
reposition block
Definition: pdblock.cpp:110
Definition: errcode.h:30
ICOORDELT_LIST * get_line(inT16 y)
Definition: polyblk.cpp:341
void set_sides(ICOORDELT_LIST *left, ICOORDELT_LIST *right)
Definition: pdblock.cpp:64
ICOORDELT_LIST rightside
Definition: pdblock.h:113
#define CLISTIZE(CLASSNAME)
Definition: clst.h:958
ICOORDELT_LIST leftside
Definition: pdblock.h:112
inT16 y() const
access_function
Definition: points.h:56
inT16 left() const
Definition: rect.h:68
PDBLK & operator=(const PDBLK &source)
Definition: pdblock.cpp:238
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
const ERRCODE BADBLOCKLINE
Definition: blckerr.h:25
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:67
const ERRCODE LOSTBLOCKLINE
Definition: blckerr.h:26
ICOORDELT_LIST * points()
Definition: polyblk.h:42
void error(const char *caller, TessErrorLogCode action, const char *format,...) const
Definition: errcode.cpp:40
integer coordinate
Definition: points.h:30
inT16 bottom() const
Definition: rect.h:61
inT16 height() const
Definition: rect.h:104
void start_block()
start iteration
Definition: pdblock.cpp:294
inT16 width() const
Definition: rect.h:111
#define FALSE
Definition: capi.h:29
void plot(ScrollView *window, inT32 num)
Definition: polyblk.cpp:245
inT16 x() const
access function
Definition: points.h:52
Definition: rect.h:30
#define TRUE
Definition: capi.h:28
#define BLOCK_LABEL_HEIGHT
Definition: pdblock.cpp:30
void move(const ICOORD vec)
Definition: rect.h:153
inT16 get_line(inT16 y, inT16 &xext)
Definition: pdblock.cpp:344
#define NULL
Definition: host.h:144
Pix * render_mask(const FCOORD &rerotation, TBOX *mask_box)
Definition: pdblock.cpp:128
inT16 top() const
Definition: rect.h:54
PolyBlockType isA() const
Definition: polyblk.h:48
BOOL8 contains(ICOORD pt)
is pt inside block
Definition: pdblock.cpp:86
Definition: points.h:189
page block
Definition: pdblock.h:32
short inT16
Definition: host.h:100
int inT32
Definition: host.h:102
void rotate(const FCOORD &vec)
Definition: rect.h:189