tesseract v5.3.3.20231005
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
35namespace tesseract {
36
37class TESS_API TBOX { // bounding box
38public:
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
320private:
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
330inline 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
344inline 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
354inline 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
363inline 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
374inline 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
396inline 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
409inline 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
419inline 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
435inline 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
445inline 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
463inline 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
486inline 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
const double y
ICOORD & operator+=(ICOORD &op1, const ICOORD &op2)
Definition: points.h:372
TBOX & operator&=(TBOX &op1, const TBOX &op2)
Definition: rect.cpp:242
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
bool DeSerialize(bool swap, FILE *fp, std::vector< T > &data)
Definition: helpers.h:205
bool Serialize(FILE *fp, const std::vector< T > &data)
Definition: helpers.h:236
int16_t TDimension
Definition: tesstypes.h:32
bool contains(const std::vector< T > &data, const T &value)
Definition: helpers.h:39
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
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
const ICOORD & botleft() const
Definition: rect.h:102
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
const ICOORD & topright() const
Definition: rect.h:114
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
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:576
#define TESS_API
Definition: export.h:32