1 /*****************************************************************************
2 *
3 * File: blkocc.cpp (Formerly blockocc.c)
4 * Description: Block Occupancy routines
5 * Author: Chris Newton
6 * Created: Fri Nov 8
7 * Modified:
8 * Language: C++
9 * Package: N/A
10 * Status: Experimental (Do Not Distribute)
11 *
12 * (c) Copyright 1991, Hewlett-Packard Company.
13 ** Licensed under the Apache License, Version 2.0 (the "License");
14 ** you may not use this file except in compliance with the License.
15 ** You may obtain a copy of the License at
16 ** http://www.apache.org/licenses/LICENSE-2.0
17 ** Unless required by applicable law or agreed to in writing, software
18 ** distributed under the License is distributed on an "AS IS" BASIS,
19 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 ** See the License for the specific language governing permissions and
21 ** limitations under the License.
22 *
23 ******************************************************************************/
24
25 /*
26 ----------------------------------------------------------------------
27 I n c l u d e s
28 ----------------------------------------------------------------------
29 */
30
31 #include "mfcpch.h"
32 #include <ctype.h>
33 #include <math.h>
34 #include "errcode.h"
35 #include "drawtord.h"
36 #include "blkocc.h"
37 #include "notdll.h"
38
39 const ERRCODE BLOCKOCC = "BlockOcc";
40
41 ELISTIZE (REGION_OCC)
42 #define EXTERN
43 EXTERN BOOL_VAR (blockocc_show_result, FALSE,
44 "Show intermediate results");
45
46 /* The values given here should reflect the values of bln_x_height and
47 * bln_baseline_offset. These are defined as part of the word class
48 * definition */
49
50 EXTERN INT_VAR (blockocc_desc_height, 0,
51 "Descender height after normalisation");
52 EXTERN INT_VAR (blockocc_asc_height, 255,
53 "Ascender height after normalisation");
54
55 EXTERN INT_VAR (blockocc_band_count, 4, "Number of bands used");
56
57 EXTERN double_VAR (textord_underline_threshold, 0.5,
58 "Fraction of width occupied");
59
60 /* ********************************************************************
61 A note on transitions.
62
63 We want to record occupancy in various bands. In general we need to consider
64 7 situations:
65
66 (1) (2) (3) (4)
67 \ / \ / \ /
68 __\_____/_____\_________/_____\_________/______ Upper Limit
69 \ / \ / \ /
70 / \ \-->--/ \--<--/ /-----\
71 v ^ / \(7)
72 \ \ \ /
73 \ \ /--<--\ /-->--\ \-----/
74 ____\______\____/_______\____/_______\_________ Lower Limit
75 \ \ / \ / \
76 (5) (6)
77 We know that following "next" pointers around an outline keeps the black area
78 on the LEFT. We only need be concerned with situations 1,2,3,5 and 7.
79 4 and 6 can be ignored as they represent small incursions into a large black
80 region which will be recorded elsewhere. Situations 3 and 5 define encloseed
81 areas bounded by the upper and lower limits respectively. Situation 1 is open
82 to the right, awaiting a closure by a situation 2 which is open to the right.
83 Situation 7 is entirely enclosed within the band.
84
85 The situations are refered to as region types and are determined by
86 find_region_type.
87
88 An empty region type is used to denote entry to an adjacent band and return
89 to the original band at the same x location.
90 ***********************************************************************/
91
92 #define REGION_TYPE_EMPTY 0
93 #define REGION_TYPE_OPEN_RIGHT 1
94 #define REGION_TYPE_OPEN_LEFT 2
95 #define REGION_TYPE_UPPER_BOUND 3
96 #define REGION_TYPE_UPPER_UNBOUND 4
97 #define REGION_TYPE_LOWER_BOUND 5
98 #define REGION_TYPE_LOWER_UNBOUND 6
99 #define REGION_TYPE_ENCLOSED 7
100
101 BAND bands[MAX_NUM_BANDS + 1]; // band defns
102
103 /**********************************************************************
104 * test_underline
105 *
106 * Check to see if the blob is an underline.
107 * Return TRUE if it is.
108 **********************************************************************/
109
test_underline(BOOL8 testing_on,PBLOB * blob,float baseline,float xheight)110 BOOL8 test_underline( //look for underlines
111 BOOL8 testing_on, //drawing blob
112 PBLOB *blob, //blob to test
113 float baseline, //coords of baseline
114 float xheight //height of line
115 ) {
116 inT16 occ;
117 inT16 blob_width; //width of blob
118 TBOX blob_box; //bounding box
119 float occs[MAX_NUM_BANDS + 1]; //total occupancy
120
121 blob_box = blob->bounding_box ();
122 set_bands(baseline, xheight); //setup block occ
123 blob_width = blob->bounding_box ().width ();
124 if (testing_on) {
125 // blob->plot(to_win,GOLDENROD,GOLDENROD);
126 // line_color_index(to_win,GOLDENROD);
127 // move2d(to_win,blob_box.left(),baseline);
128 // draw2d(to_win,blob_box.right(),baseline);
129 // move2d(to_win,blob_box.left(),baseline+xheight);
130 // draw2d(to_win,blob_box.right(),baseline+xheight);
131 tprintf
132 ("Testing underline on blob at (%d,%d)->(%d,%d), base=%g\nOccs:",
133 blob->bounding_box ().left (), blob->bounding_box ().bottom (),
134 blob->bounding_box ().right (), blob->bounding_box ().top (),
135 baseline);
136 }
137 block_occ(blob, occs);
138 if (testing_on) {
139 for (occ = 0; occ <= MAX_NUM_BANDS; occ++)
140 tprintf ("%g ", occs[occ]);
141 tprintf ("\n");
142 }
143 if (occs[1] > occs[2] + occs[2] && occs[1] > occs[3] + occs[3]
144 && occs[1] > blob_width * textord_underline_threshold)
145 return TRUE; //real underline
146 if (occs[4] > occs[2] + occs[2]
147 && occs[4] > blob_width * textord_underline_threshold)
148 return TRUE; //overline
149 return FALSE; //neither
150 }
151
152
153 /**********************************************************************
154 * test_underline
155 *
156 * Check to see if the blob is an underline.
157 * Return TRUE if it is.
158 **********************************************************************/
159
test_underline(BOOL8 testing_on,C_BLOB * blob,inT16 baseline,inT16 xheight)160 BOOL8 test_underline( //look for underlines
161 BOOL8 testing_on, //drawing blob
162 C_BLOB *blob, //blob to test
163 inT16 baseline, //coords of baseline
164 inT16 xheight //height of line
165 ) {
166 inT16 occ;
167 inT16 blob_width; //width of blob
168 TBOX blob_box; //bounding box
169 inT32 desc_occ;
170 inT32 x_occ;
171 inT32 asc_occ;
172 STATS projection;
173
174 blob_box = blob->bounding_box ();
175 blob_width = blob->bounding_box ().width ();
176 projection.set_range (blob_box.bottom (), blob_box.top () + 1);
177 if (testing_on) {
178 // blob->plot(to_win,GOLDENROD,GOLDENROD);
179 // line_color_index(to_win,GOLDENROD);
180 // move2d(to_win,blob_box.left(),baseline);
181 // draw2d(to_win,blob_box.right(),baseline);
182 // move2d(to_win,blob_box.left(),baseline+xheight);
183 // draw2d(to_win,blob_box.right(),baseline+xheight);
184 tprintf
185 ("Testing underline on blob at (%d,%d)->(%d,%d), base=%d\nOccs:",
186 blob->bounding_box ().left (), blob->bounding_box ().bottom (),
187 blob->bounding_box ().right (), blob->bounding_box ().top (),
188 baseline);
189 }
190 horizontal_cblob_projection(blob, &projection);
191 desc_occ = 0;
192 for (occ = blob_box.bottom (); occ < baseline; occ++)
193 if (occ <= blob_box.top () && projection.pile_count (occ) > desc_occ)
194 //max in region
195 desc_occ = projection.pile_count (occ);
196 x_occ = 0;
197 for (occ = baseline; occ <= baseline + xheight; occ++)
198 if (occ >= blob_box.bottom () && occ <= blob_box.top ()
199 && projection.pile_count (occ) > x_occ)
200 //max in region
201 x_occ = projection.pile_count (occ);
202 asc_occ = 0;
203 for (occ = baseline + xheight + 1; occ <= blob_box.top (); occ++)
204 if (occ >= blob_box.bottom () && projection.pile_count (occ) > asc_occ)
205 asc_occ = projection.pile_count (occ);
206 if (testing_on) {
207 tprintf ("%d %d %d\n", desc_occ, x_occ, asc_occ);
208 }
209 if (desc_occ == 0 && x_occ == 0 && asc_occ == 0) {
210 tprintf ("Bottom=%d, top=%d, base=%d, x=%d\n",
211 blob_box.bottom (), blob_box.top (), baseline, xheight);
212 projection.print (stdout, TRUE);
213 }
214 if (desc_occ > x_occ + x_occ
215 && desc_occ > blob_width * textord_underline_threshold)
216 return TRUE; //real underline
217 if (asc_occ > x_occ + x_occ
218 && asc_occ > blob_width * textord_underline_threshold)
219 return TRUE; //overline
220 return FALSE; //neither
221 }
222
223
224 /**********************************************************************
225 * horizontal_cblob_projection
226 *
227 * Compute the horizontal projection of a cblob from its outlines
228 * and add to the given STATS.
229 **********************************************************************/
230
horizontal_cblob_projection(C_BLOB * blob,STATS * stats)231 void horizontal_cblob_projection( //project outlines
232 C_BLOB *blob, //blob to project
233 STATS *stats //output
234 ) {
235 //outlines of blob
236 C_OUTLINE_IT out_it = blob->out_list ();
237
238 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
239 horizontal_coutline_projection (out_it.data (), stats);
240 }
241 }
242
243
244 /**********************************************************************
245 * horizontal_coutline_projection
246 *
247 * Compute the horizontal projection of a outline from its outlines
248 * and add to the given STATS.
249 **********************************************************************/
250
horizontal_coutline_projection(C_OUTLINE * outline,STATS * stats)251 void horizontal_coutline_projection( //project outlines
252 C_OUTLINE *outline, //outline to project
253 STATS *stats //output
254 ) {
255 ICOORD pos; //current point
256 ICOORD step; //edge step
257 inT32 length; //of outline
258 inT16 stepindex; //current step
259 C_OUTLINE_IT out_it = outline->child ();
260
261 pos = outline->start_pos ();
262 length = outline->pathlength ();
263 for (stepindex = 0; stepindex < length; stepindex++) {
264 step = outline->step (stepindex);
265 if (step.y () > 0) {
266 stats->add (pos.y (), pos.x ());
267 }
268 else if (step.y () < 0) {
269 stats->add (pos.y () - 1, -pos.x ());
270 }
271 pos += step;
272 }
273
274 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
275 horizontal_coutline_projection (out_it.data (), stats);
276 }
277 }
278
279
set_bands(float baseline,float xheight)280 void set_bands( //init from varibles
281 float baseline, //top of bottom band
282 float xheight //height of split band
283 ) {
284 inT16 int_bl, int_xh; //for band.set
285
286 bands[DOT_BAND].set (0, 0, 0, 0, 0, 0);
287
288 int_bl = (inT16) baseline;
289 int_xh = (inT16) xheight;
290 bands[1].set (int_bl, int_bl, int_bl,
291 NO_LOWER_LIMIT, NO_LOWER_LIMIT, NO_LOWER_LIMIT);
292
293 bands[2].set (int_bl + int_xh / 2, int_bl + int_xh / 2, int_bl + int_xh / 2,
294 int_bl, int_bl, int_bl);
295
296 bands[3].set (int_bl + int_xh, int_bl + int_xh, int_bl + int_xh,
297 int_bl + int_xh / 2, int_bl + int_xh / 2,
298 int_bl + int_xh / 2);
299
300 bands[4].set (NO_UPPER_LIMIT, NO_UPPER_LIMIT, NO_UPPER_LIMIT,
301 int_bl + int_xh, int_bl + int_xh, int_bl + int_xh);
302 }
303
304
305 void
block_occ(PBLOB * blob,float occs[])306 block_occ (PBLOB * blob, //blob to do
307 float occs[] //output histogram
308 ) {
309 int band_index; //current band
310 REGION_OCC *region; //current segment
311 REGION_OCC_LIST region_occ_list[MAX_NUM_BANDS + 1];
312 REGION_OCC_IT region_it; //region iterator
313
314 find_transitions(blob, region_occ_list);
315 compress_region_list(region_occ_list);
316 for (band_index = 0; band_index <= MAX_NUM_BANDS; band_index++) {
317 occs[band_index] = 0.0f;
318 region_it.set_to_list (®ion_occ_list[band_index]);
319 for (region_it.mark_cycle_pt (); !region_it.cycled_list ();
320 region_it.forward ()) {
321 region = region_it.data ();
322 occs[band_index] += region->max_x - region->min_x;
323 }
324 }
325 }
326
327
find_transitions(PBLOB * blob,REGION_OCC_LIST * region_occ_list)328 void find_transitions(PBLOB *blob, //blob to do
329 REGION_OCC_LIST *region_occ_list) {
330 OUTLINE_IT outline_it;
331 TBOX box;
332 POLYPT_IT pt_it;
333 FCOORD point1;
334 FCOORD point2;
335 FCOORD *entry_pt = &point1;
336 FCOORD *exit_pt = &point2;
337 FCOORD *temp_pt;
338 inT16 increment;
339 inT16 prev_band;
340 inT16 band;
341 inT16 next_band;
342 float min_x;
343 float max_x;
344 float min_y;
345 float max_y;
346 BOOL8 doubly_contained;
347
348 outline_it = blob->out_list ();
349 for (outline_it.mark_cycle_pt (); !outline_it.cycled_list ();
350 outline_it.forward ()) {
351 find_fbox(&outline_it, &min_x, &min_y, &max_x, &max_y);
352
353 if (bands[DOT_BAND].range_in_nominal (max_y, min_y)) {
354 record_region(DOT_BAND,
355 min_x,
356 max_x,
357 REGION_TYPE_ENCLOSED,
358 region_occ_list);
359 }
360 else {
361 band = find_containing_maximal_band (max_y, min_y,
362 &doubly_contained);
363 if (band != UNDEFINED_BAND) {
364 //No transitions
365 if (!doubly_contained)
366 record_region(band,
367 min_x,
368 max_x,
369 REGION_TYPE_ENCLOSED,
370 region_occ_list);
371 else {
372 // if (wordocc_debug_on && blockocc_show_result)
373 // {
374 // fprintf( db_win,
375 // "Ignoring doubly contained outline (%d, %d) (%d, %d)\n",
376 // box.left(), box.top(),
377 // box.right(), box.bottom());
378 // fprintf( db_win, "\tContained in bands %d and %d\n",
379 // band, band + 1 );
380 // }
381 }
382 }
383 else {
384 //There are transitns
385 /*
386 Determining a good start point for recognising transitions between bands
387 is complicated by error limits on bands. We need to find a line which
388 significantly occupies a band.
389
390 Having found such a point, we need to find a significant transition out of
391 its band and start the walk around the outline from there.
392
393 Note that we are relying on having recognised and dealt with elsewhere,
394 outlines which do not significantly occupy more than one region. A
395 particularly nasty case of this are outlines which do not significantly
396 occupy ANY band. I.e. they lie entirely within the error limits.
397 Given this condition, all remaining outlines must contain at least one
398 significant line. */
399
400 pt_it = outline_it.data ()->polypts ();
401
402 find_significant_line(pt_it, &band);
403 *entry_pt = pt_it.data ()->pos;
404 next_region(&pt_it,
405 band,
406 &next_band,
407 &min_x,
408 &max_x,
409 &increment,
410 exit_pt);
411 pt_it.mark_cycle_pt ();
412
413 // Found the first real transition, so start walking the outline from here.
414
415 do {
416 prev_band = band;
417 band = band + increment;
418
419 while (band != next_band) {
420 temp_pt = entry_pt;
421 entry_pt = exit_pt;
422 exit_pt = temp_pt;
423 min_x = max_x = entry_pt->x ();
424
425 find_trans_point (&pt_it, band, band + increment,
426 exit_pt);
427 maintain_limits (&min_x, &max_x, exit_pt->x ());
428
429 record_region (band,
430 min_x,
431 max_x,
432 find_region_type (prev_band,
433 band,
434 band + increment,
435 entry_pt->x (),
436 exit_pt->x ()),
437 region_occ_list);
438 prev_band = band;
439 band = band + increment;
440 }
441
442 temp_pt = entry_pt;
443 entry_pt = exit_pt;
444 exit_pt = temp_pt;
445 min_x = max_x = entry_pt->x ();
446 next_region(&pt_it,
447 band,
448 &next_band,
449 &min_x,
450 &max_x,
451 &increment,
452 exit_pt);
453
454 record_region (band,
455 min_x,
456 max_x,
457 find_region_type (prev_band,
458 band,
459 band + increment,
460 entry_pt->x (),
461 exit_pt->x ()),
462 region_occ_list);
463 }
464 while (!pt_it.cycled_list ());
465 }
466 }
467 }
468 }
469
470
record_region(inT16 band,float new_min,float new_max,inT16 region_type,REGION_OCC_LIST * region_occ_list)471 void record_region( //add region on list
472 inT16 band,
473 float new_min,
474 float new_max,
475 inT16 region_type,
476 REGION_OCC_LIST *region_occ_list) {
477 REGION_OCC_IT it (&(region_occ_list[band]));
478
479 // if (wordocc_debug_on && blockocc_show_result)
480 // fprintf( db_win, "\nBand %d, region type %d, from %f to %f",
481 // band, region_type, new_min, new_max );
482
483 if ((region_type == REGION_TYPE_UPPER_UNBOUND) ||
484 (region_type == REGION_TYPE_LOWER_UNBOUND) ||
485 (region_type == REGION_TYPE_EMPTY))
486 return;
487
488 if (it.empty ()) {
489 it.add_after_stay_put (new REGION_OCC (new_min, new_max, region_type));
490 }
491 else {
492
493 /* Insert in sorted order of average limit */
494
495 while ((new_min + new_max > it.data ()->min_x + it.data ()->max_x) &&
496 (!it.at_last ()))
497 it.forward ();
498
499 if ((it.at_last ()) && //at the end
500 (new_min + new_max > it.data ()->min_x + it.data ()->max_x))
501 //new range > current
502 it.add_after_stay_put (new REGION_OCC (new_min,
503 new_max, region_type));
504 else {
505 it.add_before_stay_put (new REGION_OCC (new_min,
506 new_max, region_type));
507 }
508 }
509 }
510
511
find_containing_maximal_band(float y1,float y2,BOOL8 * doubly_contained)512 inT16 find_containing_maximal_band( //find range's band
513 float y1,
514 float y2,
515 BOOL8 *doubly_contained) {
516 inT16 band;
517
518 *doubly_contained = FALSE;
519
520 for (band = 1; band <= blockocc_band_count; band++) {
521 if (bands[band].range_in_maximal (y1, y2)) {
522 if ((band < blockocc_band_count) &&
523 (bands[band + 1].range_in_maximal (y1, y2)))
524 *doubly_contained = TRUE;
525 return band;
526 }
527 }
528 return UNDEFINED_BAND;
529 }
530
531
find_significant_line(POLYPT_IT it,inT16 * band)532 void find_significant_line(POLYPT_IT it, inT16 *band) {
533
534 /* Look for a line which significantly occupies at least one band. I.e. part
535 of the line is in the non-margin part of the band. */
536
537 *band = find_overlapping_minimal_band (it.data ()->pos.y (),
538 it.data ()->pos.y () +
539 it.data ()->vec.y ());
540
541 while (*band == UNDEFINED_BAND) {
542 it.forward ();
543 *band = find_overlapping_minimal_band (it.data ()->pos.y (),
544 it.data ()->pos.y () +
545 it.data ()->vec.y ());
546 }
547 }
548
549
find_overlapping_minimal_band(float y1,float y2)550 inT16 find_overlapping_minimal_band( //find range's band
551 float y1,
552 float y2) {
553 inT16 band;
554
555 for (band = 1; band <= blockocc_band_count; band++) {
556 if (bands[band].range_overlaps_minimal (y1, y2))
557 return band;
558 }
559 return UNDEFINED_BAND;
560 }
561
562
find_region_type(inT16 entry_band,inT16 current_band,inT16 exit_band,float entry_x,float exit_x)563 inT16 find_region_type(inT16 entry_band,
564 inT16 current_band,
565 inT16 exit_band,
566 float entry_x,
567 float exit_x) {
568 if (entry_band > exit_band)
569 return REGION_TYPE_OPEN_RIGHT;
570 if (entry_band < exit_band)
571 return REGION_TYPE_OPEN_LEFT;
572 if (entry_x == exit_x)
573 return REGION_TYPE_EMPTY;
574 if (entry_band > current_band) {
575 if (entry_x < exit_x)
576 return REGION_TYPE_UPPER_BOUND;
577 else
578 return REGION_TYPE_UPPER_UNBOUND;
579 }
580 else {
581 if (entry_x > exit_x)
582 return REGION_TYPE_LOWER_BOUND;
583 else
584 return REGION_TYPE_LOWER_UNBOUND;
585 }
586 }
587
588
find_trans_point(POLYPT_IT * pt_it,inT16 current_band,inT16 next_band,FCOORD * transition_pt)589 void find_trans_point(POLYPT_IT *pt_it,
590 inT16 current_band,
591 inT16 next_band,
592 FCOORD *transition_pt) {
593 float x1, x2, y1, y2; // points of edge
594 float gradient; // m in y = mx + c
595 float offset; // c in y = mx + c
596
597 if (current_band < next_band)
598 transition_pt->set_y (bands[current_band].max);
599 //going up
600 else
601 transition_pt->set_y (bands[current_band].min);
602 //going down
603
604 x1 = pt_it->data ()->pos.x ();
605 x2 = x1 + pt_it->data ()->vec.x ();
606 y1 = pt_it->data ()->pos.y ();
607 y2 = y1 + pt_it->data ()->vec.y ();
608
609 if (x1 == x2)
610 transition_pt->set_x (x1); //avoid div by 0
611 else {
612 if (y1 == y2) //avoid div by 0
613 transition_pt->set_x ((x1 + x2) / 2.0);
614 else {
615 gradient = (y1 - y2) / (float) (x1 - x2);
616 offset = y1 - x1 * gradient;
617 transition_pt->set_x ((transition_pt->y () - offset) / gradient);
618 }
619 }
620 }
621
622
next_region(POLYPT_IT * start_pt_it,inT16 start_band,inT16 * to_band,float * min_x,float * max_x,inT16 * increment,FCOORD * exit_pt)623 void next_region(POLYPT_IT *start_pt_it,
624 inT16 start_band,
625 inT16 *to_band,
626 float *min_x,
627 float *max_x,
628 inT16 *increment,
629 FCOORD *exit_pt) {
630 /*
631 Given an edge and a band which the edge significantly occupies, find the
632 significant end of the region containing the band. I.e. find an edge which
633 points to another band such that the outline subsequetly moves significantly
634 out of the starting band.
635
636 Note that we can assume that we are significantly inside the current band to
637 start with because the edges passed will be from previous calls to this
638 routine apart from the first - the result of which is only used to establish
639 the start of the first region.
640 */
641
642 inT16 band; //band of current edge
643 inT16 prev_band = start_band; //band of prev edge
644 //edge crossing out
645 POLYPT_IT last_transition_out_it;
646 //band it pts to
647 inT16 last_trans_out_to_band = 0;
648 float ext_min_x = 0.0f;
649 float ext_max_x = 0.0f;
650
651 start_pt_it->forward ();
652 band = find_band (start_pt_it->data ()->pos.y ());
653
654 while ((band == start_band) ||
655 bands[start_band].in_maximal (start_pt_it->data ()->pos.y ())) {
656 if (band == start_band) {
657 //Return to start band
658 if (prev_band != start_band) {
659 *min_x = ext_min_x;
660 *max_x = ext_max_x;
661 }
662 maintain_limits (min_x, max_x, start_pt_it->data ()->pos.x ());
663 }
664 else {
665 if (prev_band == start_band) {
666 //Exit from start band
667 //so remember edge
668 last_transition_out_it = *start_pt_it;
669 //before we left
670 last_transition_out_it.backward ();
671 //and band it pts to
672 last_trans_out_to_band = band;
673 ext_min_x = *min_x;
674 ext_max_x = *max_x;
675 }
676 maintain_limits (&ext_min_x, &ext_max_x,
677 start_pt_it->data ()->pos.x ());
678 }
679 prev_band = band;
680 start_pt_it->forward ();
681 band = find_band (start_pt_it->data ()->pos.y ());
682 }
683
684 if (prev_band == start_band) { //exit from start band
685 *to_band = band;
686 //so remember edge
687 last_transition_out_it = *start_pt_it;
688 //before we left
689 last_transition_out_it.backward ();
690 }
691 else {
692 *to_band = last_trans_out_to_band;
693 }
694
695 if (*to_band > start_band)
696 *increment = 1;
697 else
698 *increment = -1;
699
700 find_trans_point (&last_transition_out_it, start_band,
701 start_band + *increment, exit_pt);
702 maintain_limits (min_x, max_x, exit_pt->x ());
703 *start_pt_it = last_transition_out_it;
704 }
705
706
find_band(float y)707 inT16 find_band( // find POINT's band
708 float y) {
709 inT16 band;
710
711 for (band = 1; band <= blockocc_band_count; band++) {
712 if (bands[band].in_nominal (y))
713 return band;
714 }
715 BLOCKOCC.error ("find_band", ABORT, "Cant find band for %d", y);
716 return 0;
717 }
718
719
compress_region_list(REGION_OCC_LIST * region_occ_list)720 void compress_region_list( // join open regions
721 REGION_OCC_LIST *region_occ_list) {
722 REGION_OCC_IT it (&(region_occ_list[0]));
723 REGION_OCC *open_right = NULL;
724
725 inT16 i = 0;
726
727 for (i = 0; i <= blockocc_band_count; i++) {
728 it.set_to_list (&(region_occ_list[i]));
729 if (!it.empty ()) {
730 /* First check for left right pairs. Merge them into the open right and delete
731 the open left. */
732 open_right = NULL;
733 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
734 switch (it.data ()->region_type) {
735 case REGION_TYPE_OPEN_RIGHT:
736 {
737 if (open_right != NULL)
738 BLOCKOCC.error ("compress_region_list", ABORT,
739 "unmatched right");
740 else
741 open_right = it.data ();
742 break;
743 }
744 case REGION_TYPE_OPEN_LEFT:
745 {
746 if (open_right == NULL)
747 BLOCKOCC.error ("compress_region_list", ABORT,
748 "unmatched left");
749 else {
750 open_right->max_x = it.data ()->max_x;
751 open_right = NULL;
752 delete it.extract ();
753 }
754 break;
755 }
756 default:
757 break;
758 }
759 }
760 if (open_right != NULL)
761 BLOCKOCC.error ("compress_region_list", ABORT,
762 "unmatched right remaining");
763
764 /* Now cycle the list again, merging and deleting any redundant regions */
765 it.move_to_first ();
766 open_right = it.data ();
767 while (!it.at_last ()) {
768 it.forward ();
769 if (it.data ()->min_x <= open_right->max_x) {
770 // Overlaps
771 if (it.data ()->max_x > open_right->max_x)
772 open_right->max_x = it.data ()->max_x;
773 // Extend
774 delete it.extract ();
775 }
776 else
777 open_right = it.data ();
778 }
779 }
780 }
781 }
782
783
find_fbox(OUTLINE_IT * out_it,float * min_x,float * min_y,float * max_x,float * max_y)784 void find_fbox(OUTLINE_IT *out_it,
785 float *min_x,
786 float *min_y,
787 float *max_x,
788 float *max_y) {
789 POLYPT_IT pt_it = out_it->data ()->polypts ();
790 FCOORD pt;
791 *min_x = 9999.0f;
792 *min_y = 9999.0f;
793 *max_x = 0.0f;
794 *max_y = 0.0f;
795
796 for (pt_it.mark_cycle_pt (); !pt_it.cycled_list (); pt_it.forward ()) {
797 pt = pt_it.data ()->pos;
798 maintain_limits (min_x, max_x, pt.x ());
799 maintain_limits (min_y, max_y, pt.y ());
800 }
801 }
802
803
maintain_limits(float * min_x,float * max_x,float x)804 void maintain_limits(float *min_x, float *max_x, float x) {
805 if (x > *max_x)
806 *max_x = x;
807 if (x < *min_x)
808 *min_x = x;
809 }
810