22 #include "config_auto.h"
29 #define PROJECTION_MARGIN 10 //arbitrary
35 const
double kCosSmallAngle = 0.866;
47 cblob_ptr->
rotate(rotation);
49 compute_bounding_box();
54 int left = -box.
right();
66 ICOORD bottom_pt(top_pt.x(), base_char_bottom_);
68 base_char_top_ = top_pt.y();
69 bottom_pt.rotate(rotation);
70 base_char_bottom_ = bottom_pt.y();
88 nextblob->joined =
TRUE;
95 if (cblob_ptr !=
NULL && other->cblob_ptr !=
NULL) {
96 C_OUTLINE_IT ol_it(cblob_ptr->
out_list());
97 ol_it.add_list_after(other->cblob_ptr->
out_list());
112 BLOBNBOX_IT *start_it,
125 float test_ymin, test_ymax;
130 blobcount = (
inT16) floor (box.
width () / xheight);
131 if (blobcount > 1 && cblob_ptr !=
NULL) {
133 blobwidth = (float) (box.
width () + 1) / blobcount;
134 for (blobindex = blobcount - 1, rightx = box.
right ();
135 blobindex >= 0; blobindex--, rightx -= blobwidth) {
140 blob = blob_it.data ();
143 test_ymin, test_ymax);
147 while (blob != end_it->data ());
149 leftx = (
inT16) floor (rightx - blobwidth);
150 if (leftx < box.
left ())
159 newblob->box =
TBOX (bl, tr);
161 newblob->base_char_top_ = tr.
y();
162 newblob->base_char_bottom_ = bl.
y();
163 end_it->add_after_stay_put (newblob);
173 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
176 if (neighbour !=
NULL) {
179 gaps[dir] = box.
x_gap(n_box);
181 gaps[dir] = box.
y_gap(n_box);
192 int* v_min,
int* v_max)
const {
197 *h_max =
MAX(gaps[BND_LEFT], gaps[BND_RIGHT]);
198 if (*h_max > max_dimension && *h_min < max_dimension) *h_max = *h_min;
200 *v_max =
MAX(gaps[BND_ABOVE], gaps[BND_BELOW]);
201 if (*v_max > max_dimension && *v_min < max_dimension) *v_max = *v_min;
206 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
209 neighbours_[dir] =
NULL;
210 good_stroke_neighbours_[dir] =
false;
219 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
230 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
244 int box_perimeter = 2 * (box.
height() + box.
width());
255 perimeter -= 4 *
cblob()->
area() / perimeter;
256 perimeter -= 2 * box.
width();
270 perimeter -= 4 *
cblob()->
area() / perimeter;
271 perimeter -= 2 * box.
height();
283 if (box.
left() < other.box.
left() && box.
left() < other.left_rule_)
285 if (other.box.
left() < box.
left() && other.box.
left() < left_rule_)
287 if (box.
right() > other.box.
right() && box.
right() > other.right_rule_)
289 if (other.box.
right() > box.
right() && other.box.
right() > right_rule_)
296 double fractional_tolerance,
297 double constant_tolerance)
const {
302 float h_tolerance = horz_stroke_width_ * fractional_tolerance
303 + constant_tolerance;
304 float v_tolerance = vert_stroke_width_ * fractional_tolerance
305 + constant_tolerance;
306 double p_tolerance = p_width * fractional_tolerance
307 + constant_tolerance;
308 bool h_zero = horz_stroke_width_ == 0.0f || other.horz_stroke_width_ == 0.0f;
309 bool v_zero = vert_stroke_width_ == 0.0f || other.vert_stroke_width_ == 0.0f;
310 bool h_ok = !h_zero &&
NearlyEqual(horz_stroke_width_,
311 other.horz_stroke_width_, h_tolerance);
312 bool v_ok = !v_zero &&
NearlyEqual(vert_stroke_width_,
313 other.vert_stroke_width_, v_tolerance);
314 bool p_ok = h_zero && v_zero &&
NearlyEqual(p_width, n_p_width, p_tolerance);
318 return p_ok || ((v_ok || h_ok) && (h_ok || h_zero) && (v_ok || v_zero));
325 float top = box.
top();
326 float bottom = box.
bottom();
327 if (cblob_ptr !=
NULL) {
329 static_cast<float>(right), no_rotation,
337 FCOORD bot_left(left, bottom);
338 FCOORD top_right(right, top);
339 TBOX shrunken_box(bot_left);
340 TBOX shrunken_box2(top_right);
341 shrunken_box += shrunken_box2;
347 BLOBNBOX_IT blob_it(blobs);
348 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
349 blob_it.data()->CleanNeighbours();
355 BLOBNBOX_IT blob_it(blobs);
356 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
359 delete blob->
cblob();
360 delete blob_it.extract();
365 #ifndef GRAPHICS_DISABLED
372 BLOBNBOX_IT it(list);
373 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
374 it.data()->plot(win, body_colour, child_colour);
385 BLOBNBOX_IT it(list);
386 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
389 blob->
plot(win, body_colour, child_colour);
395 switch (region_type) {
437 if (cblob_ptr !=
NULL)
438 cblob_ptr->
plot(window, blob_colour, child_colour);
460 C_OUTLINE_IT out_it = blob->
out_list ();
464 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
465 outline = out_it.data ();
468 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
470 if (pos.
x () >= leftx && pos.
x () <= rightx) {
473 vec = outline->
step (stepindex);
499 C_OUTLINE_IT out_it = blob->
out_list ();
503 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
504 outline = out_it.data ();
506 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
508 if (pos.
x () >= leftx && pos.
x () <= rightx) {
511 vec = outline->
step (stepindex);
536 C_OUTLINE_IT out_it = blob->
out_list ();
540 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
541 outline = out_it.data ();
543 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
545 if (pos.
y () >= bottomy && pos.
y () <= topy) {
548 vec = outline->
step (stepindex);
564 C_OUTLINE_LIST out_list;
566 C_OUTLINE_IT in_it = blob->
out_list ();
568 C_OUTLINE_IT out_it = &out_list;
570 for (in_it.mark_cycle_pt (); !in_it.cycled_list (); in_it.forward ()) {
571 out_it.add_after_then_move (
new C_OUTLINE (in_it.data (), rotation));
573 return new C_BLOB (&out_list);
647 initial_y_min = bottom;
650 BLOBNBOX_IT it = &blobs;
652 it.add_to_end (blob);
653 diff = top - bottom - row_size;
659 else if ((top - bottom) * 3 < row_size) {
660 diff = row_size / 3 + bottom - top;
681 BLOBNBOX_IT it = &blobs;
683 it.add_to_end (blob);
684 allowed = row_size + y_min - y_max;
686 available = top > y_max ? top - y_max : 0;
689 available += y_min - bottom;
691 available += available;
692 if (available < allowed)
695 y_min -= (y_min - bottom) * allowed / available;
697 y_max += (top - y_max) * allowed / available;
712 BLOBNBOX_IT it = &blobs;
715 it.add_before_then_move (blob);
718 while (!it.cycled_list ()
719 && it.data ()->bounding_box ().left () <=
722 if (it.cycled_list ())
723 it.add_to_end (blob);
725 it.add_before_stay_put (blob);
742 if (blob_it.empty ())
744 row_box = blob_it.data ()->bounding_box ();
745 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ())
746 row_box += blob_it.data ()->bounding_box ();
752 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
753 blob = blob_it.data();
765 void TO_ROW::clear() {
797 num_repeated_sets_ = -1;
813 C_OUTLINE_IT out_it = blob->
out_list ();
815 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
836 C_OUTLINE_IT out_it = outline->
child ();
840 for (stepindex = 0; stepindex < length; stepindex++) {
841 step = outline->
step (stepindex);
843 stats->
add (pos.
x (), -pos.
y ());
844 }
else if (step.
x () < 0) {
845 stats->
add (pos.
x () - 1, pos.
y ());
850 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
869 static void clear_blobnboxes(BLOBNBOX_LIST* boxes) {
870 BLOBNBOX_IT it = boxes;
873 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
908 clear_blobnboxes(&
blobs);
920 static void SizeFilterBlobs(
int min_height,
int max_height,
921 BLOBNBOX_LIST* src_list,
922 BLOBNBOX_LIST* noise_list,
923 BLOBNBOX_LIST* small_list,
924 BLOBNBOX_LIST* medium_list,
925 BLOBNBOX_LIST* large_list) {
926 BLOBNBOX_IT noise_it(noise_list);
927 BLOBNBOX_IT small_it(small_list);
928 BLOBNBOX_IT medium_it(medium_list);
929 BLOBNBOX_IT large_it(large_list);
930 for (BLOBNBOX_IT src_it(src_list); !src_it.empty(); src_it.forward()) {
935 if (height < min_height &&
936 (width < min_height || width > max_height))
937 noise_it.add_after_then_move(blob);
938 else if (height > max_height)
939 large_it.add_after_then_move(blob);
940 else if (height < min_height)
941 small_it.add_after_then_move(blob);
943 medium_it.add_after_then_move(blob);
955 BLOBNBOX_LIST noise_list;
956 BLOBNBOX_LIST small_list;
957 BLOBNBOX_LIST medium_list;
958 BLOBNBOX_LIST large_list;
959 SizeFilterBlobs(min_height, max_height, &
blobs,
960 &noise_list, &small_list, &medium_list, &large_list);
961 SizeFilterBlobs(min_height, max_height, &
large_blobs,
962 &noise_list, &small_list, &medium_list, &large_list);
963 SizeFilterBlobs(min_height, max_height, &
small_blobs,
964 &noise_list, &small_list, &medium_list, &large_list);
965 SizeFilterBlobs(min_height, max_height, &
noise_blobs,
966 &noise_list, &small_list, &medium_list, &large_list);
967 BLOBNBOX_IT blob_it(&
blobs);
968 blob_it.add_list_after(&medium_list);
970 blob_it.add_list_after(&large_list);
972 blob_it.add_list_after(&small_list);
974 blob_it.add_list_after(&noise_list);
989 #ifndef GRAPHICS_DISABLED
1015 BLOBNBOX_LIST *list,
1018 BLOBNBOX_IT it = list;
1019 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
1020 it.data()->plot(win, body_colour, child_colour);
1023 #endif // GRAPHICS_DISABLED