Coverage Report

Created: 2025-06-13 07:15

/src/tesseract/src/ccstruct/polyaprx.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 * File:        polyaprx.cpp
3
 * Description: Code for polygonal approximation from old edgeprog.
4
 * Author:      Ray Smith
5
 *
6
 * (C) Copyright 1993, 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 "polyaprx.h"
20
21
#include "blobs.h"   // for EDGEPT, TPOINT, VECTOR, TESSLINE
22
#include "coutln.h"  // for C_OUTLINE
23
#include "errcode.h" // for ASSERT_HOST
24
#include "mod128.h"  // for DIR128
25
#include "params.h"  // for BoolParam, BOOL_VAR
26
#include "points.h"  // for ICOORD
27
#include "rect.h"    // for TBOX
28
#include "tprintf.h" // for tprintf
29
30
#include <cstdint> // for INT16_MAX, int8_t
31
32
namespace tesseract {
33
34
1.93M
#define FASTEDGELENGTH 256
35
36
static BOOL_VAR(poly_debug, false, "Debug old poly");
37
static BOOL_VAR(poly_wide_objects_better, true,
38
                "More accurate approx on wide things");
39
40
3.87M
#define fixed_dist 20  // really an int_variable
41
#define approx_dist 15 // really an int_variable
42
43
const int par1 = 4500 / (approx_dist * approx_dist);
44
const int par2 = 6750 / (approx_dist * approx_dist);
45
46
/**********************************************************************
47
 *cutline(first,last,area) straightens out a line by partitioning
48
 *and joining the ends by a straight line*
49
 **********************************************************************/
50
51
static void cutline(       // recursive refine
52
    EDGEPT *first,         // ends of line
53
    EDGEPT *last, int area // area of object
54
8.91M
) {
55
8.91M
  EDGEPT *edge;     // current edge
56
8.91M
  TPOINT vecsum;    // vector sum
57
8.91M
  int vlen;         // approx length of vecsum
58
8.91M
  TPOINT vec;       // accumulated vector
59
8.91M
  EDGEPT *maxpoint; // worst point
60
8.91M
  int maxperp;      // max deviation
61
8.91M
  int perp;         // perp distance
62
8.91M
  int ptcount;      // no of points
63
8.91M
  int squaresum;    // sum of perps
64
65
8.91M
  edge = first; // start of line
66
8.91M
  if (edge->next == last) {
67
972k
    return; // simple line
68
972k
  }
69
70
  // vector sum
71
7.94M
  vecsum.x = last->pos.x - edge->pos.x;
72
7.94M
  vecsum.y = last->pos.y - edge->pos.y;
73
7.94M
  if (vecsum.x == 0 && vecsum.y == 0) {
74
    // special case
75
81
    vecsum.x = -edge->prev->vec.x;
76
81
    vecsum.y = -edge->prev->vec.y;
77
81
  }
78
  // absolute value
79
7.94M
  vlen = vecsum.x > 0 ? vecsum.x : -vecsum.x;
80
7.94M
  if (vecsum.y > vlen) {
81
1.95M
    vlen = vecsum.y; // maximum
82
5.98M
  } else if (-vecsum.y > vlen) {
83
2.56M
    vlen = -vecsum.y; // absolute value
84
2.56M
  }
85
86
7.94M
  vec.x = edge->vec.x; // accumulated vector
87
7.94M
  vec.y = edge->vec.y;
88
7.94M
  maxperp = 0; // none yet
89
7.94M
  squaresum = ptcount = 0;
90
7.94M
  edge = edge->next; // move to actual point
91
7.94M
  maxpoint = edge;   // in case there isn't one
92
15.5M
  do {
93
15.5M
    perp = vec.cross(vecsum); // get perp distance
94
15.5M
    if (perp != 0) {
95
14.0M
      perp *= perp; // squared deviation
96
14.0M
    }
97
15.5M
    squaresum += perp; // sum squares
98
15.5M
    ptcount++;         // count points
99
15.5M
    if (poly_debug) {
100
0
      tprintf("Cutline:Final perp=%d\n", perp);
101
0
    }
102
15.5M
    if (perp > maxperp) {
103
9.61M
      maxperp = perp;
104
9.61M
      maxpoint = edge; // find greatest deviation
105
9.61M
    }
106
15.5M
    vec.x += edge->vec.x; // accumulate vectors
107
15.5M
    vec.y += edge->vec.y;
108
15.5M
    edge = edge->next;
109
15.5M
  } while (edge != last); // test all line
110
111
7.94M
  perp = vecsum.length2();
112
7.94M
  ASSERT_HOST(perp != 0);
113
114
7.94M
  if (maxperp < 256 * INT16_MAX) {
115
7.94M
    maxperp <<= 8;
116
7.94M
    maxperp /= perp; // true max perp
117
7.94M
  } else {
118
68
    maxperp /= perp;
119
68
    maxperp <<= 8; // avoid overflow
120
68
  }
121
7.94M
  if (squaresum < 256 * INT16_MAX) {
122
    // mean squared perp
123
7.94M
    perp = (squaresum << 8) / (perp * ptcount);
124
7.94M
  } else {
125
    // avoid overflow
126
284
    perp = (squaresum / perp << 8) / ptcount;
127
284
  }
128
129
7.94M
  if (poly_debug) {
130
0
    tprintf("Cutline:A=%d, max=%.2f(%.2f%%), msd=%.2f(%.2f%%)\n", area,
131
0
            maxperp / 256.0, maxperp * 200.0 / area, perp / 256.0,
132
0
            perp * 300.0 / area);
133
0
  }
134
7.94M
  if (maxperp * par1 >= 10 * area || perp * par2 >= 10 * area || vlen >= 126) {
135
818k
    maxpoint->fixed = true;
136
    // partitions
137
818k
    cutline(first, maxpoint, area);
138
818k
    cutline(maxpoint, last, area);
139
818k
  }
140
7.94M
}
141
142
/**********************************************************************
143
 * edgesteps_to_edgepts
144
 *
145
 * Convert a C_OUTLINE to EDGEPTs.
146
 **********************************************************************/
147
148
static EDGEPT *edgesteps_to_edgepts( // convert outline
149
    C_OUTLINE *c_outline,            // input
150
    EDGEPT edgepts[]                 // output is array
151
1.93M
) {
152
1.93M
  int32_t length;    // steps in path
153
1.93M
  ICOORD pos;        // current coords
154
1.93M
  int32_t stepindex; // current step
155
1.93M
  int32_t stepinc;   // increment
156
1.93M
  int32_t epindex;   // current EDGEPT
157
1.93M
  ICOORD vec;        // for this 8 step
158
1.93M
  ICOORD prev_vec;
159
1.93M
  int8_t epdir;   // of this step
160
1.93M
  DIR128 prevdir; // previous dir
161
1.93M
  DIR128 dir;     // of this step
162
163
1.93M
  pos = c_outline->start_pos(); // start of loop
164
1.93M
  length = c_outline->pathlength();
165
1.93M
  stepindex = 0;
166
1.93M
  epindex = 0;
167
1.93M
  prevdir = -1;
168
  // repeated steps
169
1.93M
  uint32_t count = 0;
170
1.93M
  int prev_stepindex = 0;
171
55.5M
  do {
172
55.5M
    dir = c_outline->step_dir(stepindex);
173
55.5M
    vec = c_outline->step(stepindex);
174
55.5M
    if (stepindex < length - 1 &&
175
55.5M
        c_outline->step_dir(stepindex + 1) - dir == -32) {
176
7.94M
      dir += 128 - 16;
177
7.94M
      vec += c_outline->step(stepindex + 1);
178
7.94M
      stepinc = 2;
179
47.6M
    } else {
180
47.6M
      stepinc = 1;
181
47.6M
    }
182
55.5M
    if (count == 0) {
183
1.93M
      prevdir = dir;
184
1.93M
      prev_vec = vec;
185
1.93M
    }
186
55.5M
    if (prevdir.get_dir() != dir.get_dir()) {
187
22.1M
      edgepts[epindex].pos.x = pos.x();
188
22.1M
      edgepts[epindex].pos.y = pos.y();
189
22.1M
      prev_vec *= count;
190
22.1M
      edgepts[epindex].vec.x = prev_vec.x();
191
22.1M
      edgepts[epindex].vec.y = prev_vec.y();
192
22.1M
      pos += prev_vec;
193
22.1M
      edgepts[epindex].runlength = count;
194
22.1M
      edgepts[epindex].prev = &edgepts[epindex - 1];
195
      // TODO: reset is_hidden, too?
196
22.1M
      edgepts[epindex].fixed = false;
197
22.1M
      edgepts[epindex].next = &edgepts[epindex + 1];
198
22.1M
      prevdir += 64;
199
22.1M
      epdir = DIR128(0) - prevdir;
200
22.1M
      epdir >>= 4;
201
22.1M
      epdir &= 7;
202
22.1M
      edgepts[epindex].dir = epdir;
203
22.1M
      edgepts[epindex].src_outline = c_outline;
204
22.1M
      edgepts[epindex].start_step = prev_stepindex;
205
22.1M
      edgepts[epindex].step_count = stepindex - prev_stepindex;
206
22.1M
      epindex++;
207
22.1M
      prevdir = dir;
208
22.1M
      prev_vec = vec;
209
22.1M
      count = 1;
210
22.1M
      prev_stepindex = stepindex;
211
33.4M
    } else {
212
33.4M
      count++;
213
33.4M
    }
214
55.5M
    stepindex += stepinc;
215
55.5M
  } while (stepindex < length);
216
1.93M
  edgepts[epindex].pos.x = pos.x();
217
1.93M
  edgepts[epindex].pos.y = pos.y();
218
1.93M
  prev_vec *= count;
219
1.93M
  edgepts[epindex].vec.x = prev_vec.x();
220
1.93M
  edgepts[epindex].vec.y = prev_vec.y();
221
1.93M
  pos += prev_vec;
222
1.93M
  edgepts[epindex].runlength = count;
223
  // TODO: reset is_hidden, too?
224
1.93M
  edgepts[epindex].fixed = false;
225
1.93M
  edgepts[epindex].src_outline = c_outline;
226
1.93M
  edgepts[epindex].start_step = prev_stepindex;
227
1.93M
  edgepts[epindex].step_count = stepindex - prev_stepindex;
228
1.93M
  edgepts[epindex].prev = &edgepts[epindex - 1];
229
1.93M
  edgepts[epindex].next = &edgepts[0];
230
1.93M
  prevdir += 64;
231
1.93M
  epdir = DIR128(0) - prevdir;
232
1.93M
  epdir >>= 4;
233
1.93M
  epdir &= 7;
234
1.93M
  edgepts[epindex].dir = epdir;
235
1.93M
  edgepts[0].prev = &edgepts[epindex];
236
1.93M
  ASSERT_HOST(pos.x() == c_outline->start_pos().x() &&
237
1.93M
              pos.y() == c_outline->start_pos().y());
238
1.93M
  return &edgepts[0];
239
1.93M
}
240
241
/**********************************************************************
242
 *fix2(start,area) fixes points on the outline according to a trial method*
243
 **********************************************************************/
244
245
static void fix2(  // polygonal approx
246
    EDGEPT *start, // loop to approximate
247
1.93M
    int area) {
248
1.93M
  EDGEPT *edgept; // current point
249
1.93M
  EDGEPT *edgept1;
250
1.93M
  EDGEPT *loopstart; // modified start of loop
251
1.93M
  EDGEPT *linestart; // start of line segment
252
1.93M
  int fixed_count;   // no of fixed points
253
1.93M
  int8_t dir;
254
1.93M
  int d01, d12, d23, gapmin;
255
1.93M
  TPOINT d01vec, d12vec, d23vec;
256
1.93M
  EDGEPT *edgefix, *startfix;
257
1.93M
  EDGEPT *edgefix0, *edgefix1, *edgefix2, *edgefix3;
258
259
1.93M
  edgept = start; // start of loop
260
2.03M
  while (((edgept->dir - edgept->prev->dir + 1) & 7) < 3 &&
261
2.03M
         (dir = (edgept->prev->dir - edgept->next->dir) & 7) != 2 && dir != 6) {
262
102k
    edgept = edgept->next; // find suitable start
263
102k
  }
264
1.93M
  loopstart = edgept; // remember start
265
266
  // completed flag
267
1.93M
  bool stopped = false;
268
1.93M
  edgept->fixed = true; // fix it
269
16.4M
  do {
270
16.4M
    linestart = edgept;      // possible start of line
271
16.4M
    auto dir1 = edgept->dir; // first direction
272
    // length of dir1
273
16.4M
    auto sum1 = edgept->runlength;
274
16.4M
    edgept = edgept->next;
275
16.4M
    auto dir2 = edgept->dir; // 2nd direction
276
    // length in dir2
277
16.4M
    auto sum2 = edgept->runlength;
278
16.4M
    if (((dir1 - dir2 + 1) & 7) < 3) {
279
9.78M
      while (edgept->prev->dir == edgept->next->dir) {
280
1.85M
        edgept = edgept->next; // look at next
281
1.85M
        if (edgept->dir == dir1) {
282
          // sum lengths
283
1.62M
          sum1 += edgept->runlength;
284
1.62M
        } else {
285
230k
          sum2 += edgept->runlength;
286
230k
        }
287
1.85M
      }
288
289
7.92M
      if (edgept == loopstart) {
290
        // finished
291
185k
        stopped = true;
292
185k
      }
293
7.92M
      if (sum2 + sum1 > 2 && linestart->prev->dir == dir2 &&
294
7.92M
          (linestart->prev->runlength > linestart->runlength || sum2 > sum1)) {
295
        // start is back one
296
166k
        linestart = linestart->prev;
297
166k
        linestart->fixed = true;
298
166k
      }
299
300
7.92M
      if (((edgept->next->dir - edgept->dir + 1) & 7) >= 3 ||
301
7.92M
          (edgept->dir == dir1 && sum1 >= sum2) ||
302
7.92M
          ((edgept->prev->runlength < edgept->runlength ||
303
2.28M
            (edgept->dir == dir2 && sum2 >= sum1)) &&
304
5.71M
           linestart->next != edgept)) {
305
5.71M
        edgept = edgept->next;
306
5.71M
      }
307
7.92M
    }
308
    // sharp bend
309
16.4M
    edgept->fixed = true;
310
16.4M
  }
311
  // do whole loop
312
16.4M
  while (edgept != loopstart && !stopped);
313
314
1.93M
  edgept = start;
315
24.0M
  do {
316
24.0M
    if (((edgept->runlength >= 8) && (edgept->dir != 2) &&
317
24.0M
         (edgept->dir != 6)) ||
318
24.0M
        ((edgept->runlength >= 8) &&
319
23.8M
         ((edgept->dir == 2) || (edgept->dir == 6)))) {
320
1.10M
      edgept->fixed = true;
321
1.10M
      edgept1 = edgept->next;
322
1.10M
      edgept1->fixed = true;
323
1.10M
    }
324
24.0M
    edgept = edgept->next;
325
24.0M
  } while (edgept != start);
326
327
1.93M
  edgept = start;
328
24.0M
  do {
329
    // single fixed step
330
24.0M
    if (edgept->fixed &&
331
24.0M
        edgept->runlength == 1
332
        // and neighbours free
333
24.0M
        && edgept->next->fixed &&
334
24.0M
        !edgept->prev->fixed
335
        // same pair of dirs
336
24.0M
        && !edgept->next->next->fixed &&
337
24.0M
        edgept->prev->dir == edgept->next->dir &&
338
24.0M
        edgept->prev->prev->dir == edgept->next->next->dir &&
339
24.0M
        ((edgept->prev->dir - edgept->dir + 1) & 7) < 3) {
340
      // unfix it
341
60.6k
      edgept->fixed = false;
342
60.6k
      edgept->next->fixed = false;
343
60.6k
    }
344
24.0M
    edgept = edgept->next;   // do all points
345
24.0M
  } while (edgept != start); // until finished
346
347
1.93M
  stopped = false;
348
1.93M
  if (area < 450) {
349
1.90M
    area = 450;
350
1.90M
  }
351
352
1.93M
  gapmin = area * fixed_dist * fixed_dist / 44000;
353
354
1.93M
  edgept = start;
355
1.93M
  fixed_count = 0;
356
24.0M
  do {
357
24.0M
    if (edgept->fixed) {
358
16.7M
      fixed_count++;
359
16.7M
    }
360
24.0M
    edgept = edgept->next;
361
24.0M
  } while (edgept != start);
362
2.02M
  while (!edgept->fixed) {
363
88.8k
    edgept = edgept->next;
364
88.8k
  }
365
1.93M
  edgefix0 = edgept;
366
367
1.93M
  edgept = edgept->next;
368
2.80M
  while (!edgept->fixed) {
369
870k
    edgept = edgept->next;
370
870k
  }
371
1.93M
  edgefix1 = edgept;
372
373
1.93M
  edgept = edgept->next;
374
2.48M
  while (!edgept->fixed) {
375
550k
    edgept = edgept->next;
376
550k
  }
377
1.93M
  edgefix2 = edgept;
378
379
1.93M
  edgept = edgept->next;
380
2.57M
  while (!edgept->fixed) {
381
642k
    edgept = edgept->next;
382
642k
  }
383
1.93M
  edgefix3 = edgept;
384
385
1.93M
  startfix = edgefix2;
386
387
14.1M
  do {
388
14.1M
    if (fixed_count <= 3) {
389
1.09M
      break; // already too few
390
1.09M
    }
391
13.0M
    d12vec.diff(edgefix1->pos, edgefix2->pos);
392
13.0M
    d12 = d12vec.length2();
393
    // TODO(rays) investigate this change:
394
    // Only unfix a point if it is part of a low-curvature section
395
    // of outline and the total angle change of the outlines is
396
    // less than 90 degrees, ie the scalar product is positive.
397
    // if (d12 <= gapmin && edgefix0->vec.dot(edgefix2->vec) > 0) {
398
13.0M
    if (d12 <= gapmin) {
399
6.77M
      d01vec.diff(edgefix0->pos, edgefix1->pos);
400
6.77M
      d01 = d01vec.length2();
401
6.77M
      d23vec.diff(edgefix2->pos, edgefix3->pos);
402
6.77M
      d23 = d23vec.length2();
403
6.77M
      if (d01 > d23) {
404
4.02M
        edgefix2->fixed = false;
405
4.02M
        fixed_count--;
406
4.02M
      } else {
407
2.75M
        edgefix1->fixed = false;
408
2.75M
        fixed_count--;
409
2.75M
        edgefix1 = edgefix2;
410
2.75M
      }
411
6.77M
    } else {
412
6.30M
      edgefix0 = edgefix1;
413
6.30M
      edgefix1 = edgefix2;
414
6.30M
    }
415
13.0M
    edgefix2 = edgefix3;
416
13.0M
    edgept = edgept->next;
417
21.0M
    while (!edgept->fixed) {
418
7.99M
      if (edgept == startfix) {
419
439k
        stopped = true;
420
439k
      }
421
7.99M
      edgept = edgept->next;
422
7.99M
    }
423
13.0M
    edgefix3 = edgept;
424
13.0M
    edgefix = edgefix2;
425
13.0M
  } while ((edgefix != startfix) && (!stopped));
426
1.93M
}
427
428
/**********************************************************************
429
 *poly2(startpt,area,path) applies a second approximation to the outline
430
 *using the points which have been fixed by the first approximation*
431
 **********************************************************************/
432
433
static EDGEPT *poly2( // second poly
434
    EDGEPT *startpt,  // start of loop
435
    int area          // area of blob box
436
1.93M
) {
437
1.93M
  EDGEPT *edgept;    // current outline point
438
1.93M
  EDGEPT *loopstart; // starting point
439
1.93M
  EDGEPT *linestart; // start of line
440
1.93M
  int edgesum;       // correction count
441
442
1.93M
  if (area < 1200) {
443
1.92M
    area = 1200; // minimum value
444
1.92M
  }
445
446
1.93M
  loopstart = nullptr; // not found it yet
447
1.93M
  edgept = startpt;    // start of loop
448
449
3.01M
  do {
450
    // current point fixed and next not
451
3.01M
    if (edgept->fixed && !edgept->next->fixed) {
452
1.91M
      loopstart = edgept; // start of repoly
453
1.91M
      break;
454
1.91M
    }
455
1.09M
    edgept = edgept->next;     // next point
456
1.09M
  } while (edgept != startpt); // until found or finished
457
458
1.93M
  if (loopstart == nullptr && !startpt->fixed) {
459
    // fixed start of loop
460
0
    startpt->fixed = true;
461
0
    loopstart = startpt; // or start of loop
462
0
  }
463
1.93M
  if (loopstart) {
464
1.95M
    do {
465
1.95M
      edgept = loopstart; // first to do
466
7.27M
      do {
467
7.27M
        linestart = edgept;
468
7.27M
        edgesum = 0; // sum of lengths
469
21.4M
        do {
470
          // sum lengths
471
21.4M
          edgesum += edgept->runlength;
472
21.4M
          edgept = edgept->next; // move on
473
21.4M
        } while (!edgept->fixed && edgept != loopstart && edgesum < 126);
474
7.27M
        if (poly_debug) {
475
0
          tprintf("Poly2:starting at (%d,%d)+%d=(%d,%d),%d to (%d,%d)\n",
476
0
                  linestart->pos.x, linestart->pos.y, linestart->dir,
477
0
                  linestart->vec.x, linestart->vec.y, edgesum, edgept->pos.x,
478
0
                  edgept->pos.y);
479
0
        }
480
        // reapproximate
481
7.27M
        cutline(linestart, edgept, area);
482
483
9.98M
        while (edgept->next->fixed && edgept != loopstart) {
484
2.71M
          edgept = edgept->next; // look for next non-fixed
485
2.71M
        }
486
7.27M
      }
487
      // do all the loop
488
7.27M
      while (edgept != loopstart);
489
1.95M
      edgesum = 0;
490
24.1M
      do {
491
24.1M
        if (edgept->fixed) {
492
10.8M
          edgesum++;
493
10.8M
        }
494
24.1M
        edgept = edgept->next;
495
24.1M
      }
496
      // count fixed pts
497
24.1M
      while (edgept != loopstart);
498
1.95M
      if (edgesum < 3) {
499
41.7k
        area /= 2; // must have 3 pts
500
41.7k
      }
501
1.95M
    } while (edgesum < 3);
502
10.7M
    do {
503
10.7M
      linestart = edgept;
504
23.9M
      do {
505
23.9M
        edgept = edgept->next;
506
23.9M
      } while (!edgept->fixed);
507
10.7M
      linestart->next = edgept;
508
10.7M
      edgept->prev = linestart;
509
10.7M
      linestart->vec.x = edgept->pos.x - linestart->pos.x;
510
10.7M
      linestart->vec.y = edgept->pos.y - linestart->pos.y;
511
10.7M
    } while (edgept != loopstart);
512
1.91M
  } else {
513
20.4k
    edgept = startpt; // start of loop
514
20.4k
  }
515
516
1.93M
  loopstart = edgept; // new start
517
1.93M
  return loopstart;   // correct exit
518
1.93M
}
519
520
/**********************************************************************
521
 * tesspoly_outline
522
 *
523
 * Approximate an outline from chain codes form using the old tess algorithm.
524
 * If allow_detailed_fx is true, the EDGEPTs in the returned TBLOB
525
 * contain pointers to the input C_OUTLINEs that enable higher-resolution
526
 * feature extraction that does not use the polygonal approximation.
527
 **********************************************************************/
528
529
1.93M
TESSLINE *ApproximateOutline(bool allow_detailed_fx, C_OUTLINE *c_outline) {
530
1.93M
  EDGEPT stack_edgepts[FASTEDGELENGTH]; // converted path
531
1.93M
  EDGEPT *edgepts = stack_edgepts;
532
533
  // Use heap memory if the stack buffer is not big enough.
534
1.93M
  if (c_outline->pathlength() > FASTEDGELENGTH) {
535
17.0k
    edgepts = new EDGEPT[c_outline->pathlength()];
536
17.0k
  }
537
538
  // bounding box
539
1.93M
  const auto &loop_box = c_outline->bounding_box();
540
1.93M
  int32_t area = loop_box.height();
541
1.93M
  if (!poly_wide_objects_better && loop_box.width() > area) {
542
0
    area = loop_box.width();
543
0
  }
544
1.93M
  area *= area;
545
1.93M
  edgesteps_to_edgepts(c_outline, edgepts);
546
1.93M
  fix2(edgepts, area);
547
1.93M
  EDGEPT *edgept = poly2(edgepts, area); // 2nd approximation.
548
1.93M
  EDGEPT *startpt = edgept;
549
1.93M
  EDGEPT *result = nullptr;
550
1.93M
  EDGEPT *prev_result = nullptr;
551
10.7M
  do {
552
10.7M
    auto *new_pt = new EDGEPT;
553
10.7M
    new_pt->pos = edgept->pos;
554
10.7M
    new_pt->prev = prev_result;
555
10.7M
    if (prev_result == nullptr) {
556
1.93M
      result = new_pt;
557
8.86M
    } else {
558
8.86M
      prev_result->next = new_pt;
559
8.86M
      new_pt->prev = prev_result;
560
8.86M
    }
561
10.7M
    if (allow_detailed_fx) {
562
0
      new_pt->src_outline = edgept->src_outline;
563
0
      new_pt->start_step = edgept->start_step;
564
0
      new_pt->step_count = edgept->step_count;
565
0
    }
566
10.7M
    prev_result = new_pt;
567
10.7M
    edgept = edgept->next;
568
10.7M
  } while (edgept != startpt);
569
1.93M
  prev_result->next = result;
570
1.93M
  result->prev = prev_result;
571
1.93M
  if (edgepts != stack_edgepts) {
572
17.0k
    delete[] edgepts;
573
17.0k
  }
574
1.93M
  return TESSLINE::BuildFromOutlineList(result);
575
1.93M
}
576
577
} // namespace tesseract