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