tesseract 4.1.1
Loading...
Searching...
No Matches
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 <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
32class STRING;
33
34class 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
318inline 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
333inline 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
345inline 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
355inline 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
368inline 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
388inline 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
401inline 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
412inline 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
428inline 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
439inline 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
457inline 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
479inline 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
ICOORD & operator+=(ICOORD &op1, const ICOORD &op2)
Definition: points.h:381
TBOX & operator&=(TBOX &op1, const TBOX &op2)
Definition: rect.cpp:230
#define DLLSYM
Definition: platform.h:21
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
integer coordinate
Definition: points.h:32
int16_t y() const
access_function
Definition: points.h:56
int16_t x() const
access function
Definition: points.h:52
Definition: points.h:189
float y() const
Definition: points.h:210
float x() const
Definition: points.h:207
Definition: rect.h:34
bool x_overlap(const TBOX &box) const
Definition: rect.h:401
void scale(const FCOORD vec)
Definition: rect.h:186
const ICOORD & botleft() const
Definition: rect.h:92
void set_right(int x)
Definition: rect.h:82
void plot(ScrollView *fd) const
Definition: rect.h:286
void move_right_edge(const int16_t x)
Definition: rect.h:147
bool operator==(const TBOX &other) const
Definition: rect.h:54
void move(const FCOORD vec)
Definition: rect.h:163
double overlap_fraction(const TBOX &box) const
Definition: rect.h:388
void rotate(const FCOORD &vec)
Definition: rect.h:197
double x_overlap_fraction(const TBOX &box) const
Definition: rect.h:457
double y_overlap_fraction(const TBOX &box) const
Definition: rect.h:479
void move_top_edge(const int16_t y)
Definition: rect.h:152
int16_t top() const
Definition: rect.h:58
void move(const ICOORD vec)
Definition: rect.h:157
ICOORD botright() const
Definition: rect.h:96
void print() const
Definition: rect.h:278
void scale(const float f)
Definition: rect.h:175
void set_bottom(int y)
Definition: rect.h:68
int16_t width() const
Definition: rect.h:115
int32_t area() const
Definition: rect.h:122
int16_t height() const
Definition: rect.h:108
bool major_overlap(const TBOX &box) const
Definition: rect.h:368
bool overlap(const TBOX &box) const
Definition: rect.h:355
ICOORD topleft() const
Definition: rect.h:100
void set_top(int y)
Definition: rect.h:61
int x_middle() const
Definition: rect.h:85
bool y_overlap(const TBOX &box) const
Definition: rect.h:428
int16_t left() const
Definition: rect.h:72
int y_gap(const TBOX &box) const
Definition: rect.h:233
int y_middle() const
Definition: rect.h:88
int16_t bottom() const
Definition: rect.h:65
void move_left_edge(const int16_t x)
Definition: rect.h:142
void move_bottom_edge(const int16_t y)
Definition: rect.h:137
TBOX intersection(const TBOX &box) const
Definition: rect.cpp:87
bool contains(const FCOORD pt) const
Definition: rect.h:333
void set_to_given_coords(int x_min, int y_min, int x_max, int y_max)
Definition: rect.h:271
void pad(int xpad, int ypad)
Definition: rect.h:131
const ICOORD & topright() const
Definition: rect.h:104
bool null_box() const
Definition: rect.h:50
bool major_x_overlap(const TBOX &box) const
Definition: rect.h:412
TBOX()
Definition: rect.h:36
void set_left(int x)
Definition: rect.h:75
bool major_y_overlap(const TBOX &box) const
Definition: rect.h:439
int x_gap(const TBOX &box) const
Definition: rect.h:225
int16_t right() const
Definition: rect.h:79
Definition: strngs.h:45
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:600