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