tesseract  4.00.00dev
polyblk.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: polyblk.c (Formerly poly_block.c)
3  * Description: Polygonal blocks
4  * Author: Sheelagh Lloyd?
5  * Created:
6  *
7  * (C) Copyright 1993, 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 <ctype.h>
21 #include <math.h>
22 #include <stdio.h>
23 #include <memory> // std::unique_ptr
24 #include "elst.h"
25 #include "polyblk.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 #define PBLOCK_LABEL_SIZE 150
33 #define INTERSECTING MAX_INT16
34 
35 int lessthan(const void *first, const void *second);
36 
37 POLY_BLOCK::POLY_BLOCK(ICOORDELT_LIST *points, PolyBlockType t) {
38  ICOORDELT_IT v = &vertices;
39 
40  vertices.clear();
41  v.move_to_first();
42  v.add_list_before(points);
43  compute_bb();
44  type = t;
45 }
46 
47 // Initialize from box coordinates.
49  vertices.clear();
50  ICOORDELT_IT v = &vertices;
51  v.move_to_first();
52  v.add_to_end(new ICOORDELT(box.left(), box.top()));
53  v.add_to_end(new ICOORDELT(box.left(), box.bottom()));
54  v.add_to_end(new ICOORDELT(box.right(), box.bottom()));
55  v.add_to_end(new ICOORDELT(box.right(), box.top()));
56  compute_bb();
57  type = t;
58 }
59 
66 void POLY_BLOCK::compute_bb() { //constructor
67  ICOORD ibl, itr; //integer bb
68  ICOORD botleft; //bounding box
69  ICOORD topright;
70  ICOORD pos; //current pos;
71  ICOORDELT_IT pts = &vertices; //iterator
72 
73  botleft = *pts.data ();
74  topright = botleft;
75  do {
76  pos = *pts.data ();
77  if (pos.x () < botleft.x ())
78  //get bounding box
79  botleft = ICOORD (pos.x (), botleft.y ());
80  if (pos.y () < botleft.y ())
81  botleft = ICOORD (botleft.x (), pos.y ());
82  if (pos.x () > topright.x ())
83  topright = ICOORD (pos.x (), topright.y ());
84  if (pos.y () > topright.y ())
85  topright = ICOORD (topright.x (), pos.y ());
86  pts.forward ();
87  }
88  while (!pts.at_first ());
89  ibl = ICOORD (botleft.x (), botleft.y ());
90  itr = ICOORD (topright.x (), topright.y ());
91  box = TBOX (ibl, itr);
92 }
93 
94 
103  inT16 count; //winding count
104  ICOORD pt; //current point
105  ICOORD vec; //point to current point
106  ICOORD vvec; //current point to next point
107  inT32 cross; //cross product
108  ICOORDELT_IT it = &vertices; //iterator
109 
110  count = 0;
111  do {
112  pt = *it.data ();
113  vec = pt - point;
114  vvec = *it.data_relative (1) - pt;
115  //crossing the line
116  if (vec.y () <= 0 && vec.y () + vvec.y () > 0) {
117  cross = vec * vvec; //cross product
118  if (cross > 0)
119  count++; //crossing right half
120  else if (cross == 0)
121  return INTERSECTING; //going through point
122  }
123  else if (vec.y () > 0 && vec.y () + vvec.y () <= 0) {
124  cross = vec * vvec;
125  if (cross < 0)
126  count--; //crossing back
127  else if (cross == 0)
128  return INTERSECTING; //illegal
129  }
130  else if (vec.y () == 0 && vec.x () == 0)
131  return INTERSECTING;
132  it.forward ();
133  }
134  while (!it.at_first ());
135  return count; //winding number
136 }
137 
138 
141  inT16 count; // winding count
142  ICOORDELT_IT it = &vertices; // iterator
143  ICOORD vertex;
144 
145  if (!box.overlap (*(other->bounding_box ())))
146  return false; // can't be contained
147 
148  /* check that no vertex of this is inside other */
149 
150  do {
151  vertex = *it.data ();
152  // get winding number
153  count = other->winding_number (vertex);
154  if (count != INTERSECTING)
155  if (count != 0)
156  return false;
157  it.forward ();
158  }
159  while (!it.at_first ());
160 
161  /* check that all vertices of other are inside this */
162 
163  //switch lists
164  it.set_to_list (other->points ());
165  do {
166  vertex = *it.data ();
167  //try other way round
168  count = winding_number (vertex);
169  if (count != INTERSECTING)
170  if (count == 0)
171  return false;
172  it.forward ();
173  }
174  while (!it.at_first ());
175  return true;
176 }
177 
178 
186 void POLY_BLOCK::rotate(FCOORD rotation) {
187  FCOORD pos; //current pos;
188  ICOORDELT *pt; //current point
189  ICOORDELT_IT pts = &vertices; //iterator
190 
191  do {
192  pt = pts.data ();
193  pos.set_x (pt->x ());
194  pos.set_y (pt->y ());
195  pos.rotate (rotation);
196  pt->set_x ((inT16) (floor (pos.x () + 0.5)));
197  pt->set_y ((inT16) (floor (pos.y () + 0.5)));
198  pts.forward ();
199  }
200  while (!pts.at_first ());
201  compute_bb();
202 }
203 
211  ICOORDELT *pt; // current point
212  ICOORDELT_IT pts = &vertices; // Iterator.
213 
214  do {
215  pt = pts.data();
216  pt->set_x(-pt->x());
217  pts.forward();
218  }
219  while (!pts.at_first());
220  compute_bb();
221 }
222 
223 
232  ICOORDELT *pt; //current point
233  ICOORDELT_IT pts = &vertices; //iterator
234 
235  do {
236  pt = pts.data ();
237  *pt += shift;
238  pts.forward ();
239  }
240  while (!pts.at_first ());
241  compute_bb();
242 }
243 
244 
245 #ifndef GRAPHICS_DISABLED
246 void POLY_BLOCK::plot(ScrollView* window, inT32 num) {
247  ICOORDELT_IT v = &vertices;
248 
249  window->Pen(ColorForPolyBlockType(type));
250 
251  v.move_to_first ();
252 
253  if (num > 0) {
254  window->TextAttributes("Times", 80, false, false, false);
255  char temp_buff[34];
256  #if defined(__UNIX__) || defined(MINGW)
257  sprintf(temp_buff, "%" PRId32, num);
258  #else
259  ltoa (num, temp_buff, 10);
260  #endif
261  window->Text(v.data ()->x (), v.data ()->y (), temp_buff);
262  }
263 
264  window->SetCursor(v.data ()->x (), v.data ()->y ());
265  for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) {
266  window->DrawTo(v.data ()->x (), v.data ()->y ());
267  }
268  v.move_to_first ();
269  window->DrawTo(v.data ()->x (), v.data ()->y ());
270 }
271 
272 
274  inT16 y;
275  inT16 width;
276  PB_LINE_IT *lines;
277  ICOORDELT_IT s_it;
278 
279  lines = new PB_LINE_IT (this);
280  window->Pen(colour);
281 
282  for (y = this->bounding_box ()->bottom ();
283  y <= this->bounding_box ()->top (); y++) {
284  const std::unique_ptr</*non-const*/ ICOORDELT_LIST> segments(lines->get_line (y));
285  if (!segments->empty ()) {
286  s_it.set_to_list (segments.get());
287  for (s_it.mark_cycle_pt (); !s_it.cycled_list (); s_it.forward ()) {
288  // Note different use of ICOORDELT, x coord is x coord of pixel
289  // at the start of line segment, y coord is length of line segment
290  // Last pixel is start pixel + length.
291  width = s_it.data ()->y ();
292  window->SetCursor(s_it.data ()->x (), y);
293  window->DrawTo(s_it.data ()->x () + (float) width, y);
294  }
295  }
296  }
297 
298  delete lines;
299 }
300 #endif
301 
302 
305  inT16 count; // winding count
306  ICOORDELT_IT it = &vertices; // iterator
307  ICOORD vertex;
308 
309  if (!box.overlap(*(other->bounding_box())))
310  return false; // can't be any overlap.
311 
312  /* see if a vertex of this is inside other */
313 
314  do {
315  vertex = *it.data ();
316  // get winding number
317  count = other->winding_number (vertex);
318  if (count != INTERSECTING)
319  if (count != 0)
320  return true;
321  it.forward ();
322  }
323  while (!it.at_first ());
324 
325  /* see if a vertex of other is inside this */
326 
327  // switch lists
328  it.set_to_list (other->points ());
329  do {
330  vertex = *it.data();
331  // try other way round
332  count = winding_number (vertex);
333  if (count != INTERSECTING)
334  if (count != 0)
335  return true;
336  it.forward ();
337  }
338  while (!it.at_first ());
339  return false;
340 }
341 
342 
343 ICOORDELT_LIST *PB_LINE_IT::get_line(inT16 y) {
344  ICOORDELT_IT v, r;
345  ICOORDELT_LIST *result;
346  ICOORDELT *x, *current, *previous;
347  float fy, fx;
348 
349  fy = (float) (y + 0.5);
350  result = new ICOORDELT_LIST ();
351  r.set_to_list (result);
352  v.set_to_list (block->points ());
353 
354  for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) {
355  if (((v.data_relative (-1)->y () > y) && (v.data ()->y () <= y))
356  || ((v.data_relative (-1)->y () <= y) && (v.data ()->y () > y))) {
357  previous = v.data_relative (-1);
358  current = v.data ();
359  fx = (float) (0.5 + previous->x () +
360  (current->x () - previous->x ()) * (fy -
361  previous->y ()) /
362  (current->y () - previous->y ()));
363  x = new ICOORDELT ((inT16) fx, 0);
364  r.add_to_end (x);
365  }
366  }
367 
368  if (!r.empty ()) {
369  r.sort (lessthan);
370  for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ())
371  x = r.data ();
372  for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) {
373  r.data ()->set_y (r.data_relative (1)->x () - r.data ()->x ());
374  r.forward ();
375  delete (r.extract ());
376  }
377  }
378 
379  return result;
380 }
381 
382 
383 int lessthan(const void *first, const void *second) {
384  ICOORDELT *p1 = (*(ICOORDELT **) first);
385  ICOORDELT *p2 = (*(ICOORDELT **) second);
386 
387  if (p1->x () < p2->x ())
388  return (-1);
389  else if (p1->x () > p2->x ())
390  return (1);
391  else
392  return (0);
393 }
394 
395 #ifndef GRAPHICS_DISABLED
398  // Keep kPBColors in sync with PolyBlockType.
399  const ScrollView::Color kPBColors[PT_COUNT] = {
400  ScrollView::WHITE, // Type is not yet known. Keep as the 1st element.
401  ScrollView::BLUE, // Text that lives inside a column.
402  ScrollView::CYAN, // Text that spans more than one column.
403  ScrollView::MEDIUM_BLUE, // Text that is in a cross-column pull-out region.
404  ScrollView::AQUAMARINE, // Partition belonging to an equation region.
405  ScrollView::SKY_BLUE, // Partition belonging to an inline equation region.
406  ScrollView::MAGENTA, // Partition belonging to a table region.
407  ScrollView::GREEN, // Text-line runs vertically.
408  ScrollView::LIGHT_BLUE, // Text that belongs to an image.
409  ScrollView::RED, // Image that lives inside a column.
410  ScrollView::YELLOW, // Image that spans more than one column.
411  ScrollView::ORANGE, // Image in a cross-column pull-out region.
412  ScrollView::BROWN, // Horizontal Line.
413  ScrollView::DARK_GREEN, // Vertical Line.
414  ScrollView::GREY // Lies outside of any column.
415  };
416  if (type >= 0 && type < PT_COUNT) {
417  return kPBColors[type];
418  }
419  return ScrollView::WHITE;
420 }
421 #endif // GRAPHICS_DISABLED
void move(ICOORD shift)
Definition: polyblk.cpp:231
inT16 winding_number(const ICOORD &test_pt)
Definition: polyblk.cpp:102
bool overlap(const TBOX &box) const
Definition: rect.h:345
bool contains(POLY_BLOCK *other)
Definition: polyblk.cpp:140
Definition: points.h:189
int32_t inT32
Definition: host.h:38
ICOORDELT_LIST * points()
Definition: polyblk.h:42
void rotate(const FCOORD vec)
Definition: ipoints.h:471
void rotate(FCOORD rotation)
Definition: polyblk.cpp:186
void set_x(inT16 xin)
rewrite function
Definition: points.h:61
void plot(ScrollView *window, inT32 num)
Definition: polyblk.cpp:246
void compute_bb()
Definition: polyblk.cpp:66
PolyBlockType
Definition: publictypes.h:41
inT16 x() const
access function
Definition: points.h:52
void set_x(float xin)
rewrite function
Definition: points.h:216
int lessthan(const void *first, const void *second)
Definition: polyblk.cpp:383
#define INTERSECTING
Definition: polyblk.cpp:33
void set_y(float yin)
rewrite function
Definition: points.h:220
int16_t inT16
Definition: host.h:36
void SetCursor(int x, int y)
Definition: scrollview.cpp:525
inT16 left() const
Definition: rect.h:68
void reflect_in_y_axis()
Definition: polyblk.cpp:210
ICOORDELT_LIST * get_line(inT16 y)
Definition: polyblk.cpp:343
Definition: capi.h:95
inT16 y() const
access_function
Definition: points.h:56
void fill(ScrollView *window, ScrollView::Color colour)
Definition: polyblk.cpp:273
TBOX * bounding_box()
Definition: polyblk.h:38
POLY_BLOCK()
Definition: polyblk.h:30
inT16 top() const
Definition: rect.h:54
Definition: rect.h:30
static ScrollView::Color ColorForPolyBlockType(PolyBlockType type)
Returns a color to draw the given type.
Definition: polyblk.cpp:397
float y() const
Definition: points.h:212
inT16 right() const
Definition: rect.h:75
void Text(int x, int y, const char *mystring)
Definition: scrollview.cpp:658
inT16 bottom() const
Definition: rect.h:61
bool overlap(POLY_BLOCK *other)
Definition: polyblk.cpp:304
double v[max]
float x() const
Definition: points.h:209
int count(LIST var_list)
Definition: oldlist.cpp:103
void set_y(inT16 yin)
rewrite function
Definition: points.h:65
void Pen(Color color)
Definition: scrollview.cpp:726
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