Coverage Report

Created: 2026-09-14 06:59

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
8.57M
#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
5.70M
                   C_OUTLINE_IT *outline_it) {
40
5.70M
  ScrollView::Color colour; // colour to draw in
41
5.70M
  int16_t looplength;       // steps in loop
42
5.70M
  ICOORD botleft;           // bounding box
43
5.70M
  ICOORD topright;
44
5.70M
  C_OUTLINE *outline; // new outline
45
46
  // check length etc.
47
5.70M
  colour = check_path_legal(start);
48
49
5.70M
  if (colour == ScrollView::RED || colour == ScrollView::BLUE) {
50
2.83M
    looplength = loop_bounding_box(start, botleft, topright);
51
2.83M
    outline = new C_OUTLINE(start, botleft, topright, looplength);
52
    // add to list
53
2.83M
    outline_it->add_after_then_move(outline);
54
2.83M
  }
55
5.70M
}
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
5.70M
) {
70
5.70M
  int lastchain;     // last chain code
71
5.70M
  int chaindiff;     // chain code diff
72
5.70M
  int32_t length;    // length of loop
73
5.70M
  int32_t chainsum;  // sum of chain diffs
74
5.70M
  CRACKEDGE *edgept; // current point
75
5.70M
  constexpr ERRCODE ED_ILLEGAL_SUM("Illegal sum of chain codes");
76
77
5.70M
  length = 0;
78
5.70M
  chainsum = 0; // sum of chain codes
79
5.70M
  edgept = start;
80
5.70M
  lastchain = edgept->prev->stepdir; // previous chain code
81
95.1M
  do {
82
95.1M
    length++;
83
95.1M
    if (edgept->stepdir != lastchain) {
84
      // chain code difference
85
50.8M
      chaindiff = edgept->stepdir - lastchain;
86
50.8M
      if (chaindiff > 2) {
87
6.02M
        chaindiff -= 4;
88
44.7M
      } else if (chaindiff < -2) {
89
6.92M
        chaindiff += 4;
90
6.92M
      }
91
50.8M
      chainsum += chaindiff; // sum differences
92
50.8M
      lastchain = edgept->stepdir;
93
50.8M
    }
94
95.1M
    edgept = edgept->next;
95
95.1M
  } while (edgept != start && length < C_OUTLINE::kMaxOutlineLength);
96
97
5.70M
  if ((chainsum != 4 && chainsum != -4) || edgept != start || length < MINEDGELENGTH) {
98
2.87M
    if (edgept != start) {
99
62
      return ScrollView::YELLOW;
100
2.87M
    } else if (length < MINEDGELENGTH) {
101
2.87M
      return ScrollView::MAGENTA;
102
2.87M
    } else {
103
0
      ED_ILLEGAL_SUM.error("check_path_legal", TESSLOG, "chainsum=%d", chainsum);
104
0
      return ScrollView::GREEN;
105
0
    }
106
2.87M
  }
107
  // colour on inside
108
2.83M
  return chainsum < 0 ? ScrollView::BLUE : ScrollView::RED;
109
5.70M
}
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
2.83M
    ICOORD &topright) {
121
2.83M
  int16_t length;       // length of loop
122
2.83M
  int16_t leftmost;     // on top row
123
2.83M
  CRACKEDGE *edgept;    // current point
124
2.83M
  CRACKEDGE *realstart; // topleft start
125
126
2.83M
  edgept = start;
127
2.83M
  realstart = start;
128
2.83M
  botleft = topright = ICOORD(edgept->pos.x(), edgept->pos.y());
129
2.83M
  leftmost = edgept->pos.x();
130
2.83M
  length = 0; // count length
131
81.2M
  do {
132
81.2M
    edgept = edgept->next;
133
81.2M
    if (edgept->pos.x() < botleft.x()) {
134
      // get bounding box
135
8.63M
      botleft.set_x(edgept->pos.x());
136
72.6M
    } else if (edgept->pos.x() > topright.x()) {
137
3.91M
      topright.set_x(edgept->pos.x());
138
3.91M
    }
139
81.2M
    if (edgept->pos.y() < botleft.y()) {
140
      // get bounding box
141
1.11M
      botleft.set_y(edgept->pos.y());
142
80.1M
    } else if (edgept->pos.y() > topright.y()) {
143
16.0M
      realstart = edgept;
144
16.0M
      leftmost = edgept->pos.x();
145
16.0M
      topright.set_y(edgept->pos.y());
146
64.0M
    } else if (edgept->pos.y() == topright.y() && edgept->pos.x() < leftmost) {
147
      // leftmost on line
148
10.4M
      leftmost = edgept->pos.x();
149
10.4M
      realstart = edgept;
150
10.4M
    }
151
81.2M
    length++; // count elements
152
81.2M
  } while (edgept != start);
153
2.83M
  start = realstart; // shift it to topleft
154
2.83M
  return length;
155
2.83M
}
156
157
} // namespace tesseract