Tesseract
3.02
|
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 #include "mfcpch.h" 00021 #ifdef __UNIX__ 00022 #include <assert.h> 00023 #endif 00024 #include "stderr.h" 00025 #include "blobbox.h" 00026 #include "statistc.h" 00027 #include "drawtord.h" 00028 #include "tovars.h" 00029 #include "topitch.h" 00030 #include "fpchop.h" 00031 #include "notdll.h" 00032 00033 // Include automatically generated configuration file if running autoconf. 00034 #ifdef HAVE_CONFIG_H 00035 #include "config_auto.h" 00036 #endif 00037 00038 #define EXTERN 00039 00040 EXTERN INT_VAR (textord_fp_chop_error, 2, 00041 "Max allowed bending of chop cells"); 00042 EXTERN double_VAR (textord_fp_chop_snap, 0.5, 00043 "Max distance of chop pt from vertex"); 00044 00045 ELISTIZE(C_OUTLINE_FRAG) 00046 //#undef ASSERT_HOST 00047 //#define ASSERT_HOST(x) if (!(x)) AfxMessageBox(#x); 00048 /********************************************************************** 00049 * fixed_pitch_words 00050 * 00051 * Make a ROW from a fixed pitch TO_ROW. 00052 **********************************************************************/ 00053 ROW *fixed_pitch_words( //find lines 00054 TO_ROW *row, //row to do 00055 FCOORD rotation //for drawing 00056 ) { 00057 BOOL8 bol; //start of line 00058 uinT8 blanks; //in front of word 00059 uinT8 new_blanks; //blanks in empty cell 00060 inT16 chop_coord; //chop boundary 00061 inT16 prev_chop_coord; //start of cell 00062 inT16 rep_left; //left edge of rep word 00063 ROW *real_row; //output row 00064 C_OUTLINE_LIST left_coutlines; 00065 C_OUTLINE_LIST right_coutlines; 00066 C_BLOB_LIST cblobs; 00067 C_BLOB_IT cblob_it = &cblobs; 00068 WERD_LIST words; 00069 WERD_IT word_it = &words; //new words 00070 //repeated blobs 00071 WERD_IT rep_it = &row->rep_words; 00072 WERD *word; //new word 00073 inT32 xstarts[2]; //row ends 00074 double coeffs[3]; //quadratic 00075 inT32 prev_x; //end of prev blob 00076 //iterator 00077 BLOBNBOX_IT box_it = row->blob_list (); 00078 //boundaries 00079 ICOORDELT_IT cell_it = &row->char_cells; 00080 00081 #ifndef GRAPHICS_DISABLED 00082 if (textord_show_page_cuts && to_win != NULL) { 00083 plot_row_cells (to_win, ScrollView::RED, row, 0, &row->char_cells); 00084 } 00085 #endif 00086 00087 prev_x = -MAX_INT16; 00088 bol = TRUE; 00089 blanks = 0; 00090 if (rep_it.empty ()) 00091 rep_left = MAX_INT16; 00092 else 00093 rep_left = rep_it.data ()->bounding_box ().left (); 00094 if (box_it.empty ()) 00095 return NULL; //empty row 00096 xstarts[0] = box_it.data ()->bounding_box ().left (); 00097 if (rep_left < xstarts[0]) { 00098 xstarts[0] = rep_left; 00099 } 00100 if (cell_it.empty () || row->char_cells.singleton ()) { 00101 tprintf ("Row without enough char cells!\n"); 00102 tprintf ("Leftmost blob is at (%d,%d)\n", 00103 box_it.data ()->bounding_box ().left (), 00104 box_it.data ()->bounding_box ().bottom ()); 00105 return NULL; 00106 } 00107 ASSERT_HOST (!cell_it.empty () && !row->char_cells.singleton ()); 00108 prev_chop_coord = cell_it.data ()->x (); 00109 word = NULL; 00110 while (rep_left < cell_it.data ()->x ()) { 00111 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00112 blanks, row->fixed_pitch, &word_it); 00113 } 00114 cell_it.mark_cycle_pt (); 00115 if (prev_chop_coord >= cell_it.data ()->x ()) 00116 cell_it.forward (); 00117 for (; !cell_it.cycled_list (); cell_it.forward ()) { 00118 chop_coord = cell_it.data ()->x (); 00119 while (!box_it.empty () 00120 && box_it.data ()->bounding_box ().left () <= chop_coord) { 00121 if (box_it.data ()->bounding_box ().right () > prev_x) 00122 prev_x = box_it.data ()->bounding_box ().right (); 00123 split_to_blob (box_it.extract (), chop_coord, 00124 textord_fp_chop_error + 0.5f, 00125 &left_coutlines, 00126 &right_coutlines); 00127 box_it.forward (); 00128 while (!box_it.empty() && box_it.data()->cblob() == NULL) { 00129 delete box_it.extract(); 00130 box_it.forward(); 00131 } 00132 } 00133 if (!right_coutlines.empty() && left_coutlines.empty()) 00134 split_to_blob (NULL, chop_coord, 00135 textord_fp_chop_error + 0.5f, 00136 &left_coutlines, 00137 &right_coutlines); 00138 if (!left_coutlines.empty ()) 00139 cblob_it.add_after_then_move (new C_BLOB (&left_coutlines)); 00140 else { 00141 if (rep_left < chop_coord) { 00142 if (rep_left > prev_chop_coord) 00143 new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) 00144 / row->fixed_pitch + 0.5); 00145 else 00146 new_blanks = 0; 00147 } 00148 else { 00149 if (chop_coord > prev_chop_coord) 00150 new_blanks = (uinT8) floor ((chop_coord - prev_chop_coord) 00151 / row->fixed_pitch + 0.5); 00152 else 00153 new_blanks = 0; 00154 } 00155 if (!cblob_it.empty()) { 00156 if (blanks < 1 && word != NULL && !word->flag (W_REP_CHAR)) 00157 blanks = 1; 00158 word = new WERD (&cblobs, blanks, NULL); 00159 cblob_it.set_to_list (&cblobs); 00160 word->set_flag (W_DONT_CHOP, TRUE); 00161 word_it.add_after_then_move (word); 00162 if (bol) { 00163 word->set_flag (W_BOL, TRUE); 00164 bol = FALSE; 00165 } 00166 blanks = new_blanks; 00167 } 00168 else 00169 blanks += new_blanks; 00170 while (rep_left < chop_coord) { 00171 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00172 blanks, row->fixed_pitch, &word_it); 00173 } 00174 } 00175 if (prev_chop_coord < chop_coord) 00176 prev_chop_coord = chop_coord; 00177 } 00178 if (!cblob_it.empty()) { 00179 word = new WERD(&cblobs, blanks, NULL); 00180 word->set_flag (W_DONT_CHOP, TRUE); 00181 word_it.add_after_then_move (word); 00182 if (bol) 00183 word->set_flag (W_BOL, TRUE); 00184 } 00185 ASSERT_HOST (word != NULL); 00186 while (!rep_it.empty ()) { 00187 add_repeated_word (&rep_it, rep_left, prev_chop_coord, 00188 blanks, row->fixed_pitch, &word_it); 00189 } 00190 //at end of line 00191 word_it.data ()->set_flag (W_EOL, TRUE); 00192 if (prev_chop_coord > prev_x) 00193 prev_x = prev_chop_coord; 00194 xstarts[1] = prev_x + 1; 00195 coeffs[0] = 0; 00196 coeffs[1] = row->line_m (); 00197 coeffs[2] = row->line_c (); 00198 real_row = new ROW (row, (inT16) row->kern_size, (inT16) row->space_size); 00199 word_it.set_to_list (real_row->word_list ()); 00200 //put words in row 00201 word_it.add_list_after (&words); 00202 real_row->recalc_bounding_box (); 00203 return real_row; 00204 } 00205 00206 00207 /********************************************************************** 00208 * add_repeated_word 00209 * 00210 * Add repeated word into the row at the given point. 00211 **********************************************************************/ 00212 00213 WERD *add_repeated_word( //move repeated word 00214 WERD_IT *rep_it, //repeated words 00215 inT16 &rep_left, //left edge of word 00216 inT16 &prev_chop_coord, //previous word end 00217 uinT8 &blanks, //no of blanks 00218 float pitch, //char cell size 00219 WERD_IT *word_it //list of words 00220 ) { 00221 WERD *word; //word to move 00222 inT16 new_blanks; //extra blanks 00223 00224 if (rep_left > prev_chop_coord) { 00225 new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) / pitch + 0.5); 00226 blanks += new_blanks; 00227 } 00228 word = rep_it->extract (); 00229 prev_chop_coord = word->bounding_box ().right (); 00230 word_it->add_after_then_move (word); 00231 word->set_blanks (blanks); 00232 rep_it->forward (); 00233 if (rep_it->empty ()) 00234 rep_left = MAX_INT16; 00235 else 00236 rep_left = rep_it->data ()->bounding_box ().left (); 00237 blanks = 0; 00238 return word; 00239 } 00240 00241 00242 /********************************************************************** 00243 * split_to_blob 00244 * 00245 * Split a BLOBNBOX across a vertical chop line and put the pieces 00246 * into a left outline list and a right outline list. 00247 **********************************************************************/ 00248 00249 void split_to_blob( //split the blob 00250 BLOBNBOX *blob, //blob to split 00251 inT16 chop_coord, //place to chop 00252 float pitch_error, //allowed deviation 00253 C_OUTLINE_LIST *left_coutlines, //for cblobs 00254 C_OUTLINE_LIST *right_coutlines) { 00255 C_BLOB *real_cblob; //cblob to chop 00256 00257 if (blob != NULL) { 00258 real_cblob = blob->cblob(); 00259 } else { 00260 real_cblob = NULL; 00261 } 00262 if (!right_coutlines->empty() || real_cblob != NULL) 00263 fixed_chop_cblob(real_cblob, 00264 chop_coord, 00265 pitch_error, 00266 left_coutlines, 00267 right_coutlines); 00268 if (blob != NULL) 00269 delete blob; //free it 00270 } 00271 00272 /********************************************************************** 00273 * fixed_chop_cblob 00274 * 00275 * Chop the given cblob (if any) and the existing right outlines to 00276 * produce a list of outlines left of the chop point and more to the right. 00277 **********************************************************************/ 00278 00279 void fixed_chop_cblob( //split the blob 00280 C_BLOB *blob, //blob to split 00281 inT16 chop_coord, //place to chop 00282 float pitch_error, //allowed deviation 00283 C_OUTLINE_LIST *left_outlines, //left half of chop 00284 C_OUTLINE_LIST *right_outlines //right half of chop 00285 ) { 00286 C_OUTLINE *old_right; //already there 00287 C_OUTLINE_LIST new_outlines; //new right ones 00288 //ouput iterator 00289 C_OUTLINE_IT left_it = left_outlines; 00290 //in/out iterator 00291 C_OUTLINE_IT right_it = right_outlines; 00292 C_OUTLINE_IT new_it = &new_outlines; 00293 C_OUTLINE_IT blob_it; //outlines in blob 00294 00295 if (!right_it.empty ()) { 00296 while (!right_it.empty ()) { 00297 old_right = right_it.extract (); 00298 right_it.forward (); 00299 fixed_split_coutline(old_right, 00300 chop_coord, 00301 pitch_error, 00302 &left_it, 00303 &new_it); 00304 } 00305 right_it.add_list_before (&new_outlines); 00306 } 00307 if (blob != NULL) { 00308 blob_it.set_to_list (blob->out_list ()); 00309 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); 00310 blob_it.forward ()) 00311 fixed_split_coutline (blob_it.extract (), chop_coord, pitch_error, 00312 &left_it, &right_it); 00313 delete blob; 00314 } 00315 } 00316 00317 00318 /********************************************************************** 00319 * fixed_split_outline 00320 * 00321 * Chop the given outline (if necessary) placing the fragments which 00322 * fall either side of the chop line into the appropriate list. 00323 **********************************************************************/ 00324 00325 void fixed_split_coutline( //chop the outline 00326 C_OUTLINE *srcline, //source outline 00327 inT16 chop_coord, //place to chop 00328 float pitch_error, //allowed deviation 00329 C_OUTLINE_IT *left_it, //left half of chop 00330 C_OUTLINE_IT *right_it //right half of chop 00331 ) { 00332 C_OUTLINE *child; //child outline 00333 TBOX srcbox; //box of outline 00334 C_OUTLINE_LIST left_ch; //left children 00335 C_OUTLINE_LIST right_ch; //right children 00336 C_OUTLINE_FRAG_LIST left_frags;//chopped fragments 00337 C_OUTLINE_FRAG_LIST right_frags;; 00338 C_OUTLINE_IT left_ch_it = &left_ch; 00339 //for whole children 00340 C_OUTLINE_IT right_ch_it = &right_ch; 00341 //for holes 00342 C_OUTLINE_IT child_it = srcline->child (); 00343 00344 srcbox = srcline->bounding_box (); 00345 //left of line 00346 if (srcbox.left () + srcbox.right () <= chop_coord * 2 00347 //and not far over 00348 && srcbox.right () < chop_coord + pitch_error) 00349 //stick whole in left 00350 left_it->add_after_then_move (srcline); 00351 else if (srcbox.left () + srcbox.right () > chop_coord * 2 00352 && srcbox.left () > chop_coord - pitch_error) 00353 //stick whole in right 00354 right_it->add_before_stay_put (srcline); 00355 else { 00356 //needs real chopping 00357 if (fixed_chop_coutline (srcline, chop_coord, pitch_error, 00358 &left_frags, &right_frags)) { 00359 for (child_it.mark_cycle_pt (); !child_it.cycled_list (); 00360 child_it.forward ()) { 00361 child = child_it.extract (); 00362 srcbox = child->bounding_box (); 00363 if (srcbox.right () < chop_coord) 00364 left_ch_it.add_after_then_move (child); 00365 else if (srcbox.left () > chop_coord) 00366 right_ch_it.add_after_then_move (child); 00367 else { 00368 if (fixed_chop_coutline (child, chop_coord, pitch_error, 00369 &left_frags, &right_frags)) 00370 delete child; 00371 else { 00372 if (srcbox.left () + srcbox.right () <= chop_coord * 2) 00373 left_ch_it.add_after_then_move (child); 00374 else 00375 right_ch_it.add_after_then_move (child); 00376 } 00377 } 00378 } 00379 close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it); 00380 close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it); 00381 ASSERT_HOST (left_ch.empty () && right_ch.empty ()); 00382 //no children left 00383 delete srcline; //smashed up 00384 } 00385 else { 00386 if (srcbox.left () + srcbox.right () <= chop_coord * 2) 00387 //stick whole in left 00388 left_it->add_after_then_move (srcline); 00389 else 00390 right_it->add_before_stay_put (srcline); 00391 } 00392 } 00393 } 00394 00395 00396 /********************************************************************** 00397 * fixed_chop_coutline 00398 * 00399 * Chop the given coutline (if necessary) placing the fragments which 00400 * fall either side of the chop line into the appropriate list. 00401 * If the coutline lies too heavily to one side to chop, FALSE is returned. 00402 **********************************************************************/ 00403 00404 BOOL8 fixed_chop_coutline( //chop the outline 00405 C_OUTLINE *srcline, //source outline 00406 inT16 chop_coord, //place to chop 00407 float pitch_error, //allowed deviation 00408 C_OUTLINE_FRAG_LIST *left_frags, //left half of chop 00409 C_OUTLINE_FRAG_LIST *right_frags //right half of chop 00410 ) { 00411 BOOL8 first_frag; //fragment 00412 BOOL8 anticlock; //direction of loop 00413 inT16 left_edge; //of outline 00414 inT16 startindex; //in first fragment 00415 inT32 length; //of outline 00416 inT16 stepindex; //into outline 00417 inT16 head_index; //start of fragment 00418 ICOORD head_pos; //start of fragment 00419 inT16 tail_index; //end of fragment 00420 ICOORD tail_pos; //end of fragment 00421 ICOORD pos; //current point 00422 inT16 first_index = 0; //first tail 00423 ICOORD first_pos; //first tail 00424 00425 length = srcline->pathlength (); 00426 pos = srcline->start_pos (); 00427 anticlock = srcline->turn_direction () > 0; 00428 left_edge = pos.x (); 00429 tail_index = 0; 00430 tail_pos = pos; 00431 for (stepindex = 0; stepindex < length; stepindex++) { 00432 if (pos.x () < left_edge) { 00433 left_edge = pos.x (); 00434 tail_index = stepindex; 00435 tail_pos = pos; 00436 } 00437 pos += srcline->step (stepindex); 00438 } 00439 if (left_edge >= chop_coord - pitch_error) 00440 return FALSE; //not worth it 00441 00442 startindex = tail_index; 00443 first_frag = TRUE; 00444 head_index = tail_index; 00445 head_pos = tail_pos; 00446 do { 00447 do { 00448 tail_pos += srcline->step (tail_index); 00449 tail_index++; 00450 if (tail_index == length) 00451 tail_index = 0; 00452 } 00453 while (tail_pos.x () != chop_coord && tail_index != startindex); 00454 if (tail_index == startindex) { 00455 if (first_frag) 00456 return FALSE; //doesn't cross line 00457 else 00458 break; 00459 } 00460 //#ifdef __UNIX__ 00461 ASSERT_HOST (head_index != tail_index); 00462 //#endif 00463 if (!first_frag) { 00464 save_chop_cfragment(head_index, 00465 head_pos, 00466 tail_index, 00467 tail_pos, 00468 srcline, 00469 left_frags); 00470 } 00471 else { 00472 first_index = tail_index; 00473 first_pos = tail_pos; 00474 first_frag = FALSE; 00475 } 00476 while (srcline->step (tail_index).x () == 0) { 00477 tail_pos += srcline->step (tail_index); 00478 tail_index++; 00479 if (tail_index == length) 00480 tail_index = 0; 00481 } 00482 head_index = tail_index; 00483 head_pos = tail_pos; 00484 while (srcline->step (tail_index).x () > 0) { 00485 do { 00486 tail_pos += srcline->step (tail_index); 00487 tail_index++; 00488 if (tail_index == length) 00489 tail_index = 0; 00490 } 00491 while (tail_pos.x () != chop_coord); 00492 //#ifdef __UNIX__ 00493 ASSERT_HOST (head_index != tail_index); 00494 //#endif 00495 save_chop_cfragment(head_index, 00496 head_pos, 00497 tail_index, 00498 tail_pos, 00499 srcline, 00500 right_frags); 00501 while (srcline->step (tail_index).x () == 0) { 00502 tail_pos += srcline->step (tail_index); 00503 tail_index++; 00504 if (tail_index == length) 00505 tail_index = 0; 00506 } 00507 head_index = tail_index; 00508 head_pos = tail_pos; 00509 } 00510 } 00511 while (tail_index != startindex); 00512 save_chop_cfragment(head_index, 00513 head_pos, 00514 first_index, 00515 first_pos, 00516 srcline, 00517 left_frags); 00518 return TRUE; //did some chopping 00519 } 00520 00521 00522 /********************************************************************** 00523 * next_anti_left_seg 00524 * 00525 * Search the outline for a suitable point at which it crosses the 00526 * chop_coord from left to right. 00527 **********************************************************************/ 00528 00529 inT16 next_anti_left_seg( //chop the outline 00530 C_OUTLINE *srcline, //source outline 00531 inT16 tail_index, //of tailpos 00532 inT16 startindex, //end of search 00533 inT32 length, //of outline 00534 inT16 chop_coord, //place to chop 00535 float pitch_error, //allowed deviation 00536 ICOORD *tail_pos //current position 00537 ) { 00538 BOOL8 test_valid; //test pt valid 00539 inT16 chop_starty; //test chop pt 00540 inT16 test_index; //possible chop pt 00541 ICOORD test_pos; //possible chop pt 00542 ICOORD prev_step; //in x to tail pos 00543 00544 test_valid = FALSE; 00545 chop_starty = -MAX_INT16; 00546 test_index = tail_index; //stop warnings 00547 do { 00548 *tail_pos += srcline->step (tail_index); 00549 prev_step = srcline->step (tail_index); 00550 tail_index++; 00551 if (tail_index >= length) 00552 tail_index = 0; 00553 if (test_valid && tail_pos->x () == chop_coord && prev_step.x () < 0) { 00554 if (tail_pos->y () >= chop_starty) { 00555 chop_starty = -MAX_INT16; 00556 test_valid = FALSE; 00557 } 00558 else { 00559 *tail_pos = test_pos; 00560 tail_index = test_index; 00561 break; //must chop there 00562 } 00563 } 00564 if (tail_pos->x () == chop_coord 00565 && srcline->step (tail_index).x () > 0 00566 && tail_pos->y () > chop_starty) { 00567 chop_starty = tail_pos->y (); 00568 test_index = tail_index; 00569 test_pos = *tail_pos; 00570 test_valid = TRUE; 00571 } 00572 else if (tail_pos->x () == chop_coord 00573 && srcline->step (tail_index).y () < 0 00574 && prev_step.x () > 0 && tail_pos->y () > chop_starty) 00575 break; //must chop here 00576 } 00577 while (tail_index != startindex 00578 && tail_pos->x () < chop_coord + pitch_error); 00579 return tail_index; 00580 } 00581 00582 00583 /********************************************************************** 00584 * next_anti_right_seg 00585 * 00586 * Search the outline for a suitable point at which it crosses the 00587 * chop_coord from right to left. 00588 **********************************************************************/ 00589 00590 inT16 next_anti_right_seg( //chop the outline 00591 C_OUTLINE *srcline, //source outline 00592 inT16 tail_index, //of tailpos 00593 inT16 startindex, //end of search 00594 inT32 length, //of outline 00595 inT16 chop_coord, //place to chop 00596 float pitch_error, //allowed deviation 00597 ICOORD *tail_pos //current position 00598 ) { 00599 BOOL8 test_valid; //test pt valid 00600 inT16 chop_starty; //test chop pt 00601 inT16 test_index; //possible chop pt 00602 ICOORD test_pos; //possible chop pt 00603 ICOORD prev_step; //in x to tail pos 00604 00605 test_valid = FALSE; 00606 chop_starty = MAX_INT16; 00607 test_index = tail_index; //stop warnings 00608 do { 00609 //move forward 00610 *tail_pos += srcline->step (tail_index); 00611 prev_step = srcline->step (tail_index); 00612 tail_index++; 00613 if (tail_index >= length) 00614 tail_index = 0; 00615 if (test_valid && tail_pos->x () == chop_coord && prev_step.x () > 0) { 00616 if (tail_pos->y () <= chop_starty) { 00617 chop_starty = MAX_INT16; 00618 test_valid = FALSE; 00619 } 00620 else { 00621 *tail_pos = test_pos; 00622 tail_index = test_index; 00623 break; //must chop there 00624 } 00625 } 00626 if (tail_pos->x () == chop_coord 00627 && srcline->step (tail_index).x () < 0 00628 && tail_pos->y () < chop_starty) { 00629 chop_starty = tail_pos->y (); 00630 test_index = tail_index; 00631 test_pos = *tail_pos; 00632 test_valid = TRUE; //save possible chop pt 00633 } 00634 else if (tail_pos->x () == chop_coord 00635 && srcline->step (tail_index).y () > 0 00636 && prev_step.x () < 0 && tail_pos->y () < chop_starty) 00637 break; //must chop here 00638 } 00639 while (tail_index != startindex 00640 && tail_pos->x () > chop_coord - pitch_error); 00641 return tail_index; 00642 } 00643 00644 00645 /********************************************************************** 00646 * next_clock_left_seg 00647 * 00648 * Search the outline for a suitable point at which it crosses the 00649 * chop_coord from left to right. 00650 **********************************************************************/ 00651 00652 inT16 next_clock_left_seg( //chop the outline 00653 C_OUTLINE *srcline, //source outline 00654 inT16 tail_index, //of tailpos 00655 inT16 startindex, //end of search 00656 inT32 length, //of outline 00657 inT16 chop_coord, //place to chop 00658 float pitch_error, //allowed deviation 00659 ICOORD *tail_pos //current position 00660 ) { 00661 BOOL8 test_valid; //test pt valid 00662 inT16 chop_starty; //test chop pt 00663 inT16 test_index; //possible chop pt 00664 ICOORD test_pos; //possible chop pt 00665 ICOORD prev_step; //in x to tail pos 00666 00667 test_valid = FALSE; 00668 chop_starty = MAX_INT16; 00669 test_index = tail_index; //stop warnings 00670 do { 00671 *tail_pos += srcline->step (tail_index); 00672 prev_step = srcline->step (tail_index); 00673 tail_index++; 00674 if (tail_index >= length) 00675 tail_index = 0; 00676 if (test_valid && tail_pos->x () == chop_coord && prev_step.x () < 0) { 00677 if (tail_pos->y () <= chop_starty) { 00678 chop_starty = MAX_INT16; 00679 test_valid = FALSE; 00680 } 00681 else { 00682 *tail_pos = test_pos; 00683 tail_index = test_index; 00684 break; //must chop there 00685 } 00686 } 00687 if (tail_pos->x () == chop_coord 00688 && srcline->step (tail_index).x () > 0 00689 && tail_pos->y () < chop_starty) { 00690 chop_starty = tail_pos->y (); 00691 test_index = tail_index; 00692 test_pos = *tail_pos; 00693 test_valid = TRUE; 00694 } 00695 else if (tail_pos->x () == chop_coord 00696 && srcline->step (tail_index).y () > 0 00697 && prev_step.x () > 0 && tail_pos->y () < chop_starty) 00698 break; //must chop here 00699 } 00700 while (tail_index != startindex 00701 && tail_pos->x () < chop_coord + pitch_error); 00702 return tail_index; 00703 } 00704 00705 00706 /********************************************************************** 00707 * next_clock_right_seg 00708 * 00709 * Search the outline for a suitable point at which it crosses the 00710 * chop_coord from right to left. 00711 **********************************************************************/ 00712 00713 inT16 next_clock_right_seg( //chop the outline 00714 C_OUTLINE *srcline, //source outline 00715 inT16 tail_index, //of tailpos 00716 inT16 startindex, //end of search 00717 inT32 length, //of outline 00718 inT16 chop_coord, //place to chop 00719 float pitch_error, //allowed deviation 00720 ICOORD *tail_pos //current position 00721 ) { 00722 BOOL8 test_valid; //test pt valid 00723 inT16 chop_starty; //test chop pt 00724 inT16 test_index; //possible chop pt 00725 ICOORD test_pos; //possible chop pt 00726 ICOORD prev_step; //in x to tail pos 00727 00728 test_valid = FALSE; 00729 chop_starty = MAX_INT16; 00730 test_index = tail_index; //stop warnings 00731 do { 00732 //move forward 00733 *tail_pos += srcline->step (tail_index); 00734 prev_step = srcline->step (tail_index); 00735 tail_index++; 00736 if (tail_index >= length) 00737 tail_index = 0; 00738 if (test_valid && tail_pos->x () == chop_coord && prev_step.x () > 0) { 00739 if (tail_pos->y () >= chop_starty) { 00740 chop_starty = MAX_INT16; 00741 test_valid = FALSE; 00742 } 00743 else { 00744 *tail_pos = test_pos; 00745 tail_index = test_index; 00746 break; //must chop there 00747 } 00748 } 00749 if (tail_pos->x () == chop_coord 00750 && srcline->step (tail_index).x () < 0 00751 && tail_pos->y () > chop_starty) { 00752 chop_starty = tail_pos->y (); 00753 test_index = tail_index; 00754 test_pos = *tail_pos; 00755 test_valid = TRUE; //save possible chop pt 00756 } 00757 else if (tail_pos->x () == chop_coord 00758 && srcline->step (tail_index).y () < 0 00759 && prev_step.x () < 0 && tail_pos->y () > chop_starty) 00760 break; //must chop here 00761 } 00762 while (tail_index != startindex 00763 && tail_pos->x () > chop_coord - pitch_error); 00764 return tail_index; 00765 } 00766 00767 00768 /********************************************************************** 00769 * save_chop_cfragment 00770 * 00771 * Store the given fragment in the given fragment list. 00772 **********************************************************************/ 00773 00774 void save_chop_cfragment( //chop the outline 00775 inT16 head_index, //head of fragment 00776 ICOORD head_pos, //head of fragment 00777 inT16 tail_index, //tail of fragment 00778 ICOORD tail_pos, //tail of fragment 00779 C_OUTLINE *srcline, //source of edgesteps 00780 C_OUTLINE_FRAG_LIST *frags //fragment list 00781 ) { 00782 inT16 jump; //gap across end 00783 inT16 stepcount; //total steps 00784 C_OUTLINE_FRAG *head; //head of fragment 00785 C_OUTLINE_FRAG *tail; //tail of fragment 00786 inT16 tail_y; //ycoord of tail 00787 00788 ASSERT_HOST (tail_pos.x () == head_pos.x ()); 00789 ASSERT_HOST (tail_index != head_index); 00790 stepcount = tail_index - head_index; 00791 if (stepcount < 0) 00792 stepcount += srcline->pathlength (); 00793 jump = tail_pos.y () - head_pos.y (); 00794 if (jump < 0) 00795 jump = -jump; 00796 if (jump == stepcount) 00797 return; //its a nop 00798 tail_y = tail_pos.y (); 00799 head = new C_OUTLINE_FRAG (head_pos, tail_pos, srcline, 00800 head_index, tail_index); 00801 tail = new C_OUTLINE_FRAG (head, tail_y); 00802 head->other_end = tail; 00803 add_frag_to_list(head, frags); 00804 add_frag_to_list(tail, frags); 00805 } 00806 00807 00808 /********************************************************************** 00809 * C_OUTLINE_FRAG::C_OUTLINE_FRAG 00810 * 00811 * Constructors for C_OUTLINE_FRAG. 00812 **********************************************************************/ 00813 00814 C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment 00815 ICOORD start_pt, //start coord 00816 ICOORD end_pt, //end coord 00817 C_OUTLINE *outline, //source of steps 00818 inT16 start_index, 00819 inT16 end_index) { 00820 start = start_pt; 00821 end = end_pt; 00822 ycoord = start_pt.y (); 00823 stepcount = end_index - start_index; 00824 if (stepcount < 0) 00825 stepcount += outline->pathlength (); 00826 ASSERT_HOST (stepcount > 0); 00827 steps = new DIR128[stepcount]; 00828 if (end_index > start_index) { 00829 for (int i = start_index; i < end_index; ++i) 00830 steps[i - start_index] = outline->step_dir(i); 00831 } 00832 else { 00833 int len = outline->pathlength(); 00834 int i = start_index; 00835 for (; i < len; ++i) 00836 steps[i - start_index] = outline->step_dir(i); 00837 if (end_index > 0) 00838 for (; i < end_index + len; ++i) 00839 steps[i - start_index] = outline->step_dir(i - len); 00840 } 00841 other_end = NULL; 00842 delete close(); 00843 } 00844 00845 00846 C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment 00847 C_OUTLINE_FRAG *head, //other end 00848 inT16 tail_y) { 00849 ycoord = tail_y; 00850 other_end = head; 00851 start = head->start; 00852 end = head->end; 00853 steps = NULL; 00854 stepcount = 0; 00855 } 00856 00857 00858 /********************************************************************** 00859 * add_frag_to_list 00860 * 00861 * Insert the fragment in the list at the appropriate place to keep 00862 * them in ascending ycoord order. 00863 **********************************************************************/ 00864 00865 void add_frag_to_list( //ordered add 00866 C_OUTLINE_FRAG *frag, //fragment to add 00867 C_OUTLINE_FRAG_LIST *frags //fragment list 00868 ) { 00869 //output list 00870 C_OUTLINE_FRAG_IT frag_it = frags; 00871 00872 if (!frags->empty ()) { 00873 for (frag_it.mark_cycle_pt (); !frag_it.cycled_list (); 00874 frag_it.forward ()) { 00875 if (frag_it.data ()->ycoord > frag->ycoord 00876 || (frag_it.data ()->ycoord == frag->ycoord 00877 && frag->other_end->ycoord < frag->ycoord)) { 00878 frag_it.add_before_then_move (frag); 00879 return; 00880 } 00881 } 00882 } 00883 frag_it.add_to_end (frag); 00884 } 00885 00886 00887 /********************************************************************** 00888 * close_chopped_cfragments 00889 * 00890 * Clear the given list of fragments joining them up into outlines. 00891 * Each outline made soaks up any of the child outlines which it encloses. 00892 **********************************************************************/ 00893 00894 void close_chopped_cfragments( //chop the outline 00895 C_OUTLINE_FRAG_LIST *frags, //list to clear 00896 C_OUTLINE_LIST *children, //potential children 00897 float pitch_error, //allowed shrinkage 00898 C_OUTLINE_IT *dest_it //output list 00899 ) { 00900 //iterator 00901 C_OUTLINE_FRAG_IT frag_it = frags; 00902 C_OUTLINE_FRAG *bottom_frag; //bottom of cut 00903 C_OUTLINE_FRAG *top_frag; //top of cut 00904 C_OUTLINE *outline; //new outline 00905 C_OUTLINE *child; //current child 00906 C_OUTLINE_IT child_it = children; 00907 C_OUTLINE_IT olchild_it; //children of outline 00908 00909 while (!frag_it.empty ()) { 00910 frag_it.move_to_first (); 00911 //get bottom one 00912 bottom_frag = frag_it.extract (); 00913 frag_it.forward (); 00914 top_frag = frag_it.data (); //look at next 00915 if ((bottom_frag->steps == 0 && top_frag->steps == 0) 00916 || (bottom_frag->steps != 0 && top_frag->steps != 0)) { 00917 if (frag_it.data_relative (1)->ycoord == top_frag->ycoord) 00918 frag_it.forward (); 00919 } 00920 top_frag = frag_it.extract (); 00921 if (top_frag->other_end != bottom_frag) { 00922 outline = join_chopped_fragments (bottom_frag, top_frag); 00923 ASSERT_HOST (outline == NULL); 00924 } 00925 else { 00926 outline = join_chopped_fragments (bottom_frag, top_frag); 00927 ASSERT_HOST (outline != NULL); 00928 olchild_it.set_to_list (outline->child ()); 00929 for (child_it.mark_cycle_pt (); !child_it.cycled_list (); 00930 child_it.forward ()) { 00931 child = child_it.data (); 00932 if (*child < *outline) 00933 olchild_it.add_to_end (child_it.extract ()); 00934 } 00935 if (outline->bounding_box ().width () > pitch_error) 00936 dest_it->add_after_then_move (outline); 00937 else 00938 delete outline; //make it disappear 00939 } 00940 } 00941 while (!child_it.empty ()) { 00942 dest_it->add_after_then_move (child_it.extract ()); 00943 child_it.forward (); 00944 } 00945 } 00946 00947 00948 /********************************************************************** 00949 * join_chopped_fragments 00950 * 00951 * Join the two lists of POLYPTs such that neither OUTLINE_FRAG 00952 * operand keeps responsibility for the fragment. 00953 **********************************************************************/ 00954 00955 C_OUTLINE *join_chopped_fragments( //join pieces 00956 C_OUTLINE_FRAG *bottom, //bottom of cut 00957 C_OUTLINE_FRAG *top //top of cut 00958 ) { 00959 C_OUTLINE *outline; //closed loop 00960 00961 if (bottom->other_end == top) { 00962 if (bottom->steps == 0) 00963 outline = top->close (); //turn to outline 00964 else 00965 outline = bottom->close (); 00966 delete top; 00967 delete bottom; 00968 return outline; 00969 } 00970 if (bottom->steps == 0) { 00971 ASSERT_HOST (top->steps != 0); 00972 join_segments (bottom->other_end, top); 00973 } 00974 else { 00975 ASSERT_HOST (top->steps == 0); 00976 join_segments (top->other_end, bottom); 00977 } 00978 top->other_end->other_end = bottom->other_end; 00979 bottom->other_end->other_end = top->other_end; 00980 delete bottom; 00981 delete top; 00982 return NULL; 00983 } 00984 00985 00986 /********************************************************************** 00987 * join_segments 00988 * 00989 * Join the two edgestep fragments such that the second comes after 00990 * the first and the gap beween them is closed. 00991 **********************************************************************/ 00992 00993 void join_segments( //join pieces 00994 C_OUTLINE_FRAG *bottom, //bottom of cut 00995 C_OUTLINE_FRAG *top //top of cut 00996 ) { 00997 DIR128 *steps; //new steps 00998 inT32 stepcount; //no of steps 00999 inT16 fake_count; //fake steps 01000 DIR128 fake_step; //step entry 01001 01002 ASSERT_HOST (bottom->end.x () == top->start.x ()); 01003 fake_count = top->start.y () - bottom->end.y (); 01004 if (fake_count < 0) { 01005 fake_count = -fake_count; 01006 fake_step = 32; 01007 } 01008 else 01009 fake_step = 96; 01010 01011 stepcount = bottom->stepcount + fake_count + top->stepcount; 01012 steps = new DIR128[stepcount]; 01013 memmove (steps, bottom->steps, bottom->stepcount); 01014 memset (steps + bottom->stepcount, fake_step.get_dir(), fake_count); 01015 memmove (steps + bottom->stepcount + fake_count, top->steps, 01016 top->stepcount); 01017 delete [] bottom->steps; 01018 bottom->steps = steps; 01019 bottom->stepcount = stepcount; 01020 bottom->end = top->end; 01021 bottom->other_end->end = top->end; 01022 } 01023 01024 01025 /********************************************************************** 01026 * C_OUTLINE_FRAG::close 01027 * 01028 * Join the ends of this fragment and turn it into an outline. 01029 **********************************************************************/ 01030 01031 C_OUTLINE *C_OUTLINE_FRAG::close() { //join pieces 01032 DIR128 *new_steps; //new steps 01033 inT32 new_stepcount; //no of steps 01034 inT16 fake_count; //fake steps 01035 DIR128 fake_step; //step entry 01036 01037 ASSERT_HOST (start.x () == end.x ()); 01038 fake_count = start.y () - end.y (); 01039 if (fake_count < 0) { 01040 fake_count = -fake_count; 01041 fake_step = 32; 01042 } 01043 else 01044 fake_step = 96; 01045 01046 new_stepcount = stepcount + fake_count; 01047 new_steps = new DIR128[new_stepcount]; 01048 memmove(new_steps, steps, stepcount); 01049 memset (new_steps + stepcount, fake_step.get_dir(), fake_count); 01050 C_OUTLINE* result = new C_OUTLINE (start, new_steps, new_stepcount); 01051 delete [] new_steps; 01052 return result; 01053 } 01054 01055 01056 /********************************************************************** 01057 * C_OUTLINE_FRAG::operator= 01058 * 01059 * Copy this fragment. 01060 **********************************************************************/ 01061 01062 //join pieces 01063 C_OUTLINE_FRAG & C_OUTLINE_FRAG::operator= ( 01064 const C_OUTLINE_FRAG & src //fragment to copy 01065 ) { 01066 if (steps != NULL) 01067 delete [] steps; 01068 01069 stepcount = src.stepcount; 01070 steps = new DIR128[stepcount]; 01071 memmove (steps, src.steps, stepcount); 01072 start = src.start; 01073 end = src.end; 01074 ycoord = src.ycoord; 01075 return *this; 01076 }