Coverage Report

Created: 2026-01-13 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tesseract/src/textord/edgloop.cpp
Line
Count
Source
1
/**********************************************************************
2
 * File:        edgloop.cpp  (Formerly edgeloop.c)
3
 * Description: Functions to clean up an outline before approximation.
4
 * Author:      Ray Smith
5
 *
6
 * (C) Copyright 1991, Hewlett-Packard Ltd.
7
 ** Licensed under the Apache License, Version 2.0 (the "License");
8
 ** you may not use this file except in compliance with the License.
9
 ** You may obtain a copy of the License at
10
 ** http://www.apache.org/licenses/LICENSE-2.0
11
 ** Unless required by applicable law or agreed to in writing, software
12
 ** distributed under the License is distributed on an "AS IS" BASIS,
13
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 ** See the License for the specific language governing permissions and
15
 ** limitations under the License.
16
 *
17
 **********************************************************************/
18
19
// Include automatically generated configuration file if running autoconf.
20
#ifdef HAVE_CONFIG_H
21
#  include "config_auto.h"
22
#endif
23
24
#include "scanedg.h"
25
26
#include "edgloop.h"
27
28
namespace tesseract {
29
30
9.34M
#define MINEDGELENGTH 8 // min decent length
31
32
/**********************************************************************
33
 * complete_edge
34
 *
35
 * Complete the edge by cleaning it up.
36
 **********************************************************************/
37
38
void complete_edge(CRACKEDGE *start, // start of loop
39
6.18M
                   C_OUTLINE_IT *outline_it) {
40
6.18M
  ScrollView::Color colour; // colour to draw in
41
6.18M
  int16_t looplength;       // steps in loop
42
6.18M
  ICOORD botleft;           // bounding box
43
6.18M
  ICOORD topright;
44
6.18M
  C_OUTLINE *outline; // new outline
45
46
  // check length etc.
47
6.18M
  colour = check_path_legal(start);
48
49
6.18M
  if (colour == ScrollView::RED || colour == ScrollView::BLUE) {
50
3.02M
    looplength = loop_bounding_box(start, botleft, topright);
51
3.02M
    outline = new C_OUTLINE(start, botleft, topright, looplength);
52
    // add to list
53
3.02M
    outline_it->add_after_then_move(outline);
54
3.02M
  }
55
6.18M
}
56
57
/**********************************************************************
58
 * check_path_legal
59
 *
60
 * Check that the outline is legal for length and for chaincode sum.
61
 * The return value is RED for a normal black-inside outline,
62
 * BLUE for a white-inside outline, MAGENTA if it is too short,
63
 * YELLOW if it is too long, and GREEN if it is illegal.
64
 * These colours are used to draw the raw outline.
65
 **********************************************************************/
66
67
ScrollView::Color check_path_legal( // certify outline
68
    CRACKEDGE *start                // start of loop
69
6.18M
) {
70
6.18M
  int lastchain;     // last chain code
71
6.18M
  int chaindiff;     // chain code diff
72
6.18M
  int32_t length;    // length of loop
73
6.18M
  int32_t chainsum;  // sum of chain diffs
74
6.18M
  CRACKEDGE *edgept; // current point
75
6.18M
  constexpr ERRCODE ED_ILLEGAL_SUM("Illegal sum of chain codes");
76
77
6.18M
  length = 0;
78
6.18M
  chainsum = 0; // sum of chain codes
79
6.18M
  edgept = start;
80
6.18M
  lastchain = edgept->prev->stepdir; // previous chain code
81
104M
  do {
82
104M
    length++;
83
104M
    if (edgept->stepdir != lastchain) {
84
      // chain code difference
85
55.7M
      chaindiff = edgept->stepdir - lastchain;
86
55.7M
      if (chaindiff > 2) {
87
6.64M
        chaindiff -= 4;
88
49.1M
      } else if (chaindiff < -2) {
89
7.55M
        chaindiff += 4;
90
7.55M
      }
91
55.7M
      chainsum += chaindiff; // sum differences
92
55.7M
      lastchain = edgept->stepdir;
93
55.7M
    }
94
104M
    edgept = edgept->next;
95
104M
  } while (edgept != start && length < C_OUTLINE::kMaxOutlineLength);
96
97
6.18M
  if ((chainsum != 4 && chainsum != -4) || edgept != start || length < MINEDGELENGTH) {
98
3.15M
    if (edgept != start) {
99
71
      return ScrollView::YELLOW;
100
3.15M
    } else if (length < MINEDGELENGTH) {
101
3.15M
      return ScrollView::MAGENTA;
102
3.15M
    } else {
103
0
      ED_ILLEGAL_SUM.error("check_path_legal", TESSLOG, "chainsum=%d", chainsum);
104
0
      return ScrollView::GREEN;
105
0
    }
106
3.15M
  }
107
  // colour on inside
108
3.02M
  return chainsum < 0 ? ScrollView::BLUE : ScrollView::RED;
109
6.18M
}
110
111
/**********************************************************************
112
 * loop_bounding_box
113
 *
114
 * Find the bounding box of the edge loop.
115
 **********************************************************************/
116
117
int16_t loop_bounding_box( // get bounding box
118
    CRACKEDGE *&start,     // edge loop
119
    ICOORD &botleft,       // bounding box
120
3.02M
    ICOORD &topright) {
121
3.02M
  int16_t length;       // length of loop
122
3.02M
  int16_t leftmost;     // on top row
123
3.02M
  CRACKEDGE *edgept;    // current point
124
3.02M
  CRACKEDGE *realstart; // topleft start
125
126
3.02M
  edgept = start;
127
3.02M
  realstart = start;
128
3.02M
  botleft = topright = ICOORD(edgept->pos.x(), edgept->pos.y());
129
3.02M
  leftmost = edgept->pos.x();
130
3.02M
  length = 0; // count length
131
89.4M
  do {
132
89.4M
    edgept = edgept->next;
133
89.4M
    if (edgept->pos.x() < botleft.x()) {
134
      // get bounding box
135
9.84M
      botleft.set_x(edgept->pos.x());
136
79.5M
    } else if (edgept->pos.x() > topright.x()) {
137
4.32M
      topright.set_x(edgept->pos.x());
138
4.32M
    }
139
89.4M
    if (edgept->pos.y() < botleft.y()) {
140
      // get bounding box
141
1.20M
      botleft.set_y(edgept->pos.y());
142
88.2M
    } else if (edgept->pos.y() > topright.y()) {
143
17.2M
      realstart = edgept;
144
17.2M
      leftmost = edgept->pos.x();
145
17.2M
      topright.set_y(edgept->pos.y());
146
70.9M
    } else if (edgept->pos.y() == topright.y() && edgept->pos.x() < leftmost) {
147
      // leftmost on line
148
11.6M
      leftmost = edgept->pos.x();
149
11.6M
      realstart = edgept;
150
11.6M
    }
151
89.4M
    length++; // count elements
152
89.4M
  } while (edgept != start);
153
3.02M
  start = realstart; // shift it to topleft
154
3.02M
  return length;
155
3.02M
}
156
157
} // namespace tesseract