22 #include "config_auto.h" 37 ColPartition_IT it(&parts_);
38 it.add_list_after(partitions);
43 ColPartition_IT it(&parts_);
44 it.add_after_then_move(part);
50 int num_good_cols = 0;
52 ColPartition_IT it(const_cast<ColPartition_LIST*>(&parts_));
53 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
54 if (it.data()->good_width()) ++num_good_cols;
61 ColPartition_IT it(&parts_);
63 for (
int i = 0; i < index && !it.cycled_list(); ++i, it.forward());
71 ColPartition_IT it(&parts_);
72 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
82 ColPartition_IT it(&parts_);
92 int set_size = src_sets->
size();
95 for (
int i = 0; i < set_size; ++i) {
97 if (column_set ==
nullptr)
101 ColPartition_IT part_it(&parts_);
103 int prev_right = INT32_MIN;
104 part_it.mark_cycle_pt();
105 ColPartition_IT col_it(&column_set->parts_);
106 for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
110 int col_left = col_part->
left_key();
114 while (!part_it.at_last() && part->
right_key() < col_left) {
117 part = part_it.data();
121 if (part_right < col_left || col_right < part_left) {
127 bool part_width_ok = cb->
Run(part->
KeyWidth(part_left, part_right));
128 if (col_left < part_left && col_left > prev_right) {
132 bool tab_width_ok = cb->
Run(part->
KeyWidth(col_left, part_right));
133 bool box_width_ok = cb->
Run(part->
KeyWidth(col_box_left, part_right));
134 if (tab_width_ok || (!part_width_ok)) {
139 }
else if (col_box_left < part_left &&
140 (box_width_ok || !part_width_ok)) {
148 if (col_right > part_right &&
149 (part_it.at_last() ||
150 part_it.data_relative(1)->left_key() > col_right)) {
153 bool tab_width_ok = cb->
Run(part->
KeyWidth(part_left, col_right));
154 bool box_width_ok = cb->
Run(part->
KeyWidth(part_left, col_box_right));
155 if (tab_width_ok || (!part_width_ok)) {
160 }
else if (col_box_right > part_right &&
161 (box_width_ok || !part_width_ok)) {
180 tprintf(
"Considering new column candidate:\n");
185 tprintf(
"Not a legal column candidate:\n");
191 for (
int i = 0; i < column_sets->
size(); ++i) {
195 bool better = good_coverage_ > columns->good_coverage_;
196 if (good_coverage_ == columns->good_coverage_) {
197 better = good_column_count_ > columns->good_column_count_;
198 if (good_column_count_ == columns->good_column_count_) {
199 better = bad_coverage_ > columns->bad_coverage_;
206 column_sets->
insert(
this, i);
226 tprintf(
"CompatibleColumns testing compatibility\n");
230 if (other->parts_.empty()) {
232 tprintf(
"CompatibleColumns true due to empty other\n");
235 ColPartition_IT it(&other->parts_);
236 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
240 tprintf(
"CompatibleColumns ignoring image partition\n");
245 int y = part->
MidY();
250 if (right_col ==
nullptr || left_col ==
nullptr) {
252 tprintf(
"CompatibleColumns false due to partition edge outside\n");
257 if (right_col != left_col && cb->
Run(right - left)) {
259 tprintf(
"CompatibleColumns false due to good width in multiple cols\n");
265 ColPartition_IT it2= it;
266 while (!it2.at_last()) {
272 if (next_left == right) {
277 if (right_col == next_left_col) {
287 tprintf(
"CompatibleColumns false due to 2 parts of good width\n");
288 tprintf(
"part1 %d-%d, part2 %d-%d\n",
289 left, right, next_left, next_right);
299 tprintf(
"CompatibleColumns true!\n");
308 ColPartition_IT it(&part_set->parts_);
309 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
314 int y = part->
MidY();
315 BLOBNBOX_C_IT box_it(part->
boxes());
316 for (box_it.mark_cycle_pt(); !box_it.cycled_list(); box_it.forward()) {
317 const TBOX& box = it.data()->bounding_box();
323 total_width += box.
width();
332 ColPartition_IT it(&parts_);
335 bool any_text_parts =
false;
336 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
341 any_text_parts =
true;
350 return any_text_parts;
355 ColPartition_LIST copy_parts;
356 ColPartition_IT src_it(&parts_);
357 ColPartition_IT dest_it(©_parts);
358 for (src_it.mark_cycle_pt(); !src_it.cycled_list(); src_it.forward()) {
371 ColSegment_LIST *segments) {
372 ColPartition_IT it(&parts_);
373 ColSegment_IT col_it(segments);
374 col_it.move_to_last();
375 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
380 col_seg->InsertBox(
TBOX(bot_left, top_right));
381 col_it.add_after_then_move(col_seg);
388 #ifndef GRAPHICS_DISABLED 389 ColPartition_IT it(&parts_);
390 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
395 #endif // GRAPHICS_DISABLED 412 int* first_spanned_col) {
415 *first_spanned_col = -1;
416 int margin_columns = 0;
417 ColPartition_IT it(&parts_);
419 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward(), col_index += 2) {
427 *first_col = col_index;
431 *last_col = col_index;
434 if (left_margin <= part->LeftAtY(y)) {
436 *first_spanned_col = col_index;
441 if (*first_col < 0) {
443 *first_col = col_index - 1;
445 if (right_margin >= part->
RightAtY(y)) {
447 if (margin_columns == 0)
448 *first_spanned_col = col_index;
451 *last_col = col_index;
453 }
else if (left < part->LeftAtY(y) && right > part->
RightAtY(y)) {
456 if (*first_col < 0) {
458 *first_col = col_index - 1;
460 if (margin_columns == 0)
461 *first_spanned_col = col_index;
462 *last_col = col_index;
463 }
else if (right < part->LeftAtY(y)) {
465 *last_col = col_index - 1;
466 if (*first_col < 0) {
468 *first_col = col_index - 1;
474 *first_col = col_index - 1;
476 *last_col = col_index - 1;
479 if (*first_col == *last_col && right - left <
kMinColumnWidth * resolution) {
483 }
else if (margin_columns <= 1) {
485 if (margin_columns == 1 && parts_.singleton()) {
503 ColPartition_LIST* used_parts,
504 WorkingPartSet_LIST* working_set_list) {
507 WorkingPartSet_LIST work_src;
508 WorkingPartSet_IT src_it(&work_src);
509 src_it.add_list_after(working_set_list);
510 src_it.move_to_first();
511 WorkingPartSet_IT dest_it(working_set_list);
514 BLOCK_LIST completed_blocks;
515 TO_BLOCK_LIST to_blocks;
518 ColPartition_IT col_it(&parts_);
519 for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
522 while (!src_it.empty() &&
523 ((working_set = src_it.data())->column() ==
nullptr ||
527 used_parts, &completed_blocks,
534 dest_it.add_after_then_move(working_set);
535 if (first_new_set ==
nullptr)
536 first_new_set = working_set;
539 working_set = src_it.empty() ? nullptr : src_it.data();
540 if (working_set !=
nullptr &&
543 dest_it.add_after_then_move(src_it.extract());
546 first_new_set =
nullptr;
550 dest_it.add_after_then_move(working_set);
554 while (!src_it.empty()) {
555 working_set = src_it.extract();
557 used_parts, &completed_blocks,
564 dest_it.add_after_then_move(working_set);
565 if (first_new_set ==
nullptr)
566 first_new_set = working_set;
576 ColPartition_IT it(&parts_);
577 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
584 int part_right = next_part->
left_key();
585 int gap = part->
KeyWidth(part_left, part_right);
594 ColPartition_IT it(&parts_);
595 tprintf(
"Partition set of %d parts, %d good, coverage=%d+%d" 596 " (%d,%d)->(%d,%d)\n",
597 it.length(), good_column_count_, good_coverage_, bad_coverage_,
599 bounding_box_.
right(), bounding_box_.
top());
600 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
609 void ColPartitionSet::AddPartition(
ColPartition* new_part,
610 ColPartition_IT* it) {
611 AddPartitionCoverageAndBox(*new_part);
613 if (it->data()->left_key() >= new_right)
614 it->add_before_stay_put(new_part);
616 it->add_after_stay_put(new_part);
636 void ColPartitionSet::ComputeCoverage() {
638 ColPartition_IT it(&parts_);
639 good_column_count_ = 0;
642 bounding_box_ =
TBOX();
643 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
644 ColPartition* part = it.data();
645 AddPartitionCoverageAndBox(*part);
651 void ColPartitionSet::AddPartitionCoverageAndBox(
const ColPartition& part) {
652 bounding_box_ += part.bounding_box();
653 int coverage = part.ColumnWidth();
654 if (part.good_width()) {
655 good_coverage_ += coverage;
656 good_column_count_ += 2;
660 if (part.good_column())
661 ++good_column_count_;
662 bad_coverage_ += coverage;
void CopyRightTab(const ColPartition &src, bool take_box)
int GoodColumnCount() const
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)
bool MatchingColumns(const ColPartition &other) const
BlobRegionType blob_type() const
void set_column(ColPartition *col)
static bool WithinTestRegion(int detail_level, int x, int y)
bool CompatibleColumns(bool debug, ColPartitionSet *other, WidthCallback *cb)
void ImproveColumnCandidate(WidthCallback *cb, PartSetVector *src_sets)
void CopyLeftTab(const ColPartition &src, bool take_box)
void InsertCompletedBlocks(BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
ColPartition * column() const
ColPartition * GetColumnByIndex(int index)
int RightAtY(int y) const
void insert(const T &t, int index)
bool ColumnContains(int x, int y) const
void AccumulateColumnWidthsAndGaps(int *total_width, int *width_samples, int *total_gap, int *gap_samples)
void AddToColumnSetsIfUnique(PartSetVector *column_sets, WidthCallback *cb)
void ExtractCompletedBlocks(const ICOORD &bleft, const ICOORD &tright, int resolution, ColPartition_LIST *used_parts, BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
void GetColumnBoxes(int y_bottom, int y_top, ColSegment_LIST *segments)
#define ELISTIZE(CLASSNAME)
DLLSYM void tprintf(const char *format,...)
void ChangeWorkColumns(const ICOORD &bleft, const ICOORD &tright, int resolution, ColPartition_LIST *used_parts, WorkingPartSet_LIST *working_set)
void DisplayColumnEdges(int y_bottom, int y_top, ScrollView *win)
const TBOX & bounding_box() const
const double kMinColumnWidth
ColPartitionSet()=default
int UnmatchedWidth(ColPartitionSet *part_set)
ColPartition * ColumnContaining(int x, int y)
bool LegalColumnCandidate()
void SetColumnGoodness(WidthCallback *cb)
ColPartition * ShallowCopy() const
ColPartitionSet * Copy(bool good_only)
void Line(int x1, int y1, int x2, int y2)
int KeyWidth(int left_key, int right_key) const
static bool IsTextType(BlobRegionType type)