21# include "config_auto.h"
28#include <allheaders.h>
44static void position_outline(
46 C_OUTLINE_LIST *destlist
48 C_OUTLINE_IT it = destlist;
50 C_OUTLINE_IT child_it = outline->
child();
57 if (*dest_outline < *outline) {
59 dest_outline = it.extract();
61 it.add_after_then_move(outline);
63 child_it.add_to_end(dest_outline);
64 while (!it.at_last()) {
67 dest_outline = it.data();
68 if (*dest_outline < *outline) {
70 dest_outline = it.extract();
71 child_it.add_to_end(dest_outline);
81 else if (*outline < *dest_outline) {
82 position_outline(outline, dest_outline->
child());
87 }
while (!it.at_first());
89 it.add_to_end(outline);
99#ifndef GRAPHICS_DISABLED
100static void plot_outline_list(
101 C_OUTLINE_LIST *list,
107 C_OUTLINE_IT it = list;
109 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
112 outline->plot(window, colour);
113 if (!outline->child()->empty()) {
114 plot_outline_list(outline->child(), window, child_colour, child_colour);
121static void plot_normed_outline_list(
const DENORM &denorm, C_OUTLINE_LIST *list,
123 ScrollView *window) {
124 C_OUTLINE_IT it(list);
125 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
126 C_OUTLINE *outline = it.data();
127 outline->plot_normed(denorm, colour, window);
128 if (!outline->child()->empty()) {
129 plot_normed_outline_list(denorm, outline->child(), child_colour, child_colour, window);
141static void reverse_outline_list(C_OUTLINE_LIST *list) {
142 C_OUTLINE_IT it = list;
144 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
145 C_OUTLINE *outline = it.data();
148 if (!outline->child()->empty()) {
149 reverse_outline_list(outline->child());
163 for (C_OUTLINE_IT ol_it(outline_list); !ol_it.empty(); ol_it.forward()) {
166 position_outline(outline, &outlines);
174 C_OUTLINE_IT it(&outlines);
175 it.add_to_end(outline);
189 C_BLOB_IT *good_blobs_it, C_BLOB_IT *bad_blobs_it) {
191 C_OUTLINE_LIST nested_outlines;
192 for (C_OUTLINE_IT ol_it(outline_list); !ol_it.empty(); ol_it.forward()) {
195 position_outline(outline, &nested_outlines);
198 for (C_OUTLINE_IT ol_it(&nested_outlines); !ol_it.empty(); ol_it.forward()) {
200 bool blob_is_good = good_blob;
204 blob_is_good =
false;
205 ol_it.add_list_after(outline->
child());
207 auto *blob =
new C_BLOB(outline);
209 blob->CheckInverseFlagAndDirection();
211 if (!blob_is_good && bad_blobs_it !=
nullptr) {
212 bad_blobs_it->add_after_then_move(blob);
214 good_blobs_it->add_after_then_move(blob);
223 C_OUTLINE_IT ol_it(&outlines);
224 for (ol_it.mark_cycle_pt(); !ol_it.cycled_list(); ol_it.forward()) {
228 reverse_outline_list(outline->
child());
239 C_OUTLINE_LIST outlines;
241 return new C_BLOB(&outlines);
252 C_OUTLINE_IT it =
const_cast<C_OUTLINE_LIST *
>(&outlines);
255 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
269 C_OUTLINE_IT it = &outlines;
272 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
274 total += outline->
area();
286 C_OUTLINE_IT it = &outlines;
289 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
303 C_OUTLINE_IT it = &outlines;
306 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
323 C_OUTLINE_IT it = &outlines;
326 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
342 C_OUTLINE_IT it(&outlines);
344 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
345 it.data()->move(vec);
350static void RotateOutlineList(
const FCOORD &rotation, C_OUTLINE_LIST *outlines) {
351 C_OUTLINE_LIST new_outlines;
352 C_OUTLINE_IT src_it(outlines);
353 C_OUTLINE_IT dest_it(&new_outlines);
354 while (!src_it.empty()) {
355 C_OUTLINE *old_outline = src_it.extract();
357 auto *new_outline =
new C_OUTLINE(old_outline, rotation);
358 if (!old_outline->
child()->empty()) {
359 RotateOutlineList(rotation, old_outline->
child());
360 C_OUTLINE_IT child_it(new_outline->child());
361 child_it.add_list_after(old_outline->
child());
364 dest_it.add_to_end(new_outline);
366 src_it.add_list_after(&new_outlines);
376 RotateOutlineList(rotation, &outlines);
381static void ComputeEdgeOffsetsOutlineList(
int threshold,
Image pix, C_OUTLINE_LIST *list) {
382 C_OUTLINE_IT it(list);
383 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
385 if (pix !=
nullptr && pixGetDepth(pix) == 8) {
390 if (!outline->
child()->empty()) {
391 ComputeEdgeOffsetsOutlineList(threshold, pix, outline->
child());
399 ComputeEdgeOffsetsOutlineList(threshold, pix, &outlines);
418 int left = box.
left();
419 int width = box.
width();
420 int bottom = box.
bottom();
425 std::vector<int> y_mins(width + 1, box.
top());
426 C_OUTLINE_IT it(&outlines);
427 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
430 for (
int s = 0; s < outline->
pathlength(); ++s) {
431 if (pos.
y() < y_mins[pos.
x() - left]) {
432 y_mins[pos.
x() - left] = pos.
y();
434 pos += outline->
step(s);
438 int bottom_extent = 0;
439 for (
int x = 0;
x <= width; ++
x) {
440 if (y_mins[
x] == bottom || y_mins[
x] == bottom + 1) {
445 int best_min = box.
top();
447 int prev_y = box.
top();
448 int prev_prev_y = box.
top();
449 for (
int x = 0;
x < width;
x += prev_run) {
451 int y_at_x = y_mins[
x];
453 while (
x + run <= width && y_mins[
x + run] == y_at_x) {
456 if (y_at_x > bottom + 1) {
460 while (
x + total_run <= width &&
461 (y_mins[
x + total_run] == y_at_x || y_mins[
x + total_run] == y_at_x + 1)) {
465 if (prev_prev_y > y_at_x + 1 ||
x + total_run > width || y_mins[
x + total_run] > y_at_x + 1) {
468 if (prev_run > 0 && prev_y == y_at_x + 1) {
469 total_run += prev_run;
471 if (total_run > bottom_extent && y_at_x < best_min) {
477 prev_prev_y = prev_y;
480 return best_min == box.
top() ? bottom : best_min;
483static void render_outline_list(C_OUTLINE_LIST *list,
int left,
int top,
Image pix) {
484 C_OUTLINE_IT it(list);
485 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
487 outline->
render(left, top, pix);
488 if (!outline->
child()->empty()) {
489 render_outline_list(outline->
child(), left, top, pix);
494static void render_outline_list_outline(C_OUTLINE_LIST *list,
int left,
int top, Image pix) {
495 C_OUTLINE_IT it(list);
496 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
497 C_OUTLINE *outline = it.data();
506 render_outline_list(&outlines, box.
left(), box.
top(), pix);
515 render_outline_list_outline(&outlines, box.
left(), box.
top(), pix);
525#ifndef GRAPHICS_DISABLED
529 plot_outline_list(&outlines, window, blob_colour, child_colour);
536 plot_normed_outline_list(denorm, &outlines, blob_colour, child_colour, window);
const double kMaxPerimeterWidthRatio
int32_t pathlength() const
const TBOX & bounding_box() const
void set_flag(C_OUTLINE_FLAGS mask, bool value)
bool IsLegallyNested() const
ICOORD step(int index) const
int32_t perimeter() const
int16_t turn_direction() const
int32_t outer_area() const
void ComputeBinaryOffsets()
void render_outline(int left, int top, Image pix) const
int32_t count_transitions(int32_t threshold)
static void FakeOutline(const TBOX &box, C_OUTLINE_LIST *outlines)
const ICOORD & start_pos() const
void ComputeEdgeOffsets(int threshold, Image pix)
void render(int left, int top, Image pix) const
TDimension y() const
access_function
TDimension x() const
access function
TDimension height() const
TDimension bottom() const
int32_t count_transitions(int32_t threshold)
void rotate(const FCOORD &rotation)
static C_BLOB * FakeBlob(const TBOX &box)
void plot(ScrollView *window, ScrollView::Color blob_colour, ScrollView::Color child_colour)
void plot_normed(const DENORM &denorm, ScrollView::Color blob_colour, ScrollView::Color child_colour, ScrollView *window)
TBOX bounding_box() const
void ComputeEdgeOffsets(int threshold, Image pix)
int16_t EstimateBaselinePosition()
static void ConstructBlobsFromOutlines(bool good_blob, C_OUTLINE_LIST *outline_list, C_BLOB_IT *good_blobs_it, C_BLOB_IT *bad_blobs_it)
void move(const ICOORD vec)
void CheckInverseFlagAndDirection()