C++程序  |  799行  |  29.47 KB

///////////////////////////////////////////////////////////////////////
// File:        bbgrid.h
// Description: Class to hold BLOBNBOXs in a grid for fast access
//              to neighbours.
// Author:      Ray Smith
// Created:     Wed Jun 06 17:22:01 PDT 2007
//
// (C) Copyright 2007, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////

#ifndef TESSERACT_TEXTORD_BBGRID_H__
#define TESSERACT_TEXTORD_BBGRID_H__

#include "clst.h"
#include "coutln.h"
#include "rect.h"
#include "scrollview.h"

// Some code is dependent upon leptonica. If you don't have it,
// you don't get this functionality.
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif
#ifdef HAVE_LIBLEPT
#include "allheaders.h"
#endif

class BLOCK;

namespace tesseract {

#ifdef HAVE_LIBLEPT
// Helper function to return a scaled Pix with one pixel per grid cell,
// set (black) where the given outline enters the corresponding grid cell,
// and clear where the outline does not touch the grid cell.
// Also returns the grid coords of the bottom-left of the Pix, in *left
// and *bottom, which corresponds to (0, 0) on the Pix.
// Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
Pix* TraceOutlineOnReducedPix(C_OUTLINE* outline, int gridsize,
                              ICOORD bleft, int* left, int* bottom);
// As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
Pix* TraceBlockOnReducedPix(BLOCK* block, int gridsize,
                            ICOORD bleft, int* left, int* bottom);
#endif

template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch;

// The BBGrid class holds C_LISTs of template classes BBC (bounding box class)
// in a grid for fast neighbour access.
// The BBC class must have a member const TBOX& bounding_box() const.
// The BBC class must have been CLISTIZEH'ed elsewhere to make the
// list class BBC_CLIST and the iterator BBC_C_IT.
// Use of C_LISTs enables BBCs to exist in multiple cells simultaneously.
// As a consequence, ownership of BBCs is assumed to be elsewhere and
// persistent for at least the life of the BBGrid, or at least until Clear is
// called which removes all references to inserted objects without actually
// deleting them.
// Most uses derive a class from a specific instantiation of BBGrid,
// thereby making most of the ugly template notation go away.
// The friend class GridSearch, with the same template arguments, is
// used to search a grid efficiently in one of several search patterns.
template<class BBC, class BBC_CLIST, class BBC_C_IT> class BBGrid {
  friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>;
 public:
  BBGrid();
  BBGrid(int gridsize, const ICOORD& bleft, const ICOORD& tright);
  virtual ~BBGrid();

  // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
  // and bleft, tright are the bounding box of everything to go in it.
  void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);

  // Empty all the lists but leave the grid itself intact.
  void Clear();
  // Deallocate the data in the lists but otherwise leave the lists and the grid
  // intact.
  void ClearGridData(void (*free_method)(BBC*));

  // Simple accessors.
  int gridsize() const {
    return gridsize_;
  }
  int gridwidth() const {
    return gridwidth_;
  }
  int gridheight() const {
    return gridheight_;
  }
  ICOORD bleft() const {
    return bleft_;
  }
  ICOORD tright() const {
    return tright_;
  }

  // Insert a bbox into the appropriate place in the grid.
  // If h_spread, then all cells covered horizontally by the box are
  // used, otherwise, just the bottom-left. Similarly for v_spread.
  // WARNING: InsertBBox may invalidate an active GridSearch. Call
  // RepositionIterator() on any GridSearches that are active on this grid.
  void InsertBBox(bool h_spread, bool v_spread, BBC* bbox);
#ifdef HAVE_LIBLEPT
  // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
  // which each pixel corresponds to a grid cell, insert a bbox into every
  // place in the grid where the corresponding pixel is 1. The Pix is handled
  // upside-down to match the Tesseract coordinate system. (As created by
  // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
  // (0, 0) in the pix corresponds to (left, bottom) in the
  // grid (in grid coords), and the pix works up the grid from there.
  // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
  // RepositionIterator() on any GridSearches that are active on this grid.
  void InsertPixPtBBox(int left, int bottom, Pix* pix, BBC* bbox);
#endif
  // Remove the bbox from the grid.
  // WARNING: Any GridSearch operating on this grid could be invalidated!
  // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
  void RemoveBBox(BBC* bbox);

  // Compute the given grid coordinates from image coords.
  void GridCoords(int x, int y, int* grid_x, int* grid_y);

  // Clip the given grid coordinates to fit within the grid.
  void ClipGridCoords(int* x, int* y);

  // Make a window of an appropriate size to display things in the grid.
  ScrollView* MakeWindow(int x, int y, const char* window_name);

  // Display the bounding boxes of the BLOBNBOXes in this grid.
  // Use of this function requires an additional member of the BBC class:
  // ScrollView::Color BBC::BoxColor() const.
  void DisplayBoxes(ScrollView* window);

  // ASSERT_HOST that every cell contains no more than one copy of each entry.
  void AssertNoDuplicates();

  // Handle a click event in a display window.
  virtual void HandleClick(int x, int y);

 protected:
  int gridsize_;     // Pixel size of each grid cell.
  int gridwidth_;    // Size of the grid in cells.
  int gridheight_;
  int gridbuckets_;  // Total cells in grid.
  ICOORD bleft_;     // Pixel coords of bottom-left of grid.
  ICOORD tright_;    // Pixel coords of top-right of grid.
  BBC_CLIST* grid_;  // 2-d array of CLISTS of BBC elements.

 private:
};

// The GridSearch class enables neighbourhood searching on a BBGrid.
template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch {
 public:
  GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid)
      : grid_(grid), previous_return_(NULL), next_return_(NULL) {
  }

  // Get the grid x, y coords of the most recently returned BBC.
  int GridX() const {
    return x_;
  }
  int GridY() const {
    return y_;
  }
  // Apart from full search, all other searches return a box several
  // times if the box is inserted with h_spread or v_spread.
  // This method will return true for only one occurrance of each box
  // that was inserted with both h_spread and v_spread as true.
  // It will usually return false for boxes that were not inserted with
  // both h_spread=true and v_spread=true
  bool ReturnedSeedElement() const {
    TBOX box = previous_return_->bounding_box();
    int x_center = (box.left()+box.right())/2;
    int y_center = (box.top()+box.bottom())/2;
    int grid_x, grid_y;
    grid_->GridCoords(x_center, y_center, &grid_x, &grid_y);
    return (x_ == grid_x) && (y_ == grid_y);
  }

  // Various searching iterations... Note that these iterations
  // all share data members, so you can't run more than one iteration
  // in parallel in a single GridSearch instance, but multiple instances
  // can search the same BBGrid in parallel.
  // Note that all the searches can return blobs that may not exactly
  // match the search conditions, since they return everything in the
  // covered grid cells. It is up to the caller to check for
  // appropriateness.

  // Start a new full search. Will iterate all stored blobs, from the top.
  // If the blobs have been inserted using InsertBBox, (not InsertPixPtBBox)
  // then the full search guarantees to return each blob in the grid once.
  // Other searches may return a blob more than once if they have been
  // inserted using h_spread or v_spread.
  void StartFullSearch();
  // Return the next bbox in the search or NULL if done.
  BBC* NextFullSearch();

  // Start a new radius search. Will search in a spiral upto a
  // given maximum radius in grid cells from the given center in pixels.
  void StartRadSearch(int x, int y, int max_radius);
  // Return the next bbox in the radius search or NULL if the
  // maximum radius has been reached.
  BBC* NextRadSearch();

  // Start a new left or right-looking search. Will search to the side
  // for a box that vertically overlaps the given vertical line segment.
  // CAVEAT: This search returns all blobs from the cells to the side
  // of the start, and somewhat below, since there is no guarantee
  // that there may not be a taller object in a lower cell. The
  // blobs returned will include all those that vertically overlap and
  // are no more than twice as high, but may also include some that do
  // not overlap and some that are more than twice as high.
  void StartSideSearch(int x, int ymin, int ymax);
  // Return the next bbox in the side search or NULL if the
  // edge has been reached. Searches left to right or right to left
  // according to the flag.
  BBC* NextSideSearch(bool right_to_left);

  // Start a vertical-looking search. Will search up or down
  // for a box that horizontally overlaps the given line segment.
  void StartVerticalSearch(int xmin, int xmax, int y);
  // Return the next bbox in the vertical search or NULL if the
  // edge has been reached. Searches top to bottom or bottom to top
  // according to the flag.
  BBC* NextVerticalSearch(bool top_to_bottom);

  // Start a rectangular search. Will search for a box that overlaps the
  // given rectangle.
  void StartRectSearch(const TBOX& rect);
  // Return the next bbox in the rectangular search or NULL if complete.
  BBC* NextRectSearch();

  // Remove the last returned BBC. Will not invalidate this. May invalidate
  // any other concurrent GridSearch on the same grid. If any others are
  // in use, call RepositionIterator on those, to continue without harm.
  void RemoveBBox();
  void RepositionIterator();

 private:
  // Factored out helper to start a search.
  void CommonStart(int x, int y);
  // Factored out helper to complete a next search.
  BBC* CommonNext();
  // Factored out final return when search is exhausted.
  BBC* CommonEnd();
  // Factored out function to set the iterator to the current x_, y_
  // grid coords and mark the cycle pt.
  void SetIterator();

 private:
  // The grid we are searching.
  BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid_;
  // For executing a search. The different search algorithms use these in
  // different ways, but most use x_origin_ and y_origin_ as the start position.
  int x_origin_;
  int y_origin_;
  int max_radius_;
  int radius_;
  int rad_index_;
  int rad_dir_;
  TBOX rect_;
  int x_;  // The current location in grid coords, of the current search.
  int y_;
  BBC* previous_return_;  // Previous return from Next*.
  BBC* next_return_;  // Current value of it_.data() used for repositioning.
  // An iterator over the list at (x_, y_) in the grid_.
  BBC_C_IT it_;
};

// Sort function to sort a BBC by bounding_box().left().
template<class BBC>
int SortByBoxLeft(const void* void1, const void* void2) {
  // The void*s are actually doubly indirected, so get rid of one level.
  const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
  const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
  return p1->bounding_box().left() - p2->bounding_box().left();
}

///////////////////////////////////////////////////////////////////////
// BBGrid IMPLEMENTATION.
///////////////////////////////////////////////////////////////////////
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid() : grid_(NULL) {
}

template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid(
  int gridsize, const ICOORD& bleft, const ICOORD& tright)
    : grid_(NULL) {
  Init(gridsize, bleft, tright);
}

template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() {
  if (grid_ != NULL)
    delete [] grid_;
}

// (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
// and bleft, tright are the bounding box of everything to go in it.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Init(int gridsize,
                                            const ICOORD& bleft,
                                            const ICOORD& tright) {
  gridsize_ = gridsize;
  bleft_ = bleft;
  tright_ = tright;
  if (grid_ != NULL)
    delete [] grid_;
  if (gridsize_ == 0)
    gridsize_ = 1;
  gridwidth_ = (tright.x() - bleft.x() + gridsize_ - 1) / gridsize_;
  gridheight_ = (tright.y() - bleft.y() + gridsize_ - 1) / gridsize_;
  gridbuckets_ = gridwidth_ * gridheight_;
  grid_ = new BBC_CLIST[gridbuckets_];
}

// Clear all lists, but leave the array of lists present.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Clear() {
  for (int i = 0; i < gridbuckets_; ++i) {
    grid_[i].shallow_clear();
  }
}

// Deallocate the data in the lists but otherwise leave the lists and the grid
// intact.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClearGridData(
    void (*free_method)(BBC*)) {
  if (grid_ == NULL) return;
  GridSearch<BBC, BBC_CLIST, BBC_C_IT> search(this);
  search.StartFullSearch();
  BBC* bb;
  BBC_CLIST bb_list;
  BBC_C_IT it(&bb_list);
  while ((bb = search.NextFullSearch()) != NULL) {
    it.add_after_then_move(bb);
  }
  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
    free_method(it.data());
  }
}

// Insert a bbox into the appropriate place in the grid.
// If h_spread, then all cells covered horizontally by the box are
// used, otherwise, just the bottom-left. Similarly for v_spread.
// WARNING: InsertBBox may invalidate an active GridSearch. Call
// RepositionIterator() on any GridSearches that are active on this grid.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread,
                                                  BBC* bbox) {
  TBOX box = bbox->bounding_box();
  int start_x, start_y, end_x, end_y;
  GridCoords(box.left(), box.bottom(), &start_x, &start_y);
  GridCoords(box.right(), box.top(), &end_x, &end_y);
  if (!h_spread)
    end_x = start_x;
  if (!v_spread)
    end_y = start_y;
  int grid_index = start_y * gridwidth_;
  for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
    for (int x = start_x; x <= end_x; ++x) {
      grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox);
    }
  }
}

#ifdef HAVE_LIBLEPT
// Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
// which each pixel corresponds to a grid cell, insert a bbox into every
// place in the grid where the corresponding pixel is 1. The Pix is handled
// upside-down to match the Tesseract coordinate system. (As created by
// TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
// (0, 0) in the pix corresponds to (left, bottom) in the
// grid (in grid coords), and the pix works up the grid from there.
// WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
// RepositionIterator() on any GridSearches that are active on this grid.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertPixPtBBox(int left, int bottom,
                                                       Pix* pix, BBC* bbox) {
  int width = pixGetWidth(pix);
  int height = pixGetHeight(pix);
  for (int y = 0; y < height; ++y) {
    l_uint32* data = pixGetData(pix) + y * pixGetWpl(pix);
    for (int x = 0; x < width; ++x) {
      if (GET_DATA_BIT(data, x)) {
        grid_[(bottom + y) * gridwidth_ + x + left].
          add_sorted(SortByBoxLeft<BBC>, true, bbox);
      }
    }
  }
}
#endif

// Remove the bbox from the grid.
// WARNING: Any GridSearch operating on this grid could be invalidated!
// If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox(BBC* bbox) {
  TBOX box = bbox->bounding_box();
  int start_x, start_y, end_x, end_y;
  GridCoords(box.left(), box.bottom(), &start_x, &start_y);
  GridCoords(box.right(), box.top(), &end_x, &end_y);
  int grid_index = start_y * gridwidth_;
  for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
    for (int x = start_x; x <= end_x; ++x) {
      BBC_C_IT it(&grid_[grid_index + x]);
      for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
        if (it.data() == bbox)
          it.extract();
      }
    }
  }
}

// Compute the given grid coordinates from image coords.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::GridCoords(int x, int y,
                                                  int* grid_x, int* grid_y) {
  *grid_x = (x - bleft_.x()) / gridsize_;
  *grid_y = (y - bleft_.y()) / gridsize_;
  ClipGridCoords(grid_x, grid_y);
}

// Clip the given grid coordinates to fit within the grid.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClipGridCoords(int* x, int* y) {
  if (*x < 0) *x = 0;
  if (*x >= gridwidth_) *x = gridwidth_ - 1;
  if (*y < 0) *y = 0;
  if (*y >= gridheight_) *y = gridheight_ - 1;
}

template<class G> class TabEventHandler : public SVEventHandler {
 public:
  explicit TabEventHandler(G* grid) : grid_(grid) {
  }
  void Notify(const SVEvent* sv_event) {
    if (sv_event->type == SVET_CLICK) {
      grid_->HandleClick(sv_event->x, sv_event->y);
    }
  }
 private:
  G* grid_;
};

// Make a window of an appropriate size to display things in the grid.
// Position the window at the given x,y.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
ScrollView* BBGrid<BBC, BBC_CLIST, BBC_C_IT>::MakeWindow(
    int x, int y, const char* window_name) {
  ScrollView* tab_win = NULL;
#ifndef GRAPHICS_DISABLED
  tab_win = new ScrollView(window_name, x, y,
                           tright_.x() - bleft_.x(),
                           tright_.y() - bleft_.y(),
                           tright_.x() - bleft_.x(),
                           tright_.y() - bleft_.y(),
                           true);
  TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >* handler =
    new TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >(this);
  tab_win->AddEventHandler(handler);
  tab_win->Pen(ScrollView::GREY);
  tab_win->Rectangle(0, 0, tright_.x(), tright_.y());
#endif
  return tab_win;
}

// Create a window at (x,y) and display the bounding boxes of the
// BLOBNBOXes in this grid.
// Use of this function requires an additional member of the BBC class:
// ScrollView::Color BBC::BoxColor() const.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::DisplayBoxes(ScrollView* tab_win) {
#ifndef GRAPHICS_DISABLED
  tab_win->Pen(ScrollView::BLUE);
  tab_win->Brush(ScrollView::NONE);

  // For every bbox in the grid, display it.
  GridSearch<BBC, BBC_CLIST, BBC_C_IT> gsearch(this);
  gsearch.StartFullSearch();
  BBC* bbox;
  while ((bbox = gsearch.NextFullSearch()) != NULL) {
    TBOX box = bbox->bounding_box();
    int left_x = box.left();
    int right_x = box.right();
    int top_y = box.top();
    int bottom_y = box.bottom();
    ScrollView::Color box_color = bbox->BoxColor();
    tab_win->Pen(box_color);
    tab_win->Rectangle(left_x, bottom_y, right_x, top_y);
  }
  tab_win->Update();
#endif
}

// ASSERT_HOST that every cell contains no more than one copy of each entry.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::AssertNoDuplicates() {
  // Process all grid cells.
  for (int i = gridwidth_ * gridheight_ - 1; i >= 0; --i) {
    // Iterate over all elements excent the last.
    for (BBC_C_IT it(&grid_[i]); !it.at_last(); it.forward()) {
      BBC* ptr = it.data();
      BBC_C_IT it2(it);
      // None of the rest of the elements in the list should equal ptr.
      for (it2.forward(); !it2.at_first(); it2.forward()) {
        ASSERT_HOST(it2.data() != ptr);
      }
    }
  }
}

// Handle a click event in a display window.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::HandleClick(int x, int y) {
  tprintf("Click at (%d, %d)\n", x, y);
}

///////////////////////////////////////////////////////////////////////
// GridSearch IMPLEMENTATION.
///////////////////////////////////////////////////////////////////////

// Start a new full search. Will iterate all stored blobs.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartFullSearch() {
  // Full search uses x_ and y_ as the current grid
  // cell being searched.
  CommonStart(grid_->bleft_.x(), grid_->tright_.y());
}

// Return the next bbox in the search or NULL if done.
// The other searches will return a box that overlaps the grid cell
// thereby duplicating boxes, but NextFullSearch only returns each box once.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextFullSearch() {
  int x;
  int y;
  do {
    while (it_.cycled_list()) {
      ++x_;
      if (x_ >= grid_->gridwidth_) {
        --y_;
        if (y_ < 0)
          return CommonEnd();
        x_ = 0;
      }
      SetIterator();
    }
    CommonNext();
    TBOX box = previous_return_->bounding_box();
    grid_->GridCoords(box.left(), box.bottom(), &x, &y);
  } while (x != x_ || y != y_);
  return previous_return_;
}

// Start a new radius search.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRadSearch(int x, int y,
                                                          int max_radius) {
  // Rad search uses x_origin_ and y_origin_ as the center of the circle.
  // The radius_ is the radius of the (diamond-shaped) circle and
  // rad_index/rad_dir_ combine to determine the position around it.
  max_radius_ = max_radius;
  radius_ = 0;
  rad_index_ = 0;
  rad_dir_ = 3;
  CommonStart(x, y);
}

// Return the next bbox in the radius search or NULL if the
// maximum radius has been reached.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRadSearch() {
  while (it_.cycled_list()) {
    ++rad_index_;
    if (rad_index_ >= radius_) {
      ++rad_dir_;
      rad_index_ = 0;
      if (rad_dir_ >= 4) {
        ++radius_;
        if (radius_ > max_radius_)
          return CommonEnd();
        rad_dir_ = 0;
      }
    }
    ICOORD offset = C_OUTLINE::chain_step(rad_dir_);
    offset *= radius_ - rad_index_;
    offset += C_OUTLINE::chain_step(rad_dir_ + 1) * rad_index_;
    x_ = x_origin_ + offset.x();
    y_ = y_origin_ + offset.y();
    if (x_ >= 0 && x_ < grid_->gridwidth_ &&
        y_ >= 0 && y_ < grid_->gridheight_)
      SetIterator();
  }
  return CommonNext();
}

// Start a new left or right-looking search. Will search to the side
// for a box that vertically overlaps the given vertical line segment.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartSideSearch(int x,
                                                           int ymin, int ymax) {
  // Right search records the x in x_origin_, the ymax in y_origin_
  // and the size of the vertical strip to search in radius_.
  // To guarantee finding overlapping objects of upto twice the
  // given size, double the height.
  radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_;
  rad_index_ = 0;
  CommonStart(x, ymax);
}

// Return the next bbox in the side search or NULL if the
// edge has been reached. Searches left to right or right to left
// according to the flag.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextSideSearch(bool right_to_left) {
  while (it_.cycled_list()) {
    ++rad_index_;
    if (rad_index_ > radius_) {
      if (right_to_left)
        --x_;
      else
        ++x_;
      rad_index_ = 0;
      if (x_ < 0 || x_ >= grid_->gridwidth_)
        return CommonEnd();
    }
    y_ = y_origin_ - rad_index_;
    if (y_ >= 0 && y_ < grid_->gridheight_)
      SetIterator();
  }
  return CommonNext();
}

// Start a vertical-looking search. Will search up or down
// for a box that horizontally overlaps the given line segment.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartVerticalSearch(int xmin,
                                                               int xmax,
                                                               int y) {
  // Right search records the xmin in x_origin_, the y in y_origin_
  // and the size of the horizontal strip to search in radius_.
  radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_;
  rad_index_ = 0;
  CommonStart(xmin, y);
}

// Return the next bbox in the vertical search or NULL if the
// edge has been reached. Searches top to bottom or bottom to top
// according to the flag.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextVerticalSearch(
    bool top_to_bottom) {
  while (it_.cycled_list()) {
    ++rad_index_;
    if (rad_index_ > radius_) {
      if (top_to_bottom)
        --y_;
      else
        ++y_;
      rad_index_ = 0;
      if (y_ < 0 || y_ >= grid_->gridheight_)
        return CommonEnd();
    }
    x_ = x_origin_ + rad_index_;
    if (x_ >= 0 && x_ < grid_->gridwidth_)
      SetIterator();
  }
  return CommonNext();
}

// Start a rectangular search. Will search for a box that overlaps the
// given rectangle.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRectSearch(const TBOX& rect) {
  // Rect search records the xmin in x_origin_, the ymin in y_origin_
  // and the xmax in max_radius_.
  // The search proceeds left to right, top to bottom.
  rect_ = rect;
  CommonStart(rect.left(), rect.top());
  grid_->GridCoords(rect.right(), rect.bottom(),  // - rect.height(),
                    &max_radius_, &y_origin_);
}

// Return the next bbox in the rectangular search or NULL if complete.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRectSearch() {
  while (it_.cycled_list()) {
    ++x_;
    if (x_ > max_radius_) {
      --y_;
      x_ = x_origin_;
      if (y_ < y_origin_)
        return CommonEnd();
    }
    SetIterator();
  }
  return CommonNext();
}

// Remove the last returned BBC. Will not invalidate this. May invalidate
// any other concurrent GridSearch on the same grid. If any others are
// in use, call RepositionIterator on those, to continue without harm.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox() {
  if (previous_return_ != NULL) {
    // Remove all instances of previous_return_ from the list, so the iterator
    // remains valid after removal from the rest of the grid cells.
    // if previous_return_ is not on the list, then it has been removed already.
    BBC* prev_data = NULL;
    BBC* new_previous_return = NULL;
    it_.move_to_first();
    for (it_.mark_cycle_pt(); !it_.cycled_list();) {
      if (it_.data() ==  previous_return_) {
        new_previous_return = prev_data;
        it_.extract();
        it_.forward();
        next_return_ = it_.cycled_list() ? NULL : it_.data();
      } else {
        prev_data = it_.data();
        it_.forward();
      }
    }
    grid_->RemoveBBox(previous_return_);
    previous_return_ = new_previous_return;
    RepositionIterator();
  }
}

template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RepositionIterator() {
  // Reset the iterator back to one past the previous return.
  // If the previous_return_ is no longer in the list, then
  // next_return_ serves as a backup.
  it_.move_to_first();
  for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) {
    if (it_.data() == previous_return_ ||
        it_.data_relative(1) == next_return_) {
      CommonNext();
      return;
    }
  }
  // We ran off the end of the list. Move to a new cell next time.
  previous_return_ = NULL;
  next_return_ = NULL;
}

// Factored out helper to start a search.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonStart(int x, int y) {
  grid_->GridCoords(x, y, &x_origin_, &y_origin_);
  x_ = x_origin_;
  y_ = y_origin_;
  SetIterator();
  previous_return_ = NULL;
  next_return_ = it_.empty() ? NULL : it_.data();
}

// Factored out helper to complete a next search.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() {
  previous_return_ = it_.data();
  it_.forward();
  next_return_ = it_.cycled_list() ? NULL : it_.data();
  return previous_return_;
}

// Factored out final return when search is exhausted.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() {
  previous_return_ = NULL;
  next_return_ = NULL;
  return NULL;
}

// Factored out function to set the iterator to the current x_, y_
// grid coords and mark the cycle pt.
template<class BBC, class BBC_CLIST, class BBC_C_IT>
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() {
  it_= &(grid_->grid_[y_ * grid_->gridwidth_ + x_]);
  it_.mark_cycle_pt();
}

}  // namespace tesseract.

#endif  // TESSERACT_TEXTORD_BBGRID_H__