|
tesseract 3.04.01
|
00001 /********************************************************************** 00002 * File: rect.h (Formerly box.h) 00003 * Description: Bounding box class definition. 00004 * Author: Phil Cheatle 00005 * Created: Wed Oct 16 15:18:45 BST 1991 00006 * 00007 * (C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #ifndef RECT_H 00021 #define RECT_H 00022 00023 #include <math.h> 00024 #include "points.h" 00025 #include "ndminx.h" 00026 #include "scrollview.h" 00027 #include "strngs.h" 00028 #include "tprintf.h" 00029 00030 class DLLSYM TBOX { // bounding box 00031 public: 00032 TBOX (): // empty constructor making a null box 00033 bot_left (MAX_INT16, MAX_INT16), top_right (-MAX_INT16, -MAX_INT16) { 00034 } 00035 00036 TBOX( // constructor 00037 const ICOORD pt1, // one corner 00038 const ICOORD pt2); // the other corner 00039 00040 TBOX( // constructor 00041 inT16 left, inT16 bottom, inT16 right, inT16 top); 00042 00043 TBOX( // box around FCOORD 00044 const FCOORD pt); 00045 00046 bool null_box() const { // Is box null 00047 return ((left () >= right ()) || (top () <= bottom ())); 00048 } 00049 00050 bool operator==(const TBOX& other) const { 00051 return bot_left == other.bot_left && top_right == other.top_right; 00052 } 00053 00054 inT16 top() const { // coord of top 00055 return top_right.y (); 00056 } 00057 void set_top(int y) { 00058 top_right.set_y(y); 00059 } 00060 00061 inT16 bottom() const { // coord of bottom 00062 return bot_left.y (); 00063 } 00064 void set_bottom(int y) { 00065 bot_left.set_y(y); 00066 } 00067 00068 inT16 left() const { // coord of left 00069 return bot_left.x (); 00070 } 00071 void set_left(int x) { 00072 bot_left.set_x(x); 00073 } 00074 00075 inT16 right() const { // coord of right 00076 return top_right.x (); 00077 } 00078 void set_right(int x) { 00079 top_right.set_x(x); 00080 } 00081 int x_middle() const { 00082 return (bot_left.x() + top_right.x()) / 2; 00083 } 00084 int y_middle() const { 00085 return (bot_left.y() + top_right.y()) / 2; 00086 } 00087 00088 const ICOORD &botleft() const { // access function 00089 return bot_left; 00090 } 00091 00092 ICOORD botright() const { // ~ access function 00093 return ICOORD (top_right.x (), bot_left.y ()); 00094 } 00095 00096 ICOORD topleft() const { // ~ access function 00097 return ICOORD (bot_left.x (), top_right.y ()); 00098 } 00099 00100 const ICOORD &topright() const { // access function 00101 return top_right; 00102 } 00103 00104 inT16 height() const { // how high is it? 00105 if (!null_box ()) 00106 return top_right.y () - bot_left.y (); 00107 else 00108 return 0; 00109 } 00110 00111 inT16 width() const { // how high is it? 00112 if (!null_box ()) 00113 return top_right.x () - bot_left.x (); 00114 else 00115 return 0; 00116 } 00117 00118 inT32 area() const { // what is the area? 00119 if (!null_box ()) 00120 return width () * height (); 00121 else 00122 return 0; 00123 } 00124 00125 // Pads the box on either side by the supplied x,y pad amounts. 00126 // NO checks for exceeding any bounds like 0 or an image size. 00127 void pad(int xpad, int ypad) { 00128 ICOORD pad(xpad, ypad); 00129 bot_left -= pad; 00130 top_right += pad; 00131 } 00132 00133 void move_bottom_edge( // move one edge 00134 const inT16 y) { // by +/- y 00135 bot_left += ICOORD (0, y); 00136 } 00137 00138 void move_left_edge( // move one edge 00139 const inT16 x) { // by +/- x 00140 bot_left += ICOORD (x, 0); 00141 } 00142 00143 void move_right_edge( // move one edge 00144 const inT16 x) { // by +/- x 00145 top_right += ICOORD (x, 0); 00146 } 00147 00148 void move_top_edge( // move one edge 00149 const inT16 y) { // by +/- y 00150 top_right += ICOORD (0, y); 00151 } 00152 00153 void move( // move box 00154 const ICOORD vec) { // by vector 00155 bot_left += vec; 00156 top_right += vec; 00157 } 00158 00159 void move( // move box 00160 const FCOORD vec) { // by float vector 00161 bot_left.set_x ((inT16) floor (bot_left.x () + vec.x ())); 00162 // round left 00163 bot_left.set_y ((inT16) floor (bot_left.y () + vec.y ())); 00164 // round down 00165 top_right.set_x ((inT16) ceil (top_right.x () + vec.x ())); 00166 // round right 00167 top_right.set_y ((inT16) ceil (top_right.y () + vec.y ())); 00168 // round up 00169 } 00170 00171 void scale( // scale box 00172 const float f) { // by multiplier 00173 bot_left.set_x ((inT16) floor (bot_left.x () * f)); // round left 00174 bot_left.set_y ((inT16) floor (bot_left.y () * f)); // round down 00175 top_right.set_x ((inT16) ceil (top_right.x () * f)); // round right 00176 top_right.set_y ((inT16) ceil (top_right.y () * f)); // round up 00177 } 00178 void scale( // scale box 00179 const FCOORD vec) { // by float vector 00180 bot_left.set_x ((inT16) floor (bot_left.x () * vec.x ())); 00181 bot_left.set_y ((inT16) floor (bot_left.y () * vec.y ())); 00182 top_right.set_x ((inT16) ceil (top_right.x () * vec.x ())); 00183 top_right.set_y ((inT16) ceil (top_right.y () * vec.y ())); 00184 } 00185 00186 // rotate doesn't enlarge the box - it just rotates the bottom-left 00187 // and top-right corners. Use rotate_large if you want to guarantee 00188 // that all content is contained within the rotated box. 00189 void rotate(const FCOORD& vec) { // by vector 00190 bot_left.rotate (vec); 00191 top_right.rotate (vec); 00192 *this = TBOX (bot_left, top_right); 00193 } 00194 // rotate_large constructs the containing bounding box of all 4 00195 // corners after rotating them. It therefore guarantees that all 00196 // original content is contained within, but also slightly enlarges the box. 00197 void rotate_large(const FCOORD& vec); 00198 00199 bool contains( // is pt inside box 00200 const FCOORD pt) const; 00201 00202 bool contains( // is box inside box 00203 const TBOX &box) const; 00204 00205 bool overlap( // do boxes overlap 00206 const TBOX &box) const; 00207 00208 bool major_overlap( // do boxes overlap more than half 00209 const TBOX &box) const; 00210 00211 // Do boxes overlap on x axis. 00212 bool x_overlap(const TBOX &box) const; 00213 00214 // Return the horizontal gap between the boxes. If the boxes 00215 // overlap horizontally then the return value is negative, indicating 00216 // the amount of the overlap. 00217 int x_gap(const TBOX& box) const { 00218 return MAX(bot_left.x(), box.bot_left.x()) - 00219 MIN(top_right.x(), box.top_right.x()); 00220 } 00221 00222 // Return the vertical gap between the boxes. If the boxes 00223 // overlap vertically then the return value is negative, indicating 00224 // the amount of the overlap. 00225 int y_gap(const TBOX& box) const { 00226 return MAX(bot_left.y(), box.bot_left.y()) - 00227 MIN(top_right.y(), box.top_right.y()); 00228 } 00229 00230 // Do boxes overlap on x axis by more than 00231 // half of the width of the narrower box. 00232 bool major_x_overlap(const TBOX &box) const; 00233 00234 // Do boxes overlap on y axis. 00235 bool y_overlap(const TBOX &box) const; 00236 00237 // Do boxes overlap on y axis by more than 00238 // half of the height of the shorter box. 00239 bool major_y_overlap(const TBOX &box) const; 00240 00241 // fraction of current box's area covered by other 00242 double overlap_fraction(const TBOX &box) const; 00243 00244 // fraction of the current box's projected area covered by the other's 00245 double x_overlap_fraction(const TBOX& box) const; 00246 00247 // fraction of the current box's projected area covered by the other's 00248 double y_overlap_fraction(const TBOX& box) const; 00249 00250 // Returns true if the boxes are almost equal on x axis. 00251 bool x_almost_equal(const TBOX &box, int tolerance) const; 00252 00253 // Returns true if the boxes are almost equal 00254 bool almost_equal(const TBOX &box, int tolerance) const; 00255 00256 TBOX intersection( // shared area box 00257 const TBOX &box) const; 00258 00259 TBOX bounding_union( // box enclosing both 00260 const TBOX &box) const; 00261 00262 // Sets the box boundaries to the given coordinates. 00263 void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) { 00264 bot_left.set_x(x_min); 00265 bot_left.set_y(y_min); 00266 top_right.set_x(x_max); 00267 top_right.set_y(y_max); 00268 } 00269 00270 void print() const { // print 00271 tprintf("Bounding box=(%d,%d)->(%d,%d)\n", 00272 left(), bottom(), right(), top()); 00273 } 00274 // Appends the bounding box as (%d,%d)->(%d,%d) to a STRING. 00275 void print_to_str(STRING *str) const; 00276 00277 #ifndef GRAPHICS_DISABLED 00278 void plot( // use current settings 00279 ScrollView* fd) const { // where to paint 00280 fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (), 00281 top_right.y ()); 00282 } 00283 00284 void plot( // paint box 00285 ScrollView* fd, // where to paint 00286 ScrollView::Color fill_colour, // colour for inside 00287 ScrollView::Color border_colour) const; // colour for border 00288 #endif 00289 // Writes to the given file. Returns false in case of error. 00290 bool Serialize(FILE* fp) const; 00291 // Reads from the given file. Returns false in case of error. 00292 // If swap is true, assumes a big/little-endian swap is needed. 00293 bool DeSerialize(bool swap, FILE* fp); 00294 00295 friend TBOX& operator+=(TBOX&, const TBOX&); 00296 // in place union 00297 friend TBOX& operator&=(TBOX&, const TBOX&); 00298 // in place intersection 00299 00300 private: 00301 ICOORD bot_left; // bottom left corner 00302 ICOORD top_right; // top right corner 00303 }; 00304 00305 /********************************************************************** 00306 * TBOX::TBOX() Constructor from 1 FCOORD 00307 * 00308 **********************************************************************/ 00309 00310 inline TBOX::TBOX( // constructor 00311 const FCOORD pt // floating centre 00312 ) { 00313 bot_left = ICOORD ((inT16) floor (pt.x ()), (inT16) floor (pt.y ())); 00314 top_right = ICOORD ((inT16) ceil (pt.x ()), (inT16) ceil (pt.y ())); 00315 } 00316 00317 00318 /********************************************************************** 00319 * TBOX::contains() Is point within box 00320 * 00321 **********************************************************************/ 00322 00323 inline bool TBOX::contains(const FCOORD pt) const { 00324 return ((pt.x () >= bot_left.x ()) && 00325 (pt.x () <= top_right.x ()) && 00326 (pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ())); 00327 } 00328 00329 00330 /********************************************************************** 00331 * TBOX::contains() Is box within box 00332 * 00333 **********************************************************************/ 00334 00335 inline bool TBOX::contains(const TBOX &box) const { 00336 return (contains (box.bot_left) && contains (box.top_right)); 00337 } 00338 00339 00340 /********************************************************************** 00341 * TBOX::overlap() Do two boxes overlap? 00342 * 00343 **********************************************************************/ 00344 00345 inline bool TBOX::overlap( // do boxes overlap 00346 const TBOX &box) const { 00347 return ((box.bot_left.x () <= top_right.x ()) && 00348 (box.top_right.x () >= bot_left.x ()) && 00349 (box.bot_left.y () <= top_right.y ()) && 00350 (box.top_right.y () >= bot_left.y ())); 00351 } 00352 00353 /********************************************************************** 00354 * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest? 00355 * 00356 **********************************************************************/ 00357 00358 inline bool TBOX::major_overlap( // Do boxes overlap more that half. 00359 const TBOX &box) const { 00360 int overlap = MIN(box.top_right.x(), top_right.x()); 00361 overlap -= MAX(box.bot_left.x(), bot_left.x()); 00362 overlap += overlap; 00363 if (overlap < MIN(box.width(), width())) 00364 return false; 00365 overlap = MIN(box.top_right.y(), top_right.y()); 00366 overlap -= MAX(box.bot_left.y(), bot_left.y()); 00367 overlap += overlap; 00368 if (overlap < MIN(box.height(), height())) 00369 return false; 00370 return true; 00371 } 00372 00373 /********************************************************************** 00374 * TBOX::overlap_fraction() Fraction of area covered by the other box 00375 * 00376 **********************************************************************/ 00377 00378 inline double TBOX::overlap_fraction(const TBOX &box) const { 00379 double fraction = 0.0; 00380 if (this->area()) { 00381 fraction = this->intersection(box).area() * 1.0 / this->area(); 00382 } 00383 return fraction; 00384 } 00385 00386 /********************************************************************** 00387 * TBOX::x_overlap() Do two boxes overlap on x-axis 00388 * 00389 **********************************************************************/ 00390 00391 inline bool TBOX::x_overlap(const TBOX &box) const { 00392 return ((box.bot_left.x() <= top_right.x()) && 00393 (box.top_right.x() >= bot_left.x())); 00394 } 00395 00396 /********************************************************************** 00397 * TBOX::major_x_overlap() Do two boxes overlap by more than half the 00398 * width of the narrower box on the x-axis 00399 * 00400 **********************************************************************/ 00401 00402 inline bool TBOX::major_x_overlap(const TBOX &box) const { 00403 inT16 overlap = box.width(); 00404 if (this->left() > box.left()) { 00405 overlap -= this->left() - box.left(); 00406 } 00407 if (this->right() < box.right()) { 00408 overlap -= box.right() - this->right(); 00409 } 00410 return (overlap >= box.width() / 2 || overlap >= this->width() / 2); 00411 } 00412 00413 /********************************************************************** 00414 * TBOX::y_overlap() Do two boxes overlap on y-axis 00415 * 00416 **********************************************************************/ 00417 00418 inline bool TBOX::y_overlap(const TBOX &box) const { 00419 return ((box.bot_left.y() <= top_right.y()) && 00420 (box.top_right.y() >= bot_left.y())); 00421 } 00422 00423 /********************************************************************** 00424 * TBOX::major_y_overlap() Do two boxes overlap by more than half the 00425 * height of the shorter box on the y-axis 00426 * 00427 **********************************************************************/ 00428 00429 inline bool TBOX::major_y_overlap(const TBOX &box) const { 00430 inT16 overlap = box.height(); 00431 if (this->bottom() > box.bottom()) { 00432 overlap -= this->bottom() - box.bottom(); 00433 } 00434 if (this->top() < box.top()) { 00435 overlap -= box.top() - this->top(); 00436 } 00437 return (overlap >= box.height() / 2 || overlap >= this->height() / 2); 00438 } 00439 00440 /********************************************************************** 00441 * TBOX::x_overlap_fraction() Calculates the horizontal overlap of the 00442 * given boxes as a fraction of this boxes 00443 * width. 00444 * 00445 **********************************************************************/ 00446 00447 inline double TBOX::x_overlap_fraction(const TBOX& other) const { 00448 int low = MAX(left(), other.left()); 00449 int high = MIN(right(), other.right()); 00450 int width = right() - left(); 00451 if (width == 0) { 00452 int x = left(); 00453 if (other.left() <= x && x <= other.right()) 00454 return 1.0; 00455 else 00456 return 0.0; 00457 } else { 00458 return MAX(0, static_cast<double>(high - low) / width); 00459 } 00460 } 00461 00462 /********************************************************************** 00463 * TBOX::y_overlap_fraction() Calculates the vertical overlap of the 00464 * given boxes as a fraction of this boxes 00465 * height. 00466 * 00467 **********************************************************************/ 00468 00469 inline double TBOX::y_overlap_fraction(const TBOX& other) const { 00470 int low = MAX(bottom(), other.bottom()); 00471 int high = MIN(top(), other.top()); 00472 int height = top() - bottom(); 00473 if (height == 0) { 00474 int y = bottom(); 00475 if (other.bottom() <= y && y <= other.top()) 00476 return 1.0; 00477 else 00478 return 0.0; 00479 } else { 00480 return MAX(0, static_cast<double>(high - low) / height); 00481 } 00482 } 00483 00484 #endif