Coverage Report

Created: 2026-07-25 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tesseract/src/textord/bbgrid.h
Line
Count
Source
1
///////////////////////////////////////////////////////////////////////
2
// File:        bbgrid.h
3
// Description: Class to hold BLOBNBOXs in a grid for fast access
4
//              to neighbours.
5
// Author:      Ray Smith
6
//
7
// (C) Copyright 2007, Google Inc.
8
// Licensed under the Apache License, Version 2.0 (the "License");
9
// you may not use this file except in compliance with the License.
10
// You may obtain a copy of the License at
11
// http://www.apache.org/licenses/LICENSE-2.0
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17
//
18
///////////////////////////////////////////////////////////////////////
19
20
#ifndef TESSERACT_TEXTORD_BBGRID_H_
21
#define TESSERACT_TEXTORD_BBGRID_H_
22
23
#include <unordered_set>
24
25
#include "clst.h"
26
#include "coutln.h"
27
#include "image.h"      // for Image
28
#include "rect.h"
29
#include "scrollview.h"
30
31
class BLOCK;
32
33
namespace tesseract {
34
35
// Helper function to return a scaled Pix with one pixel per grid cell,
36
// set (black) where the given outline enters the corresponding grid cell,
37
// and clear where the outline does not touch the grid cell.
38
// Also returns the grid coords of the bottom-left of the Pix, in *left
39
// and *bottom, which corresponds to (0, 0) on the Pix.
40
// Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
41
Image TraceOutlineOnReducedPix(C_OUTLINE *outline, int gridsize, ICOORD bleft, int *left,
42
                              int *bottom);
43
// As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
44
Image TraceBlockOnReducedPix(BLOCK *block, int gridsize, ICOORD bleft, int *left, int *bottom);
45
46
template <class BBC, class BBC_CLIST, class BBC_C_IT>
47
class GridSearch;
48
49
// The GridBase class is the base class for BBGrid and IntGrid.
50
// It holds the geometry and scale of the grid.
51
class TESS_API GridBase {
52
public:
53
13.8k
  GridBase() = default;
54
  GridBase(int gridsize, const ICOORD &bleft, const ICOORD &tright);
55
  virtual ~GridBase();
56
57
  // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
58
  // and bleft, tright are the bounding box of everything to go in it.
59
  void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright);
60
61
  // Simple accessors.
62
0
  int gridsize() const {
63
0
    return gridsize_;
64
0
  }
65
0
  int gridwidth() const {
66
0
    return gridwidth_;
67
0
  }
68
0
  int gridheight() const {
69
0
    return gridheight_;
70
0
  }
71
0
  const ICOORD &bleft() const {
72
0
    return bleft_;
73
0
  }
74
0
  const ICOORD &tright() const {
75
0
    return tright_;
76
0
  }
77
  // Compute the given grid coordinates from image coords.
78
  void GridCoords(int x, int y, int *grid_x, int *grid_y) const;
79
80
  // Clip the given grid coordinates to fit within the grid.
81
  void ClipGridCoords(int *x, int *y) const;
82
83
protected:
84
  // TODO(rays) Make these private and migrate to the accessors in subclasses.
85
  int gridsize_;  // Pixel size of each grid cell.
86
  int gridwidth_; // Size of the grid in cells.
87
  int gridheight_;
88
  int gridbuckets_; // Total cells in grid.
89
  ICOORD bleft_;    // Pixel coords of bottom-left of grid.
90
  ICOORD tright_;   // Pixel coords of top-right of grid.
91
92
private:
93
};
94
95
// The IntGrid maintains a single int for each cell in a grid.
96
class IntGrid : public GridBase {
97
public:
98
  IntGrid();
99
  IntGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright);
100
  ~IntGrid() override;
101
102
  // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
103
  // and bleft, tright are the bounding box of everything to go in it.
104
  void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright);
105
106
  // Clear all the ints in the grid to zero.
107
  void Clear();
108
109
  // Rotate the grid by rotation, keeping cell contents.
110
  // rotation must be a multiple of 90 degrees.
111
  // NOTE: due to partial cells, cell coverage in the rotated grid will be
112
  // inexact. This is why there is no Rotate for the generic BBGrid.
113
  void Rotate(const FCOORD &rotation);
114
115
  // Returns a new IntGrid containing values equal to the sum of all the
116
  // neighbouring cells. The returned grid must be deleted after use.
117
  IntGrid *NeighbourhoodSum() const;
118
119
0
  int GridCellValue(int grid_x, int grid_y) const {
120
0
    ClipGridCoords(&grid_x, &grid_y);
121
0
    return grid_[grid_y * gridwidth_ + grid_x];
122
0
  }
123
0
  void SetGridCell(int grid_x, int grid_y, int value) {
124
0
    ASSERT_HOST(grid_x >= 0 && grid_x < gridwidth());
125
0
    ASSERT_HOST(grid_y >= 0 && grid_y < gridheight());
126
0
    grid_[grid_y * gridwidth_ + grid_x] = value;
127
0
  }
128
  // Returns true if more than half the area of the rect is covered by grid
129
  // cells that are over the threshold.
130
  bool RectMostlyOverThreshold(const TBOX &rect, int threshold) const;
131
132
  // Returns true if any cell value in the given rectangle is zero.
133
  bool AnyZeroInRect(const TBOX &rect) const;
134
135
  // Returns a full-resolution binary pix in which each cell over the given
136
  // threshold is filled as a black square. pixDestroy after use.
137
  Image ThresholdToPix(int threshold) const;
138
139
private:
140
  int *grid_; // 2-d array of ints.
141
};
142
143
// The BBGrid class holds C_LISTs of template classes BBC (bounding box class)
144
// in a grid for fast neighbour access.
145
// The BBC class must have a member const TBOX& bounding_box() const.
146
// The BBC class must have been CLISTIZEH'ed elsewhere to make the
147
// list class BBC_CLIST and the iterator BBC_C_IT.
148
// Use of C_LISTs enables BBCs to exist in multiple cells simultaneously.
149
// As a consequence, ownership of BBCs is assumed to be elsewhere and
150
// persistent for at least the life of the BBGrid, or at least until Clear is
151
// called which removes all references to inserted objects without actually
152
// deleting them.
153
// Most uses derive a class from a specific instantiation of BBGrid,
154
// thereby making most of the ugly template notation go away.
155
// The friend class GridSearch, with the same template arguments, is
156
// used to search a grid efficiently in one of several search patterns.
157
template <class BBC, class BBC_CLIST, class BBC_C_IT>
158
class BBGrid : public GridBase {
159
  friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>;
160
161
public:
162
  BBGrid();
163
  BBGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright);
164
  ~BBGrid() override;
165
166
  // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
167
  // and bleft, tright are the bounding box of everything to go in it.
168
  void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright);
169
170
  // Empty all the lists but leave the grid itself intact.
171
  void Clear();
172
  // Deallocate the data in the lists but otherwise leave the lists and the grid
173
  // intact.
174
  void ClearGridData(void (*free_method)(BBC *));
175
176
  // Insert a bbox into the appropriate place in the grid.
177
  // If h_spread, then all cells covered horizontally by the box are
178
  // used, otherwise, just the bottom-left. Similarly for v_spread.
179
  // WARNING: InsertBBox may invalidate an active GridSearch. Call
180
  // RepositionIterator() on any GridSearches that are active on this grid.
181
  void InsertBBox(bool h_spread, bool v_spread, BBC *bbox);
182
183
  // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
184
  // which each pixel corresponds to a grid cell, insert a bbox into every
185
  // place in the grid where the corresponding pixel is 1. The Pix is handled
186
  // upside-down to match the Tesseract coordinate system. (As created by
187
  // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
188
  // (0, 0) in the pix corresponds to (left, bottom) in the
189
  // grid (in grid coords), and the pix works up the grid from there.
190
  // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
191
  // RepositionIterator() on any GridSearches that are active on this grid.
192
  void InsertPixPtBBox(int left, int bottom, Image pix, BBC *bbox);
193
194
  // Remove the bbox from the grid.
195
  // WARNING: Any GridSearch operating on this grid could be invalidated!
196
  // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
197
  void RemoveBBox(BBC *bbox);
198
199
  // Returns true if the given rectangle has no overlapping elements.
200
  bool RectangleEmpty(const TBOX &rect);
201
202
  // Returns an IntGrid showing the number of elements in each cell.
203
  // Returned IntGrid must be deleted after use.
204
  IntGrid *CountCellElements();
205
206
#ifndef GRAPHICS_DISABLED
207
208
  // Make a window of an appropriate size to display things in the grid.
209
  ScrollView *MakeWindow(int x, int y, const char *window_name);
210
211
  // Display the bounding boxes of the BLOBNBOXes in this grid.
212
  // Use of this function requires an additional member of the BBC class:
213
  // ScrollView::Color BBC::BoxColor() const.
214
  void DisplayBoxes(ScrollView *window);
215
216
#endif // !GRAPHICS_DISABLED
217
218
  // ASSERT_HOST that every cell contains no more than one copy of each entry.
219
  void AssertNoDuplicates();
220
221
  // Handle a click event in a display window.
222
  virtual void HandleClick(int x, int y);
223
224
protected:
225
  BBC_CLIST *grid_; // 2-d array of CLISTS of BBC elements.
226
227
private:
228
};
229
230
// The GridSearch class enables neighbourhood searching on a BBGrid.
231
template <class BBC, class BBC_CLIST, class BBC_C_IT>
232
class GridSearch {
233
public:
234
13.8k
  GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid) : grid_(grid) {}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>*)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>*)
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>*)
tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>*)
Line
Count
Source
234
13.8k
  GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid) : grid_(grid) {}
235
236
  // Get the grid x, y coords of the most recently returned BBC.
237
0
  int GridX() const {
238
0
    return x_;
239
0
  }
240
0
  int GridY() const {
241
0
    return y_;
242
0
  }
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::GridY() const
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::GridY() const
243
244
  // Sets the search mode to return a box only once.
245
  // Efficiency warning: Implementation currently uses a squared-order
246
  // search in the number of returned elements. Use only where a small
247
  // number of elements are spread over a wide area, eg ColPartitions.
248
0
  void SetUniqueMode(bool mode) {
249
0
    unique_mode_ = mode;
250
0
  }
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::SetUniqueMode(bool)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::SetUniqueMode(bool)
251
  // TODO(rays) Replace calls to ReturnedSeedElement with SetUniqueMode.
252
  // It only works if the search includes the bottom-left corner.
253
  // Apart from full search, all other searches return a box several
254
  // times if the box is inserted with h_spread or v_spread.
255
  // This method will return true for only one occurrence of each box
256
  // that was inserted with both h_spread and v_spread as true.
257
  // It will usually return false for boxes that were not inserted with
258
  // both h_spread=true and v_spread=true
259
  bool ReturnedSeedElement() const {
260
    TBOX box = previous_return_->bounding_box();
261
    int x_center = (box.left() + box.right()) / 2;
262
    int y_center = (box.top() + box.bottom()) / 2;
263
    int grid_x, grid_y;
264
    grid_->GridCoords(x_center, y_center, &grid_x, &grid_y);
265
    return (x_ == grid_x) && (y_ == grid_y);
266
  }
267
268
  // Various searching iterations... Note that these iterations
269
  // all share data members, so you can't run more than one iteration
270
  // in parallel in a single GridSearch instance, but multiple instances
271
  // can search the same BBGrid in parallel.
272
  // Note that all the searches can return blobs that may not exactly
273
  // match the search conditions, since they return everything in the
274
  // covered grid cells. It is up to the caller to check for
275
  // appropriateness.
276
  // TODO(rays) NextRectSearch only returns valid elements. Make the other
277
  // searches test before return also and remove the tests from code
278
  // that uses GridSearch.
279
280
  // Start a new full search. Will iterate all stored blobs, from the top.
281
  // If the blobs have been inserted using InsertBBox, (not InsertPixPtBBox)
282
  // then the full search guarantees to return each blob in the grid once.
283
  // Other searches may return a blob more than once if they have been
284
  // inserted using h_spread or v_spread.
285
  void StartFullSearch();
286
  // Return the next bbox in the search or nullptr if done.
287
  BBC *NextFullSearch();
288
289
  // Start a new radius search. Will search in a spiral up to a
290
  // given maximum radius in grid cells from the given center in pixels.
291
  void StartRadSearch(int x, int y, int max_radius);
292
  // Return the next bbox in the radius search or nullptr if the
293
  // maximum radius has been reached.
294
  BBC *NextRadSearch();
295
296
  // Start a new left or right-looking search. Will search to the side
297
  // for a box that vertically overlaps the given vertical line segment.
298
  // CAVEAT: This search returns all blobs from the cells to the side
299
  // of the start, and somewhat below, since there is no guarantee
300
  // that there may not be a taller object in a lower cell. The
301
  // blobs returned will include all those that vertically overlap and
302
  // are no more than twice as high, but may also include some that do
303
  // not overlap and some that are more than twice as high.
304
  void StartSideSearch(int x, int ymin, int ymax);
305
  // Return the next bbox in the side search or nullptr if the
306
  // edge has been reached. Searches left to right or right to left
307
  // according to the flag.
308
  BBC *NextSideSearch(bool right_to_left);
309
310
  // Start a vertical-looking search. Will search up or down
311
  // for a box that horizontally overlaps the given line segment.
312
  void StartVerticalSearch(int xmin, int xmax, int y);
313
  // Return the next bbox in the vertical search or nullptr if the
314
  // edge has been reached. Searches top to bottom or bottom to top
315
  // according to the flag.
316
  BBC *NextVerticalSearch(bool top_to_bottom);
317
318
  // Start a rectangular search. Will search for a box that overlaps the
319
  // given rectangle.
320
  void StartRectSearch(const TBOX &rect);
321
  // Return the next bbox in the rectangular search or nullptr if complete.
322
  BBC *NextRectSearch();
323
324
  // Remove the last returned BBC. Will not invalidate this. May invalidate
325
  // any other concurrent GridSearch on the same grid. If any others are
326
  // in use, call RepositionIterator on those, to continue without harm.
327
  void RemoveBBox();
328
  void RepositionIterator();
329
330
private:
331
  // Factored out helper to start a search.
332
  void CommonStart(int x, int y);
333
  // Factored out helper to complete a next search.
334
  BBC *CommonNext();
335
  // Factored out final return when search is exhausted.
336
  BBC *CommonEnd();
337
  // Factored out function to set the iterator to the current x_, y_
338
  // grid coords and mark the cycle pt.
339
  void SetIterator();
340
341
private:
342
  // The grid we are searching.
343
  BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid_ = nullptr;
344
  // For executing a search. The different search algorithms use these in
345
  // different ways, but most use x_origin_ and y_origin_ as the start position.
346
  int x_origin_ = 0;
347
  int y_origin_ = 0;
348
  int max_radius_ = 0;
349
  int radius_ = 0;
350
  int rad_index_ = 0;
351
  int rad_dir_ = 0;
352
  TBOX rect_;
353
  int x_ = 0; // The current location in grid coords, of the current search.
354
  int y_ = 0;
355
  bool unique_mode_ = false;
356
  BBC *previous_return_ = nullptr; // Previous return from Next*.
357
  BBC *next_return_ = nullptr;     // Current value of it_.data() used for repositioning.
358
  // An iterator over the list at (x_, y_) in the grid_.
359
  BBC_C_IT it_;
360
  // Set of unique returned elements used when unique_mode_ is true.
361
  std::unordered_set<BBC *> returns_;
362
};
363
364
// Sort function to sort a BBC by bounding_box().left().
365
template <class BBC>
366
10.7M
int SortByBoxLeft(const BBC *p1, const BBC *p2) {
367
10.7M
  int result = p1->bounding_box().left() - p2->bounding_box().left();
368
10.7M
  if (result != 0) {
369
9.94M
    return result;
370
9.94M
  }
371
800k
  result = p1->bounding_box().right() - p2->bounding_box().right();
372
800k
  if (result != 0) {
373
286k
    return result;
374
286k
  }
375
513k
  result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
376
513k
  if (result != 0) {
377
513k
    return result;
378
513k
  }
379
418
  return p1->bounding_box().top() - p2->bounding_box().top();
380
513k
}
Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::ColPartition>(tesseract::ColPartition const*, tesseract::ColPartition const*)
Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::BLOBNBOX>(tesseract::BLOBNBOX const*, tesseract::BLOBNBOX const*)
Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::ColSegment>(tesseract::ColSegment const*, tesseract::ColSegment const*)
int tesseract::SortByBoxLeft<tesseract::WordWithBox>(tesseract::WordWithBox const*, tesseract::WordWithBox const*)
Line
Count
Source
366
10.7M
int SortByBoxLeft(const BBC *p1, const BBC *p2) {
367
10.7M
  int result = p1->bounding_box().left() - p2->bounding_box().left();
368
10.7M
  if (result != 0) {
369
9.94M
    return result;
370
9.94M
  }
371
800k
  result = p1->bounding_box().right() - p2->bounding_box().right();
372
800k
  if (result != 0) {
373
286k
    return result;
374
286k
  }
375
513k
  result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
376
513k
  if (result != 0) {
377
513k
    return result;
378
513k
  }
379
418
  return p1->bounding_box().top() - p2->bounding_box().top();
380
513k
}
381
382
template <class BBC>
383
0
bool StdSortByBoxLeft(const BBC *p1, const BBC *p2) {
384
0
  int result = p1->bounding_box().left() - p2->bounding_box().left();
385
0
  if (result != 0) {
386
0
    return result < 0;
387
0
  }
388
0
  result = p1->bounding_box().right() - p2->bounding_box().right();
389
0
  if (result != 0) {
390
0
    return result < 0;
391
0
  }
392
0
  result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
393
0
  if (result != 0) {
394
0
    return result < 0;
395
0
  }
396
0
  return p1->bounding_box().top() < p2->bounding_box().top();
397
0
}
398
399
// Sort function to sort a BBC by bounding_box().right() in right-to-left order.
400
template <class BBC>
401
int SortRightToLeft(const BBC *p1, const BBC *p2) {
402
  int result = p2->bounding_box().right() - p1->bounding_box().right();
403
  if (result != 0) {
404
    return result;
405
  }
406
  result = p2->bounding_box().left() - p1->bounding_box().left();
407
  if (result != 0) {
408
    return result;
409
  }
410
  result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
411
  if (result != 0) {
412
    return result;
413
  }
414
  return p1->bounding_box().top() - p2->bounding_box().top();
415
}
416
417
template <class BBC>
418
0
bool StdSortRightToLeft(const BBC *p1, const BBC *p2) {
419
0
  int result = p2->bounding_box().right() - p1->bounding_box().right();
420
0
  if (result != 0) {
421
0
    return result < 0;
422
0
  }
423
0
  result = p2->bounding_box().left() - p1->bounding_box().left();
424
0
  if (result != 0) {
425
0
    return result < 0;
426
0
  }
427
0
  result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
428
0
  if (result != 0) {
429
0
    return result < 0;
430
0
  }
431
0
  return p1->bounding_box().top() < p2->bounding_box().top();
432
0
}
433
434
// Sort function to sort a BBC by bounding_box().bottom().
435
template <class BBC>
436
0
int SortByBoxBottom(const BBC *p1, const BBC *p2) {
437
0
  int result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
438
0
  if (result != 0) {
439
0
    return result;
440
0
  }
441
0
  result = p1->bounding_box().top() - p2->bounding_box().top();
442
0
  if (result != 0) {
443
0
    return result;
444
0
  }
445
0
  result = p1->bounding_box().left() - p2->bounding_box().left();
446
0
  if (result != 0) {
447
0
    return result;
448
0
  }
449
0
  return p1->bounding_box().right() - p2->bounding_box().right();
450
0
}
451
452
///////////////////////////////////////////////////////////////////////
453
// BBGrid IMPLEMENTATION.
454
///////////////////////////////////////////////////////////////////////
455
template <class BBC, class BBC_CLIST, class BBC_C_IT>
456
0
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid() : grid_(nullptr) {}
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::BBGrid()
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::BBGrid()
457
458
template <class BBC, class BBC_CLIST, class BBC_C_IT>
459
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright)
460
13.8k
    : grid_(nullptr) {
461
13.8k
  Init(gridsize, bleft, tright);
462
13.8k
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
Line
Count
Source
460
13.8k
    : grid_(nullptr) {
461
13.8k
  Init(gridsize, bleft, tright);
462
13.8k
}
463
464
template <class BBC, class BBC_CLIST, class BBC_C_IT>
465
13.8k
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() {
466
13.8k
  delete[] grid_;
467
13.8k
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::~BBGrid()
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::~BBGrid()
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::~BBGrid()
tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::~BBGrid()
Line
Count
Source
465
13.8k
BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() {
466
13.8k
  delete[] grid_;
467
13.8k
}
468
469
// (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
470
// and bleft, tright are the bounding box of everything to go in it.
471
template <class BBC, class BBC_CLIST, class BBC_C_IT>
472
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Init(int gridsize, const ICOORD &bleft,
473
13.8k
                                            const ICOORD &tright) {
474
13.8k
  GridBase::Init(gridsize, bleft, tright);
475
13.8k
  delete[] grid_;
476
13.8k
  grid_ = new BBC_CLIST[gridbuckets_];
477
13.8k
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&)
Line
Count
Source
473
13.8k
                                            const ICOORD &tright) {
474
13.8k
  GridBase::Init(gridsize, bleft, tright);
475
13.8k
  delete[] grid_;
476
13.8k
  grid_ = new BBC_CLIST[gridbuckets_];
477
13.8k
}
478
479
// Clear all lists, but leave the array of lists present.
480
template <class BBC, class BBC_CLIST, class BBC_C_IT>
481
0
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Clear() {
482
0
  for (int i = 0; i < gridbuckets_; ++i) {
483
0
    grid_[i].shallow_clear();
484
0
  }
485
0
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::Clear()
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::Clear()
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::Clear()
486
487
// Deallocate the data in the lists but otherwise leave the lists and the grid
488
// intact.
489
template <class BBC, class BBC_CLIST, class BBC_C_IT>
490
0
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClearGridData(void (*free_method)(BBC *)) {
491
0
  if (grid_ == nullptr) {
492
0
    return;
493
0
  }
494
0
  GridSearch<BBC, BBC_CLIST, BBC_C_IT> search(this);
495
0
  search.StartFullSearch();
496
0
  BBC *bb;
497
0
  BBC_CLIST bb_list;
498
0
  BBC_C_IT it(&bb_list);
499
0
  while ((bb = search.NextFullSearch()) != nullptr) {
500
0
    it.add_after_then_move(bb);
501
0
  }
502
0
  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
503
0
    free_method(it.data());
504
0
  }
505
0
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::ClearGridData(void (*)(tesseract::ColPartition*))
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::ClearGridData(void (*)(tesseract::ColSegment*))
506
507
// Insert a bbox into the appropriate place in the grid.
508
// If h_spread, then all cells covered horizontally by the box are
509
// used, otherwise, just the bottom-left. Similarly for v_spread.
510
// WARNING: InsertBBox may invalidate an active GridSearch. Call
511
// RepositionIterator() on any GridSearches that are active on this grid.
512
template <class BBC, class BBC_CLIST, class BBC_C_IT>
513
196k
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread, BBC *bbox) {
514
196k
  TBOX box = bbox->bounding_box();
515
196k
  int start_x, start_y, end_x, end_y;
516
196k
  GridCoords(box.left(), box.bottom(), &start_x, &start_y);
517
196k
  GridCoords(box.right(), box.top(), &end_x, &end_y);
518
196k
  if (!h_spread) {
519
0
    end_x = start_x;
520
0
  }
521
196k
  if (!v_spread) {
522
0
    end_y = start_y;
523
0
  }
524
196k
  int grid_index = start_y * gridwidth_;
525
1.02M
  for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
526
5.37M
    for (int x = start_x; x <= end_x; ++x) {
527
4.54M
      grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox);
528
4.54M
    }
529
826k
  }
530
196k
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::InsertBBox(bool, bool, tesseract::ColPartition*)
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::InsertBBox(bool, bool, tesseract::BLOBNBOX*)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::InsertBBox(bool, bool, tesseract::ColSegment*)
tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::InsertBBox(bool, bool, tesseract::WordWithBox*)
Line
Count
Source
513
196k
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread, BBC *bbox) {
514
196k
  TBOX box = bbox->bounding_box();
515
196k
  int start_x, start_y, end_x, end_y;
516
196k
  GridCoords(box.left(), box.bottom(), &start_x, &start_y);
517
196k
  GridCoords(box.right(), box.top(), &end_x, &end_y);
518
196k
  if (!h_spread) {
519
0
    end_x = start_x;
520
0
  }
521
196k
  if (!v_spread) {
522
0
    end_y = start_y;
523
0
  }
524
196k
  int grid_index = start_y * gridwidth_;
525
1.02M
  for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
526
5.37M
    for (int x = start_x; x <= end_x; ++x) {
527
4.54M
      grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox);
528
4.54M
    }
529
826k
  }
530
196k
}
531
532
// Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
533
// which each pixel corresponds to a grid cell, insert a bbox into every
534
// place in the grid where the corresponding pixel is 1. The Pix is handled
535
// upside-down to match the Tesseract coordinate system. (As created by
536
// TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
537
// (0, 0) in the pix corresponds to (left, bottom) in the
538
// grid (in grid coords), and the pix works up the grid from there.
539
// WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
540
// RepositionIterator() on any GridSearches that are active on this grid.
541
template <class BBC, class BBC_CLIST, class BBC_C_IT>
542
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertPixPtBBox(int left, int bottom, Image pix, BBC *bbox) {
543
  int width = pixGetWidth(pix);
544
  int height = pixGetHeight(pix);
545
  for (int y = 0; y < height; ++y) {
546
    l_uint32 *data = pixGetData(pix) + y * pixGetWpl(pix);
547
    for (int x = 0; x < width; ++x) {
548
      if (Image::getDataBit(data, x)) {
549
        grid_[(bottom + y) * gridwidth_ + x + left].add_sorted(SortByBoxLeft<BBC>, true, bbox);
550
      }
551
    }
552
  }
553
}
554
555
// Remove the bbox from the grid.
556
// WARNING: Any GridSearch operating on this grid could be invalidated!
557
// If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
558
template <class BBC, class BBC_CLIST, class BBC_C_IT>
559
0
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox(BBC *bbox) {
560
0
  TBOX box = bbox->bounding_box();
561
0
  int start_x, start_y, end_x, end_y;
562
0
  GridCoords(box.left(), box.bottom(), &start_x, &start_y);
563
0
  GridCoords(box.right(), box.top(), &end_x, &end_y);
564
0
  int grid_index = start_y * gridwidth_;
565
0
  for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
566
0
    for (int x = start_x; x <= end_x; ++x) {
567
0
      BBC_C_IT it(&grid_[grid_index + x]);
568
0
      for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
569
0
        if (it.data() == bbox) {
570
0
          it.extract();
571
0
        }
572
0
      }
573
0
    }
574
0
  }
575
0
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RemoveBBox(tesseract::ColPartition*)
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::RemoveBBox(tesseract::BLOBNBOX*)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RemoveBBox(tesseract::ColSegment*)
576
577
// Returns true if the given rectangle has no overlapping elements.
578
template <class BBC, class BBC_CLIST, class BBC_C_IT>
579
bool BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RectangleEmpty(const TBOX &rect) {
580
  GridSearch<BBC, BBC_CLIST, BBC_C_IT> rsearch(this);
581
  rsearch.StartRectSearch(rect);
582
  return rsearch.NextRectSearch() == nullptr;
583
}
584
585
// Returns an IntGrid showing the number of elements in each cell.
586
// Returned IntGrid must be deleted after use.
587
template <class BBC, class BBC_CLIST, class BBC_C_IT>
588
0
IntGrid *BBGrid<BBC, BBC_CLIST, BBC_C_IT>::CountCellElements() {
589
0
  auto *intgrid = new IntGrid(gridsize(), bleft(), tright());
590
0
  for (int y = 0; y < gridheight(); ++y) {
591
0
    for (int x = 0; x < gridwidth(); ++x) {
592
0
      int cell_count = grid_[y * gridwidth() + x].length();
593
0
      intgrid->SetGridCell(x, y, cell_count);
594
0
    }
595
0
  }
596
0
  return intgrid;
597
0
}
598
599
#ifndef GRAPHICS_DISABLED
600
template <class G>
601
class TabEventHandler : public SVEventHandler {
602
public:
603
  explicit TabEventHandler(G *grid) : grid_(grid) {}
604
  void Notify(const SVEvent *sv_event) override {
605
    if (sv_event->type == SVET_CLICK) {
606
      grid_->HandleClick(sv_event->x, sv_event->y);
607
    }
608
  }
609
610
private:
611
  G *grid_;
612
};
613
614
// Make a window of an appropriate size to display things in the grid.
615
// Position the window at the given x,y.
616
template <class BBC, class BBC_CLIST, class BBC_C_IT>
617
ScrollView *BBGrid<BBC, BBC_CLIST, BBC_C_IT>::MakeWindow(int x, int y, const char *window_name) {
618
  auto tab_win =
619
      new ScrollView(window_name, x, y, tright_.x() - bleft_.x(), tright_.y() - bleft_.y(),
620
                     tright_.x() - bleft_.x(), tright_.y() - bleft_.y(), true);
621
  auto *handler = new TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT>>(this);
622
  tab_win->AddEventHandler(handler);
623
  tab_win->Pen(ScrollView::GREY);
624
  tab_win->Rectangle(0, 0, tright_.x() - bleft_.x(), tright_.y() - bleft_.y());
625
  return tab_win;
626
}
627
628
// Create a window at (x,y) and display the bounding boxes of the
629
// BLOBNBOXes in this grid.
630
// Use of this function requires an additional member of the BBC class:
631
// ScrollView::Color BBC::BoxColor() const.
632
template <class BBC, class BBC_CLIST, class BBC_C_IT>
633
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::DisplayBoxes(ScrollView *tab_win) {
634
  tab_win->Pen(ScrollView::BLUE);
635
  tab_win->Brush(ScrollView::NONE);
636
637
  // For every bbox in the grid, display it.
638
  GridSearch<BBC, BBC_CLIST, BBC_C_IT> gsearch(this);
639
  gsearch.StartFullSearch();
640
  BBC *bbox;
641
  while ((bbox = gsearch.NextFullSearch()) != nullptr) {
642
    const TBOX &box = bbox->bounding_box();
643
    int left_x = box.left();
644
    int right_x = box.right();
645
    int top_y = box.top();
646
    int bottom_y = box.bottom();
647
    ScrollView::Color box_color = bbox->BoxColor();
648
    tab_win->Pen(box_color);
649
    tab_win->Rectangle(left_x, bottom_y, right_x, top_y);
650
  }
651
  tab_win->Update();
652
}
653
654
#endif // !GRAPHICS_DISABLED
655
656
// ASSERT_HOST that every cell contains no more than one copy of each entry.
657
template <class BBC, class BBC_CLIST, class BBC_C_IT>
658
0
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::AssertNoDuplicates() {
659
  // Process all grid cells.
660
0
  for (int i = gridwidth_ * gridheight_ - 1; i >= 0; --i) {
661
    // Iterate over all elements excent the last.
662
0
    for (BBC_C_IT it(&grid_[i]); !it.at_last(); it.forward()) {
663
0
      BBC *ptr = it.data();
664
0
      BBC_C_IT it2(it);
665
      // None of the rest of the elements in the list should equal ptr.
666
0
      for (it2.forward(); !it2.at_first(); it2.forward()) {
667
0
        ASSERT_HOST(it2.data() != ptr);
668
0
      }
669
0
    }
670
0
  }
671
0
}
672
673
// Handle a click event in a display window.
674
template <class BBC, class BBC_CLIST, class BBC_C_IT>
675
0
void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::HandleClick(int x, int y) {
676
0
  tprintf("Click at (%d, %d)\n", x, y);
677
0
}
Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::HandleClick(int, int)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::HandleClick(int, int)
Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::HandleClick(int, int)
Unexecuted instantiation: tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::HandleClick(int, int)
678
679
///////////////////////////////////////////////////////////////////////
680
// GridSearch IMPLEMENTATION.
681
///////////////////////////////////////////////////////////////////////
682
683
// Start a new full search. Will iterate all stored blobs.
684
template <class BBC, class BBC_CLIST, class BBC_C_IT>
685
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartFullSearch() {
686
  // Full search uses x_ and y_ as the current grid
687
  // cell being searched.
688
0
  CommonStart(grid_->bleft_.x(), grid_->tright_.y());
689
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartFullSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartFullSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::StartFullSearch()
690
691
// Return the next bbox in the search or nullptr if done.
692
// The other searches will return a box that overlaps the grid cell
693
// thereby duplicating boxes, but NextFullSearch only returns each box once.
694
template <class BBC, class BBC_CLIST, class BBC_C_IT>
695
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextFullSearch() {
696
0
  int x;
697
0
  int y;
698
0
  do {
699
0
    while (it_.cycled_list()) {
700
0
      ++x_;
701
0
      if (x_ >= grid_->gridwidth_) {
702
0
        --y_;
703
0
        if (y_ < 0) {
704
0
          return CommonEnd();
705
0
        }
706
0
        x_ = 0;
707
0
      }
708
0
      SetIterator();
709
0
    }
710
0
    CommonNext();
711
0
    TBOX box = previous_return_->bounding_box();
712
0
    grid_->GridCoords(box.left(), box.bottom(), &x, &y);
713
0
  } while (x != x_ || y != y_);
714
0
  return previous_return_;
715
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextFullSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextFullSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::NextFullSearch()
716
717
// Start a new radius search.
718
template <class BBC, class BBC_CLIST, class BBC_C_IT>
719
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRadSearch(int x, int y, int max_radius) {
720
  // Rad search uses x_origin_ and y_origin_ as the center of the circle.
721
  // The radius_ is the radius of the (diamond-shaped) circle and
722
  // rad_index/rad_dir_ combine to determine the position around it.
723
0
  max_radius_ = max_radius;
724
0
  radius_ = 0;
725
0
  rad_index_ = 0;
726
0
  rad_dir_ = 3;
727
0
  CommonStart(x, y);
728
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartRadSearch(int, int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartRadSearch(int, int, int)
729
730
// Return the next bbox in the radius search or nullptr if the
731
// maximum radius has been reached.
732
template <class BBC, class BBC_CLIST, class BBC_C_IT>
733
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRadSearch() {
734
0
  for (;;) {
735
0
    while (it_.cycled_list()) {
736
0
      ++rad_index_;
737
0
      if (rad_index_ >= radius_) {
738
0
        ++rad_dir_;
739
0
        rad_index_ = 0;
740
0
        if (rad_dir_ >= 4) {
741
0
          ++radius_;
742
0
          if (radius_ > max_radius_) {
743
0
            return CommonEnd();
744
0
          }
745
0
          rad_dir_ = 0;
746
0
        }
747
0
      }
748
0
      ICOORD offset = C_OUTLINE::chain_step(rad_dir_);
749
0
      offset *= radius_ - rad_index_;
750
0
      offset += C_OUTLINE::chain_step(rad_dir_ + 1) * rad_index_;
751
0
      x_ = x_origin_ + offset.x();
752
0
      y_ = y_origin_ + offset.y();
753
0
      if (x_ >= 0 && x_ < grid_->gridwidth_ && y_ >= 0 && y_ < grid_->gridheight_) {
754
0
        SetIterator();
755
0
      }
756
0
    }
757
0
    CommonNext();
758
0
    if (!unique_mode_) {
759
0
      break;
760
0
    }
761
0
    auto inserted = returns_.insert(previous_return_);
762
0
    if (inserted.second) {
763
0
      break;
764
0
    }
765
0
  }
766
0
  return previous_return_;
767
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextRadSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextRadSearch()
768
769
// Start a new left or right-looking search. Will search to the side
770
// for a box that vertically overlaps the given vertical line segment.
771
template <class BBC, class BBC_CLIST, class BBC_C_IT>
772
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartSideSearch(int x, int ymin, int ymax) {
773
  // Right search records the x in x_origin_, the ymax in y_origin_
774
  // and the size of the vertical strip to search in radius_.
775
  // To guarantee finding overlapping objects of up to twice the
776
  // given size, double the height.
777
0
  radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_;
778
0
  rad_index_ = 0;
779
0
  CommonStart(x, ymax);
780
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartSideSearch(int, int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartSideSearch(int, int, int)
781
782
// Return the next bbox in the side search or nullptr if the
783
// edge has been reached. Searches left to right or right to left
784
// according to the flag.
785
template <class BBC, class BBC_CLIST, class BBC_C_IT>
786
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextSideSearch(bool right_to_left) {
787
0
  for (;;) {
788
0
    while (it_.cycled_list()) {
789
0
      ++rad_index_;
790
0
      if (rad_index_ > radius_) {
791
0
        if (right_to_left) {
792
0
          --x_;
793
0
        } else {
794
0
          ++x_;
795
0
        }
796
0
        rad_index_ = 0;
797
0
        if (x_ < 0 || x_ >= grid_->gridwidth_) {
798
0
          return CommonEnd();
799
0
        }
800
0
      }
801
0
      y_ = y_origin_ - rad_index_;
802
0
      if (y_ >= 0 && y_ < grid_->gridheight_) {
803
0
        SetIterator();
804
0
      }
805
0
    }
806
0
    CommonNext();
807
0
    if (!unique_mode_) {
808
0
      break;
809
0
    }
810
0
    auto inserted = returns_.insert(previous_return_);
811
0
    if (inserted.second) {
812
0
      break;
813
0
    }
814
0
  }
815
0
  return previous_return_;
816
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextSideSearch(bool)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextSideSearch(bool)
817
818
// Start a vertical-looking search. Will search up or down
819
// for a box that horizontally overlaps the given line segment.
820
template <class BBC, class BBC_CLIST, class BBC_C_IT>
821
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartVerticalSearch(int xmin, int xmax, int y) {
822
  // Right search records the xmin in x_origin_, the y in y_origin_
823
  // and the size of the horizontal strip to search in radius_.
824
0
  radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_;
825
0
  rad_index_ = 0;
826
0
  CommonStart(xmin, y);
827
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartVerticalSearch(int, int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartVerticalSearch(int, int, int)
828
829
// Return the next bbox in the vertical search or nullptr if the
830
// edge has been reached. Searches top to bottom or bottom to top
831
// according to the flag.
832
template <class BBC, class BBC_CLIST, class BBC_C_IT>
833
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextVerticalSearch(bool top_to_bottom) {
834
0
  for (;;) {
835
0
    while (it_.cycled_list()) {
836
0
      ++rad_index_;
837
0
      if (rad_index_ > radius_) {
838
0
        if (top_to_bottom) {
839
0
          --y_;
840
0
        } else {
841
0
          ++y_;
842
0
        }
843
0
        rad_index_ = 0;
844
0
        if (y_ < 0 || y_ >= grid_->gridheight_) {
845
0
          return CommonEnd();
846
0
        }
847
0
      }
848
0
      x_ = x_origin_ + rad_index_;
849
0
      if (x_ >= 0 && x_ < grid_->gridwidth_) {
850
0
        SetIterator();
851
0
      }
852
0
    }
853
0
    CommonNext();
854
0
    if (!unique_mode_) {
855
0
      break;
856
0
    }
857
0
    auto inserted = returns_.insert(previous_return_);
858
0
    if (inserted.second) {
859
0
      break;
860
0
    }
861
0
  }
862
0
  return previous_return_;
863
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextVerticalSearch(bool)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextVerticalSearch(bool)
864
865
// Start a rectangular search. Will search for a box that overlaps the
866
// given rectangle.
867
template <class BBC, class BBC_CLIST, class BBC_C_IT>
868
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRectSearch(const TBOX &rect) {
869
  // Rect search records the xmin in x_origin_, the ymin in y_origin_
870
  // and the xmax in max_radius_.
871
  // The search proceeds left to right, top to bottom.
872
0
  rect_ = rect;
873
0
  CommonStart(rect.left(), rect.top());
874
0
  grid_->GridCoords(rect.right(), rect.bottom(), // - rect.height(),
875
0
                    &max_radius_, &y_origin_);
876
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartRectSearch(tesseract::TBOX const&)
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartRectSearch(tesseract::TBOX const&)
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::StartRectSearch(tesseract::TBOX const&)
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::StartRectSearch(tesseract::TBOX const&)
877
878
// Return the next bbox in the rectangular search or nullptr if complete.
879
template <class BBC, class BBC_CLIST, class BBC_C_IT>
880
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRectSearch() {
881
0
  for (;;) {
882
0
    while (it_.cycled_list()) {
883
0
      ++x_;
884
0
      if (x_ > max_radius_) {
885
0
        --y_;
886
0
        x_ = x_origin_;
887
0
        if (y_ < y_origin_) {
888
0
          return CommonEnd();
889
0
        }
890
0
      }
891
0
      SetIterator();
892
0
    }
893
0
    CommonNext();
894
0
    if (!rect_.overlap(previous_return_->bounding_box())) {
895
0
      continue;
896
0
    }
897
0
    if (!unique_mode_) {
898
0
      break;
899
0
    }
900
0
    auto inserted = returns_.insert(previous_return_);
901
0
    if (inserted.second) {
902
0
      break;
903
0
    }
904
0
  }
905
0
  return previous_return_;
906
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextRectSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextRectSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::NextRectSearch()
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::NextRectSearch()
907
908
// Remove the last returned BBC. Will not invalidate this. May invalidate
909
// any other concurrent GridSearch on the same grid. If any others are
910
// in use, call RepositionIterator on those, to continue without harm.
911
template <class BBC, class BBC_CLIST, class BBC_C_IT>
912
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox() {
913
0
  if (previous_return_ != nullptr) {
914
    // Remove all instances of previous_return_ from the list, so the iterator
915
    // remains valid after removal from the rest of the grid cells.
916
    // if previous_return_ is not on the list, then it has been removed already.
917
0
    BBC *prev_data = nullptr;
918
0
    BBC *new_previous_return = nullptr;
919
0
    it_.move_to_first();
920
0
    for (it_.mark_cycle_pt(); !it_.cycled_list();) {
921
0
      if (it_.data() == previous_return_) {
922
0
        new_previous_return = prev_data;
923
0
        it_.extract();
924
0
        it_.forward();
925
0
        next_return_ = it_.cycled_list() ? nullptr : it_.data();
926
0
      } else {
927
0
        prev_data = it_.data();
928
0
        it_.forward();
929
0
      }
930
0
    }
931
0
    grid_->RemoveBBox(previous_return_);
932
0
    previous_return_ = new_previous_return;
933
0
    RepositionIterator();
934
0
  }
935
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RemoveBBox()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RemoveBBox()
936
937
template <class BBC, class BBC_CLIST, class BBC_C_IT>
938
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RepositionIterator() {
939
  // Something was deleted, so we have little choice but to clear the
940
  // returns list.
941
0
  returns_.clear();
942
  // Reset the iterator back to one past the previous return.
943
  // If the previous_return_ is no longer in the list, then
944
  // next_return_ serves as a backup.
945
0
  it_.move_to_first();
946
  // Special case, the first element was removed and reposition
947
  // iterator was called. In this case, the data is fine, but the
948
  // cycle point is not. Detect it and return.
949
0
  if (!it_.empty() && it_.data() == next_return_) {
950
0
    it_.mark_cycle_pt();
951
0
    return;
952
0
  }
953
0
  for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) {
954
0
    if (it_.data() == previous_return_ || it_.data_relative(1) == next_return_) {
955
0
      CommonNext();
956
0
      return;
957
0
    }
958
0
  }
959
  // We ran off the end of the list. Move to a new cell next time.
960
0
  previous_return_ = nullptr;
961
0
  next_return_ = nullptr;
962
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RepositionIterator()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RepositionIterator()
963
964
// Factored out helper to start a search.
965
template <class BBC, class BBC_CLIST, class BBC_C_IT>
966
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonStart(int x, int y) {
967
0
  grid_->GridCoords(x, y, &x_origin_, &y_origin_);
968
0
  x_ = x_origin_;
969
0
  y_ = y_origin_;
970
0
  SetIterator();
971
0
  previous_return_ = nullptr;
972
0
  next_return_ = it_.empty() ? nullptr : it_.data();
973
0
  returns_.clear();
974
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonStart(int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonStart(int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonStart(int, int)
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonStart(int, int)
975
976
// Factored out helper to complete a next search.
977
template <class BBC, class BBC_CLIST, class BBC_C_IT>
978
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() {
979
0
  previous_return_ = it_.data();
980
0
  it_.forward();
981
0
  next_return_ = it_.cycled_list() ? nullptr : it_.data();
982
0
  return previous_return_;
983
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonNext()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonNext()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonNext()
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonNext()
984
985
// Factored out final return when search is exhausted.
986
template <class BBC, class BBC_CLIST, class BBC_C_IT>
987
0
BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() {
988
0
  previous_return_ = nullptr;
989
0
  next_return_ = nullptr;
990
0
  return nullptr;
991
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonEnd()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonEnd()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonEnd()
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonEnd()
992
993
// Factored out function to set the iterator to the current x_, y_
994
// grid coords and mark the cycle pt.
995
template <class BBC, class BBC_CLIST, class BBC_C_IT>
996
0
void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() {
997
0
  it_ = &(grid_->grid_[y_ * grid_->gridwidth_ + x_]);
998
0
  it_.mark_cycle_pt();
999
0
}
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::SetIterator()
Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::SetIterator()
Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::SetIterator()
Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::SetIterator()
1000
1001
} // namespace tesseract.
1002
1003
#endif // TESSERACT_TEXTORD_BBGRID_H_