Tesseract 3.01
/data/source/tesseract-ocr/ccstruct/rect.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines