1 /**********************************************************************
2 * File: blobbox.cpp (Formerly blobnbox.c)
3 * Description: Code for the textord blob class.
4 * Author: Ray Smith
5 * Created: Thu Jul 30 09:08:51 BST 1992
6 *
7 * (C) Copyright 1992, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h"
21 #include "blobbox.h"
22
23 #define PROJECTION_MARGIN 10 //arbitrary
24 #define EXTERN
25
26 EXTERN double_VAR (textord_error_weight, 3,
27 "Weighting for error in believability");
28 EXTERN BOOL_VAR (pitsync_projection_fix, TRUE,
29 "Fix bug in projection profile");
30
ELIST2IZE(TO_ROW)31 ELISTIZE (BLOBNBOX) ELIST2IZE (TO_ROW) ELISTIZE (TO_BLOCK)
32 /**********************************************************************
33 * BLOBNBOX::merge
34 *
35 * Merge this blob with the given blob, which should be after this.
36 **********************************************************************/
37 void BLOBNBOX::merge( //merge blobs
38 BLOBNBOX *nextblob //blob to join with
39 ) {
40 box += nextblob->box; //merge boxes
41 nextblob->joined = TRUE;
42 }
43
44
45 /**********************************************************************
46 * BLOBNBOX::chop
47 *
48 * Chop this blob into equal sized pieces using the x height as a guide.
49 * The blob is not actually chopped. Instead, fake blobs are inserted
50 * with the relevant bounding boxes.
51 **********************************************************************/
52
chop(BLOBNBOX_IT * start_it,BLOBNBOX_IT * end_it,FCOORD rotation,float xheight)53 void BLOBNBOX::chop( //chop blobs
54 BLOBNBOX_IT *start_it, //location of this
55 BLOBNBOX_IT *end_it, //iterator
56 FCOORD rotation, //for landscape
57 float xheight //of line
58 ) {
59 inT16 blobcount; //no of blobs
60 BLOBNBOX *newblob; //fake blob
61 BLOBNBOX *blob; //current blob
62 inT16 blobindex; //number of chop
63 inT16 leftx; //left edge of blob
64 float blobwidth; //width of each
65 float rightx; //right edge to scan
66 float ymin, ymax; //limits of new blob
67 float test_ymin, test_ymax; //limits of part blob
68 ICOORD bl, tr; //corners of box
69 BLOBNBOX_IT blob_it; //blob iterator
70
71 //get no of chops
72 blobcount = (inT16) floor (box.width () / xheight);
73 if (blobcount > 1 && (blob_ptr != NULL || cblob_ptr != NULL)) {
74 //width of each
75 blobwidth = (float) (box.width () + 1) / blobcount;
76 for (blobindex = blobcount - 1, rightx = box.right ();
77 blobindex >= 0; blobindex--, rightx -= blobwidth) {
78 ymin = (float) MAX_INT32;
79 ymax = (float) -MAX_INT32;
80 blob_it = *start_it;
81 do {
82 blob = blob_it.data ();
83 if (blob->blob_ptr != NULL)
84 find_blob_limits (blob->blob_ptr, rightx - blobwidth, rightx,
85 rotation, test_ymin, test_ymax);
86 else
87 find_cblob_vlimits (blob->cblob_ptr, rightx - blobwidth,
88 rightx,
89 /*rotation, */ test_ymin, test_ymax);
90 blob_it.forward ();
91 if (test_ymin < ymin)
92 ymin = test_ymin;
93 if (test_ymax > ymax)
94 ymax = test_ymax;
95 }
96 while (blob != end_it->data ());
97 if (ymin < ymax) {
98 leftx = (inT16) floor (rightx - blobwidth);
99 if (leftx < box.left ())
100 leftx = box.left (); //clip to real box
101 bl = ICOORD (leftx, (inT16) floor (ymin));
102 tr = ICOORD ((inT16) ceil (rightx), (inT16) ceil (ymax));
103 if (blobindex == 0)
104 box = TBOX (bl, tr); //change box
105 else {
106 newblob = new BLOBNBOX;
107 //box is all it has
108 newblob->box = TBOX (bl, tr);
109 //stay on current
110 end_it->add_after_stay_put (newblob);
111 }
112 }
113 }
114 }
115 }
116
117
118 /**********************************************************************
119 * find_blob_limits
120 *
121 * Scan the outlines of the blob to locate the y min and max
122 * between the given x limits.
123 **********************************************************************/
124
find_blob_limits(PBLOB * blob,float leftx,float rightx,FCOORD rotation,float & ymin,float & ymax)125 void find_blob_limits( //get y limits
126 PBLOB *blob, //blob to search
127 float leftx, //x limits
128 float rightx,
129 FCOORD rotation, //for landscape
130 float &ymin, //output y limits
131 float &ymax) {
132 float testy; //y intercept
133 FCOORD pos; //rotated
134 FCOORD vec;
135 POLYPT *polypt; //current point
136 //outlines
137 OUTLINE_IT out_it = blob->out_list ();
138 POLYPT_IT poly_it; //outline pts
139
140 ymin = (float) MAX_INT32;
141 ymax = (float) -MAX_INT32;
142 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
143 //get points
144 poly_it.set_to_list (out_it.data ()->polypts ());
145 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list ();
146 poly_it.forward ()) {
147 polypt = poly_it.data ();
148 pos = polypt->pos;
149 pos.rotate (rotation);
150 vec = polypt->vec;
151 vec.rotate (rotation);
152 if ((pos.x () < leftx && pos.x () + vec.x () > leftx)
153 || (pos.x () > leftx && pos.x () + vec.x () < leftx)) {
154 testy = pos.y () + vec.y () * (leftx - pos.x ()) / vec.x ();
155 //intercept of boundary
156 if (testy < ymin)
157 ymin = testy;
158 if (testy > ymax)
159 ymax = testy;
160 }
161 if (pos.x () >= leftx && pos.x () <= rightx) {
162 if (pos.y () > ymax)
163 ymax = pos.y ();
164 if (pos.y () < ymin)
165 ymin = pos.y ();
166 }
167 if ((pos.x () > rightx && pos.x () + vec.x () < rightx)
168 || (pos.x () < rightx && pos.x () + vec.x () > rightx)) {
169 testy = pos.y () + vec.y () * (rightx - pos.x ()) / vec.x ();
170 //intercept of boundary
171 if (testy < ymin)
172 ymin = testy;
173 if (testy > ymax)
174 ymax = testy;
175 }
176 }
177 }
178 }
179
180
181 /**********************************************************************
182 * find_cblob_limits
183 *
184 * Scan the outlines of the cblob to locate the y min and max
185 * between the given x limits.
186 **********************************************************************/
187
find_cblob_limits(C_BLOB * blob,float leftx,float rightx,FCOORD rotation,float & ymin,float & ymax)188 void find_cblob_limits( //get y limits
189 C_BLOB *blob, //blob to search
190 float leftx, //x limits
191 float rightx,
192 FCOORD rotation, //for landscape
193 float &ymin, //output y limits
194 float &ymax) {
195 inT16 stepindex; //current point
196 ICOORD pos; //current coords
197 ICOORD vec; //rotated step
198 C_OUTLINE *outline; //current outline
199 //outlines
200 C_OUTLINE_IT out_it = blob->out_list ();
201
202 ymin = (float) MAX_INT32;
203 ymax = (float) -MAX_INT32;
204 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
205 outline = out_it.data ();
206 pos = outline->start_pos (); //get coords
207 pos.rotate (rotation);
208 for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
209 //inside
210 if (pos.x () >= leftx && pos.x () <= rightx) {
211 if (pos.y () > ymax)
212 ymax = pos.y ();
213 if (pos.y () < ymin)
214 ymin = pos.y ();
215 }
216 vec = outline->step (stepindex);
217 vec.rotate (rotation);
218 pos += vec; //move to next
219 }
220 }
221 }
222
223
224 /**********************************************************************
225 * find_cblob_vlimits
226 *
227 * Scan the outlines of the cblob to locate the y min and max
228 * between the given x limits.
229 **********************************************************************/
230
find_cblob_vlimits(C_BLOB * blob,float leftx,float rightx,float & ymin,float & ymax)231 void find_cblob_vlimits( //get y limits
232 C_BLOB *blob, //blob to search
233 float leftx, //x limits
234 float rightx,
235 float &ymin, //output y limits
236 float &ymax) {
237 inT16 stepindex; //current point
238 ICOORD pos; //current coords
239 ICOORD vec; //rotated step
240 C_OUTLINE *outline; //current outline
241 //outlines
242 C_OUTLINE_IT out_it = blob->out_list ();
243
244 ymin = (float) MAX_INT32;
245 ymax = (float) -MAX_INT32;
246 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
247 outline = out_it.data ();
248 pos = outline->start_pos (); //get coords
249 for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
250 //inside
251 if (pos.x () >= leftx && pos.x () <= rightx) {
252 if (pos.y () > ymax)
253 ymax = pos.y ();
254 if (pos.y () < ymin)
255 ymin = pos.y ();
256 }
257 vec = outline->step (stepindex);
258 pos += vec; //move to next
259 }
260 }
261 }
262
263
264 /**********************************************************************
265 * find_cblob_hlimits
266 *
267 * Scan the outlines of the cblob to locate the x min and max
268 * between the given y limits.
269 **********************************************************************/
270
find_cblob_hlimits(C_BLOB * blob,float bottomy,float topy,float & xmin,float & xmax)271 void find_cblob_hlimits( //get x limits
272 C_BLOB *blob, //blob to search
273 float bottomy, //y limits
274 float topy,
275 float &xmin, //output x limits
276 float &xmax) {
277 inT16 stepindex; //current point
278 ICOORD pos; //current coords
279 ICOORD vec; //rotated step
280 C_OUTLINE *outline; //current outline
281 //outlines
282 C_OUTLINE_IT out_it = blob->out_list ();
283
284 xmin = (float) MAX_INT32;
285 xmax = (float) -MAX_INT32;
286 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
287 outline = out_it.data ();
288 pos = outline->start_pos (); //get coords
289 for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
290 //inside
291 if (pos.y () >= bottomy && pos.y () <= topy) {
292 if (pos.x () > xmax)
293 xmax = pos.x ();
294 if (pos.x () < xmin)
295 xmin = pos.x ();
296 }
297 vec = outline->step (stepindex);
298 pos += vec; //move to next
299 }
300 }
301 }
302
303
304 /**********************************************************************
305 * rotate_blob
306 *
307 * Poly copy the blob and rotate the copy by the given vector.
308 **********************************************************************/
309
rotate_blob(PBLOB * blob,FCOORD rotation)310 PBLOB *rotate_blob( //get y limits
311 PBLOB *blob, //blob to search
312 FCOORD rotation //vector to rotate by
313 ) {
314 PBLOB *copy; //copy of blob
315 POLYPT *polypt; //current point
316 OUTLINE_IT out_it;
317 POLYPT_IT poly_it; //outline pts
318
319 copy = new PBLOB;
320 *copy = *blob; //deep copy
321 out_it.set_to_list (copy->out_list ());
322 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
323 //get points
324 poly_it.set_to_list (out_it.data ()->polypts ());
325 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list ();
326 poly_it.forward ()) {
327 polypt = poly_it.data ();
328 //rotate it
329 polypt->pos.rotate (rotation);
330 polypt->vec.rotate (rotation);
331 }
332 out_it.data ()->compute_bb ();
333 }
334 return copy;
335 }
336
337
338 /**********************************************************************
339 * rotate_cblob
340 *
341 * Poly copy the blob and rotate the copy by the given vector.
342 **********************************************************************/
343
rotate_cblob(C_BLOB * blob,float xheight,FCOORD rotation)344 PBLOB *rotate_cblob( //rotate it
345 C_BLOB *blob, //blob to search
346 float xheight, //for poly approx
347 FCOORD rotation //for landscape
348 ) {
349 PBLOB *copy; //copy of blob
350 POLYPT *polypt; //current point
351 OUTLINE_IT out_it;
352 POLYPT_IT poly_it; //outline pts
353
354 copy = new PBLOB (blob, xheight);
355 out_it.set_to_list (copy->out_list ());
356 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
357 //get points
358 poly_it.set_to_list (out_it.data ()->polypts ());
359 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list ();
360 poly_it.forward ()) {
361 polypt = poly_it.data ();
362 //rotate it
363 polypt->pos.rotate (rotation);
364 polypt->vec.rotate (rotation);
365 }
366 out_it.data ()->compute_bb ();
367 }
368 return copy;
369 }
370
371
372 /**********************************************************************
373 * crotate_cblob
374 *
375 * Rotate the copy by the given vector and return a C_BLOB.
376 **********************************************************************/
377
crotate_cblob(C_BLOB * blob,FCOORD rotation)378 C_BLOB *crotate_cblob( //rotate it
379 C_BLOB *blob, //blob to search
380 FCOORD rotation //for landscape
381 ) {
382 C_OUTLINE_LIST out_list; //output outlines
383 //input outlines
384 C_OUTLINE_IT in_it = blob->out_list ();
385 //output outlines
386 C_OUTLINE_IT out_it = &out_list;
387
388 for (in_it.mark_cycle_pt (); !in_it.cycled_list (); in_it.forward ()) {
389 out_it.add_after_then_move (new C_OUTLINE (in_it.data (), rotation));
390 }
391 return new C_BLOB (&out_list);
392 }
393
394
395 /**********************************************************************
396 * box_next
397 *
398 * Compute the bounding box of this blob with merging of x overlaps
399 * but no pre-chopping.
400 * Then move the iterator on to the start of the next blob.
401 **********************************************************************/
402
box_next(BLOBNBOX_IT * it)403 TBOX box_next( //get bounding box
404 BLOBNBOX_IT *it //iterator to blobds
405 ) {
406 BLOBNBOX *blob; //current blob
407 TBOX result; //total box
408
409 blob = it->data ();
410 result = blob->bounding_box ();
411 do {
412 it->forward ();
413 blob = it->data ();
414 if (blob->blob () == NULL && blob->cblob () == NULL)
415 //was pre-chopped
416 result += blob->bounding_box ();
417 }
418 //until next real blob
419 while ((blob->blob () == NULL && blob->cblob () == NULL) || blob->joined_to_prev ());
420 return result;
421 }
422
423
424 /**********************************************************************
425 * box_next_pre_chopped
426 *
427 * Compute the bounding box of this blob with merging of x overlaps
428 * but WITH pre-chopping.
429 * Then move the iterator on to the start of the next pre-chopped blob.
430 **********************************************************************/
431
box_next_pre_chopped(BLOBNBOX_IT * it)432 TBOX box_next_pre_chopped( //get bounding box
433 BLOBNBOX_IT *it //iterator to blobds
434 ) {
435 BLOBNBOX *blob; //current blob
436 TBOX result; //total box
437
438 blob = it->data ();
439 result = blob->bounding_box ();
440 do {
441 it->forward ();
442 blob = it->data ();
443 }
444 //until next real blob
445 while (blob->joined_to_prev ());
446 return result;
447 }
448
449
450 /**********************************************************************
451 * TO_ROW::TO_ROW
452 *
453 * Constructor to make a row from a blob.
454 **********************************************************************/
455
TO_ROW(BLOBNBOX * blob,float top,float bottom,float row_size)456 TO_ROW::TO_ROW ( //constructor
457 BLOBNBOX * blob, //first blob
458 float top, //corrected top
459 float bottom, //of row
460 float row_size //ideal
461 ): y_min(bottom), y_max(top), initial_y_min(bottom), num_repeated_sets_(-1) {
462 float diff; //in size
463 BLOBNBOX_IT it = &blobs; //list of blobs
464
465 it.add_to_end (blob);
466 diff = top - bottom - row_size;
467 if (diff > 0) {
468 y_max -= diff / 2;
469 y_min += diff / 2;
470 }
471 //very small object
472 else if ((top - bottom) * 3 < row_size) {
473 diff = row_size / 3 + bottom - top;
474 y_max += diff / 2;
475 y_min -= diff / 2;
476 }
477 }
478
479
480 /**********************************************************************
481 * TO_ROW:add_blob
482 *
483 * Add the blob to the end of the row.
484 **********************************************************************/
485
add_blob(BLOBNBOX * blob,float top,float bottom,float row_size)486 void TO_ROW::add_blob( //constructor
487 BLOBNBOX *blob, //first blob
488 float top, //corrected top
489 float bottom, //of row
490 float row_size //ideal
491 ) {
492 float allowed; //allowed expansion
493 float available; //expansion
494 BLOBNBOX_IT it = &blobs; //list of blobs
495
496 it.add_to_end (blob);
497 allowed = row_size + y_min - y_max;
498 if (allowed > 0) {
499 available = top > y_max ? top - y_max : 0;
500 if (bottom < y_min)
501 //total available
502 available += y_min - bottom;
503 if (available > 0) {
504 available += available; //do it gradually
505 if (available < allowed)
506 available = allowed;
507 if (bottom < y_min)
508 y_min -= (y_min - bottom) * allowed / available;
509 if (top > y_max)
510 y_max += (top - y_max) * allowed / available;
511 }
512 }
513 }
514
515
516 /**********************************************************************
517 * TO_ROW:insert_blob
518 *
519 * Add the blob to the row in the correct position.
520 **********************************************************************/
521
insert_blob(BLOBNBOX * blob)522 void TO_ROW::insert_blob( //constructor
523 BLOBNBOX *blob //first blob
524 ) {
525 BLOBNBOX_IT it = &blobs; //list of blobs
526
527 if (it.empty ())
528 it.add_before_then_move (blob);
529 else {
530 it.mark_cycle_pt ();
531 while (!it.cycled_list ()
532 && it.data ()->bounding_box ().left () <=
533 blob->bounding_box ().left ())
534 it.forward ();
535 if (it.cycled_list ())
536 it.add_to_end (blob);
537 else
538 it.add_before_stay_put (blob);
539 }
540 }
541
542
543 /**********************************************************************
544 * TO_ROW::compute_vertical_projection
545 *
546 * Compute the vertical projection of a TO_ROW from its blobs.
547 **********************************************************************/
548
compute_vertical_projection()549 void TO_ROW::compute_vertical_projection() { //project whole row
550 TBOX row_box; //bound of row
551 BLOBNBOX *blob; //current blob
552 TBOX blob_box; //bounding box
553 BLOBNBOX_IT blob_it = blob_list ();
554
555 if (blob_it.empty ())
556 return;
557 row_box = blob_it.data ()->bounding_box ();
558 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ())
559 row_box += blob_it.data ()->bounding_box ();
560
561 projection.set_range (row_box.left () - PROJECTION_MARGIN,
562 row_box.right () + PROJECTION_MARGIN);
563 projection_left = row_box.left () - PROJECTION_MARGIN;
564 projection_right = row_box.right () + PROJECTION_MARGIN;
565 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
566 blob = blob_it.data ();
567 if (blob->blob () != NULL)
568 vertical_blob_projection (blob->blob (), &projection);
569 else if (blob->cblob () != NULL)
570 vertical_cblob_projection (blob->cblob (), &projection);
571 }
572 }
573
574
575 /**********************************************************************
576 * vertical_blob_projection
577 *
578 * Compute the vertical projection of a blob from its outlines
579 * and add to the given STATS.
580 **********************************************************************/
581
vertical_blob_projection(PBLOB * blob,STATS * stats)582 void vertical_blob_projection( //project outlines
583 PBLOB *blob, //blob to project
584 STATS *stats //output
585 ) {
586 //outlines of blob
587 OUTLINE_IT out_it = blob->out_list ();
588
589 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
590 vertical_outline_projection (out_it.data (), stats);
591 }
592 }
593
594
595 /**********************************************************************
596 * vertical_outline_projection
597 *
598 * Compute the vertical projection of a outline from its outlines
599 * and add to the given STATS.
600 **********************************************************************/
601
vertical_outline_projection(OUTLINE * outline,STATS * stats)602 void vertical_outline_projection( //project outlines
603 OUTLINE *outline, //outline to project
604 STATS *stats //output
605 ) {
606 POLYPT *polypt; //current point
607 inT32 xcoord; //current pixel coord
608 float end_x; //end of vec
609 POLYPT_IT poly_it = outline->polypts ();
610 OUTLINE_IT out_it = outline->child ();
611 float ymean; //amount to add
612 float width; //amount of x
613
614 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) {
615 polypt = poly_it.data ();
616 end_x = polypt->pos.x () + polypt->vec.x ();
617 if (polypt->vec.x () > 0) {
618 for (xcoord = (inT32) floor (polypt->pos.x ());
619 xcoord < end_x; xcoord++) {
620 if (polypt->pos.x () < xcoord) {
621 width = (float) xcoord;
622 ymean =
623 polypt->vec.y () * (xcoord -
624 polypt->pos.x ()) / polypt->vec.x () +
625 polypt->pos.y ();
626 }
627 else {
628 width = polypt->pos.x ();
629 ymean = polypt->pos.y ();
630 }
631 if (end_x > xcoord + 1) {
632 width -= xcoord + 1;
633 ymean +=
634 polypt->vec.y () * (xcoord + 1 -
635 polypt->pos.x ()) / polypt->vec.x () +
636 polypt->pos.y ();
637 }
638 else {
639 width -= end_x;
640 ymean += polypt->pos.y () + polypt->vec.y ();
641 }
642 ymean = ymean * width / 2;
643 stats->add (xcoord, (inT32) floor (ymean + 0.5));
644 }
645 }
646 else if (polypt->vec.x () < 0) {
647 for (xcoord = (inT32) floor (end_x);
648 xcoord < polypt->pos.x (); xcoord++) {
649 if (polypt->pos.x () > xcoord + 1) {
650 width = xcoord + 1.0f;
651 ymean =
652 polypt->vec.y () * (xcoord + 1 -
653 polypt->pos.x ()) / polypt->vec.x () +
654 polypt->pos.y ();
655 }
656 else {
657 width = polypt->pos.x ();
658 ymean = polypt->pos.y ();
659 }
660 if (end_x < xcoord) {
661 width -= xcoord;
662 ymean +=
663 polypt->vec.y () * (xcoord -
664 polypt->pos.x ()) / polypt->vec.x () +
665 polypt->pos.y ();
666 }
667 else {
668 width -= end_x;
669 ymean += polypt->pos.y () + polypt->vec.y ();
670 }
671 ymean = ymean * width / 2;
672 stats->add (xcoord, (inT32) floor (ymean + 0.5));
673 }
674 }
675 }
676
677 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
678 vertical_outline_projection (out_it.data (), stats);
679 }
680 }
681
682
683 /**********************************************************************
684 * vertical_cblob_projection
685 *
686 * Compute the vertical projection of a cblob from its outlines
687 * and add to the given STATS.
688 **********************************************************************/
689
vertical_cblob_projection(C_BLOB * blob,STATS * stats)690 void vertical_cblob_projection( //project outlines
691 C_BLOB *blob, //blob to project
692 STATS *stats //output
693 ) {
694 //outlines of blob
695 C_OUTLINE_IT out_it = blob->out_list ();
696
697 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
698 vertical_coutline_projection (out_it.data (), stats);
699 }
700 }
701
702
703 /**********************************************************************
704 * vertical_coutline_projection
705 *
706 * Compute the vertical projection of a outline from its outlines
707 * and add to the given STATS.
708 **********************************************************************/
709
vertical_coutline_projection(C_OUTLINE * outline,STATS * stats)710 void vertical_coutline_projection( //project outlines
711 C_OUTLINE *outline, //outline to project
712 STATS *stats //output
713 ) {
714 ICOORD pos; //current point
715 ICOORD step; //edge step
716 inT32 length; //of outline
717 inT16 stepindex; //current step
718 C_OUTLINE_IT out_it = outline->child ();
719
720 pos = outline->start_pos ();
721 length = outline->pathlength ();
722 for (stepindex = 0; stepindex < length; stepindex++) {
723 step = outline->step (stepindex);
724 if (step.x () > 0) {
725 if (pitsync_projection_fix)
726 stats->add (pos.x (), -pos.y ());
727 else
728 stats->add (pos.x (), pos.y ());
729 }
730 else if (step.x () < 0) {
731 if (pitsync_projection_fix)
732 stats->add (pos.x () - 1, pos.y ());
733 else
734 stats->add (pos.x () - 1, -pos.y ());
735 }
736 pos += step;
737 }
738
739 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
740 vertical_coutline_projection (out_it.data (), stats);
741 }
742 }
743
744
745 /**********************************************************************
746 * TO_BLOCK::TO_BLOCK
747 *
748 * Constructor to make a TO_BLOCK from a real block.
749 **********************************************************************/
750
TO_BLOCK(BLOCK * src_block)751 TO_BLOCK::TO_BLOCK( //make a block
752 BLOCK *src_block //real block
753 ) {
754 block = src_block;
755 }
756
clear_blobnboxes(BLOBNBOX_LIST * boxes)757 static void clear_blobnboxes(BLOBNBOX_LIST* boxes) {
758 BLOBNBOX_IT it = boxes;
759 // A BLOBNBOX generally doesn't own its blobs, so if they do, you
760 // have to delete them explicitly.
761 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
762 BLOBNBOX* box = it.data();
763 if (box->blob() != NULL)
764 delete box->blob();
765 if (box->cblob() != NULL)
766 delete box->cblob();
767 }
768 }
769
~TO_BLOCK()770 TO_BLOCK::~TO_BLOCK() {
771 // Any residual BLOBNBOXes at this stage own their blobs, so delete them.
772 clear_blobnboxes(&blobs);
773 clear_blobnboxes(&underlines);
774 clear_blobnboxes(&noise_blobs);
775 clear_blobnboxes(&small_blobs);
776 clear_blobnboxes(&large_blobs);
777 }
778
779 // Draw the blobs on the various lists in the block in different colors.
780 #ifndef GRAPHICS_DISABLED
plot_graded_blobs(ScrollView * to_win)781 void TO_BLOCK::plot_graded_blobs(ScrollView* to_win) {
782 plot_blob_list(to_win, &noise_blobs, ScrollView::CORAL, ScrollView::BLUE);
783 plot_blob_list(to_win, &small_blobs,
784 ScrollView::GOLDENROD, ScrollView::YELLOW);
785 plot_blob_list(to_win, &large_blobs,
786 ScrollView::DARK_GREEN, ScrollView::YELLOW);
787 plot_blob_list(to_win, &blobs, ScrollView::WHITE, ScrollView::BROWN);
788 }
789 #endif
790
791 /**********************************************************************
792 * plot_blob_list
793 *
794 * Draw a list of blobs.
795 **********************************************************************/
796
797 #ifndef GRAPHICS_DISABLED
plot_blob_list(ScrollView * win,BLOBNBOX_LIST * list,ScrollView::Color body_colour,ScrollView::Color child_colour)798 void plot_blob_list(ScrollView* win, // window to draw in
799 BLOBNBOX_LIST *list, // blob list
800 ScrollView::Color body_colour, // colour to draw
801 ScrollView::Color child_colour) { // colour of child
802 BLOBNBOX_IT it = list;
803 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
804 it.data()->plot(win, body_colour, child_colour);
805 }
806 }
807 #endif
808
809
810