tesseract  v4.0.0-17-g361f3264
Open Source OCR Engine
rect.h
1 /**********************************************************************
2  * File: rect.h (Formerly box.h)
3  * Description: Bounding box class definition.
4  * Author: Phil Cheatle
5  * Created: Wed Oct 16 15:18:45 BST 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 #ifndef RECT_H
21 #define RECT_H
22 
23 #include <algorithm> // for std::max, std::min
24 #include <cmath> // for std::ceil, std::floor
25 #include <cstdint> // for INT16_MAX
26 #include <cstdio> // for FILE
27 #include "platform.h" // for DLLSYM
28 #include "points.h" // for ICOORD, FCOORD
29 #include "scrollview.h" // for ScrollView, ScrollView::Color
30 #include "tprintf.h" // for tprintf
31 
32 class STRING;
33 
34 class DLLSYM TBOX { // bounding box
35  public:
36  TBOX (): // empty constructor making a null box
37  bot_left (INT16_MAX, INT16_MAX), top_right (-INT16_MAX, -INT16_MAX) {
38  }
39 
40  TBOX( // constructor
41  const ICOORD pt1, // one corner
42  const ICOORD pt2); // the other corner
43 
44  TBOX( // constructor
45  int16_t left, int16_t bottom, int16_t right, int16_t top);
46 
47  TBOX( // box around FCOORD
48  const FCOORD pt);
49 
50  bool null_box() const { // Is box null
51  return ((left () >= right ()) || (top () <= bottom ()));
52  }
53 
54  bool operator==(const TBOX& other) const {
55  return bot_left == other.bot_left && top_right == other.top_right;
56  }
57 
58  int16_t top() const { // coord of top
59  return top_right.y ();
60  }
61  void set_top(int y) {
62  top_right.set_y(y);
63  }
64 
65  int16_t bottom() const { // coord of bottom
66  return bot_left.y ();
67  }
68  void set_bottom(int y) {
69  bot_left.set_y(y);
70  }
71 
72  int16_t left() const { // coord of left
73  return bot_left.x ();
74  }
75  void set_left(int x) {
76  bot_left.set_x(x);
77  }
78 
79  int16_t right() const { // coord of right
80  return top_right.x ();
81  }
82  void set_right(int x) {
83  top_right.set_x(x);
84  }
85  int x_middle() const {
86  return (bot_left.x() + top_right.x()) / 2;
87  }
88  int y_middle() const {
89  return (bot_left.y() + top_right.y()) / 2;
90  }
91 
92  const ICOORD &botleft() const { // access function
93  return bot_left;
94  }
95 
96  ICOORD botright() const { // ~ access function
97  return ICOORD (top_right.x (), bot_left.y ());
98  }
99 
100  ICOORD topleft() const { // ~ access function
101  return ICOORD (bot_left.x (), top_right.y ());
102  }
103 
104  const ICOORD &topright() const { // access function
105  return top_right;
106  }
107 
108  int16_t height() const { // how high is it?
109  if (!null_box ())
110  return top_right.y () - bot_left.y ();
111  else
112  return 0;
113  }
114 
115  int16_t width() const { // how high is it?
116  if (!null_box ())
117  return top_right.x () - bot_left.x ();
118  else
119  return 0;
120  }
121 
122  int32_t area() const { // what is the area?
123  if (!null_box ())
124  return width () * height ();
125  else
126  return 0;
127  }
128 
129  // Pads the box on either side by the supplied x,y pad amounts.
130  // NO checks for exceeding any bounds like 0 or an image size.
131  void pad(int xpad, int ypad) {
132  ICOORD pad(xpad, ypad);
133  bot_left -= pad;
134  top_right += pad;
135  }
136 
137  void move_bottom_edge( // move one edge
138  const int16_t y) { // by +/- y
139  bot_left += ICOORD (0, y);
140  }
141 
142  void move_left_edge( // move one edge
143  const int16_t x) { // by +/- x
144  bot_left += ICOORD (x, 0);
145  }
146 
147  void move_right_edge( // move one edge
148  const int16_t x) { // by +/- x
149  top_right += ICOORD (x, 0);
150  }
151 
152  void move_top_edge( // move one edge
153  const int16_t y) { // by +/- y
154  top_right += ICOORD (0, y);
155  }
156 
157  void move( // move box
158  const ICOORD vec) { // by vector
159  bot_left += vec;
160  top_right += vec;
161  }
162 
163  void move( // move box
164  const FCOORD vec) { // by float vector
165  bot_left.set_x(static_cast<int16_t>(std::floor(bot_left.x() + vec.x())));
166  // round left
167  bot_left.set_y(static_cast<int16_t>(std::floor(bot_left.y() + vec.y())));
168  // round down
169  top_right.set_x(static_cast<int16_t>(std::ceil(top_right.x() + vec.x())));
170  // round right
171  top_right.set_y(static_cast<int16_t>(std::ceil(top_right.y() + vec.y())));
172  // round up
173  }
174 
175  void scale( // scale box
176  const float f) { // by multiplier
177  // round left
178  bot_left.set_x(static_cast<int16_t>(std::floor(bot_left.x() * f)));
179  // round down
180  bot_left.set_y(static_cast<int16_t>(std::floor(bot_left.y() * f)));
181  // round right
182  top_right.set_x(static_cast<int16_t>(std::ceil(top_right.x() * f)));
183  // round up
184  top_right.set_y(static_cast<int16_t>(std::ceil(top_right.y() * f)));
185  }
186  void scale( // scale box
187  const FCOORD vec) { // by float vector
188  bot_left.set_x(static_cast<int16_t>(std::floor(bot_left.x() * vec.x())));
189  bot_left.set_y(static_cast<int16_t>(std::floor(bot_left.y() * vec.y())));
190  top_right.set_x(static_cast<int16_t>(std::ceil(top_right.x() * vec.x())));
191  top_right.set_y(static_cast<int16_t>(std::ceil(top_right.y() * vec.y())));
192  }
193 
194  // rotate doesn't enlarge the box - it just rotates the bottom-left
195  // and top-right corners. Use rotate_large if you want to guarantee
196  // that all content is contained within the rotated box.
197  void rotate(const FCOORD& vec) { // by vector
198  bot_left.rotate (vec);
199  top_right.rotate (vec);
200  *this = TBOX (bot_left, top_right);
201  }
202  // rotate_large constructs the containing bounding box of all 4
203  // corners after rotating them. It therefore guarantees that all
204  // original content is contained within, but also slightly enlarges the box.
205  void rotate_large(const FCOORD& vec);
206 
207  bool contains( // is pt inside box
208  const FCOORD pt) const;
209 
210  bool contains( // is box inside box
211  const TBOX &box) const;
212 
213  bool overlap( // do boxes overlap
214  const TBOX &box) const;
215 
216  bool major_overlap( // do boxes overlap more than half
217  const TBOX &box) const;
218 
219  // Do boxes overlap on x axis.
220  bool x_overlap(const TBOX &box) const;
221 
222  // Return the horizontal gap between the boxes. If the boxes
223  // overlap horizontally then the return value is negative, indicating
224  // the amount of the overlap.
225  int x_gap(const TBOX& box) const {
226  return std::max(bot_left.x(), box.bot_left.x()) -
227  std::min(top_right.x(), box.top_right.x());
228  }
229 
230  // Return the vertical gap between the boxes. If the boxes
231  // overlap vertically then the return value is negative, indicating
232  // the amount of the overlap.
233  int y_gap(const TBOX& box) const {
234  return std::max(bot_left.y(), box.bot_left.y()) -
235  std::min(top_right.y(), box.top_right.y());
236  }
237 
238  // Do boxes overlap on x axis by more than
239  // half of the width of the narrower box.
240  bool major_x_overlap(const TBOX &box) const;
241 
242  // Do boxes overlap on y axis.
243  bool y_overlap(const TBOX &box) const;
244 
245  // Do boxes overlap on y axis by more than
246  // half of the height of the shorter box.
247  bool major_y_overlap(const TBOX &box) const;
248 
249  // fraction of current box's area covered by other
250  double overlap_fraction(const TBOX &box) const;
251 
252  // fraction of the current box's projected area covered by the other's
253  double x_overlap_fraction(const TBOX& box) const;
254 
255  // fraction of the current box's projected area covered by the other's
256  double y_overlap_fraction(const TBOX& box) const;
257 
258  // Returns true if the boxes are almost equal on x axis.
259  bool x_almost_equal(const TBOX &box, int tolerance) const;
260 
261  // Returns true if the boxes are almost equal
262  bool almost_equal(const TBOX &box, int tolerance) const;
263 
264  TBOX intersection( // shared area box
265  const TBOX &box) const;
266 
267  TBOX bounding_union( // box enclosing both
268  const TBOX &box) const;
269 
270  // Sets the box boundaries to the given coordinates.
271  void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) {
272  bot_left.set_x(x_min);
273  bot_left.set_y(y_min);
274  top_right.set_x(x_max);
275  top_right.set_y(y_max);
276  }
277 
278  void print() const { // print
279  tprintf("Bounding box=(%d,%d)->(%d,%d)\n",
280  left(), bottom(), right(), top());
281  }
282  // Appends the bounding box as (%d,%d)->(%d,%d) to a STRING.
283  void print_to_str(STRING *str) const;
284 
285 #ifndef GRAPHICS_DISABLED
286  void plot( // use current settings
287  ScrollView* fd) const { // where to paint
288  fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (),
289  top_right.y ());
290  }
291 
292  void plot( // paint box
293  ScrollView* fd, // where to paint
294  ScrollView::Color fill_colour, // colour for inside
295  ScrollView::Color border_colour) const; // colour for border
296 #endif
297  // Writes to the given file. Returns false in case of error.
298  bool Serialize(FILE* fp) const;
299  // Reads from the given file. Returns false in case of error.
300  // If swap is true, assumes a big/little-endian swap is needed.
301  bool DeSerialize(bool swap, FILE* fp);
302 
303  friend TBOX& operator+=(TBOX&, const TBOX&);
304  // in place union
305  friend TBOX& operator&=(TBOX&, const TBOX&);
306  // in place intersection
307 
308  private:
309  ICOORD bot_left; // bottom left corner
310  ICOORD top_right; // top right corner
311 };
312 
313 /**********************************************************************
314  * TBOX::TBOX() Constructor from 1 FCOORD
315  *
316  **********************************************************************/
317 
318 inline TBOX::TBOX( // constructor
319  const FCOORD pt // floating centre
320  ) {
321  bot_left = ICOORD(static_cast<int16_t>(std::floor(pt.x())),
322  static_cast<int16_t>(std::floor(pt.y())));
323  top_right = ICOORD(static_cast<int16_t>(std::ceil(pt.x())),
324  static_cast<int16_t>(std::ceil(pt.y())));
325 }
326 
327 
328 /**********************************************************************
329  * TBOX::contains() Is point within box
330  *
331  **********************************************************************/
332 
333 inline bool TBOX::contains(const FCOORD pt) const {
334  return ((pt.x () >= bot_left.x ()) &&
335  (pt.x () <= top_right.x ()) &&
336  (pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ()));
337 }
338 
339 
340 /**********************************************************************
341  * TBOX::contains() Is box within box
342  *
343  **********************************************************************/
344 
345 inline bool TBOX::contains(const TBOX &box) const {
346  return (contains (box.bot_left) && contains (box.top_right));
347 }
348 
349 
350 /**********************************************************************
351  * TBOX::overlap() Do two boxes overlap?
352  *
353  **********************************************************************/
354 
355 inline bool TBOX::overlap( // do boxes overlap
356  const TBOX &box) const {
357  return ((box.bot_left.x () <= top_right.x ()) &&
358  (box.top_right.x () >= bot_left.x ()) &&
359  (box.bot_left.y () <= top_right.y ()) &&
360  (box.top_right.y () >= bot_left.y ()));
361 }
362 
363 /**********************************************************************
364  * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest?
365  *
366  **********************************************************************/
367 
368 inline bool TBOX::major_overlap( // Do boxes overlap more that half.
369  const TBOX &box) const {
370  int overlap = std::min(box.top_right.x(), top_right.x());
371  overlap -= std::max(box.bot_left.x(), bot_left.x());
372  overlap += overlap;
373  if (overlap < std::min(box.width(), width()))
374  return false;
375  overlap = std::min(box.top_right.y(), top_right.y());
376  overlap -= std::max(box.bot_left.y(), bot_left.y());
377  overlap += overlap;
378  if (overlap < std::min(box.height(), height()))
379  return false;
380  return true;
381 }
382 
383 /**********************************************************************
384  * TBOX::overlap_fraction() Fraction of area covered by the other box
385  *
386  **********************************************************************/
387 
388 inline double TBOX::overlap_fraction(const TBOX &box) const {
389  double fraction = 0.0;
390  if (this->area()) {
391  fraction = this->intersection(box).area() * 1.0 / this->area();
392  }
393  return fraction;
394 }
395 
396 /**********************************************************************
397  * TBOX::x_overlap() Do two boxes overlap on x-axis
398  *
399  **********************************************************************/
400 
401 inline bool TBOX::x_overlap(const TBOX &box) const {
402  return ((box.bot_left.x() <= top_right.x()) &&
403  (box.top_right.x() >= bot_left.x()));
404 }
405 
406 /**********************************************************************
407  * TBOX::major_x_overlap() Do two boxes overlap by more than half the
408  * width of the narrower box on the x-axis
409  *
410  **********************************************************************/
411 
412 inline bool TBOX::major_x_overlap(const TBOX &box) const {
413  int16_t overlap = box.width();
414  if (this->left() > box.left()) {
415  overlap -= this->left() - box.left();
416  }
417  if (this->right() < box.right()) {
418  overlap -= box.right() - this->right();
419  }
420  return (overlap >= box.width() / 2 || overlap >= this->width() / 2);
421 }
422 
423 /**********************************************************************
424  * TBOX::y_overlap() Do two boxes overlap on y-axis
425  *
426  **********************************************************************/
427 
428 inline bool TBOX::y_overlap(const TBOX &box) const {
429  return ((box.bot_left.y() <= top_right.y()) &&
430  (box.top_right.y() >= bot_left.y()));
431 }
432 
433 /**********************************************************************
434  * TBOX::major_y_overlap() Do two boxes overlap by more than half the
435  * height of the shorter box on the y-axis
436  *
437  **********************************************************************/
438 
439 inline bool TBOX::major_y_overlap(const TBOX &box) const {
440  int16_t overlap = box.height();
441  if (this->bottom() > box.bottom()) {
442  overlap -= this->bottom() - box.bottom();
443  }
444  if (this->top() < box.top()) {
445  overlap -= box.top() - this->top();
446  }
447  return (overlap >= box.height() / 2 || overlap >= this->height() / 2);
448 }
449 
450 /**********************************************************************
451  * TBOX::x_overlap_fraction() Calculates the horizontal overlap of the
452  * given boxes as a fraction of this boxes
453  * width.
454  *
455  **********************************************************************/
456 
457 inline double TBOX::x_overlap_fraction(const TBOX& other) const {
458  int low = std::max(left(), other.left());
459  int high = std::min(right(), other.right());
460  int width = right() - left();
461  if (width == 0) {
462  int x = left();
463  if (other.left() <= x && x <= other.right())
464  return 1.0;
465  else
466  return 0.0;
467  } else {
468  return std::max(0.0, static_cast<double>(high - low) / width);
469  }
470 }
471 
472 /**********************************************************************
473  * TBOX::y_overlap_fraction() Calculates the vertical overlap of the
474  * given boxes as a fraction of this boxes
475  * height.
476  *
477  **********************************************************************/
478 
479 inline double TBOX::y_overlap_fraction(const TBOX& other) const {
480  int low = std::max(bottom(), other.bottom());
481  int high = std::min(top(), other.top());
482  int height = top() - bottom();
483  if (height == 0) {
484  int y = bottom();
485  if (other.bottom() <= y && y <= other.top())
486  return 1.0;
487  else
488  return 0.0;
489  } else {
490  return std::max(0.0, static_cast<double>(high - low) / height);
491  }
492 }
493 
494 #endif
double overlap_fraction(const TBOX &box) const
Definition: rect.h:388
TBOX()
Definition: rect.h:36
int32_t area() const
Definition: rect.h:122
void move_bottom_edge(const int16_t y)
Definition: rect.h:137
void set_right(int x)
Definition: rect.h:82
int16_t right() const
Definition: rect.h:79
int x_middle() const
Definition: rect.h:85
int16_t x() const
access function
Definition: points.h:53
float y() const
Definition: points.h:211
void plot(ScrollView *fd) const
Definition: rect.h:286
bool y_overlap(const TBOX &box) const
Definition: rect.h:428
Color
Definition: scrollview.h:105
bool major_y_overlap(const TBOX &box) const
Definition: rect.h:439
Definition: rect.h:34
void set_left(int x)
Definition: rect.h:75
void move(const FCOORD vec)
Definition: rect.h:163
ICOORD top_right
Definition: rect.h:310
ICOORD botright() const
Definition: rect.h:96
void move(const ICOORD vec)
Definition: rect.h:157
bool x_overlap(const TBOX &box) const
Definition: rect.h:401
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:602
void scale(const float f)
Definition: rect.h:175
bool overlap(const TBOX &box) const
Definition: rect.h:355
int y_gap(const TBOX &box) const
Definition: rect.h:233
int16_t bottom() const
Definition: rect.h:65
void print() const
Definition: rect.h:278
bool contains(const FCOORD pt) const
Definition: rect.h:333
float x() const
Definition: points.h:208
ICOORD topleft() const
Definition: rect.h:100
const ICOORD & topright() const
Definition: rect.h:104
void move_right_edge(const int16_t x)
Definition: rect.h:147
Definition: scrollview.h:102
bool operator==(const TBOX &other) const
Definition: rect.h:54
void rotate(const FCOORD &vec)
Definition: rect.h:197
ICOORD bot_left
Definition: rect.h:309
int16_t y() const
access_function
Definition: points.h:57
double y_overlap_fraction(const TBOX &box) const
Definition: rect.h:479
bool major_x_overlap(const TBOX &box) const
Definition: rect.h:412
bool null_box() const
Definition: rect.h:50
void scale(const FCOORD vec)
Definition: rect.h:186
int x_gap(const TBOX &box) const
Definition: rect.h:225
Definition: strngs.h:45
int y_middle() const
Definition: rect.h:88
void set_top(int y)
Definition: rect.h:61
integer coordinate
Definition: points.h:32
int16_t top() const
Definition: rect.h:58
double x_overlap_fraction(const TBOX &box) const
Definition: rect.h:457
void pad(int xpad, int ypad)
Definition: rect.h:131
const ICOORD & botleft() const
Definition: rect.h:92
int16_t left() const
Definition: rect.h:72
int16_t height() const
Definition: rect.h:108
int16_t width() const
Definition: rect.h:115
void set_to_given_coords(int x_min, int y_min, int x_max, int y_max)
Definition: rect.h:271
void move_left_edge(const int16_t x)
Definition: rect.h:142
void move_top_edge(const int16_t y)
Definition: rect.h:152
void set_bottom(int y)
Definition: rect.h:68
Definition: points.h:189
bool major_overlap(const TBOX &box) const
Definition: rect.h:368