20#ifndef TESSERACT_TEXTORD_BBGRID_H_
21#define TESSERACT_TEXTORD_BBGRID_H_
23#include <unordered_set>
30#include <allheaders.h>
47template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
60 void Init(
int gridsize,
const ICOORD &bleft,
const ICOORD &tright);
79 void GridCoords(
int x,
int y,
int *grid_x,
int *grid_y)
const;
82 void ClipGridCoords(
int *
x,
int *
y)
const;
158template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
160 friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>;
207#ifndef GRAPHICS_DISABLED
232template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
261 TBOX box = previous_return_->bounding_box();
262 int x_center = (box.
left() + box.
right()) / 2;
263 int y_center = (box.
top() + box.
bottom()) / 2;
265 grid_->GridCoords(x_center, y_center, &grid_x, &grid_y);
266 return (x_ == grid_x) && (y_ == grid_y);
333 void CommonStart(
int x,
int y);
356 bool unique_mode_ =
false;
357 BBC *previous_return_ =
nullptr;
358 BBC *next_return_ =
nullptr;
362 std::unordered_set<BBC *> returns_;
369 const BBC *p1 = *
static_cast<const BBC *
const *
>(void1);
370 const BBC *p2 = *
static_cast<const BBC *
const *
>(void2);
371 int result = p1->bounding_box().left() - p2->bounding_box().left();
375 result = p1->bounding_box().right() - p2->bounding_box().right();
379 result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
383 return p1->bounding_box().top() - p2->bounding_box().top();
389 const BBC *p1 = *
static_cast<const BBC *
const *
>(void1);
390 const BBC *p2 = *
static_cast<const BBC *
const *
>(void2);
391 int result = p1->bounding_box().left() - p2->bounding_box().left();
395 result = p1->bounding_box().right() - p2->bounding_box().right();
399 result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
403 return p1->bounding_box().top() < p2->bounding_box().top();
410 const BBC *p1 = *
static_cast<const BBC *
const *
>(void1);
411 const BBC *p2 = *
static_cast<const BBC *
const *
>(void2);
412 int result = p2->bounding_box().right() - p1->bounding_box().right();
416 result = p2->bounding_box().left() - p1->bounding_box().left();
420 result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
424 return p1->bounding_box().top() - p2->bounding_box().top();
430 const BBC *p1 = *
static_cast<const BBC *
const *
>(void1);
431 const BBC *p2 = *
static_cast<const BBC *
const *
>(void2);
432 int result = p2->bounding_box().right() - p1->bounding_box().right();
436 result = p2->bounding_box().left() - p1->bounding_box().left();
440 result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
444 return p1->bounding_box().top() < p2->bounding_box().top();
451 const BBC *p1 = *
static_cast<const BBC *
const *
>(void1);
452 const BBC *p2 = *
static_cast<const BBC *
const *
>(void2);
453 int result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
457 result = p1->bounding_box().top() - p2->bounding_box().top();
461 result = p1->bounding_box().left() - p2->bounding_box().left();
465 return p1->bounding_box().right() - p2->bounding_box().right();
471template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
474template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
480template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
487template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
492 grid_ =
new BBC_CLIST[gridbuckets_];
496template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
498 for (
int i = 0;
i < gridbuckets_; ++
i) {
499 grid_[
i].shallow_clear();
505template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
507 if (grid_ ==
nullptr) {
514 BBC_C_IT it(&bb_list);
515 while ((bb =
search.NextFullSearch()) !=
nullptr) {
516 it.add_after_then_move(bb);
518 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
519 free_method(it.data());
528template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
530 TBOX box = bbox->bounding_box();
531 int start_x, start_y, end_x, end_y;
532 GridCoords(box.
left(), box.
bottom(), &start_x, &start_y);
533 GridCoords(box.
right(), box.
top(), &end_x, &end_y);
540 int grid_index = start_y * gridwidth_;
541 for (
int y = start_y;
y <= end_y; ++
y, grid_index += gridwidth_) {
542 for (
int x = start_x;
x <= end_x; ++
x) {
543 grid_[grid_index +
x].add_sorted(SortByBoxLeft<BBC>,
true, bbox);
557template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
559 int width = pixGetWidth(pix);
560 int height = pixGetHeight(pix);
561 for (
int y = 0;
y < height; ++
y) {
562 l_uint32 *data = pixGetData(pix) +
y * pixGetWpl(pix);
563 for (
int x = 0;
x < width; ++
x) {
564 if (GET_DATA_BIT(data,
x)) {
565 grid_[(bottom +
y) * gridwidth_ +
x + left].add_sorted(SortByBoxLeft<BBC>,
true, bbox);
574template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
576 TBOX box = bbox->bounding_box();
577 int start_x, start_y, end_x, end_y;
578 GridCoords(box.
left(), box.
bottom(), &start_x, &start_y);
579 GridCoords(box.
right(), box.
top(), &end_x, &end_y);
580 int grid_index = start_y * gridwidth_;
581 for (
int y = start_y;
y <= end_y; ++
y, grid_index += gridwidth_) {
582 for (
int x = start_x;
x <= end_x; ++
x) {
583 BBC_C_IT it(&grid_[grid_index +
x]);
584 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
585 if (it.data() == bbox) {
594template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
603template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
605 auto *intgrid =
new IntGrid(gridsize(), bleft(), tright());
606 for (
int y = 0;
y < gridheight(); ++
y) {
607 for (
int x = 0;
x < gridwidth(); ++
x) {
608 int cell_count = grid_[
y * gridwidth() +
x].length();
609 intgrid->SetGridCell(
x,
y, cell_count);
615#ifndef GRAPHICS_DISABLED
622 grid_->HandleClick(sv_event->
x, sv_event->
y);
632template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
635 new ScrollView(window_name,
x,
y, tright_.x() - bleft_.x(), tright_.y() - bleft_.y(),
636 tright_.x() - bleft_.x(), tright_.y() - bleft_.y(),
true);
638 tab_win->AddEventHandler(handler);
640 tab_win->Rectangle(0, 0, tright_.x() - bleft_.x(), tright_.y() - bleft_.y());
648template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
658 const TBOX &box = bbox->bounding_box();
659 int left_x = box.
left();
660 int right_x = box.
right();
661 int top_y = box.
top();
662 int bottom_y = box.
bottom();
664 tab_win->
Pen(box_color);
665 tab_win->
Rectangle(left_x, bottom_y, right_x, top_y);
673template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
676 for (
int i = gridwidth_ * gridheight_ - 1;
i >= 0; --
i) {
678 for (BBC_C_IT it(&grid_[
i]); !it.at_last(); it.forward()) {
679 BBC *ptr = it.data();
682 for (it2.forward(); !it2.at_first(); it2.forward()) {
690template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
700template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
704 CommonStart(grid_->bleft_.x(), grid_->tright_.y());
710template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
715 while (it_.cycled_list()) {
717 if (x_ >= grid_->gridwidth_) {
727 TBOX box = previous_return_->bounding_box();
729 }
while (
x != x_ ||
y != y_);
730 return previous_return_;
734template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
739 max_radius_ = max_radius;
748template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
751 while (it_.cycled_list()) {
753 if (rad_index_ >= radius_) {
758 if (radius_ > max_radius_) {
765 offset *= radius_ - rad_index_;
767 x_ = x_origin_ + offset.
x();
768 y_ = y_origin_ + offset.
y();
769 if (x_ >= 0 && x_ < grid_->gridwidth_ && y_ >= 0 && y_ < grid_->gridheight_) {
777 auto inserted = returns_.insert(previous_return_);
778 if (inserted.second) {
782 return previous_return_;
787template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
793 radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_;
795 CommonStart(
x, ymax);
801template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
804 while (it_.cycled_list()) {
806 if (rad_index_ > radius_) {
813 if (x_ < 0 || x_ >= grid_->gridwidth_) {
817 y_ = y_origin_ - rad_index_;
818 if (y_ >= 0 && y_ < grid_->gridheight_) {
826 auto inserted = returns_.insert(previous_return_);
827 if (inserted.second) {
831 return previous_return_;
836template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
840 radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_;
842 CommonStart(xmin,
y);
848template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
851 while (it_.cycled_list()) {
853 if (rad_index_ > radius_) {
860 if (y_ < 0 || y_ >= grid_->gridheight_) {
864 x_ = x_origin_ + rad_index_;
865 if (x_ >= 0 && x_ < grid_->gridwidth_) {
873 auto inserted = returns_.insert(previous_return_);
874 if (inserted.second) {
878 return previous_return_;
883template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
889 CommonStart(rect.
left(), rect.
top());
891 &max_radius_, &y_origin_);
895template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
898 while (it_.cycled_list()) {
900 if (x_ > max_radius_) {
903 if (y_ < y_origin_) {
910 if (!rect_.overlap(previous_return_->bounding_box())) {
916 auto inserted = returns_.insert(previous_return_);
917 if (inserted.second) {
921 return previous_return_;
927template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
929 if (previous_return_ !=
nullptr) {
933 BBC *prev_data =
nullptr;
934 BBC *new_previous_return =
nullptr;
936 for (it_.mark_cycle_pt(); !it_.cycled_list();) {
937 if (it_.data() == previous_return_) {
938 new_previous_return = prev_data;
941 next_return_ = it_.cycled_list() ? nullptr : it_.data();
943 prev_data = it_.data();
948 previous_return_ = new_previous_return;
949 RepositionIterator();
953template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
965 if (!it_.empty() && it_.data() == next_return_) {
969 for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) {
970 if (it_.data() == previous_return_ || it_.data_relative(1) == next_return_) {
976 previous_return_ =
nullptr;
977 next_return_ =
nullptr;
981template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
983 grid_->GridCoords(
x,
y, &x_origin_, &y_origin_);
987 previous_return_ =
nullptr;
988 next_return_ = it_.empty() ? nullptr : it_.data();
993template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
994BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() {
995 previous_return_ = it_.data();
997 next_return_ = it_.cycled_list() ? nullptr : it_.data();
998 return previous_return_;
1002template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
1003BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() {
1004 previous_return_ =
nullptr;
1005 next_return_ =
nullptr;
1011template <
class BBC,
class BBC_CLIST,
class BBC_C_IT>
1012void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() {
1013 it_ = &(grid_->grid_[y_ * grid_->gridwidth_ + x_]);
1014 it_.mark_cycle_pt();
void tprintf(const char *format,...)
bool StdSortRightToLeft(const void *void1, const void *void2)
int SortByBoxBottom(const void *void1, const void *void2)
Image TraceOutlineOnReducedPix(C_OUTLINE *outline, int gridsize, ICOORD bleft, int *left, int *bottom)
Image TraceBlockOnReducedPix(BLOCK *block, int gridsize, ICOORD bleft, int *left, int *bottom)
int SortByBoxLeft(const void *void1, const void *void2)
bool StdSortByBoxLeft(const void *void1, const void *void2)
LIST search(LIST list, void *key, int_compare is_equal)
int SortRightToLeft(const void *void1, const void *void2)
static ICOORD chain_step(int chaindir)
TDimension y() const
access_function
TDimension x() const
access function
TDimension bottom() const
bool ReturnedSeedElement() const
void StartVerticalSearch(int xmin, int xmax, int y)
void StartRadSearch(int x, int y, int max_radius)
void SetUniqueMode(bool mode)
GridSearch(BBGrid< BBC, BBC_CLIST, BBC_C_IT > *grid)
BBC * NextSideSearch(bool right_to_left)
void StartSideSearch(int x, int ymin, int ymax)
BBC * NextVerticalSearch(bool top_to_bottom)
void RepositionIterator()
void StartRectSearch(const TBOX &rect)
void ClipGridCoords(int *x, int *y) const
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
const ICOORD & bleft() const
const ICOORD & tright() const
IntGrid * NeighbourhoodSum() const
int GridCellValue(int grid_x, int grid_y) const
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
bool RectMostlyOverThreshold(const TBOX &rect, int threshold) const
Image ThresholdToPix(int threshold) const
void SetGridCell(int grid_x, int grid_y, int value)
void Rotate(const FCOORD &rotation)
bool AnyZeroInRect(const TBOX &rect) const
void DisplayBoxes(ScrollView *window)
void AssertNoDuplicates()
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
IntGrid * CountCellElements()
void InsertBBox(bool h_spread, bool v_spread, BBC *bbox)
virtual void HandleClick(int x, int y)
void ClearGridData(void(*free_method)(BBC *))
void InsertPixPtBBox(int left, int bottom, Image pix, BBC *bbox)
ScrollView * MakeWindow(int x, int y, const char *window_name)
bool RectangleEmpty(const TBOX &rect)
void RemoveBBox(BBC *bbox)
BBGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright)
void Notify(const SVEvent *sv_event) override
void Rectangle(int x1, int y1, int x2, int y2)