500 {
501 bool faking;
502 bool mid_cut;
503 int16_t left_edge;
504 int16_t right_edge;
505 int16_t x;
506 int16_t array_origin;
507 int16_t offset;
508 int16_t projection_offset;
509 int16_t prev_zero;
510 int16_t next_zero;
511 int16_t zero_offset;
512 int16_t best_left_x = 0;
513 int16_t best_right_x = 0;
515 int minindex;
516 int test_index;
517 double best_cost;
518 double mean_sum;
520 int16_t best_fake;
521 int16_t best_count;
522 FPSEGPT_IT seg_it = seg_list;
523
524 end = (end - start) % pitch;
525 if (pitch < 3)
526 pitch = 3;
527 if ((pitch - 3) / 2 < pitch_error)
528 pitch_error = (pitch - 3) / 2;
529
531 for (left_edge = projection_left; projection->
pile_count (left_edge) == 0
532 && left_edge < projection_right; left_edge++);
533 for (right_edge = projection_right; projection->
pile_count (right_edge) == 0
534 && right_edge > left_edge; right_edge--);
535 array_origin = left_edge - pitch;
536
537 std::vector<FPCUTPT> cutpts(right_edge - left_edge + pitch * 2 + 1);
538
539 std::vector<bool> mins(pitch_error * 2 + 1);
540 for (x = array_origin; x < left_edge; x++)
541
542 cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
543 zero_count, pitch, x, 0);
544 prev_zero = left_edge - 1;
545 for (offset = 0; offset <= pitch_error; offset++, x++)
546
547 cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
548 zero_count, pitch, x, offset);
549
550 best_cost = FLT_MAX;
551 best_end = nullptr;
552 for (offset = -pitch_error, minindex = 0; offset < pitch_error;
553 offset++, minindex++)
554 mins[minindex] = projection->
local_min (x + offset);
555 next_zero = x + zero_offset + 1;
556 for (offset = next_zero - 1; offset >= x; offset--) {
557 if (projection->
pile_count (offset) <= zero_count) {
558 next_zero = offset;
559 break;
560 }
561 }
562 while (x < right_edge - pitch_error) {
563 mins[minindex] = projection->
local_min (x + pitch_error);
564 minindex++;
565 if (minindex > pitch_error * 2)
566 minindex = 0;
567 faking = false;
568 mid_cut = false;
569 offset = 0;
570 if (projection->
pile_count (x) <= zero_count) {
571 prev_zero = x;
572 }
573 else {
574 for (offset = 1; offset <= pitch_error; offset++)
575 if (projection->
pile_count (x + offset) <= zero_count
576 || projection->
pile_count (x - offset) <= zero_count)
577 break;
578 }
579 if (offset > pitch_error) {
580 if (x - prev_zero > zero_offset && next_zero - x > zero_offset) {
581 for (offset = 0; offset <= pitch_error; offset++) {
582 test_index = minindex + pitch_error + offset;
583 if (test_index > pitch_error * 2)
584 test_index -= pitch_error * 2 + 1;
585 if (mins[test_index])
586 break;
587 test_index = minindex + pitch_error - offset;
588 if (test_index > pitch_error * 2)
589 test_index -= pitch_error * 2 + 1;
590 if (mins[test_index])
591 break;
592 }
593 }
594 if (offset > pitch_error) {
596 faking = true;
597 }
598 else {
599 projection_offset =
600 static_cast<int16_t
>(projection->
pile_count (x) / projection_scale);
601 if (projection_offset > offset)
602 offset = projection_offset;
603 mid_cut = true;
604 }
605 }
606 if ((start == 0 && end == 0)
608 || (x - projection_left - start) % pitch <= end)
609 cutpts[x - array_origin].assign(&cutpts[0], array_origin, x,
610 faking, mid_cut, offset, projection,
611 projection_scale, zero_count, pitch,
612 pitch_error);
613 else
614 cutpts[x - array_origin].assign_cheap(&cutpts[0], array_origin, x,
615 faking, mid_cut, offset,
616 projection, projection_scale,
617 zero_count, pitch,
618 pitch_error);
619 x++;
620 if (next_zero < x || next_zero == x + zero_offset)
621 next_zero = x + zero_offset + 1;
622 if (projection->
pile_count (x + zero_offset) <= zero_count)
623 next_zero = x + zero_offset;
624 }
625
626 best_fake = INT16_MAX;
627 best_cost = INT32_MAX;
628 best_count = INT16_MAX;
629 while (x < right_edge + pitch) {
630 offset = x < right_edge ? right_edge - x : 0;
631 cutpts[x - array_origin].assign(&cutpts[0], array_origin, x,
632 false, false, offset, projection,
633 projection_scale, zero_count, pitch,
634 pitch_error);
635 cutpts[x - array_origin].terminal = true;
636 if (cutpts[x - array_origin].index () +
637 cutpts[x - array_origin].fake_count <= best_count + best_fake) {
638 if (cutpts[x - array_origin].fake_count < best_fake
639 || (cutpts[x - array_origin].fake_count == best_fake
640 && cutpts[x - array_origin].cost_function () < best_cost)) {
641 best_fake = cutpts[x - array_origin].fake_count;
642 best_cost = cutpts[x - array_origin].cost_function ();
643 best_left_x = x;
644 best_right_x = x;
645 best_count = cutpts[x - array_origin].index ();
646 }
647 else if (cutpts[x - array_origin].fake_count == best_fake
648 && x == best_right_x + 1
649 && cutpts[x - array_origin].cost_function () == best_cost) {
650
651 best_right_x = x;
652 }
653 }
654 x++;
655 }
657
658 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
659
660
661
662
663
664
665
666
667 occupation_count = -1;
668 do {
669 for (x = best_end->
position () - pitch + pitch_error;
670 x < best_end->
position () - pitch_error
672 if (x < best_end->position () - pitch_error)
673 occupation_count++;
674
675 segpt =
new FPSEGPT (best_end);
676 seg_it.add_before_then_move (segpt);
678 }
679 while (best_end != nullptr);
680 seg_it.move_to_last ();
681 mean_sum = seg_it.data ()->
sum ();
682 mean_sum = mean_sum * mean_sum / best_count;
683 if (seg_it.data ()->squares () - mean_sum < 0)
684 tprintf (
"Impossible sqsum=%g, mean=%g, total=%d\n",
685 seg_it.data ()->squares (), seg_it.data ()->sum (), best_count);
686 return seg_it.data ()->squares () - mean_sum;
687}
bool textord_fast_pitch_test
bool local_min(int32_t x) const