Tesseract  3.02
tesseract-ocr/textord/bbgrid.h
Go to the documentation of this file.
00001 
00002 // File:        bbgrid.h
00003 // Description: Class to hold BLOBNBOXs in a grid for fast access
00004 //              to neighbours.
00005 // Author:      Ray Smith
00006 // Created:     Wed Jun 06 17:22:01 PDT 2007
00007 //
00008 // (C) Copyright 2007, Google Inc.
00009 // Licensed under the Apache License, Version 2.0 (the "License");
00010 // you may not use this file except in compliance with the License.
00011 // You may obtain a copy of the License at
00012 // http://www.apache.org/licenses/LICENSE-2.0
00013 // Unless required by applicable law or agreed to in writing, software
00014 // distributed under the License is distributed on an "AS IS" BASIS,
00015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016 // See the License for the specific language governing permissions and
00017 // limitations under the License.
00018 //
00020 
00021 #ifndef TESSERACT_TEXTORD_BBGRID_H__
00022 #define TESSERACT_TEXTORD_BBGRID_H__
00023 
00024 #include "clst.h"
00025 #include "coutln.h"
00026 #include "rect.h"
00027 #include "scrollview.h"
00028 
00029 // Some code is dependent upon leptonica. If you don't have it,
00030 // you don't get this functionality.
00031 #ifdef HAVE_CONFIG_H
00032 #include "config_auto.h"
00033 #endif
00034 
00035 #include "allheaders.h"
00036 
00037 class BLOCK;
00038 
00039 namespace tesseract {
00040 
00041 // Helper function to return a scaled Pix with one pixel per grid cell,
00042 // set (black) where the given outline enters the corresponding grid cell,
00043 // and clear where the outline does not touch the grid cell.
00044 // Also returns the grid coords of the bottom-left of the Pix, in *left
00045 // and *bottom, which corresponds to (0, 0) on the Pix.
00046 // Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
00047 Pix* TraceOutlineOnReducedPix(C_OUTLINE* outline, int gridsize,
00048                               ICOORD bleft, int* left, int* bottom);
00049 // As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
00050 Pix* TraceBlockOnReducedPix(BLOCK* block, int gridsize,
00051                             ICOORD bleft, int* left, int* bottom);
00052 
00053 template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch;
00054 
00055 // The GridBase class is the base class for BBGrid and IntGrid.
00056 // It holds the geometry and scale of the grid.
00057 class GridBase {
00058  public:
00059   GridBase();
00060   GridBase(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00061   virtual ~GridBase();
00062 
00063   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00064   // and bleft, tright are the bounding box of everything to go in it.
00065   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00066 
00067   // Simple accessors.
00068   int gridsize() const {
00069     return gridsize_;
00070   }
00071   int gridwidth() const {
00072     return gridwidth_;
00073   }
00074   int gridheight() const {
00075     return gridheight_;
00076   }
00077   const ICOORD& bleft() const {
00078     return bleft_;
00079   }
00080   const ICOORD& tright() const {
00081     return tright_;
00082   }
00083   // Compute the given grid coordinates from image coords.
00084   void GridCoords(int x, int y, int* grid_x, int* grid_y) const;
00085 
00086   // Clip the given grid coordinates to fit within the grid.
00087   void ClipGridCoords(int* x, int* y) const;
00088 
00089  protected:
00090   // TODO(rays) Make these private and migrate to the accessors in subclasses.
00091   int gridsize_;     // Pixel size of each grid cell.
00092   int gridwidth_;    // Size of the grid in cells.
00093   int gridheight_;
00094   int gridbuckets_;  // Total cells in grid.
00095   ICOORD bleft_;     // Pixel coords of bottom-left of grid.
00096   ICOORD tright_;    // Pixel coords of top-right of grid.
00097 
00098  private:
00099 };
00100 
00101 // The IntGrid maintains a single int for each cell in a grid.
00102 class IntGrid : public GridBase {
00103  public:
00104   IntGrid();
00105   IntGrid(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00106   virtual ~IntGrid();
00107 
00108   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00109   // and bleft, tright are the bounding box of everything to go in it.
00110   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00111 
00112   // Clear all the ints in the grid to zero.
00113   void Clear();
00114 
00115   // Rotate the grid by rotation, keeping cell contents.
00116   // rotation must be a multiple of 90 degrees.
00117   // NOTE: due to partial cells, cell coverage in the rotated grid will be
00118   // inexact. This is why there is no Rotate for the generic BBGrid.
00119   void Rotate(const FCOORD& rotation);
00120 
00121   // Returns a new IntGrid containing values equal to the sum of all the
00122   // neighbouring cells. The returned grid must be deleted after use.
00123   IntGrid* NeighbourhoodSum() const;
00124 
00125   int GridCellValue(int grid_x, int grid_y) const {
00126     ClipGridCoords(&grid_x, &grid_y);
00127     return grid_[grid_y * gridwidth_ + grid_x];
00128   }
00129   void SetGridCell(int grid_x, int grid_y, int value) {
00130     ASSERT_HOST(grid_x >= 0 && grid_x < gridwidth());
00131     ASSERT_HOST(grid_y >= 0 && grid_y < gridheight());
00132     grid_[grid_y * gridwidth_ + grid_x] = value;
00133   }
00134   // Returns true if more than half the area of the rect is covered by grid
00135   // cells that are over the theshold.
00136   bool RectMostlyOverThreshold(const TBOX& rect, int threshold) const;
00137 
00138   // Returns true if any cell value in the given rectangle is zero.
00139   bool AnyZeroInRect(const TBOX& rect) const;
00140 
00141   // Returns a full-resolution binary pix in which each cell over the given
00142   // threshold is filled as a black square. pixDestroy after use.
00143   Pix* ThresholdToPix(int threshold) const;
00144 
00145  private:
00146   int* grid_;  // 2-d array of ints.
00147 };
00148 
00149 // The BBGrid class holds C_LISTs of template classes BBC (bounding box class)
00150 // in a grid for fast neighbour access.
00151 // The BBC class must have a member const TBOX& bounding_box() const.
00152 // The BBC class must have been CLISTIZEH'ed elsewhere to make the
00153 // list class BBC_CLIST and the iterator BBC_C_IT.
00154 // Use of C_LISTs enables BBCs to exist in multiple cells simultaneously.
00155 // As a consequence, ownership of BBCs is assumed to be elsewhere and
00156 // persistent for at least the life of the BBGrid, or at least until Clear is
00157 // called which removes all references to inserted objects without actually
00158 // deleting them.
00159 // Most uses derive a class from a specific instantiation of BBGrid,
00160 // thereby making most of the ugly template notation go away.
00161 // The friend class GridSearch, with the same template arguments, is
00162 // used to search a grid efficiently in one of several search patterns.
00163 template<class BBC, class BBC_CLIST, class BBC_C_IT> class BBGrid
00164   : public GridBase {
00165   friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>;
00166  public:
00167   BBGrid();
00168   BBGrid(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00169   virtual ~BBGrid();
00170 
00171   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00172   // and bleft, tright are the bounding box of everything to go in it.
00173   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00174 
00175   // Empty all the lists but leave the grid itself intact.
00176   void Clear();
00177   // Deallocate the data in the lists but otherwise leave the lists and the grid
00178   // intact.
00179   void ClearGridData(void (*free_method)(BBC*));
00180 
00181   // Insert a bbox into the appropriate place in the grid.
00182   // If h_spread, then all cells covered horizontally by the box are
00183   // used, otherwise, just the bottom-left. Similarly for v_spread.
00184   // WARNING: InsertBBox may invalidate an active GridSearch. Call
00185   // RepositionIterator() on any GridSearches that are active on this grid.
00186   void InsertBBox(bool h_spread, bool v_spread, BBC* bbox);
00187 
00188   // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
00189   // which each pixel corresponds to a grid cell, insert a bbox into every
00190   // place in the grid where the corresponding pixel is 1. The Pix is handled
00191   // upside-down to match the Tesseract coordinate system. (As created by
00192   // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
00193   // (0, 0) in the pix corresponds to (left, bottom) in the
00194   // grid (in grid coords), and the pix works up the grid from there.
00195   // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
00196   // RepositionIterator() on any GridSearches that are active on this grid.
00197   void InsertPixPtBBox(int left, int bottom, Pix* pix, BBC* bbox);
00198 
00199   // Remove the bbox from the grid.
00200   // WARNING: Any GridSearch operating on this grid could be invalidated!
00201   // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
00202   void RemoveBBox(BBC* bbox);
00203 
00204   // Returns true if the given rectangle has no overlapping elements.
00205   bool RectangleEmpty(const TBOX& rect);
00206 
00207   // Returns an IntGrid showing the number of elements in each cell.
00208   // Returned IntGrid must be deleted after use.
00209   IntGrid* CountCellElements();
00210 
00211   // Make a window of an appropriate size to display things in the grid.
00212   ScrollView* MakeWindow(int x, int y, const char* window_name);
00213 
00214   // Display the bounding boxes of the BLOBNBOXes in this grid.
00215   // Use of this function requires an additional member of the BBC class:
00216   // ScrollView::Color BBC::BoxColor() const.
00217   void DisplayBoxes(ScrollView* window);
00218 
00219   // ASSERT_HOST that every cell contains no more than one copy of each entry.
00220   void AssertNoDuplicates();
00221 
00222   // Handle a click event in a display window.
00223   virtual void HandleClick(int x, int y);
00224 
00225  protected:
00226   BBC_CLIST* grid_;  // 2-d array of CLISTS of BBC elements.
00227 
00228  private:
00229 };
00230 
00231 // The GridSearch class enables neighbourhood searching on a BBGrid.
00232 template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch {
00233  public:
00234   GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid)
00235       : grid_(grid), unique_mode_(false),
00236         previous_return_(NULL), next_return_(NULL) {
00237   }
00238 
00239   // Get the grid x, y coords of the most recently returned BBC.
00240   int GridX() const {
00241     return x_;
00242   }
00243   int GridY() const {
00244     return y_;
00245   }
00246 
00247   // Sets the search mode to return a box only once.
00248   // Efficiency warning: Implementation currently uses a squared-order
00249   // search in the number of returned elements. Use only where a small
00250   // number of elements are spread over a wide area, eg ColPartitions.
00251   void SetUniqueMode(bool mode) {
00252     unique_mode_ = mode;
00253   }
00254   // TODO(rays) Replace calls to ReturnedSeedElement with SetUniqueMode.
00255   // It only works if the search includes the bottom-left corner.
00256   // Apart from full search, all other searches return a box several
00257   // times if the box is inserted with h_spread or v_spread.
00258   // This method will return true for only one occurrence of each box
00259   // that was inserted with both h_spread and v_spread as true.
00260   // It will usually return false for boxes that were not inserted with
00261   // both h_spread=true and v_spread=true
00262   bool ReturnedSeedElement() const {
00263     TBOX box = previous_return_->bounding_box();
00264     int x_center = (box.left()+box.right())/2;
00265     int y_center = (box.top()+box.bottom())/2;
00266     int grid_x, grid_y;
00267     grid_->GridCoords(x_center, y_center, &grid_x, &grid_y);
00268     return (x_ == grid_x) && (y_ == grid_y);
00269   }
00270 
00271   // Various searching iterations... Note that these iterations
00272   // all share data members, so you can't run more than one iteration
00273   // in parallel in a single GridSearch instance, but multiple instances
00274   // can search the same BBGrid in parallel.
00275   // Note that all the searches can return blobs that may not exactly
00276   // match the search conditions, since they return everything in the
00277   // covered grid cells. It is up to the caller to check for
00278   // appropriateness.
00279   // TODO(rays) NextRectSearch only returns valid elements. Make the other
00280   // searches test before return also and remove the tests from code
00281   // that uses GridSearch.
00282 
00283   // Start a new full search. Will iterate all stored blobs, from the top.
00284   // If the blobs have been inserted using InsertBBox, (not InsertPixPtBBox)
00285   // then the full search guarantees to return each blob in the grid once.
00286   // Other searches may return a blob more than once if they have been
00287   // inserted using h_spread or v_spread.
00288   void StartFullSearch();
00289   // Return the next bbox in the search or NULL if done.
00290   BBC* NextFullSearch();
00291 
00292   // Start a new radius search. Will search in a spiral upto a
00293   // given maximum radius in grid cells from the given center in pixels.
00294   void StartRadSearch(int x, int y, int max_radius);
00295   // Return the next bbox in the radius search or NULL if the
00296   // maximum radius has been reached.
00297   BBC* NextRadSearch();
00298 
00299   // Start a new left or right-looking search. Will search to the side
00300   // for a box that vertically overlaps the given vertical line segment.
00301   // CAVEAT: This search returns all blobs from the cells to the side
00302   // of the start, and somewhat below, since there is no guarantee
00303   // that there may not be a taller object in a lower cell. The
00304   // blobs returned will include all those that vertically overlap and
00305   // are no more than twice as high, but may also include some that do
00306   // not overlap and some that are more than twice as high.
00307   void StartSideSearch(int x, int ymin, int ymax);
00308   // Return the next bbox in the side search or NULL if the
00309   // edge has been reached. Searches left to right or right to left
00310   // according to the flag.
00311   BBC* NextSideSearch(bool right_to_left);
00312 
00313   // Start a vertical-looking search. Will search up or down
00314   // for a box that horizontally overlaps the given line segment.
00315   void StartVerticalSearch(int xmin, int xmax, int y);
00316   // Return the next bbox in the vertical search or NULL if the
00317   // edge has been reached. Searches top to bottom or bottom to top
00318   // according to the flag.
00319   BBC* NextVerticalSearch(bool top_to_bottom);
00320 
00321   // Start a rectangular search. Will search for a box that overlaps the
00322   // given rectangle.
00323   void StartRectSearch(const TBOX& rect);
00324   // Return the next bbox in the rectangular search or NULL if complete.
00325   BBC* NextRectSearch();
00326 
00327   // Remove the last returned BBC. Will not invalidate this. May invalidate
00328   // any other concurrent GridSearch on the same grid. If any others are
00329   // in use, call RepositionIterator on those, to continue without harm.
00330   void RemoveBBox();
00331   void RepositionIterator();
00332 
00333  private:
00334   // Factored out helper to start a search.
00335   void CommonStart(int x, int y);
00336   // Factored out helper to complete a next search.
00337   BBC* CommonNext();
00338   // Factored out final return when search is exhausted.
00339   BBC* CommonEnd();
00340   // Factored out function to set the iterator to the current x_, y_
00341   // grid coords and mark the cycle pt.
00342   void SetIterator();
00343 
00344  private:
00345   // The grid we are searching.
00346   BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid_;
00347   // For executing a search. The different search algorithms use these in
00348   // different ways, but most use x_origin_ and y_origin_ as the start position.
00349   int x_origin_;
00350   int y_origin_;
00351   int max_radius_;
00352   int radius_;
00353   int rad_index_;
00354   int rad_dir_;
00355   TBOX rect_;
00356   int x_;  // The current location in grid coords, of the current search.
00357   int y_;
00358   bool unique_mode_;
00359   BBC* previous_return_;  // Previous return from Next*.
00360   BBC* next_return_;  // Current value of it_.data() used for repositioning.
00361   // An iterator over the list at (x_, y_) in the grid_.
00362   BBC_C_IT it_;
00363   // List of unique returned elements used when unique_mode_ is true.
00364   BBC_CLIST returns_;
00365 };
00366 
00367 // Sort function to sort a BBC by bounding_box().left().
00368 template<class BBC>
00369 int SortByBoxLeft(const void* void1, const void* void2) {
00370   // The void*s are actually doubly indirected, so get rid of one level.
00371   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00372   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00373   int result = p1->bounding_box().left() - p2->bounding_box().left();
00374   if (result != 0)
00375     return result;
00376   result = p1->bounding_box().right() - p2->bounding_box().right();
00377   if (result != 0)
00378     return result;
00379   result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00380   if (result != 0)
00381     return result;
00382   return p1->bounding_box().top() - p2->bounding_box().top();
00383 }
00384 
00385 // Sort function to sort a BBC by bounding_box().right() in right-to-left order.
00386 template<class BBC>
00387 int SortRightToLeft(const void* void1, const void* void2) {
00388   // The void*s are actually doubly indirected, so get rid of one level.
00389   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00390   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00391   int result = p2->bounding_box().right() - p1->bounding_box().right();
00392   if (result != 0)
00393     return result;
00394   result = p2->bounding_box().left() - p1->bounding_box().left();
00395   if (result != 0)
00396     return result;
00397   result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00398   if (result != 0)
00399     return result;
00400   return p1->bounding_box().top() - p2->bounding_box().top();
00401 }
00402 
00403 // Sort function to sort a BBC by bounding_box().bottom().
00404 template<class BBC>
00405 int SortByBoxBottom(const void* void1, const void* void2) {
00406   // The void*s are actually doubly indirected, so get rid of one level.
00407   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00408   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00409   int result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00410   if (result != 0)
00411     return result;
00412   result =  p1->bounding_box().top() - p2->bounding_box().top();
00413   if (result != 0)
00414     return result;
00415   result = p1->bounding_box().left() - p2->bounding_box().left();
00416   if (result != 0)
00417     return result;
00418   return p1->bounding_box().right() - p2->bounding_box().right();
00419 }
00420 
00422 // BBGrid IMPLEMENTATION.
00424 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00425 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid() : grid_(NULL) {
00426 }
00427 
00428 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00429 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid(
00430   int gridsize, const ICOORD& bleft, const ICOORD& tright)
00431     : grid_(NULL) {
00432   Init(gridsize, bleft, tright);
00433 }
00434 
00435 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00436 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() {
00437   if (grid_ != NULL)
00438     delete [] grid_;
00439 }
00440 
00441 // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00442 // and bleft, tright are the bounding box of everything to go in it.
00443 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00444 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Init(int gridsize,
00445                                             const ICOORD& bleft,
00446                                             const ICOORD& tright) {
00447   GridBase::Init(gridsize, bleft, tright);
00448   if (grid_ != NULL)
00449     delete [] grid_;
00450   grid_ = new BBC_CLIST[gridbuckets_];
00451 }
00452 
00453 // Clear all lists, but leave the array of lists present.
00454 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00455 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Clear() {
00456   for (int i = 0; i < gridbuckets_; ++i) {
00457     grid_[i].shallow_clear();
00458   }
00459 }
00460 
00461 // Deallocate the data in the lists but otherwise leave the lists and the grid
00462 // intact.
00463 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00464 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClearGridData(
00465     void (*free_method)(BBC*)) {
00466   if (grid_ == NULL) return;
00467   GridSearch<BBC, BBC_CLIST, BBC_C_IT> search(this);
00468   search.StartFullSearch();
00469   BBC* bb;
00470   BBC_CLIST bb_list;
00471   BBC_C_IT it(&bb_list);
00472   while ((bb = search.NextFullSearch()) != NULL) {
00473     it.add_after_then_move(bb);
00474   }
00475   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00476     free_method(it.data());
00477   }
00478 }
00479 
00480 // Insert a bbox into the appropriate place in the grid.
00481 // If h_spread, then all cells covered horizontally by the box are
00482 // used, otherwise, just the bottom-left. Similarly for v_spread.
00483 // WARNING: InsertBBox may invalidate an active GridSearch. Call
00484 // RepositionIterator() on any GridSearches that are active on this grid.
00485 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00486 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread,
00487                                                   BBC* bbox) {
00488   TBOX box = bbox->bounding_box();
00489   int start_x, start_y, end_x, end_y;
00490   GridCoords(box.left(), box.bottom(), &start_x, &start_y);
00491   GridCoords(box.right(), box.top(), &end_x, &end_y);
00492   if (!h_spread)
00493     end_x = start_x;
00494   if (!v_spread)
00495     end_y = start_y;
00496   int grid_index = start_y * gridwidth_;
00497   for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
00498     for (int x = start_x; x <= end_x; ++x) {
00499       grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox);
00500     }
00501   }
00502 }
00503 
00504 // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
00505 // which each pixel corresponds to a grid cell, insert a bbox into every
00506 // place in the grid where the corresponding pixel is 1. The Pix is handled
00507 // upside-down to match the Tesseract coordinate system. (As created by
00508 // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
00509 // (0, 0) in the pix corresponds to (left, bottom) in the
00510 // grid (in grid coords), and the pix works up the grid from there.
00511 // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
00512 // RepositionIterator() on any GridSearches that are active on this grid.
00513 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00514 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertPixPtBBox(int left, int bottom,
00515                                                        Pix* pix, BBC* bbox) {
00516   int width = pixGetWidth(pix);
00517   int height = pixGetHeight(pix);
00518   for (int y = 0; y < height; ++y) {
00519     l_uint32* data = pixGetData(pix) + y * pixGetWpl(pix);
00520     for (int x = 0; x < width; ++x) {
00521       if (GET_DATA_BIT(data, x)) {
00522         grid_[(bottom + y) * gridwidth_ + x + left].
00523           add_sorted(SortByBoxLeft<BBC>, true, bbox);
00524       }
00525     }
00526   }
00527 }
00528 
00529 // Remove the bbox from the grid.
00530 // WARNING: Any GridSearch operating on this grid could be invalidated!
00531 // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
00532 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00533 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox(BBC* bbox) {
00534   TBOX box = bbox->bounding_box();
00535   int start_x, start_y, end_x, end_y;
00536   GridCoords(box.left(), box.bottom(), &start_x, &start_y);
00537   GridCoords(box.right(), box.top(), &end_x, &end_y);
00538   int grid_index = start_y * gridwidth_;
00539   for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
00540     for (int x = start_x; x <= end_x; ++x) {
00541       BBC_C_IT it(&grid_[grid_index + x]);
00542       for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00543         if (it.data() == bbox)
00544           it.extract();
00545       }
00546     }
00547   }
00548 }
00549 
00550 // Returns true if the given rectangle has no overlapping elements.
00551 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00552 bool BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RectangleEmpty(const TBOX& rect) {
00553   GridSearch<BBC, BBC_CLIST, BBC_C_IT> rsearch(this);
00554   rsearch.StartRectSearch(rect);
00555   return rsearch.NextRectSearch() == NULL;
00556 }
00557 
00558 // Returns an IntGrid showing the number of elements in each cell.
00559 // Returned IntGrid must be deleted after use.
00560 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00561 IntGrid* BBGrid<BBC, BBC_CLIST, BBC_C_IT>::CountCellElements() {
00562   IntGrid* intgrid = new IntGrid(gridsize(), bleft(), tright());
00563   for (int y = 0; y < gridheight(); ++y) {
00564     for (int x = 0; x < gridwidth(); ++x) {
00565       int cell_count = grid_[y * gridwidth() + x].length();
00566       intgrid->SetGridCell(x, y, cell_count);
00567     }
00568   }
00569   return intgrid;
00570 }
00571 
00572 
00573 template<class G> class TabEventHandler : public SVEventHandler {
00574  public:
00575   explicit TabEventHandler(G* grid) : grid_(grid) {
00576   }
00577   void Notify(const SVEvent* sv_event) {
00578     if (sv_event->type == SVET_CLICK) {
00579       grid_->HandleClick(sv_event->x, sv_event->y);
00580     }
00581   }
00582  private:
00583   G* grid_;
00584 };
00585 
00586 // Make a window of an appropriate size to display things in the grid.
00587 // Position the window at the given x,y.
00588 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00589 ScrollView* BBGrid<BBC, BBC_CLIST, BBC_C_IT>::MakeWindow(
00590     int x, int y, const char* window_name) {
00591   ScrollView* tab_win = NULL;
00592 #ifndef GRAPHICS_DISABLED
00593   tab_win = new ScrollView(window_name, x, y,
00594                            tright_.x() - bleft_.x(),
00595                            tright_.y() - bleft_.y(),
00596                            tright_.x() - bleft_.x(),
00597                            tright_.y() - bleft_.y(),
00598                            true);
00599   TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >* handler =
00600     new TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >(this);
00601   tab_win->AddEventHandler(handler);
00602   tab_win->Pen(ScrollView::GREY);
00603   tab_win->Rectangle(0, 0, tright_.x() - bleft_.x(), tright_.y() - bleft_.y());
00604 #endif
00605   return tab_win;
00606 }
00607 
00608 // Create a window at (x,y) and display the bounding boxes of the
00609 // BLOBNBOXes in this grid.
00610 // Use of this function requires an additional member of the BBC class:
00611 // ScrollView::Color BBC::BoxColor() const.
00612 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00613 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::DisplayBoxes(ScrollView* tab_win) {
00614 #ifndef GRAPHICS_DISABLED
00615   tab_win->Pen(ScrollView::BLUE);
00616   tab_win->Brush(ScrollView::NONE);
00617 
00618   // For every bbox in the grid, display it.
00619   GridSearch<BBC, BBC_CLIST, BBC_C_IT> gsearch(this);
00620   gsearch.StartFullSearch();
00621   BBC* bbox;
00622   while ((bbox = gsearch.NextFullSearch()) != NULL) {
00623     TBOX box = bbox->bounding_box();
00624     int left_x = box.left();
00625     int right_x = box.right();
00626     int top_y = box.top();
00627     int bottom_y = box.bottom();
00628     ScrollView::Color box_color = bbox->BoxColor();
00629     tab_win->Pen(box_color);
00630     tab_win->Rectangle(left_x, bottom_y, right_x, top_y);
00631   }
00632   tab_win->Update();
00633 #endif
00634 }
00635 
00636 // ASSERT_HOST that every cell contains no more than one copy of each entry.
00637 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00638 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::AssertNoDuplicates() {
00639   // Process all grid cells.
00640   for (int i = gridwidth_ * gridheight_ - 1; i >= 0; --i) {
00641     // Iterate over all elements excent the last.
00642     for (BBC_C_IT it(&grid_[i]); !it.at_last(); it.forward()) {
00643       BBC* ptr = it.data();
00644       BBC_C_IT it2(it);
00645       // None of the rest of the elements in the list should equal ptr.
00646       for (it2.forward(); !it2.at_first(); it2.forward()) {
00647         ASSERT_HOST(it2.data() != ptr);
00648       }
00649     }
00650   }
00651 }
00652 
00653 // Handle a click event in a display window.
00654 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00655 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::HandleClick(int x, int y) {
00656   tprintf("Click at (%d, %d)\n", x, y);
00657 }
00658 
00660 // GridSearch IMPLEMENTATION.
00662 
00663 // Start a new full search. Will iterate all stored blobs.
00664 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00665 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartFullSearch() {
00666   // Full search uses x_ and y_ as the current grid
00667   // cell being searched.
00668   CommonStart(grid_->bleft_.x(), grid_->tright_.y());
00669 }
00670 
00671 // Return the next bbox in the search or NULL if done.
00672 // The other searches will return a box that overlaps the grid cell
00673 // thereby duplicating boxes, but NextFullSearch only returns each box once.
00674 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00675 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextFullSearch() {
00676   int x;
00677   int y;
00678   do {
00679     while (it_.cycled_list()) {
00680       ++x_;
00681       if (x_ >= grid_->gridwidth_) {
00682         --y_;
00683         if (y_ < 0)
00684           return CommonEnd();
00685         x_ = 0;
00686       }
00687       SetIterator();
00688     }
00689     CommonNext();
00690     TBOX box = previous_return_->bounding_box();
00691     grid_->GridCoords(box.left(), box.bottom(), &x, &y);
00692   } while (x != x_ || y != y_);
00693   return previous_return_;
00694 }
00695 
00696 // Start a new radius search.
00697 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00698 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRadSearch(int x, int y,
00699                                                           int max_radius) {
00700   // Rad search uses x_origin_ and y_origin_ as the center of the circle.
00701   // The radius_ is the radius of the (diamond-shaped) circle and
00702   // rad_index/rad_dir_ combine to determine the position around it.
00703   max_radius_ = max_radius;
00704   radius_ = 0;
00705   rad_index_ = 0;
00706   rad_dir_ = 3;
00707   CommonStart(x, y);
00708 }
00709 
00710 // Return the next bbox in the radius search or NULL if the
00711 // maximum radius has been reached.
00712 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00713 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRadSearch() {
00714   do {
00715     while (it_.cycled_list()) {
00716       ++rad_index_;
00717       if (rad_index_ >= radius_) {
00718         ++rad_dir_;
00719         rad_index_ = 0;
00720         if (rad_dir_ >= 4) {
00721           ++radius_;
00722           if (radius_ > max_radius_)
00723             return CommonEnd();
00724           rad_dir_ = 0;
00725         }
00726       }
00727       ICOORD offset = C_OUTLINE::chain_step(rad_dir_);
00728       offset *= radius_ - rad_index_;
00729       offset += C_OUTLINE::chain_step(rad_dir_ + 1) * rad_index_;
00730       x_ = x_origin_ + offset.x();
00731       y_ = y_origin_ + offset.y();
00732       if (x_ >= 0 && x_ < grid_->gridwidth_ &&
00733           y_ >= 0 && y_ < grid_->gridheight_)
00734         SetIterator();
00735     }
00736     CommonNext();
00737   } while (unique_mode_ &&
00738            !returns_.add_sorted(SortByBoxLeft<BBC>, true, previous_return_));
00739   return previous_return_;
00740 }
00741 
00742 // Start a new left or right-looking search. Will search to the side
00743 // for a box that vertically overlaps the given vertical line segment.
00744 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00745 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartSideSearch(int x,
00746                                                            int ymin, int ymax) {
00747   // Right search records the x in x_origin_, the ymax in y_origin_
00748   // and the size of the vertical strip to search in radius_.
00749   // To guarantee finding overlapping objects of upto twice the
00750   // given size, double the height.
00751   radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_;
00752   rad_index_ = 0;
00753   CommonStart(x, ymax);
00754 }
00755 
00756 // Return the next bbox in the side search or NULL if the
00757 // edge has been reached. Searches left to right or right to left
00758 // according to the flag.
00759 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00760 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextSideSearch(bool right_to_left) {
00761   do {
00762     while (it_.cycled_list()) {
00763       ++rad_index_;
00764       if (rad_index_ > radius_) {
00765         if (right_to_left)
00766           --x_;
00767         else
00768           ++x_;
00769         rad_index_ = 0;
00770         if (x_ < 0 || x_ >= grid_->gridwidth_)
00771           return CommonEnd();
00772       }
00773       y_ = y_origin_ - rad_index_;
00774       if (y_ >= 0 && y_ < grid_->gridheight_)
00775         SetIterator();
00776     }
00777     CommonNext();
00778   } while (unique_mode_ &&
00779            !returns_.add_sorted(SortByBoxLeft<BBC>, true, previous_return_));
00780   return previous_return_;
00781 }
00782 
00783 // Start a vertical-looking search. Will search up or down
00784 // for a box that horizontally overlaps the given line segment.
00785 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00786 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartVerticalSearch(int xmin,
00787                                                                int xmax,
00788                                                                int y) {
00789   // Right search records the xmin in x_origin_, the y in y_origin_
00790   // and the size of the horizontal strip to search in radius_.
00791   radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_;
00792   rad_index_ = 0;
00793   CommonStart(xmin, y);
00794 }
00795 
00796 // Return the next bbox in the vertical search or NULL if the
00797 // edge has been reached. Searches top to bottom or bottom to top
00798 // according to the flag.
00799 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00800 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextVerticalSearch(
00801     bool top_to_bottom) {
00802   do {
00803     while (it_.cycled_list()) {
00804       ++rad_index_;
00805       if (rad_index_ > radius_) {
00806         if (top_to_bottom)
00807           --y_;
00808         else
00809           ++y_;
00810         rad_index_ = 0;
00811         if (y_ < 0 || y_ >= grid_->gridheight_)
00812           return CommonEnd();
00813       }
00814       x_ = x_origin_ + rad_index_;
00815       if (x_ >= 0 && x_ < grid_->gridwidth_)
00816         SetIterator();
00817     }
00818     CommonNext();
00819   } while (unique_mode_ &&
00820            !returns_.add_sorted(SortByBoxLeft<BBC>, true, previous_return_));
00821   return previous_return_;
00822 }
00823 
00824 // Start a rectangular search. Will search for a box that overlaps the
00825 // given rectangle.
00826 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00827 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRectSearch(const TBOX& rect) {
00828   // Rect search records the xmin in x_origin_, the ymin in y_origin_
00829   // and the xmax in max_radius_.
00830   // The search proceeds left to right, top to bottom.
00831   rect_ = rect;
00832   CommonStart(rect.left(), rect.top());
00833   grid_->GridCoords(rect.right(), rect.bottom(),  // - rect.height(),
00834                     &max_radius_, &y_origin_);
00835 }
00836 
00837 // Return the next bbox in the rectangular search or NULL if complete.
00838 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00839 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRectSearch() {
00840   do {
00841     while (it_.cycled_list()) {
00842       ++x_;
00843       if (x_ > max_radius_) {
00844         --y_;
00845         x_ = x_origin_;
00846         if (y_ < y_origin_)
00847           return CommonEnd();
00848       }
00849       SetIterator();
00850     }
00851     CommonNext();
00852   } while (!rect_.overlap(previous_return_->bounding_box()) ||
00853            (unique_mode_ &&
00854             !returns_.add_sorted(SortByBoxLeft<BBC>, true, previous_return_)));
00855   return previous_return_;
00856 }
00857 
00858 // Remove the last returned BBC. Will not invalidate this. May invalidate
00859 // any other concurrent GridSearch on the same grid. If any others are
00860 // in use, call RepositionIterator on those, to continue without harm.
00861 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00862 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox() {
00863   if (previous_return_ != NULL) {
00864     // Remove all instances of previous_return_ from the list, so the iterator
00865     // remains valid after removal from the rest of the grid cells.
00866     // if previous_return_ is not on the list, then it has been removed already.
00867     BBC* prev_data = NULL;
00868     BBC* new_previous_return = NULL;
00869     it_.move_to_first();
00870     for (it_.mark_cycle_pt(); !it_.cycled_list();) {
00871       if (it_.data() ==  previous_return_) {
00872         new_previous_return = prev_data;
00873         it_.extract();
00874         it_.forward();
00875         next_return_ = it_.cycled_list() ? NULL : it_.data();
00876       } else {
00877         prev_data = it_.data();
00878         it_.forward();
00879       }
00880     }
00881     grid_->RemoveBBox(previous_return_);
00882     previous_return_ = new_previous_return;
00883     RepositionIterator();
00884   }
00885 }
00886 
00887 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00888 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RepositionIterator() {
00889   // Something was deleted, so we have little choice but to clear the
00890   // returns list.
00891   returns_.shallow_clear();
00892   // Reset the iterator back to one past the previous return.
00893   // If the previous_return_ is no longer in the list, then
00894   // next_return_ serves as a backup.
00895   it_.move_to_first();
00896   // Special case, the first element was removed and reposition
00897   // iterator was called. In this case, the data is fine, but the
00898   // cycle point is not. Detect it and return.
00899   if (!it_.empty() && it_.data() == next_return_) {
00900     it_.mark_cycle_pt();
00901     return;
00902   }
00903   for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) {
00904     if (it_.data() == previous_return_ ||
00905         it_.data_relative(1) == next_return_) {
00906       CommonNext();
00907       return;
00908     }
00909   }
00910   // We ran off the end of the list. Move to a new cell next time.
00911   previous_return_ = NULL;
00912   next_return_ = NULL;
00913 }
00914 
00915 // Factored out helper to start a search.
00916 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00917 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonStart(int x, int y) {
00918   grid_->GridCoords(x, y, &x_origin_, &y_origin_);
00919   x_ = x_origin_;
00920   y_ = y_origin_;
00921   SetIterator();
00922   previous_return_ = NULL;
00923   next_return_ = it_.empty() ? NULL : it_.data();
00924   returns_.shallow_clear();
00925 }
00926 
00927 // Factored out helper to complete a next search.
00928 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00929 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() {
00930   previous_return_ = it_.data();
00931   it_.forward();
00932   next_return_ = it_.cycled_list() ? NULL : it_.data();
00933   return previous_return_;
00934 }
00935 
00936 // Factored out final return when search is exhausted.
00937 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00938 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() {
00939   previous_return_ = NULL;
00940   next_return_ = NULL;
00941   return NULL;
00942 }
00943 
00944 // Factored out function to set the iterator to the current x_, y_
00945 // grid coords and mark the cycle pt.
00946 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00947 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() {
00948   it_= &(grid_->grid_[y_ * grid_->gridwidth_ + x_]);
00949   it_.mark_cycle_pt();
00950 }
00951 
00952 }  // namespace tesseract.
00953 
00954 #endif  // TESSERACT_TEXTORD_BBGRID_H__