33 #include "config_auto.h"
39 "Use original wiseowl xheight");
47 "Fix bug in modes threshold for xheights");
51 "Max lost before fallback line used");
54 "X fraction for new partition");
57 #define X_HEIGHT_FRACTION 0.7
58 #define DESCENDER_FRACTION 0.5
59 #define MIN_ASC_FRACTION 0.20
60 #define MIN_DESC_FRACTION 0.25
61 #define MINASCRISE 2.0
62 #define MAXHEIGHTVARIANCE 0.15
64 #define MAXOVERLAP 0.1
66 #define HEIGHTBUCKETS 200
67 #define DELTAHEIGHT 5.0
74 #define ABS(x) ((x)<0 ? (-(x)) : (x))
84 void Textord::make_old_baselines(
TO_BLOCK *block,
89 TO_ROW_IT row_it = block->
get_rows();
93 for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) {
95 find_textlines(block, row, 2,
NULL);
97 find_textlines(block, row, 2, prev_baseline);
101 prev_baseline =
NULL;
104 tprintf(
"Row baseline generation failed on row at (%d,%d)\n",
105 blob_it.data()->bounding_box().left(),
106 blob_it.data()->bounding_box().bottom());
109 correlate_lines(block, gradient);
122 void Textord::correlate_lines(
TO_BLOCK *block,
float gradient) {
125 register int rowindex;
127 TO_ROW_IT row_it = block->
get_rows ();
129 rowcount = row_it.length ();
137 for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
139 rows[rowindex++] = row_it.data ();
142 correlate_neighbours(block, rows, rowcount);
145 block->
xheight = (float) correlate_with_stats(rows, rowcount, block);
151 compute_block_xheight(block, gradient);
164 void Textord::correlate_neighbours(
TO_BLOCK *block,
168 register int rowindex;
169 register int otherrow;
174 for (rowindex = 0; rowindex < rowcount; rowindex++) {
175 row = rows[rowindex];
178 for (otherrow = rowindex - 2;
180 && (rows[otherrow]->
xheight < 0.0
184 for (otherrow = rowindex + 1;
186 && (rows[otherrow]->
xheight < 0.0
191 find_textlines(block, row, 2, &rows[upperrow]->
baseline);
192 if (row->
xheight < 0 && lowerrow < rowcount)
193 find_textlines(block, row, 2, &rows[lowerrow]->
baseline);
196 find_textlines(block, row, 1, &rows[upperrow]->
baseline);
197 else if (lowerrow < rowcount)
198 find_textlines(block, row, 1, &rows[lowerrow]->
baseline);
203 for (biggest = 0.0
f, rowindex = 0; rowindex < rowcount; rowindex++) {
204 row = rows[rowindex];
220 int Textord::correlate_with_stats(
TO_ROW **rows,
224 register int rowindex;
237 xcount = fullcount = desccount = 0;
238 lineheight = ascheight = fullheight = descheight = 0.0;
239 for (rowindex = 0; rowindex < rowcount; rowindex++) {
240 row = rows[rowindex];
258 lineheight /= xcount;
260 fullheight = lineheight + ascheight / xcount;
266 fullheight /= fullcount;
270 if (desccount > 0 && (!
oldbl_corrfix || desccount >= rowcount / 2))
271 descheight /= desccount;
276 if (lineheight > 0.0
f)
281 for (rowindex = 0; rowindex < rowcount; rowindex++) {
282 row = rows[rowindex];
288 row->
ascrise = fullheight - lineheight;
290 xshift = lineheight - row->
xheight;
311 if (row->
ascrise < minascheight)
315 if (row->
descdrop > mindescheight) {
324 return (
int) lineheight;
334 void Textord::find_textlines(
TO_BLOCK *block,
355 blobcount = row->
blob_list ()->length ();
356 partids = (
char *)
alloc_mem (blobcount *
sizeof (
char));
357 xcoords = (
int *)
alloc_mem (blobcount *
sizeof (
int));
358 ycoords = (
int *)
alloc_mem (blobcount *
sizeof (
int));
360 ydiffs = (
float *)
alloc_mem (blobcount *
sizeof (
float));
363 holed_line, blobcount);
371 (
"\nInput height=%g, Estimate x-height=%d pixels, jumplimit=%.2f\n",
372 block->
line_size, lineheight, jumplimit);
379 xcoords, ycoords, spline, &row->
baseline, jumplimit);
380 #ifndef GRAPHICS_DISABLED
386 &partcount, partids, partsizes,
389 partids, bestpart, xcoords, ycoords);
392 degree, pointcount, xstarts);
396 xcoords, ycoords, pointcount, degree);
400 xcoords, xstarts, segments));
422 blobcount, &row->
baseline, jumplimit);
425 blobcount, &row->
baseline, jumplimit);
456 register int blobindex;
462 if (blob_it.empty ())
466 blob_it.mark_cycle_pt ();
470 if (blobcoords[blobindex].height () > lineheight * 0.25)
471 heightstat.
add (blobcoords[blobindex].height (), 1);
473 || blobcoords[blobindex].height () > lineheight * 0.25
474 || blob_it.cycled_list ()) {
479 if (blobcoords[blobindex].height ()
481 && blobcoords[blobindex].
width ()
489 if (losscount > maxlosscount)
491 maxlosscount = losscount;
495 while (!blob_it.cycled_list ());
498 outcount = blobindex;
502 return (
int) heightstat.
ile (0.25);
504 return blobcoords[0].
height ();
530 float prevy, thisy, nexty;
532 float maxmax, minmin;
543 leftedge = blobcoords[0].
left ();
545 rightedge = blobcoords[blobcount - 1].
right ();
547 || spline->segments < 3
549 || spline->xcoords[1] > leftedge +
MAXOVERLAP * (rightedge - leftedge)
550 || spline->xcoords[spline->segments - 1] < rightedge
554 xstarts[0] = blobcoords[0].
left () - 1;
555 for (blobindex = 0; blobindex < blobcount; blobindex++) {
556 xcoords[blobindex] = (blobcoords[blobindex].
left ()
557 + blobcoords[blobindex].
right ()) / 2;
558 ycoords[blobindex] = blobcoords[blobindex].
bottom ();
560 xstarts[1] = blobcoords[blobcount - 1].
right () + 1;
564 *baseline =
QSPLINE (xstarts, segments, xcoords, ycoords, blobcount, 1);
566 if (blobcount >= 3) {
570 maxmax = minmin = 0.0f;
571 thisy = ycoords[0] - baseline->
y (xcoords[0]);
572 nexty = ycoords[1] - baseline->
y (xcoords[1]);
573 for (blobindex = 2; blobindex < blobcount; blobindex++) {
576 nexty = ycoords[blobindex] - baseline->
y (xcoords[blobindex]);
578 if (
ABS (thisy - prevy) < jumplimit &&
ABS (thisy - nexty) < jumplimit) {
584 if (ycount >= 3 && ((y1 < y2 && y2 >= y3)
586 || (y1 > y2 && y2 <= y3))) {
589 xturns[segment] = x2;
590 yturns[segment] = y2;
595 maxmax = minmin = y3;
604 x2 = blobcoords[blobindex - 1].
right ();
610 if (maxmax - minmin > jumplimit) {
612 for (blobindex = 0, segment = 1; blobindex < ycount;
614 if (yturns[blobindex] > minmin + jumplimit
615 || yturns[blobindex] < maxmax - jumplimit) {
618 || yturns[blobindex] > prevy + jumplimit
619 || yturns[blobindex] < prevy - jumplimit) {
621 xstarts[segment] = xturns[blobindex];
623 prevy = yturns[blobindex];
626 else if ((prevy > minmin + jumplimit && yturns[blobindex] > prevy)
628 || (prevy < maxmax - jumplimit && yturns[blobindex] < prevy)) {
629 xstarts[segment - 1] = xturns[blobindex];
631 prevy = yturns[blobindex];
635 xstarts[segment] = blobcoords[blobcount - 1].
right () + 1;
638 *baseline =
QSPLINE (xstarts, segments, xcoords, ycoords, blobcount, 1);
644 shift =
ICOORD (0, (
inT16) (blobcoords[0].bottom ()
645 - spline->
y (blobcoords[0].
right ())));
646 baseline->
move (shift);
679 leftedge = blobcoords[0].
left ();
681 rightedge = blobcoords[blobcount - 1].
right();
682 for (blobindex = 0; blobindex < blobcount; blobindex++) {
683 lms.
Add(
ICOORD((blobcoords[blobindex].left() +
684 blobcoords[blobindex].right()) / 2,
685 blobcoords[blobindex].bottom()));
688 xstarts[0] = leftedge;
689 xstarts[1] = rightedge;
691 coeffs[1] = gradient;
693 *baseline =
QSPLINE (1, xstarts, coeffs);
695 && spline->segments >= 3
697 && spline->xcoords[1] <= leftedge +
MAXOVERLAP * (rightedge - leftedge)
698 && spline->xcoords[spline->segments - 1] >= rightedge
701 x = (leftedge + rightedge) / 2.0;
702 shift =
ICOORD (0, (
inT16) (gradient * x + c - spline->
y (x)));
703 baseline->
move (shift);
728 register int blobindex;
735 for (bestpart = 0; bestpart <
MAXPARTS; bestpart++)
736 partsizes[bestpart] = 0;
738 startx =
get_ydiffs (blobcoords, blobcount, spline, ydiffs);
742 float last_delta = 0.0f;
743 for (blobindex = startx; blobindex < blobcount; blobindex++) {
745 diff = ydiffs[blobindex];
747 tprintf (
"%d(%d,%d), ", blobindex,
748 blobcoords[blobindex].left (),
749 blobcoords[blobindex].bottom ());
752 &drift, &last_delta, numparts);
754 partids[blobindex] = bestpart;
755 partsizes[bestpart]++;
763 for (blobindex = startx; blobindex >= 0; blobindex--) {
764 diff = ydiffs[blobindex];
766 tprintf (
"%d(%d,%d), ", blobindex,
767 blobcoords[blobindex].left (),
768 blobcoords[blobindex].bottom ());
771 &drift, &last_delta, numparts);
773 partids[blobindex] = bestpart;
774 partsizes[bestpart]++;
777 for (biggestpart = 0, bestpart = 1; bestpart < *numparts; bestpart++)
778 if (partsizes[bestpart] >= partsizes[biggestpart])
779 biggestpart = bestpart;
809 register int blobindex;
819 prevpart = biggestpart;
822 for (blobindex = 0; blobindex < blobcount; blobindex++) {
823 if (partids[blobindex] != prevpart) {
827 if (prevpart != biggestpart && runlength >
MAXBADRUN) {
829 for (test_blob = startx; test_blob < blobindex; test_blob++) {
830 coord =
FCOORD ((blobcoords[test_blob].left ()
831 + blobcoords[test_blob].right ()) / 2.0,
832 blobcoords[test_blob].bottom ());
833 stats.
add (coord.
x (), coord.
y ());
839 tprintf (
"Fitted line y=%g x + %g\n", m, c);
842 for (test_blob = 1; !found_one
843 && (startx - test_blob >= 0
844 || blobindex + test_blob <= blobcount); test_blob++) {
845 if (startx - test_blob >= 0
846 && partids[startx - test_blob] == biggestpart) {
848 coord =
FCOORD ((blobcoords[startx - test_blob].left ()
849 + blobcoords[startx -
850 test_blob].right ()) /
853 test_blob].bottom ());
854 diff = m * coord.
x () + c - coord.
y ();
857 (
"Diff of common blob to suspect part=%g at (%g,%g)\n",
858 diff, coord.
x (), coord.
y ());
859 if (diff < jumplimit && -diff < jumplimit)
862 if (blobindex + test_blob <= blobcount
863 && partids[blobindex + test_blob - 1] == biggestpart) {
866 FCOORD ((blobcoords[blobindex + test_blob - 1].
867 left () + blobcoords[blobindex + test_blob -
869 blobcoords[blobindex + test_blob -
871 diff = m * coord.
x () + c - coord.
y ();
874 (
"Diff of common blob to suspect part=%g at (%g,%g)\n",
875 diff, coord.
x (), coord.
y ());
876 if (diff < jumplimit && -diff < jumplimit)
883 (
"Merged %d blobs back into part %d from %d starting at (%d,%d)\n",
884 runlength, biggestpart, prevpart,
885 blobcoords[startx].left (),
886 blobcoords[startx].bottom ());
888 partsizes[prevpart] -= runlength;
889 for (test_blob = startx; test_blob < blobindex; test_blob++)
890 partids[test_blob] = biggestpart;
893 prevpart = partids[blobindex];
918 register int blobindex;
931 lastx = blobcoords[0].
left ();
933 for (blobindex = 0; blobindex < blobcount; blobindex++) {
935 xcentre = (blobcoords[blobindex].
left () + blobcoords[blobindex].
right ()) >> 1;
937 drift += spline->
step (lastx, xcentre);
939 diff = blobcoords[blobindex].
bottom ();
940 diff -= spline->
y (xcentre);
942 ydiffs[blobindex] = diff;
945 diffsum -=
ABS (ydiffs[blobindex - 3]);
946 diffsum +=
ABS (diff);
947 if (blobindex >= 2 && diffsum < bestsum) {
949 bestindex = blobindex - 1;
972 register int partition;
984 delta = diff - partdiffs[lastpart] - *drift;
986 tprintf (
"Diff=%.2f, Delta=%.3f, Drift=%.3f, ", diff, delta, *drift);
988 if (
ABS (delta) > jumplimit / 2) {
990 bestdelta = diff - partdiffs[0] - *drift;
992 for (partition = 1; partition < *partcount; partition++) {
993 delta = diff - partdiffs[partition] - *drift;
994 if (
ABS (delta) <
ABS (bestdelta)) {
996 bestpart = partition;
1001 if (
ABS (bestdelta) > jumplimit
1003 bestpart = (*partcount)++;
1005 partdiffs[bestpart] = diff - *drift;
1010 bestpart = lastpart;
1013 if (bestpart == lastpart
1014 && (
ABS (delta - *lastdelta) < jumplimit / 2
1015 ||
ABS (delta) < jumplimit / 2))
1017 *drift = (3 * *drift + delta) / 3;
1098 register int blobindex;
1102 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1103 if (partids[blobindex] == bestpart) {
1105 xcoords[pointcount] = (blobcoords[blobindex].
left () + blobcoords[blobindex].
right ()) >> 1;
1106 ycoords[pointcount++] = blobcoords[blobindex].
bottom ();
1126 int degree,
int pointcount,
1129 register int ptindex;
1130 register int segment;
1131 int lastmin, lastmax;
1136 xstarts[0] = xcoords[0] - 1;
1137 max_x = xcoords[pointcount - 1] + 1;
1141 if (pointcount > 3) {
1143 lastmax = lastmin = 0;
1144 while (ptindex < pointcount - 1 && turncount <
SPLINESIZE - 1) {
1146 if (ycoords[ptindex - 1] > ycoords[ptindex] && ycoords[ptindex] <= ycoords[ptindex + 1]) {
1147 if (ycoords[ptindex] < ycoords[lastmax] -
TURNLIMIT) {
1148 if (turncount == 0 || turnpoints[turncount - 1] != lastmax)
1150 turnpoints[turncount++] = lastmax;
1153 else if (ycoords[ptindex] < ycoords[lastmin]) {
1159 if (ycoords[ptindex - 1] < ycoords[ptindex] && ycoords[ptindex] >= ycoords[ptindex + 1]) {
1160 if (ycoords[ptindex] > ycoords[lastmin] +
TURNLIMIT) {
1161 if (turncount == 0 || turnpoints[turncount - 1] != lastmin)
1163 turnpoints[turncount++] = lastmin;
1166 else if (ycoords[ptindex] > ycoords[lastmax]) {
1173 if (ycoords[ptindex] < ycoords[lastmax] -
TURNLIMIT
1174 && (turncount == 0 || turnpoints[turncount - 1] != lastmax)) {
1177 turnpoints[turncount++] = lastmax;
1179 turnpoints[turncount++] = ptindex;
1181 else if (ycoords[ptindex] > ycoords[lastmin] +
TURNLIMIT
1183 && (turncount == 0 || turnpoints[turncount - 1] != lastmin)) {
1186 turnpoints[turncount++] = lastmin;
1188 turnpoints[turncount++] = ptindex;
1190 else if (turncount > 0 && turnpoints[turncount - 1] == lastmin
1192 if (ycoords[ptindex] > ycoords[lastmax])
1193 turnpoints[turncount++] = ptindex;
1195 turnpoints[turncount++] = lastmax;
1197 else if (turncount > 0 && turnpoints[turncount - 1] == lastmax
1199 if (ycoords[ptindex] < ycoords[lastmin])
1200 turnpoints[turncount++] = ptindex;
1202 turnpoints[turncount++] = lastmin;
1207 tprintf (
"First turn is %d at (%d,%d)\n",
1208 turnpoints[0], xcoords[turnpoints[0]], ycoords[turnpoints[0]]);
1209 for (segment = 1; segment < turncount; segment++) {
1211 lastmax = (ycoords[turnpoints[segment - 1]] + ycoords[turnpoints[segment]]) / 2;
1214 if (ycoords[turnpoints[segment - 1]] < ycoords[turnpoints[segment]])
1216 for (ptindex = turnpoints[segment - 1] + 1; ptindex < turnpoints[segment] && ycoords[ptindex + 1] <= lastmax; ptindex++);
1219 for (ptindex = turnpoints[segment - 1] + 1; ptindex < turnpoints[segment] && ycoords[ptindex + 1] >= lastmax; ptindex++);
1222 xstarts[segment] = (xcoords[ptindex - 1] + xcoords[ptindex]
1223 + xcoords[turnpoints[segment - 1]]
1224 + xcoords[turnpoints[segment]] + 2) / 4;
1227 tprintf (
"Turn %d is %d at (%d,%d), mid pt is %d@%d, final @%d\n",
1228 segment, turnpoints[segment],
1229 xcoords[turnpoints[segment]], ycoords[turnpoints[segment]],
1230 ptindex - 1, xcoords[ptindex - 1], xstarts[segment]);
1233 xstarts[segment] = max_x;
1254 register int segment;
1255 int startindex, centreindex, endindex;
1256 float leftcoord, rightcoord;
1257 int leftindex, rightindex;
1262 for (segment = 1; segment < segments - 1; segment++) {
1263 step = baseline->
step ((xstarts[segment - 1] + xstarts[segment]) / 2.0,
1264 (xstarts[segment] + xstarts[segment + 1]) / 2.0);
1267 if (step > jumplimit) {
1268 while (xcoords[startindex] < xstarts[segment - 1])
1270 centreindex = startindex;
1271 while (xcoords[centreindex] < xstarts[segment])
1273 endindex = centreindex;
1274 while (xcoords[endindex] < xstarts[segment + 1])
1278 tprintf (
"Too many segments to resegment spline!!\n");
1281 while (centreindex - startindex <
1284 while (endindex - centreindex <
1287 leftindex = (startindex + startindex + centreindex) / 3;
1288 rightindex = (centreindex + endindex + endindex) / 3;
1290 (xcoords[startindex] * 2 + xcoords[centreindex]) / 3.0;
1292 (xcoords[centreindex] + xcoords[endindex] * 2) / 3.0;
1293 while (xcoords[leftindex] > leftcoord
1296 while (xcoords[leftindex] < leftcoord
1297 && centreindex - leftindex >
1300 if (xcoords[leftindex] - leftcoord >
1301 leftcoord - xcoords[leftindex - 1])
1303 while (xcoords[rightindex] > rightcoord
1304 && rightindex - centreindex >
1307 while (xcoords[rightindex] < rightcoord
1310 if (xcoords[rightindex] - rightcoord >
1311 rightcoord - xcoords[rightindex - 1])
1314 tprintf (
"Splitting spline at %d with step %g at (%d,%d)\n",
1317 step ((xstarts[segment - 1] +
1318 xstarts[segment]) / 2.0,
1320 xstarts[segment + 1]) / 2.0),
1321 (xcoords[leftindex - 1] + xcoords[leftindex]) / 2,
1322 (xcoords[rightindex - 1] + xcoords[rightindex]) / 2);
1324 (xcoords[leftindex - 1] +
1325 xcoords[leftindex]) / 2,
1326 (xcoords[rightindex - 1] +
1327 xcoords[rightindex]) / 2, segments);
1332 (
"Resegmenting spline failed - insufficient pts (%d,%d,%d,%d)\n",
1333 startindex, centreindex, endindex,
1357 int coord2,
int &segments
1361 for (index = segments; index > segment; index--)
1362 xstarts[index + 1] = xstarts[index];
1364 xstarts[segment] = coord1;
1365 xstarts[segment + 1] = coord2;
1386 register int blobindex;
1387 register int partition;
1398 for (partition = 0; partition < partcount; partition++)
1399 partsteps[partition] = 0.0;
1400 for (runlength = 0, blobindex = 0; blobindex < blobcount; blobindex++) {
1401 xcentre = (blobcoords[blobindex].
left ()
1402 + blobcoords[blobindex].
right ()) >> 1;
1404 if (partids[blobindex] != bestpart) {
1406 if (runlength > biggestrun)
1407 biggestrun = runlength;
1408 partsteps[partids[blobindex]] += blobcoords[blobindex].
bottom ()
1418 poscount = negcount = 0;
1419 bestpos = bestneg = 0.0;
1420 for (partition = 0; partition < partcount; partition++) {
1421 if (partition != bestpart) {
1424 if (partsizes[partition]==0)
1425 partsteps[partition]=0;
1427 partsteps[partition] /= partsizes[partition];
1432 && partsizes[partition] > poscount) {
1434 bestpos = partsteps[partition];
1436 poscount = partsizes[partition];
1439 && partsizes[partition] > negcount) {
1441 bestneg = partsteps[partition];
1443 negcount = partsizes[partition];
1448 partsteps[bestpart] /= blobcount;
1470 register int blobindex;
1480 register float diff;
1482 if (blobcount > 1) {
1483 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1484 xcentre = (blobcoords[blobindex].
left ()
1485 + blobcoords[blobindex].
right ()) / 2;
1487 height = (int) (blobcoords[blobindex].top () - baseline->
y (xcentre) + 0.5);
1490 heightstat.
add (height, 1);
1493 lineheight = (int) heightstat.
ile (0.25);
1494 if (lineheight <= 0)
1495 lineheight = (int) heightstat.
ile (0.5);
1498 lineheight = initialheight;
1501 lineheight = (int) (blobcoords[0].top ()
1502 - baseline->
y ((blobcoords[0].left ()
1503 + blobcoords[0].right ()) / 2) +
1509 for (ascenders = 0.0
f, asccount = 0, blobindex = 0; blobindex < blobcount;
1511 xcentre = (blobcoords[blobindex].
left ()
1512 + blobcoords[blobindex].
right ()) / 2;
1513 diff = blobcoords[blobindex].
top () - baseline->
y (xcentre);
1515 if (diff > lineheight + jumplimit) {
1519 else if (diff > lineheight - jumplimit) {
1527 xsum = (float) lineheight;
1530 row->
ascrise = ascenders / asccount - xsum;
1551 int init_lineheight,
1564 const int kBaselineTouch = 2;
1565 const int kGoodStrength = 8;
1566 const float kMinHeight = 0.25;
1568 sign_bit = row->
xheight > 0 ? 1 : -1;
1573 for (blobindex = 0; blobindex < blobcount; blobindex++) {
1574 int xcenter = (blobcoords[blobindex].
left () +
1575 blobcoords[blobindex].
right ()) / 2;
1576 float base = baseline->
y(xcenter);
1577 float bottomdiff = fabs(base - blobcoords[blobindex].bottom());
1579 bottomdiff <= kBaselineTouch ? kGoodStrength : 1;
1580 int height =
static_cast<int>(blobcoords[blobindex].
top () - base + 0.5);
1581 if (blobcoords[blobindex].height () > init_lineheight * kMinHeight) {
1584 heightstat.
add (height, strength);
1586 if (xcenter > rights[height])
1587 rights[height] = xcenter;
1588 if (xcenter > 0 && (lefts[height] == 0 || xcenter < lefts[height]))
1589 lefts[height] = xcenter;
1592 mode_count += strength;
1596 mode_threshold = (int) (blobcount * 0.1);
1598 mode_threshold = (int) (mode_count * 0.1);
1601 tprintf (
"blobcount=%d, mode_count=%d, mode_t=%d\n",
1602 blobcount, mode_count, mode_threshold);
1606 for (blobindex = 0; blobindex <
MODENUM; blobindex++)
1607 tprintf (
"mode[%d]=%d ", blobindex, modelist[blobindex]);
1610 pick_x_height(row, modelist, lefts, rights, &heightstat, mode_threshold);
1635 int modelist[],
int modenum
1646 for (mode_count = 0; mode_count < modenum; mode_count++) {
1648 for (i = 0; i < statnum; i++) {
1651 ((stats->
pile_count (i) == last_max) && (i > last_i))) {
1658 total_max += last_max;
1659 if (last_max <= total_max / mode_factor)
1661 modelist[mode_count] =
mode;
1674 int lefts[],
int rights[],
1676 int mode_threshold) {
1681 int found_one_bigger =
FALSE;
1682 int best_x_height = 0;
1686 for (x = 0; x <
MODENUM; x++) {
1687 for (y = 0; y <
MODENUM; y++) {
1689 if (modelist[x] && modelist[y] &&
1690 heightstat->
pile_count (modelist[x]) > mode_threshold &&
1692 MIN(rights[modelist[x]], rights[modelist[y]]) >
1693 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1694 ratio = (float) modelist[y] / (
float) modelist[x];
1695 if (1.2 < ratio && ratio < 1.8) {
1697 best_x_height = modelist[x];
1698 num_in_best = heightstat->
pile_count (modelist[x]);
1702 found_one_bigger =
FALSE;
1703 for (z = 0; z <
MODENUM; z++) {
1704 if (modelist[z] == best_x_height + 1 &&
1706 MIN(rights[modelist[x]], rights[modelist[y]]) >
1707 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1708 ratio = (float) modelist[y] / (
float) modelist[z];
1709 if ((1.2 < ratio && ratio < 1.8) &&
1712 num_in_best * 0.5) {
1714 found_one_bigger =
TRUE;
1720 while (found_one_bigger);
1724 best_asc = modelist[y];
1725 num_in_best = heightstat->
pile_count (modelist[y]);
1729 found_one_bigger =
FALSE;
1730 for (z = 0; z <
MODENUM; z++) {
1731 if (modelist[z] > best_asc &&
1733 MIN(rights[modelist[x]], rights[modelist[y]]) >
1734 MAX(lefts[modelist[x]], lefts[modelist[y]]))) {
1735 ratio = (float) modelist[z] / (
float) best_x_height;
1736 if ((1.2 < ratio && ratio < 1.8) &&
1739 num_in_best * 0.5) {
1740 best_asc = modelist[z];
1741 found_one_bigger =
TRUE;
1747 while (found_one_bigger);
1749 row->
xheight = (float) best_x_height;
1750 row->
ascrise = (float) best_asc - best_x_height;
1757 best_x_height = modelist[0];
1758 num_in_best = heightstat->
pile_count (best_x_height);
1761 found_one_bigger =
FALSE;
1762 for (z = 1; z <
MODENUM; z++) {
1764 if ((modelist[z] == best_x_height + 1) &&
1765 (heightstat->
pile_count (modelist[z]) > num_in_best * 0.5)) {
1767 found_one_bigger =
TRUE;
1772 while (found_one_bigger);
1775 row->
xheight = (float) best_x_height;