tesseract
3.03
|
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 00082 const ICOORD &botleft() const { // access function 00083 return bot_left; 00084 } 00085 00086 ICOORD botright() const { // ~ access function 00087 return ICOORD (top_right.x (), bot_left.y ()); 00088 } 00089 00090 ICOORD topleft() const { // ~ access function 00091 return ICOORD (bot_left.x (), top_right.y ()); 00092 } 00093 00094 const ICOORD &topright() const { // access function 00095 return top_right; 00096 } 00097 00098 inT16 height() const { // how high is it? 00099 if (!null_box ()) 00100 return top_right.y () - bot_left.y (); 00101 else 00102 return 0; 00103 } 00104 00105 inT16 width() const { // how high is it? 00106 if (!null_box ()) 00107 return top_right.x () - bot_left.x (); 00108 else 00109 return 0; 00110 } 00111 00112 inT32 area() const { // what is the area? 00113 if (!null_box ()) 00114 return width () * height (); 00115 else 00116 return 0; 00117 } 00118 00119 // Pads the box on either side by the supplied x,y pad amounts. 00120 // NO checks for exceeding any bounds like 0 or an image size. 00121 void pad(int xpad, int ypad) { 00122 ICOORD pad(xpad, ypad); 00123 bot_left -= pad; 00124 top_right += pad; 00125 } 00126 00127 void move_bottom_edge( // move one edge 00128 const inT16 y) { // by +/- y 00129 bot_left += ICOORD (0, y); 00130 } 00131 00132 void move_left_edge( // move one edge 00133 const inT16 x) { // by +/- x 00134 bot_left += ICOORD (x, 0); 00135 } 00136 00137 void move_right_edge( // move one edge 00138 const inT16 x) { // by +/- x 00139 top_right += ICOORD (x, 0); 00140 } 00141 00142 void move_top_edge( // move one edge 00143 const inT16 y) { // by +/- y 00144 top_right += ICOORD (0, y); 00145 } 00146 00147 void move( // move box 00148 const ICOORD vec) { // by vector 00149 bot_left += vec; 00150 top_right += vec; 00151 } 00152 00153 void move( // move box 00154 const FCOORD vec) { // by float vector 00155 bot_left.set_x ((inT16) floor (bot_left.x () + vec.x ())); 00156 // round left 00157 bot_left.set_y ((inT16) floor (bot_left.y () + vec.y ())); 00158 // round down 00159 top_right.set_x ((inT16) ceil (top_right.x () + vec.x ())); 00160 // round right 00161 top_right.set_y ((inT16) ceil (top_right.y () + vec.y ())); 00162 // round up 00163 } 00164 00165 void scale( // scale box 00166 const float f) { // by multiplier 00167 bot_left.set_x ((inT16) floor (bot_left.x () * f)); // round left 00168 bot_left.set_y ((inT16) floor (bot_left.y () * f)); // round down 00169 top_right.set_x ((inT16) ceil (top_right.x () * f)); // round right 00170 top_right.set_y ((inT16) ceil (top_right.y () * f)); // round up 00171 } 00172 void scale( // scale box 00173 const FCOORD vec) { // by float vector 00174 bot_left.set_x ((inT16) floor (bot_left.x () * vec.x ())); 00175 bot_left.set_y ((inT16) floor (bot_left.y () * vec.y ())); 00176 top_right.set_x ((inT16) ceil (top_right.x () * vec.x ())); 00177 top_right.set_y ((inT16) ceil (top_right.y () * vec.y ())); 00178 } 00179 00180 // rotate doesn't enlarge the box - it just rotates the bottom-left 00181 // and top-right corners. Use rotate_large if you want to guarantee 00182 // that all content is contained within the rotated box. 00183 void rotate(const FCOORD& vec) { // by vector 00184 bot_left.rotate (vec); 00185 top_right.rotate (vec); 00186 *this = TBOX (bot_left, top_right); 00187 } 00188 // rotate_large constructs the containing bounding box of all 4 00189 // corners after rotating them. It therefore guarantees that all 00190 // original content is contained within, but also slightly enlarges the box. 00191 void rotate_large(const FCOORD& vec); 00192 00193 bool contains( // is pt inside box 00194 const FCOORD pt) const; 00195 00196 bool contains( // is box inside box 00197 const TBOX &box) const; 00198 00199 bool overlap( // do boxes overlap 00200 const TBOX &box) const; 00201 00202 bool major_overlap( // do boxes overlap more than half 00203 const TBOX &box) const; 00204 00205 // Do boxes overlap on x axis. 00206 bool x_overlap(const TBOX &box) const; 00207 00208 // Return the horizontal gap between the boxes. If the boxes 00209 // overlap horizontally then the return value is negative, indicating 00210 // the amount of the overlap. 00211 int x_gap(const TBOX& box) const { 00212 return MAX(bot_left.x(), box.bot_left.x()) - 00213 MIN(top_right.x(), box.top_right.x()); 00214 } 00215 00216 // Return the vertical gap between the boxes. If the boxes 00217 // overlap vertically then the return value is negative, indicating 00218 // the amount of the overlap. 00219 int y_gap(const TBOX& box) const { 00220 return MAX(bot_left.y(), box.bot_left.y()) - 00221 MIN(top_right.y(), box.top_right.y()); 00222 } 00223 00224 // Do boxes overlap on x axis by more than 00225 // half of the width of the narrower box. 00226 bool major_x_overlap(const TBOX &box) const; 00227 00228 // Do boxes overlap on y axis. 00229 bool y_overlap(const TBOX &box) const; 00230 00231 // Do boxes overlap on y axis by more than 00232 // half of the height of the shorter box. 00233 bool major_y_overlap(const TBOX &box) const; 00234 00235 // fraction of current box's area covered by other 00236 double overlap_fraction(const TBOX &box) const; 00237 00238 // fraction of the current box's projected area covered by the other's 00239 double x_overlap_fraction(const TBOX& box) const; 00240 00241 // fraction of the current box's projected area covered by the other's 00242 double y_overlap_fraction(const TBOX& box) const; 00243 00244 // Returns true if the boxes are almost equal on x axis. 00245 bool x_almost_equal(const TBOX &box, int tolerance) const; 00246 00247 // Returns true if the boxes are almost equal 00248 bool almost_equal(const TBOX &box, int tolerance) const; 00249 00250 TBOX intersection( // shared area box 00251 const TBOX &box) const; 00252 00253 TBOX bounding_union( // box enclosing both 00254 const TBOX &box) const; 00255 00256 // Sets the box boundaries to the given coordinates. 00257 void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) { 00258 bot_left.set_x(x_min); 00259 bot_left.set_y(y_min); 00260 top_right.set_x(x_max); 00261 top_right.set_y(y_max); 00262 } 00263 00264 void print() const { // print 00265 tprintf("Bounding box=(%d,%d)->(%d,%d)\n", 00266 left(), bottom(), right(), top()); 00267 } 00268 // Appends the bounding box as (%d,%d)->(%d,%d) to a STRING. 00269 void print_to_str(STRING *str) const; 00270 00271 #ifndef GRAPHICS_DISABLED 00272 void plot( // use current settings 00273 ScrollView* fd) const { // where to paint 00274 fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (), 00275 top_right.y ()); 00276 } 00277 00278 void plot( // paint box 00279 ScrollView* fd, // where to paint 00280 ScrollView::Color fill_colour, // colour for inside 00281 ScrollView::Color border_colour) const; // colour for border 00282 #endif 00283 // Writes to the given file. Returns false in case of error. 00284 bool Serialize(FILE* fp) const; 00285 // Reads from the given file. Returns false in case of error. 00286 // If swap is true, assumes a big/little-endian swap is needed. 00287 bool DeSerialize(bool swap, FILE* fp); 00288 00289 friend TBOX& operator+=(TBOX&, const TBOX&); 00290 // in place union 00291 friend TBOX& operator&=(TBOX&, const TBOX&); 00292 // in place intersection 00293 00294 private: 00295 ICOORD bot_left; // bottom left corner 00296 ICOORD top_right; // top right corner 00297 }; 00298 00299 /********************************************************************** 00300 * TBOX::TBOX() Constructor from 1 FCOORD 00301 * 00302 **********************************************************************/ 00303 00304 inline TBOX::TBOX( // construtor 00305 const FCOORD pt // floating centre 00306 ) { 00307 bot_left = ICOORD ((inT16) floor (pt.x ()), (inT16) floor (pt.y ())); 00308 top_right = ICOORD ((inT16) ceil (pt.x ()), (inT16) ceil (pt.y ())); 00309 } 00310 00311 00312 /********************************************************************** 00313 * TBOX::contains() Is point within box 00314 * 00315 **********************************************************************/ 00316 00317 inline bool TBOX::contains(const FCOORD pt) const { 00318 return ((pt.x () >= bot_left.x ()) && 00319 (pt.x () <= top_right.x ()) && 00320 (pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ())); 00321 } 00322 00323 00324 /********************************************************************** 00325 * TBOX::contains() Is box within box 00326 * 00327 **********************************************************************/ 00328 00329 inline bool TBOX::contains(const TBOX &box) const { 00330 return (contains (box.bot_left) && contains (box.top_right)); 00331 } 00332 00333 00334 /********************************************************************** 00335 * TBOX::overlap() Do two boxes overlap? 00336 * 00337 **********************************************************************/ 00338 00339 inline bool TBOX::overlap( // do boxes overlap 00340 const TBOX &box) const { 00341 return ((box.bot_left.x () <= top_right.x ()) && 00342 (box.top_right.x () >= bot_left.x ()) && 00343 (box.bot_left.y () <= top_right.y ()) && 00344 (box.top_right.y () >= bot_left.y ())); 00345 } 00346 00347 /********************************************************************** 00348 * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest? 00349 * 00350 **********************************************************************/ 00351 00352 inline bool TBOX::major_overlap( // Do boxes overlap more that half. 00353 const TBOX &box) const { 00354 int overlap = MIN(box.top_right.x(), top_right.x()); 00355 overlap -= MAX(box.bot_left.x(), bot_left.x()); 00356 overlap += overlap; 00357 if (overlap < MIN(box.width(), width())) 00358 return false; 00359 overlap = MIN(box.top_right.y(), top_right.y()); 00360 overlap -= MAX(box.bot_left.y(), bot_left.y()); 00361 overlap += overlap; 00362 if (overlap < MIN(box.height(), height())) 00363 return false; 00364 return true; 00365 } 00366 00367 /********************************************************************** 00368 * TBOX::overlap_fraction() Fraction of area covered by the other box 00369 * 00370 **********************************************************************/ 00371 00372 inline double TBOX::overlap_fraction(const TBOX &box) const { 00373 double fraction = 0.0; 00374 if (this->area()) { 00375 fraction = this->intersection(box).area() * 1.0 / this->area(); 00376 } 00377 return fraction; 00378 } 00379 00380 /********************************************************************** 00381 * TBOX::x_overlap() Do two boxes overlap on x-axis 00382 * 00383 **********************************************************************/ 00384 00385 inline bool TBOX::x_overlap(const TBOX &box) const { 00386 return ((box.bot_left.x() <= top_right.x()) && 00387 (box.top_right.x() >= bot_left.x())); 00388 } 00389 00390 /********************************************************************** 00391 * TBOX::major_x_overlap() Do two boxes overlap by more than half the 00392 * width of the narrower box on the x-axis 00393 * 00394 **********************************************************************/ 00395 00396 inline bool TBOX::major_x_overlap(const TBOX &box) const { 00397 inT16 overlap = box.width(); 00398 if (this->left() > box.left()) { 00399 overlap -= this->left() - box.left(); 00400 } 00401 if (this->right() < box.right()) { 00402 overlap -= box.right() - this->right(); 00403 } 00404 return (overlap >= box.width() / 2 || overlap >= this->width() / 2); 00405 } 00406 00407 /********************************************************************** 00408 * TBOX::y_overlap() Do two boxes overlap on y-axis 00409 * 00410 **********************************************************************/ 00411 00412 inline bool TBOX::y_overlap(const TBOX &box) const { 00413 return ((box.bot_left.y() <= top_right.y()) && 00414 (box.top_right.y() >= bot_left.y())); 00415 } 00416 00417 /********************************************************************** 00418 * TBOX::major_y_overlap() Do two boxes overlap by more than half the 00419 * height of the shorter box on the y-axis 00420 * 00421 **********************************************************************/ 00422 00423 inline bool TBOX::major_y_overlap(const TBOX &box) const { 00424 inT16 overlap = box.height(); 00425 if (this->bottom() > box.bottom()) { 00426 overlap -= this->bottom() - box.bottom(); 00427 } 00428 if (this->top() < box.top()) { 00429 overlap -= box.top() - this->top(); 00430 } 00431 return (overlap >= box.height() / 2 || overlap >= this->height() / 2); 00432 } 00433 00434 /********************************************************************** 00435 * TBOX::x_overlap_fraction() Calculates the horizontal overlap of the 00436 * given boxes as a fraction of this boxes 00437 * width. 00438 * 00439 **********************************************************************/ 00440 00441 inline double TBOX::x_overlap_fraction(const TBOX& other) const { 00442 int low = MAX(left(), other.left()); 00443 int high = MIN(right(), other.right()); 00444 int width = right() - left(); 00445 if (width == 0) { 00446 int x = left(); 00447 if (other.left() <= x && x <= other.right()) 00448 return 1.0; 00449 else 00450 return 0.0; 00451 } else { 00452 return MAX(0, static_cast<double>(high - low) / width); 00453 } 00454 } 00455 00456 /********************************************************************** 00457 * TBOX::y_overlap_fraction() Calculates the vertical overlap of the 00458 * given boxes as a fraction of this boxes 00459 * height. 00460 * 00461 **********************************************************************/ 00462 00463 inline double TBOX::y_overlap_fraction(const TBOX& other) const { 00464 int low = MAX(bottom(), other.bottom()); 00465 int high = MIN(top(), other.top()); 00466 int height = top() - bottom(); 00467 if (height == 0) { 00468 int y = bottom(); 00469 if (other.bottom() <= y && y <= other.top()) 00470 return 1.0; 00471 else 00472 return 0.0; 00473 } else { 00474 return MAX(0, static_cast<double>(high - low) / height); 00475 } 00476 } 00477 00478 #endif