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