tesseract
3.03
|
00001 /********************************************************************** 00002 * File: fpchop.cpp (Formerly fp_chop.c) 00003 * Description: Code to chop fixed pitch text into character cells. 00004 * Author: Ray Smith 00005 * Created: Thu Sep 16 11:14:15 BST 1993 00006 * 00007 * (C) Copyright 1993, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #ifdef __UNIX__ 00021 #include <assert.h> 00022 #endif 00023 #include "stderr.h" 00024 #include "blobbox.h" 00025 #include "statistc.h" 00026 #include "drawtord.h" 00027 #include "tovars.h" 00028 #include "topitch.h" 00029 #include "fpchop.h" 00030 00031 // Include automatically generated configuration file if running autoconf. 00032 #ifdef HAVE_CONFIG_H 00033 #include "config_auto.h" 00034 #endif 00035 00036 #define EXTERN 00037 00038 EXTERN INT_VAR (textord_fp_chop_error, 2, 00039 "Max allowed bending of chop cells"); 00040 EXTERN double_VAR (textord_fp_chop_snap, 0.5, 00041 "Max distance of chop pt from vertex"); 00042 00043 ELISTIZE(C_OUTLINE_FRAG) 00044 //#undef ASSERT_HOST 00045 //#define ASSERT_HOST(x) if (!(x)) AfxMessageBox(#x); 00046 /********************************************************************** 00047 * fixed_pitch_words 00048 * 00049 * Make a ROW from a fixed pitch TO_ROW. 00050 **********************************************************************/ 00051 ROW *fixed_pitch_words( //find lines 00052 TO_ROW *row, //row to do 00053 FCOORD rotation //for drawing 00054 ) { 00055 BOOL8 bol; //start of line 00056 uinT8 blanks; //in front of word 00057 uinT8 new_blanks; //blanks in empty cell 00058 inT16 chop_coord; //chop boundary 00059 inT16 prev_chop_coord; //start of cell 00060 inT16 rep_left; //left edge of rep word 00061 ROW *real_row; //output row 00062 C_OUTLINE_LIST left_coutlines; 00063 C_OUTLINE_LIST right_coutlines; 00064 C_BLOB_LIST cblobs; 00065 C_BLOB_IT cblob_it = &cblobs; 00066 WERD_LIST words; 00067 WERD_IT word_it = &words; //new words 00068 //repeated blobs 00069 WERD_IT rep_it = &row->rep_words; 00070 WERD *word; //new word 00071 inT32 xstarts[2]; //row ends 00072 inT32 prev_x; //end of prev blob 00073 //iterator 00074 BLOBNBOX_IT box_it = row->blob_list (); 00075 //boundaries 00076 ICOORDELT_IT cell_it = &row->char_cells; 00077 00078 #ifndef GRAPHICS_DISABLED 00079 if (textord_show_page_cuts && to_win != NULL) { 00080 plot_row_cells (to_win, ScrollView::RED, row, 0, &row->char_cells); 00081 } 00082 #endif 00083 00084 prev_x = -MAX_INT16; 00085 bol = TRUE; 00086 blanks = 0; 00087 if (rep_it.empty ()) 00088 rep_left = MAX_INT16; 00089 else 00090 rep_left = rep_it.data ()->bounding_box ().left (); 00091 if (box_it.empty ()) 00092 return NULL; //empty row 00093 xstarts[0] = box_it.data ()->bounding_box ().left (); 00094 if (rep_left < xstarts[0]) { 00095 xstarts[0] = rep_left; 00096 } 00097 if (cell_it.empty () || row->char_cells.singleton ()) { 00098 tprintf ("Row without enough char cells!\n"); 00099 tprintf ("Leftmost blob is at (%d,%d)\n", 00100 box_it.data ()->bounding_box ().left (), 00101 box_it.data ()->bounding_box ().bottom ()); 00102 return NULL; 00103 } 00104 ASSERT_HOST (!cell_it.empty () && !row->char_cells.singleton ()); 00105 prev_chop_coord = cell_it.data ()->x (); 00106 word = NULL; 00107 while (rep_left < cell_it.data ()->x ()) { 00108 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00109 blanks, row->fixed_pitch, &word_it); 00110 } 00111 cell_it.mark_cycle_pt (); 00112 if (prev_chop_coord >= cell_it.data ()->x ()) 00113 cell_it.forward (); 00114 for (; !cell_it.cycled_list (); cell_it.forward ()) { 00115 chop_coord = cell_it.data ()->x (); 00116 while (!box_it.empty () 00117 && box_it.data ()->bounding_box ().left () <= chop_coord) { 00118 if (box_it.data ()->bounding_box ().right () > prev_x) 00119 prev_x = box_it.data ()->bounding_box ().right (); 00120 split_to_blob (box_it.extract (), chop_coord, 00121 textord_fp_chop_error + 0.5f, 00122 &left_coutlines, 00123 &right_coutlines); 00124 box_it.forward (); 00125 while (!box_it.empty() && box_it.data()->cblob() == NULL) { 00126 delete box_it.extract(); 00127 box_it.forward(); 00128 } 00129 } 00130 if (!right_coutlines.empty() && left_coutlines.empty()) 00131 split_to_blob (NULL, chop_coord, 00132 textord_fp_chop_error + 0.5f, 00133 &left_coutlines, 00134 &right_coutlines); 00135 if (!left_coutlines.empty()) { 00136 cblob_it.add_after_then_move(new C_BLOB(&left_coutlines)); 00137 } else { 00138 if (rep_left < chop_coord) { 00139 if (rep_left > prev_chop_coord) 00140 new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) 00141 / row->fixed_pitch + 0.5); 00142 else 00143 new_blanks = 0; 00144 } 00145 else { 00146 if (chop_coord > prev_chop_coord) 00147 new_blanks = (uinT8) floor ((chop_coord - prev_chop_coord) 00148 / row->fixed_pitch + 0.5); 00149 else 00150 new_blanks = 0; 00151 } 00152 if (!cblob_it.empty()) { 00153 if (blanks < 1 && word != NULL && !word->flag (W_REP_CHAR)) 00154 blanks = 1; 00155 word = new WERD (&cblobs, blanks, NULL); 00156 cblob_it.set_to_list (&cblobs); 00157 word->set_flag (W_DONT_CHOP, TRUE); 00158 word_it.add_after_then_move (word); 00159 if (bol) { 00160 word->set_flag (W_BOL, TRUE); 00161 bol = FALSE; 00162 } 00163 blanks = new_blanks; 00164 } 00165 else 00166 blanks += new_blanks; 00167 while (rep_left < chop_coord) { 00168 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00169 blanks, row->fixed_pitch, &word_it); 00170 } 00171 } 00172 if (prev_chop_coord < chop_coord) 00173 prev_chop_coord = chop_coord; 00174 } 00175 if (!cblob_it.empty()) { 00176 word = new WERD(&cblobs, blanks, NULL); 00177 word->set_flag (W_DONT_CHOP, TRUE); 00178 word_it.add_after_then_move (word); 00179 if (bol) 00180 word->set_flag (W_BOL, TRUE); 00181 } 00182 ASSERT_HOST (word != NULL); 00183 while (!rep_it.empty ()) { 00184 add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00185 blanks, row->fixed_pitch, &word_it); 00186 } 00187 //at end of line 00188 word_it.data ()->set_flag (W_EOL, TRUE); 00189 if (prev_chop_coord > prev_x) 00190 prev_x = prev_chop_coord; 00191 xstarts[1] = prev_x + 1; 00192 real_row = new ROW (row, (inT16) row->kern_size, (inT16) row->space_size); 00193 word_it.set_to_list (real_row->word_list ()); 00194 //put words in row 00195 word_it.add_list_after (&words); 00196 real_row->recalc_bounding_box (); 00197 return real_row; 00198 } 00199 00200 00201 /********************************************************************** 00202 * add_repeated_word 00203 * 00204 * Add repeated word into the row at the given point. 00205 **********************************************************************/ 00206 00207 WERD *add_repeated_word( //move repeated word 00208 WERD_IT *rep_it, //repeated words 00209 inT16 &rep_left, //left edge of word 00210 inT16 &prev_chop_coord, //previous word end 00211 uinT8 &blanks, //no of blanks 00212 float pitch, //char cell size 00213 WERD_IT *word_it //list of words 00214 ) { 00215 WERD *word; //word to move 00216 inT16 new_blanks; //extra blanks 00217 00218 if (rep_left > prev_chop_coord) { 00219 new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) / pitch + 0.5); 00220 blanks += new_blanks; 00221 } 00222 word = rep_it->extract (); 00223 prev_chop_coord = word->bounding_box ().right (); 00224 word_it->add_after_then_move (word); 00225 word->set_blanks (blanks); 00226 rep_it->forward (); 00227 if (rep_it->empty ()) 00228 rep_left = MAX_INT16; 00229 else 00230 rep_left = rep_it->data ()->bounding_box ().left (); 00231 blanks = 0; 00232 return word; 00233 } 00234 00235 00236 /********************************************************************** 00237 * split_to_blob 00238 * 00239 * Split a BLOBNBOX across a vertical chop line and put the pieces 00240 * into a left outline list and a right outline list. 00241 **********************************************************************/ 00242 00243 void split_to_blob( //split the blob 00244 BLOBNBOX *blob, //blob to split 00245 inT16 chop_coord, //place to chop 00246 float pitch_error, //allowed deviation 00247 C_OUTLINE_LIST *left_coutlines, //for cblobs 00248 C_OUTLINE_LIST *right_coutlines) { 00249 C_BLOB *real_cblob; //cblob to chop 00250 00251 if (blob != NULL) { 00252 real_cblob = blob->cblob(); 00253 } else { 00254 real_cblob = NULL; 00255 } 00256 if (!right_coutlines->empty() || real_cblob != NULL) 00257 fixed_chop_cblob(real_cblob, 00258 chop_coord, 00259 pitch_error, 00260 left_coutlines, 00261 right_coutlines); 00262 if (blob != NULL) 00263 delete blob; //free it 00264 } 00265 00266 /********************************************************************** 00267 * fixed_chop_cblob 00268 * 00269 * Chop the given cblob (if any) and the existing right outlines to 00270 * produce a list of outlines left of the chop point and more to the right. 00271 **********************************************************************/ 00272 00273 void fixed_chop_cblob( //split the blob 00274 C_BLOB *blob, //blob to split 00275 inT16 chop_coord, //place to chop 00276 float pitch_error, //allowed deviation 00277 C_OUTLINE_LIST *left_outlines, //left half of chop 00278 C_OUTLINE_LIST *right_outlines //right half of chop 00279 ) { 00280 C_OUTLINE *old_right; //already there 00281 C_OUTLINE_LIST new_outlines; //new right ones 00282 //ouput iterator 00283 C_OUTLINE_IT left_it = left_outlines; 00284 //in/out iterator 00285 C_OUTLINE_IT right_it = right_outlines; 00286 C_OUTLINE_IT new_it = &new_outlines; 00287 C_OUTLINE_IT blob_it; //outlines in blob 00288 00289 if (!right_it.empty ()) { 00290 while (!right_it.empty ()) { 00291 old_right = right_it.extract (); 00292 right_it.forward (); 00293 fixed_split_coutline(old_right, 00294 chop_coord, 00295 pitch_error, 00296 &left_it, 00297 &new_it); 00298 } 00299 right_it.add_list_before (&new_outlines); 00300 } 00301 if (blob != NULL) { 00302 blob_it.set_to_list (blob->out_list ()); 00303 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); 00304 blob_it.forward ()) 00305 fixed_split_coutline (blob_it.extract (), chop_coord, pitch_error, 00306 &left_it, &right_it); 00307 delete blob; 00308 } 00309 } 00310 00311 00312 /********************************************************************** 00313 * fixed_split_outline 00314 * 00315 * Chop the given outline (if necessary) placing the fragments which 00316 * fall either side of the chop line into the appropriate list. 00317 **********************************************************************/ 00318 00319 void fixed_split_coutline( //chop the outline 00320 C_OUTLINE *srcline, //source outline 00321 inT16 chop_coord, //place to chop 00322 float pitch_error, //allowed deviation 00323 C_OUTLINE_IT *left_it, //left half of chop 00324 C_OUTLINE_IT *right_it //right half of chop 00325 ) { 00326 C_OUTLINE *child; //child outline 00327 TBOX srcbox; //box of outline 00328 C_OUTLINE_LIST left_ch; //left children 00329 C_OUTLINE_LIST right_ch; //right children 00330 C_OUTLINE_FRAG_LIST left_frags;//chopped fragments 00331 C_OUTLINE_FRAG_LIST right_frags;; 00332 C_OUTLINE_IT left_ch_it = &left_ch; 00333 //for whole children 00334 C_OUTLINE_IT right_ch_it = &right_ch; 00335 //for holes 00336 C_OUTLINE_IT child_it = srcline->child (); 00337 00338 srcbox = srcline->bounding_box(); 00339 if (srcbox.left() + srcbox.right() <= chop_coord * 2 00340 && srcbox.right() < chop_coord + pitch_error) { 00341 // Whole outline is in the left side or not far over the chop_coord, 00342 // so put the whole thing on the left. 00343 left_it->add_after_then_move(srcline); 00344 } else if (srcbox.left() + srcbox.right() > chop_coord * 2 00345 && srcbox.left () > chop_coord - pitch_error) { 00346 // Whole outline is in the right side or not far over the chop_coord, 00347 // so put the whole thing on the right. 00348 right_it->add_before_stay_put(srcline); 00349 } else { 00350 // Needs real chopping. 00351 if (fixed_chop_coutline(srcline, chop_coord, pitch_error, 00352 &left_frags, &right_frags)) { 00353 for (child_it.mark_cycle_pt(); !child_it.cycled_list(); 00354 child_it.forward()) { 00355 child = child_it.extract(); 00356 srcbox = child->bounding_box(); 00357 if (srcbox.right() < chop_coord) { 00358 // Whole child is on the left. 00359 left_ch_it.add_after_then_move(child); 00360 } else if (srcbox.left() > chop_coord) { 00361 // Whole child is on the right. 00362 right_ch_it.add_after_then_move (child); 00363 } else { 00364 // No pitch_error is allowed when chopping children to prevent 00365 // impossible outlines from being created. 00366 if (fixed_chop_coutline(child, chop_coord, 0.0f, 00367 &left_frags, &right_frags)) { 00368 delete child; 00369 } else { 00370 if (srcbox.left() + srcbox.right() <= chop_coord * 2) 00371 left_ch_it.add_after_then_move(child); 00372 else 00373 right_ch_it.add_after_then_move(child); 00374 } 00375 } 00376 } 00377 close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it); 00378 close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it); 00379 ASSERT_HOST(left_ch.empty() && right_ch.empty()); 00380 // No children left. 00381 delete srcline; // Smashed up. 00382 } else { 00383 // Chop failed. Just use middle coord. 00384 if (srcbox.left() + srcbox.right() <= chop_coord * 2) 00385 left_it->add_after_then_move(srcline); // Stick whole in left. 00386 else 00387 right_it->add_before_stay_put(srcline); 00388 } 00389 } 00390 } 00391 00392 00393 /********************************************************************** 00394 * fixed_chop_coutline 00395 * 00396 * Chop the given coutline (if necessary) placing the fragments which 00397 * fall either side of the chop line into the appropriate list. 00398 * If the coutline lies too heavily to one side to chop, FALSE is returned. 00399 **********************************************************************/ 00400 00401 BOOL8 fixed_chop_coutline( //chop the outline 00402 C_OUTLINE *srcline, //source outline 00403 inT16 chop_coord, //place to chop 00404 float pitch_error, //allowed deviation 00405 C_OUTLINE_FRAG_LIST *left_frags, //left half of chop 00406 C_OUTLINE_FRAG_LIST *right_frags //right half of chop 00407 ) { 00408 BOOL8 first_frag; //fragment 00409 inT16 left_edge; //of outline 00410 inT16 startindex; //in first fragment 00411 inT32 length; //of outline 00412 inT16 stepindex; //into outline 00413 inT16 head_index; //start of fragment 00414 ICOORD head_pos; //start of fragment 00415 inT16 tail_index; //end of fragment 00416 ICOORD tail_pos; //end of fragment 00417 ICOORD pos; //current point 00418 inT16 first_index = 0; //first tail 00419 ICOORD first_pos; //first tail 00420 00421 length = srcline->pathlength (); 00422 pos = srcline->start_pos (); 00423 left_edge = pos.x (); 00424 tail_index = 0; 00425 tail_pos = pos; 00426 for (stepindex = 0; stepindex < length; stepindex++) { 00427 if (pos.x () < left_edge) { 00428 left_edge = pos.x (); 00429 tail_index = stepindex; 00430 tail_pos = pos; 00431 } 00432 pos += srcline->step (stepindex); 00433 } 00434 if (left_edge >= chop_coord - pitch_error) 00435 return FALSE; //not worth it 00436 00437 startindex = tail_index; 00438 first_frag = TRUE; 00439 head_index = tail_index; 00440 head_pos = tail_pos; 00441 do { 00442 do { 00443 tail_pos += srcline->step (tail_index); 00444 tail_index++; 00445 if (tail_index == length) 00446 tail_index = 0; 00447 } 00448 while (tail_pos.x () != chop_coord && tail_index != startindex); 00449 if (tail_index == startindex) { 00450 if (first_frag) 00451 return FALSE; //doesn't cross line 00452 else 00453 break; 00454 } 00455 //#ifdef __UNIX__ 00456 ASSERT_HOST (head_index != tail_index); 00457 //#endif 00458 if (!first_frag) { 00459 save_chop_cfragment(head_index, 00460 head_pos, 00461 tail_index, 00462 tail_pos, 00463 srcline, 00464 left_frags); 00465 } 00466 else { 00467 first_index = tail_index; 00468 first_pos = tail_pos; 00469 first_frag = FALSE; 00470 } 00471 while (srcline->step (tail_index).x () == 0) { 00472 tail_pos += srcline->step (tail_index); 00473 tail_index++; 00474 if (tail_index == length) 00475 tail_index = 0; 00476 } 00477 head_index = tail_index; 00478 head_pos = tail_pos; 00479 while (srcline->step (tail_index).x () > 0) { 00480 do { 00481 tail_pos += srcline->step (tail_index); 00482 tail_index++; 00483 if (tail_index == length) 00484 tail_index = 0; 00485 } 00486 while (tail_pos.x () != chop_coord); 00487 //#ifdef __UNIX__ 00488 ASSERT_HOST (head_index != tail_index); 00489 //#endif 00490 save_chop_cfragment(head_index, 00491 head_pos, 00492 tail_index, 00493 tail_pos, 00494 srcline, 00495 right_frags); 00496 while (srcline->step (tail_index).x () == 0) { 00497 tail_pos += srcline->step (tail_index); 00498 tail_index++; 00499 if (tail_index == length) 00500 tail_index = 0; 00501 } 00502 head_index = tail_index; 00503 head_pos = tail_pos; 00504 } 00505 } 00506 while (tail_index != startindex); 00507 save_chop_cfragment(head_index, 00508 head_pos, 00509 first_index, 00510 first_pos, 00511 srcline, 00512 left_frags); 00513 return TRUE; //did some chopping 00514 } 00515 00516 /********************************************************************** 00517 * save_chop_cfragment 00518 * 00519 * Store the given fragment in the given fragment list. 00520 **********************************************************************/ 00521 00522 void save_chop_cfragment( //chop the outline 00523 inT16 head_index, //head of fragment 00524 ICOORD head_pos, //head of fragment 00525 inT16 tail_index, //tail of fragment 00526 ICOORD tail_pos, //tail of fragment 00527 C_OUTLINE *srcline, //source of edgesteps 00528 C_OUTLINE_FRAG_LIST *frags //fragment list 00529 ) { 00530 inT16 jump; //gap across end 00531 inT16 stepcount; //total steps 00532 C_OUTLINE_FRAG *head; //head of fragment 00533 C_OUTLINE_FRAG *tail; //tail of fragment 00534 inT16 tail_y; //ycoord of tail 00535 00536 ASSERT_HOST (tail_pos.x () == head_pos.x ()); 00537 ASSERT_HOST (tail_index != head_index); 00538 stepcount = tail_index - head_index; 00539 if (stepcount < 0) 00540 stepcount += srcline->pathlength (); 00541 jump = tail_pos.y () - head_pos.y (); 00542 if (jump < 0) 00543 jump = -jump; 00544 if (jump == stepcount) 00545 return; //its a nop 00546 tail_y = tail_pos.y (); 00547 head = new C_OUTLINE_FRAG (head_pos, tail_pos, srcline, 00548 head_index, tail_index); 00549 tail = new C_OUTLINE_FRAG (head, tail_y); 00550 head->other_end = tail; 00551 add_frag_to_list(head, frags); 00552 add_frag_to_list(tail, frags); 00553 } 00554 00555 00556 /********************************************************************** 00557 * C_OUTLINE_FRAG::C_OUTLINE_FRAG 00558 * 00559 * Constructors for C_OUTLINE_FRAG. 00560 **********************************************************************/ 00561 00562 C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment 00563 ICOORD start_pt, //start coord 00564 ICOORD end_pt, //end coord 00565 C_OUTLINE *outline, //source of steps 00566 inT16 start_index, 00567 inT16 end_index) { 00568 start = start_pt; 00569 end = end_pt; 00570 ycoord = start_pt.y (); 00571 stepcount = end_index - start_index; 00572 if (stepcount < 0) 00573 stepcount += outline->pathlength (); 00574 ASSERT_HOST (stepcount > 0); 00575 steps = new DIR128[stepcount]; 00576 if (end_index > start_index) { 00577 for (int i = start_index; i < end_index; ++i) 00578 steps[i - start_index] = outline->step_dir(i); 00579 } 00580 else { 00581 int len = outline->pathlength(); 00582 int i = start_index; 00583 for (; i < len; ++i) 00584 steps[i - start_index] = outline->step_dir(i); 00585 if (end_index > 0) 00586 for (; i < end_index + len; ++i) 00587 steps[i - start_index] = outline->step_dir(i - len); 00588 } 00589 other_end = NULL; 00590 delete close(); 00591 } 00592 00593 00594 C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment 00595 C_OUTLINE_FRAG *head, //other end 00596 inT16 tail_y) { 00597 ycoord = tail_y; 00598 other_end = head; 00599 start = head->start; 00600 end = head->end; 00601 steps = NULL; 00602 stepcount = 0; 00603 } 00604 00605 00606 /********************************************************************** 00607 * add_frag_to_list 00608 * 00609 * Insert the fragment in the list at the appropriate place to keep 00610 * them in ascending ycoord order. 00611 **********************************************************************/ 00612 00613 void add_frag_to_list( //ordered add 00614 C_OUTLINE_FRAG *frag, //fragment to add 00615 C_OUTLINE_FRAG_LIST *frags //fragment list 00616 ) { 00617 //output list 00618 C_OUTLINE_FRAG_IT frag_it = frags; 00619 00620 if (!frags->empty ()) { 00621 for (frag_it.mark_cycle_pt (); !frag_it.cycled_list (); 00622 frag_it.forward ()) { 00623 if (frag_it.data ()->ycoord > frag->ycoord 00624 || (frag_it.data ()->ycoord == frag->ycoord 00625 && frag->other_end->ycoord < frag->ycoord)) { 00626 frag_it.add_before_then_move (frag); 00627 return; 00628 } 00629 } 00630 } 00631 frag_it.add_to_end (frag); 00632 } 00633 00634 00635 /********************************************************************** 00636 * close_chopped_cfragments 00637 * 00638 * Clear the given list of fragments joining them up into outlines. 00639 * Each outline made soaks up any of the child outlines which it encloses. 00640 **********************************************************************/ 00641 00642 void close_chopped_cfragments( //chop the outline 00643 C_OUTLINE_FRAG_LIST *frags, //list to clear 00644 C_OUTLINE_LIST *children, //potential children 00645 float pitch_error, //allowed shrinkage 00646 C_OUTLINE_IT *dest_it //output list 00647 ) { 00648 //iterator 00649 C_OUTLINE_FRAG_IT frag_it = frags; 00650 C_OUTLINE_FRAG *bottom_frag; //bottom of cut 00651 C_OUTLINE_FRAG *top_frag; //top of cut 00652 C_OUTLINE *outline; //new outline 00653 C_OUTLINE *child; //current child 00654 C_OUTLINE_IT child_it = children; 00655 C_OUTLINE_IT olchild_it; //children of outline 00656 00657 while (!frag_it.empty()) { 00658 frag_it.move_to_first(); 00659 // get bottom one 00660 bottom_frag = frag_it.extract(); 00661 frag_it.forward(); 00662 top_frag = frag_it.data(); // look at next 00663 if ((bottom_frag->steps == 0 && top_frag->steps == 0) 00664 || (bottom_frag->steps != 0 && top_frag->steps != 0)) { 00665 if (frag_it.data_relative(1)->ycoord == top_frag->ycoord) 00666 frag_it.forward(); 00667 } 00668 top_frag = frag_it.extract(); 00669 if (top_frag->other_end != bottom_frag) { 00670 outline = join_chopped_fragments(bottom_frag, top_frag); 00671 ASSERT_HOST(outline == NULL); 00672 } else { 00673 outline = join_chopped_fragments(bottom_frag, top_frag); 00674 if (outline != NULL) { 00675 olchild_it.set_to_list(outline->child()); 00676 for (child_it.mark_cycle_pt(); !child_it.cycled_list(); 00677 child_it.forward()) { 00678 child = child_it.data(); 00679 if (*child < *outline) 00680 olchild_it.add_to_end(child_it.extract()); 00681 } 00682 if (outline->bounding_box().width() > pitch_error) 00683 dest_it->add_after_then_move(outline); 00684 else 00685 delete outline; // Make it disappear. 00686 } 00687 } 00688 } 00689 while (!child_it.empty ()) { 00690 dest_it->add_after_then_move (child_it.extract ()); 00691 child_it.forward (); 00692 } 00693 } 00694 00695 00696 /********************************************************************** 00697 * join_chopped_fragments 00698 * 00699 * Join the two lists of POLYPTs such that neither OUTLINE_FRAG 00700 * operand keeps responsibility for the fragment. 00701 **********************************************************************/ 00702 00703 C_OUTLINE *join_chopped_fragments( //join pieces 00704 C_OUTLINE_FRAG *bottom, //bottom of cut 00705 C_OUTLINE_FRAG *top //top of cut 00706 ) { 00707 C_OUTLINE *outline; //closed loop 00708 00709 if (bottom->other_end == top) { 00710 if (bottom->steps == 0) 00711 outline = top->close (); //turn to outline 00712 else 00713 outline = bottom->close (); 00714 delete top; 00715 delete bottom; 00716 return outline; 00717 } 00718 if (bottom->steps == 0) { 00719 ASSERT_HOST (top->steps != 0); 00720 join_segments (bottom->other_end, top); 00721 } 00722 else { 00723 ASSERT_HOST (top->steps == 0); 00724 join_segments (top->other_end, bottom); 00725 } 00726 top->other_end->other_end = bottom->other_end; 00727 bottom->other_end->other_end = top->other_end; 00728 delete bottom; 00729 delete top; 00730 return NULL; 00731 } 00732 00733 00734 /********************************************************************** 00735 * join_segments 00736 * 00737 * Join the two edgestep fragments such that the second comes after 00738 * the first and the gap beween them is closed. 00739 **********************************************************************/ 00740 00741 void join_segments( //join pieces 00742 C_OUTLINE_FRAG *bottom, //bottom of cut 00743 C_OUTLINE_FRAG *top //top of cut 00744 ) { 00745 DIR128 *steps; //new steps 00746 inT32 stepcount; //no of steps 00747 inT16 fake_count; //fake steps 00748 DIR128 fake_step; //step entry 00749 00750 ASSERT_HOST (bottom->end.x () == top->start.x ()); 00751 fake_count = top->start.y () - bottom->end.y (); 00752 if (fake_count < 0) { 00753 fake_count = -fake_count; 00754 fake_step = 32; 00755 } 00756 else 00757 fake_step = 96; 00758 00759 stepcount = bottom->stepcount + fake_count + top->stepcount; 00760 steps = new DIR128[stepcount]; 00761 memmove (steps, bottom->steps, bottom->stepcount); 00762 memset (steps + bottom->stepcount, fake_step.get_dir(), fake_count); 00763 memmove (steps + bottom->stepcount + fake_count, top->steps, 00764 top->stepcount); 00765 delete [] bottom->steps; 00766 bottom->steps = steps; 00767 bottom->stepcount = stepcount; 00768 bottom->end = top->end; 00769 bottom->other_end->end = top->end; 00770 } 00771 00772 00773 /********************************************************************** 00774 * C_OUTLINE_FRAG::close 00775 * 00776 * Join the ends of this fragment and turn it into an outline. 00777 **********************************************************************/ 00778 00779 C_OUTLINE *C_OUTLINE_FRAG::close() { //join pieces 00780 DIR128 *new_steps; //new steps 00781 inT32 new_stepcount; //no of steps 00782 inT16 fake_count; //fake steps 00783 DIR128 fake_step; //step entry 00784 00785 ASSERT_HOST (start.x () == end.x ()); 00786 fake_count = start.y () - end.y (); 00787 if (fake_count < 0) { 00788 fake_count = -fake_count; 00789 fake_step = 32; 00790 } 00791 else 00792 fake_step = 96; 00793 00794 new_stepcount = stepcount + fake_count; 00795 if (new_stepcount > C_OUTLINE::kMaxOutlineLength) 00796 return NULL; // Can't join them 00797 new_steps = new DIR128[new_stepcount]; 00798 memmove(new_steps, steps, stepcount); 00799 memset (new_steps + stepcount, fake_step.get_dir(), fake_count); 00800 C_OUTLINE* result = new C_OUTLINE (start, new_steps, new_stepcount); 00801 delete [] new_steps; 00802 return result; 00803 } 00804 00805 00806 /********************************************************************** 00807 * C_OUTLINE_FRAG::operator= 00808 * 00809 * Copy this fragment. 00810 **********************************************************************/ 00811 00812 //join pieces 00813 C_OUTLINE_FRAG & C_OUTLINE_FRAG::operator= ( 00814 const C_OUTLINE_FRAG & src //fragment to copy 00815 ) { 00816 if (steps != NULL) 00817 delete [] steps; 00818 00819 stepcount = src.stepcount; 00820 steps = new DIR128[stepcount]; 00821 memmove (steps, src.steps, stepcount); 00822 start = src.start; 00823 end = src.end; 00824 ycoord = src.ycoord; 00825 return *this; 00826 }