21# include "config_auto.h"
34 ColPartition_IT it(&parts_);
35 it.add_list_after(partitions);
40 ColPartition_IT it(&parts_);
41 it.add_after_then_move(part);
47 int num_good_cols = 0;
49 ColPartition_IT it(
const_cast<ColPartition_LIST *
>(&parts_));
50 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
51 if (it.data()->good_width()) {
60 ColPartition_IT it(&parts_);
62 for (
int i = 0;
i < index && !it.cycled_list(); ++
i, it.forward()) {
65 if (it.cycled_list()) {
73 ColPartition_IT it(&parts_);
74 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
85 ColPartition_IT it(&parts_);
95 int set_size = src_sets->size();
98 for (
int i = 0;
i < set_size; ++
i) {
100 if (column_set ==
nullptr) {
105 ColPartition_IT part_it(&parts_);
107 int prev_right = INT32_MIN;
108 part_it.mark_cycle_pt();
109 ColPartition_IT col_it(&column_set->parts_);
110 for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
115 int col_left = col_part->
left_key();
119 while (!part_it.at_last() && part->
right_key() < col_left) {
122 part = part_it.data();
126 if (part_right < col_left || col_right < part_left) {
132 bool part_width_ok = cb(part->
KeyWidth(part_left, part_right));
133 if (col_left < part_left && col_left > prev_right) {
137 bool tab_width_ok = cb(part->
KeyWidth(col_left, part_right));
138 bool box_width_ok = cb(part->
KeyWidth(col_box_left, part_right));
139 if (tab_width_ok || (!part_width_ok)) {
144 }
else if (col_box_left < part_left &&
145 (box_width_ok || !part_width_ok)) {
153 if (col_right > part_right &&
154 (part_it.at_last() ||
155 part_it.data_relative(1)->left_key() > col_right)) {
158 bool tab_width_ok = cb(part->
KeyWidth(part_left, col_right));
159 bool box_width_ok = cb(part->
KeyWidth(part_left, col_box_right));
160 if (tab_width_ok || (!part_width_ok)) {
165 }
else if (col_box_right > part_right &&
166 (box_width_ok || !part_width_ok)) {
185 tprintf(
"Considering new column candidate:\n");
190 tprintf(
"Not a legal column candidate:\n");
196 for (
unsigned i = 0;
i < column_sets->size(); ++
i) {
200 bool better = good_coverage_ > columns->good_coverage_;
201 if (good_coverage_ == columns->good_coverage_) {
202 better = good_column_count_ > columns->good_column_count_;
203 if (good_column_count_ == columns->good_column_count_) {
204 better = bad_coverage_ > columns->bad_coverage_;
212 column_sets->insert(column_sets->begin() +
i,
this);
226 column_sets->push_back(
this);
234 tprintf(
"CompatibleColumns testing compatibility\n");
238 if (other->parts_.empty()) {
240 tprintf(
"CompatibleColumns true due to empty other\n");
244 ColPartition_IT it(&other->parts_);
245 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
249 tprintf(
"CompatibleColumns ignoring image partition\n");
254 int y = part->
MidY();
259 if (right_col ==
nullptr || left_col ==
nullptr) {
261 tprintf(
"CompatibleColumns false due to partition edge outside\n");
266 if (right_col != left_col && cb(right - left)) {
268 tprintf(
"CompatibleColumns false due to good width in multiple cols\n");
274 ColPartition_IT it2 = it;
275 while (!it2.at_last()) {
282 if (next_left == right) {
287 if (right_col == next_left_col) {
297 tprintf(
"CompatibleColumns false due to 2 parts of good width\n");
298 tprintf(
"part1 %d-%d, part2 %d-%d\n", left, right, next_left,
309 tprintf(
"CompatibleColumns true!\n");
319 ColPartition_IT it(&part_set->parts_);
320 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
325 int y = part->
MidY();
326 BLOBNBOX_C_IT box_it(part->
boxes());
327 for (box_it.mark_cycle_pt(); !box_it.cycled_list(); box_it.forward()) {
328 const TBOX &box = it.data()->bounding_box();
333 if (col ==
nullptr) {
334 total_width += box.
width();
344 ColPartition_IT it(&parts_);
348 bool any_text_parts =
false;
349 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
355 any_text_parts =
true;
364 return any_text_parts;
369 ColPartition_LIST copy_parts;
370 ColPartition_IT src_it(&parts_);
371 ColPartition_IT dest_it(©_parts);
372 for (src_it.mark_cycle_pt(); !src_it.cycled_list(); src_it.forward()) {
379 if (dest_it.empty()) {
387 ColSegment_LIST *segments) {
388 ColPartition_IT it(&parts_);
389 ColSegment_IT col_it(segments);
390 col_it.move_to_last();
391 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
396 col_seg->InsertBox(
TBOX(bot_left, top_right));
397 col_it.add_after_then_move(col_seg);
401#ifndef GRAPHICS_DISABLED
406 ColPartition_IT it(&parts_);
407 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
424 int resolution,
int left,
int right,
int height,
int y,
int left_margin,
425 int right_margin,
int *first_col,
int *last_col,
int *first_spanned_col) {
428 *first_spanned_col = -1;
429 int margin_columns = 0;
430 ColPartition_IT it(&parts_);
432 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward(), col_index += 2) {
440 *first_col = col_index;
444 *last_col = col_index;
447 if (left_margin <= part->LeftAtY(
y)) {
449 *first_spanned_col = col_index;
454 if (*first_col < 0) {
456 *first_col = col_index - 1;
460 if (margin_columns == 0) {
461 *first_spanned_col = col_index;
465 *last_col = col_index;
467 }
else if (left < part->LeftAtY(
y) && right > part->
RightAtY(
y)) {
470 if (*first_col < 0) {
472 *first_col = col_index - 1;
474 if (margin_columns == 0) {
475 *first_spanned_col = col_index;
477 *last_col = col_index;
478 }
else if (right < part->LeftAtY(
y)) {
480 *last_col = col_index - 1;
481 if (*first_col < 0) {
483 *first_col = col_index - 1;
488 if (*first_col < 0) {
489 *first_col = col_index - 1;
492 *last_col = col_index - 1;
496 if (*first_col == *last_col && right - left <
kMinColumnWidth * resolution) {
500 }
else if (margin_columns <= 1) {
502 if (margin_columns == 1 && parts_.singleton()) {
518 const ICOORD &tright,
int resolution,
519 ColPartition_LIST *used_parts,
520 WorkingPartSet_LIST *working_set_list) {
523 WorkingPartSet_LIST work_src;
524 WorkingPartSet_IT src_it(&work_src);
525 src_it.add_list_after(working_set_list);
526 src_it.move_to_first();
527 WorkingPartSet_IT dest_it(working_set_list);
530 BLOCK_LIST completed_blocks;
531 TO_BLOCK_LIST to_blocks;
534 ColPartition_IT col_it(&parts_);
535 for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
538 while (!src_it.empty() &&
539 ((working_set = src_it.data())->column() ==
nullptr ||
543 &completed_blocks, &to_blocks);
549 dest_it.add_after_then_move(working_set);
550 if (first_new_set ==
nullptr) {
551 first_new_set = working_set;
555 working_set = src_it.empty() ? nullptr : src_it.data();
556 if (working_set !=
nullptr &&
559 dest_it.add_after_then_move(src_it.extract());
562 first_new_set =
nullptr;
566 dest_it.add_after_then_move(working_set);
570 while (!src_it.empty()) {
571 working_set = src_it.extract();
573 &completed_blocks, &to_blocks);
579 dest_it.add_after_then_move(working_set);
580 if (first_new_set ==
nullptr) {
581 first_new_set = working_set;
592 ColPartition_IT it(&parts_);
593 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
600 int part_right = next_part->
left_key();
601 int gap = part->
KeyWidth(part_left, part_right);
610 ColPartition_IT it(&parts_);
612 "Partition set of %d parts, %d good, coverage=%d+%d"
613 " (%d,%d)->(%d,%d)\n",
614 it.length(), good_column_count_, good_coverage_, bad_coverage_,
616 bounding_box_.
top());
617 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
626void ColPartitionSet::AddPartition(
ColPartition *new_part,
627 ColPartition_IT *it) {
628 AddPartitionCoverageAndBox(*new_part);
630 if (it->data()->left_key() >= new_right) {
631 it->add_before_stay_put(new_part);
633 it->add_after_stay_put(new_part);
654void ColPartitionSet::ComputeCoverage() {
656 ColPartition_IT it(&parts_);
657 good_column_count_ = 0;
660 bounding_box_ =
TBOX();
661 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
662 ColPartition *part = it.data();
663 AddPartitionCoverageAndBox(*part);
669void ColPartitionSet::AddPartitionCoverageAndBox(
const ColPartition &part) {
670 bounding_box_ += part.bounding_box();
671 int coverage = part.ColumnWidth();
672 if (part.good_width()) {
673 good_coverage_ += coverage;
674 good_column_count_ += 2;
679 if (part.good_column()) {
680 ++good_column_count_;
682 bad_coverage_ += coverage;
void tprintf(const char *format,...)
std::function< bool(int)> WidthCallback
std::vector< ColPartitionSet * > PartSetVector
const double kMinColumnWidth
static bool IsTextType(BlobRegionType type)
TDimension bottom() const
static bool WithinTestRegion(int detail_level, int x, int y)
int KeyWidth(int left_key, int right_key) const
void SetColumnGoodness(const WidthCallback &cb)
BlobRegionType blob_type() const
const TBOX & bounding_box() const
ColPartition * ShallowCopy() const
void CopyRightTab(const ColPartition &src, bool take_box)
int RightAtY(int y) const
bool ColumnContains(int x, int y) const
bool MatchingColumns(const ColPartition &other) const
void CopyLeftTab(const ColPartition &src, bool take_box)
int GoodColumnCount() const
void AccumulateColumnWidthsAndGaps(int *total_width, int *width_samples, int *total_gap, int *gap_samples)
void DisplayColumnEdges(int y_bottom, int y_top, ScrollView *win)
bool CompatibleColumns(bool debug, ColPartitionSet *other, const WidthCallback &cb)
ColumnSpanningType SpanningType(int resolution, int left, int right, int height, int y, int left_margin, int right_margin, int *first_col, int *last_col, int *first_spanned_col)
ColPartition * GetColumnByIndex(int index)
void ChangeWorkColumns(const ICOORD &bleft, const ICOORD &tright, int resolution, ColPartition_LIST *used_parts, WorkingPartSet_LIST *working_set)
ColPartitionSet * Copy(bool good_only)
ColPartition * ColumnContaining(int x, int y)
bool LegalColumnCandidate()
ColPartitionSet()=default
void AddToColumnSetsIfUnique(PartSetVector *column_sets, const WidthCallback &cb)
int UnmatchedWidth(ColPartitionSet *part_set)
void ImproveColumnCandidate(const WidthCallback &cb, PartSetVector *src_sets)
void GetColumnBoxes(int y_bottom, int y_top, ColSegment_LIST *segments)
void set_column(ColPartition *col)
ColPartition * column() const
void ExtractCompletedBlocks(const ICOORD &bleft, const ICOORD &tright, int resolution, ColPartition_LIST *used_parts, BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
void InsertCompletedBlocks(BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
void Line(int x1, int y1, int x2, int y2)