Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: pithsync.cpp (Formerly pitsync2.c) 00003 * Description: Code to find the optimum fixed pitch segmentation of some blobs. 00004 * Author: Ray Smith 00005 * Created: Thu Nov 19 11:48:05 GMT 1992 00006 * 00007 * (C) Copyright 1992, 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 <math.h> 00025 #include "memry.h" 00026 #include "makerow.h" 00027 #include "pitsync1.h" 00028 #include "topitch.h" 00029 #include "pithsync.h" 00030 #include "tprintf.h" 00031 00032 #define PROJECTION_MARGIN 10 //arbitrary 00033 00034 #define EXTERN 00035 00036 /********************************************************************** 00037 * FPCUTPT::setup 00038 * 00039 * Constructor to make a new FPCUTPT. 00040 **********************************************************************/ 00041 00042 void FPCUTPT::setup( //constructor 00043 FPCUTPT *cutpts, //predecessors 00044 inT16 array_origin, //start coord 00045 STATS *projection, //vertical occupation 00046 inT16 zero_count, //official zero 00047 inT16 pitch, //proposed pitch 00048 inT16 x, //position 00049 inT16 offset //dist to gap 00050 ) { 00051 //half of pitch 00052 inT16 half_pitch = pitch / 2 - 1; 00053 uinT32 lead_flag; //new flag 00054 inT32 ind; //current position 00055 00056 if (half_pitch > 31) 00057 half_pitch = 31; 00058 else if (half_pitch < 0) 00059 half_pitch = 0; 00060 lead_flag = 1 << half_pitch; 00061 00062 pred = NULL; 00063 mean_sum = 0; 00064 sq_sum = offset * offset; 00065 cost = sq_sum; 00066 faked = FALSE; 00067 terminal = FALSE; 00068 fake_count = 0; 00069 xpos = x; 00070 region_index = 0; 00071 mid_cuts = 0; 00072 if (x == array_origin) { 00073 back_balance = 0; 00074 fwd_balance = 0; 00075 for (ind = 0; ind <= half_pitch; ind++) { 00076 fwd_balance >>= 1; 00077 if (projection->pile_count (ind) > zero_count) 00078 fwd_balance |= lead_flag; 00079 } 00080 } 00081 else { 00082 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00083 back_balance &= lead_flag + lead_flag - 1; 00084 if (projection->pile_count (x) > zero_count) 00085 back_balance |= 1; 00086 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00087 if (projection->pile_count (x + half_pitch) > zero_count) 00088 fwd_balance |= lead_flag; 00089 } 00090 } 00091 00092 00093 /********************************************************************** 00094 * FPCUTPT::assign 00095 * 00096 * Constructor to make a new FPCUTPT. 00097 **********************************************************************/ 00098 00099 void FPCUTPT::assign( //constructor 00100 FPCUTPT *cutpts, //predecessors 00101 inT16 array_origin, //start coord 00102 inT16 x, //position 00103 BOOL8 faking, //faking this one 00104 BOOL8 mid_cut, //cheap cut. 00105 inT16 offset, //dist to gap 00106 STATS *projection, //vertical occupation 00107 float projection_scale, //scaling 00108 inT16 zero_count, //official zero 00109 inT16 pitch, //proposed pitch 00110 inT16 pitch_error //allowed tolerance 00111 ) { 00112 int index; //test index 00113 int balance_index; //for balance factor 00114 inT16 balance_count; //ding factor 00115 inT16 r_index; //test cut number 00116 FPCUTPT *segpt; //segment point 00117 inT32 dist; //from prev segment 00118 double sq_dist; //squared distance 00119 double mean; //mean pitch 00120 double total; //total dists 00121 double factor; //cost function 00122 //half of pitch 00123 inT16 half_pitch = pitch / 2 - 1; 00124 uinT32 lead_flag; //new flag 00125 00126 if (half_pitch > 31) 00127 half_pitch = 31; 00128 else if (half_pitch < 0) 00129 half_pitch = 0; 00130 lead_flag = 1 << half_pitch; 00131 00132 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00133 back_balance &= lead_flag + lead_flag - 1; 00134 if (projection->pile_count (x) > zero_count) 00135 back_balance |= 1; 00136 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00137 if (projection->pile_count (x + half_pitch) > zero_count) 00138 fwd_balance |= lead_flag; 00139 00140 xpos = x; 00141 cost = MAX_FLOAT32; 00142 pred = NULL; 00143 faked = faking; 00144 terminal = FALSE; 00145 region_index = 0; 00146 fake_count = MAX_INT16; 00147 for (index = x - pitch - pitch_error; index <= x - pitch + pitch_error; 00148 index++) { 00149 if (index >= array_origin) { 00150 segpt = &cutpts[index - array_origin]; 00151 dist = x - segpt->xpos; 00152 if (!segpt->terminal && segpt->fake_count < MAX_INT16) { 00153 balance_count = 0; 00154 if (textord_balance_factor > 0) { 00155 if (textord_fast_pitch_test) { 00156 lead_flag = back_balance ^ segpt->fwd_balance; 00157 balance_count = 0; 00158 while (lead_flag != 0) { 00159 balance_count++; 00160 lead_flag &= lead_flag - 1; 00161 } 00162 } 00163 else { 00164 for (balance_index = 0; 00165 index + balance_index < x - balance_index; 00166 balance_index++) 00167 balance_count += 00168 (projection->pile_count (index + balance_index) <= 00169 zero_count) ^ (projection->pile_count (x - 00170 balance_index) 00171 <= zero_count); 00172 } 00173 balance_count = 00174 (inT16) (balance_count * textord_balance_factor / 00175 projection_scale); 00176 } 00177 r_index = segpt->region_index + 1; 00178 total = segpt->mean_sum + dist; 00179 balance_count += offset; 00180 sq_dist = 00181 dist * dist + segpt->sq_sum + balance_count * balance_count; 00182 mean = total / r_index; 00183 factor = mean - pitch; 00184 factor *= factor; 00185 factor += sq_dist / (r_index) - mean * mean; 00186 if (factor < cost && segpt->fake_count + faked <= fake_count) { 00187 cost = factor; //find least cost 00188 pred = segpt; //save path 00189 mean_sum = total; 00190 sq_sum = sq_dist; 00191 fake_count = segpt->fake_count + faked; 00192 mid_cuts = segpt->mid_cuts + mid_cut; 00193 region_index = r_index; 00194 } 00195 } 00196 } 00197 } 00198 } 00199 00200 00201 /********************************************************************** 00202 * FPCUTPT::assign_cheap 00203 * 00204 * Constructor to make a new FPCUTPT on the cheap. 00205 **********************************************************************/ 00206 00207 void FPCUTPT::assign_cheap( //constructor 00208 FPCUTPT *cutpts, //predecessors 00209 inT16 array_origin, //start coord 00210 inT16 x, //position 00211 BOOL8 faking, //faking this one 00212 BOOL8 mid_cut, //cheap cut. 00213 inT16 offset, //dist to gap 00214 STATS *projection, //vertical occupation 00215 float projection_scale, //scaling 00216 inT16 zero_count, //official zero 00217 inT16 pitch, //proposed pitch 00218 inT16 pitch_error //allowed tolerance 00219 ) { 00220 int index; //test index 00221 inT16 balance_count; //ding factor 00222 inT16 r_index; //test cut number 00223 FPCUTPT *segpt; //segment point 00224 inT32 dist; //from prev segment 00225 double sq_dist; //squared distance 00226 double mean; //mean pitch 00227 double total; //total dists 00228 double factor; //cost function 00229 //half of pitch 00230 inT16 half_pitch = pitch / 2 - 1; 00231 uinT32 lead_flag; //new flag 00232 00233 if (half_pitch > 31) 00234 half_pitch = 31; 00235 else if (half_pitch < 0) 00236 half_pitch = 0; 00237 lead_flag = 1 << half_pitch; 00238 00239 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00240 back_balance &= lead_flag + lead_flag - 1; 00241 if (projection->pile_count (x) > zero_count) 00242 back_balance |= 1; 00243 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00244 if (projection->pile_count (x + half_pitch) > zero_count) 00245 fwd_balance |= lead_flag; 00246 00247 xpos = x; 00248 cost = MAX_FLOAT32; 00249 pred = NULL; 00250 faked = faking; 00251 terminal = FALSE; 00252 region_index = 0; 00253 fake_count = MAX_INT16; 00254 index = x - pitch; 00255 if (index >= array_origin) { 00256 segpt = &cutpts[index - array_origin]; 00257 dist = x - segpt->xpos; 00258 if (!segpt->terminal && segpt->fake_count < MAX_INT16) { 00259 balance_count = 0; 00260 if (textord_balance_factor > 0) { 00261 lead_flag = back_balance ^ segpt->fwd_balance; 00262 balance_count = 0; 00263 while (lead_flag != 0) { 00264 balance_count++; 00265 lead_flag &= lead_flag - 1; 00266 } 00267 balance_count = (inT16) (balance_count * textord_balance_factor 00268 / projection_scale); 00269 } 00270 r_index = segpt->region_index + 1; 00271 total = segpt->mean_sum + dist; 00272 balance_count += offset; 00273 sq_dist = 00274 dist * dist + segpt->sq_sum + balance_count * balance_count; 00275 mean = total / r_index; 00276 factor = mean - pitch; 00277 factor *= factor; 00278 factor += sq_dist / (r_index) - mean * mean; 00279 cost = factor; //find least cost 00280 pred = segpt; //save path 00281 mean_sum = total; 00282 sq_sum = sq_dist; 00283 fake_count = segpt->fake_count + faked; 00284 mid_cuts = segpt->mid_cuts + mid_cut; 00285 region_index = r_index; 00286 } 00287 } 00288 } 00289 00290 00291 /********************************************************************** 00292 * check_pitch_sync 00293 * 00294 * Construct the lattice of possible segmentation points and choose the 00295 * optimal path. Return the optimal path only. 00296 * The return value is a measure of goodness of the sync. 00297 **********************************************************************/ 00298 00299 double check_pitch_sync2( //find segmentation 00300 BLOBNBOX_IT *blob_it, //blobs to do 00301 inT16 blob_count, //no of blobs 00302 inT16 pitch, //pitch estimate 00303 inT16 pitch_error, //tolerance 00304 STATS *projection, //vertical 00305 inT16 projection_left, //edges //scale factor 00306 inT16 projection_right, 00307 float projection_scale, 00308 inT16 &occupation_count, //no of occupied cells 00309 FPSEGPT_LIST *seg_list, //output list 00310 inT16 start, //start of good range 00311 inT16 end //end of good range 00312 ) { 00313 BOOL8 faking; //illegal cut pt 00314 BOOL8 mid_cut; //cheap cut pt. 00315 inT16 x; //current coord 00316 inT16 blob_index; //blob number 00317 inT16 left_edge; //of word 00318 inT16 right_edge; //of word 00319 inT16 array_origin; //x coord of array 00320 inT16 offset; //dist to legal area 00321 inT16 zero_count; //projection zero 00322 inT16 best_left_x = 0; //for equals 00323 inT16 best_right_x = 0; //right edge 00324 TBOX this_box; //bounding box 00325 TBOX next_box; //box of next blob 00326 FPSEGPT *segpt; //segment point 00327 FPCUTPT *cutpts; //array of points 00328 double best_cost; //best path 00329 double mean_sum; //computes result 00330 FPCUTPT *best_end; //end of best path 00331 inT16 best_fake; //best fake level 00332 inT16 best_count; //no of cuts 00333 BLOBNBOX_IT this_it; //copy iterator 00334 FPSEGPT_IT seg_it = seg_list; //output iterator 00335 00336 // tprintf("Computing sync on word of %d blobs with pitch %d\n", 00337 // blob_count, pitch); 00338 // if (blob_count==8 && pitch==27) 00339 // projection->print(stdout,TRUE); 00340 zero_count = 0; 00341 if (pitch < 3) 00342 pitch = 3; //nothing ludicrous 00343 if ((pitch - 3) / 2 < pitch_error) 00344 pitch_error = (pitch - 3) / 2; 00345 this_it = *blob_it; 00346 this_box = box_next (&this_it);//get box 00347 // left_edge=this_box.left(); //left of word 00348 // right_edge=this_box.right(); 00349 // for (blob_index=1;blob_index<blob_count;blob_index++) 00350 // { 00351 // this_box=box_next(&this_it); 00352 // if (this_box.right()>right_edge) 00353 // right_edge=this_box.right(); 00354 // } 00355 for (left_edge = projection_left; projection->pile_count (left_edge) == 0 00356 && left_edge < projection_right; left_edge++); 00357 for (right_edge = projection_right; projection->pile_count (right_edge) == 0 00358 && right_edge > left_edge; right_edge--); 00359 ASSERT_HOST (right_edge >= left_edge); 00360 if (pitsync_linear_version >= 4) 00361 return check_pitch_sync3 (projection_left, projection_right, zero_count, 00362 pitch, pitch_error, projection, 00363 projection_scale, occupation_count, seg_list, 00364 start, end); 00365 array_origin = left_edge - pitch; 00366 cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1) 00367 * sizeof (FPCUTPT)); 00368 for (x = array_origin; x < left_edge; x++) 00369 //free cuts 00370 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0); 00371 for (offset = 0; offset <= pitch_error; offset++, x++) 00372 //not quite free 00373 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset); 00374 00375 this_it = *blob_it; 00376 best_cost = MAX_FLOAT32; 00377 best_end = NULL; 00378 this_box = box_next (&this_it);//first box 00379 next_box = box_next (&this_it);//second box 00380 blob_index = 1; 00381 while (x < right_edge - pitch_error) { 00382 if (x > this_box.right () + pitch_error && blob_index < blob_count) { 00383 this_box = next_box; 00384 next_box = box_next (&this_it); 00385 blob_index++; 00386 } 00387 faking = FALSE; 00388 mid_cut = FALSE; 00389 if (x <= this_box.left ()) 00390 offset = 0; 00391 else if (x <= this_box.left () + pitch_error) 00392 offset = x - this_box.left (); 00393 else if (x >= this_box.right ()) 00394 offset = 0; 00395 else if (x >= next_box.left () && blob_index < blob_count) { 00396 offset = x - next_box.left (); 00397 if (this_box.right () - x < offset) 00398 offset = this_box.right () - x; 00399 } 00400 else if (x >= this_box.right () - pitch_error) 00401 offset = this_box.right () - x; 00402 else if (x - this_box.left () > pitch * pitsync_joined_edge 00403 && this_box.right () - x > pitch * pitsync_joined_edge) { 00404 mid_cut = TRUE; 00405 offset = 0; 00406 } 00407 else { 00408 faking = TRUE; 00409 offset = projection->pile_count (x); 00410 } 00411 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00412 faking, mid_cut, offset, projection, 00413 projection_scale, zero_count, pitch, 00414 pitch_error); 00415 x++; 00416 } 00417 00418 best_fake = MAX_INT16; 00419 best_cost = MAX_INT32; 00420 best_count = MAX_INT16; 00421 while (x < right_edge + pitch) { 00422 offset = x < right_edge ? right_edge - x : 0; 00423 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00424 FALSE, FALSE, offset, projection, 00425 projection_scale, zero_count, pitch, 00426 pitch_error); 00427 cutpts[x - array_origin].terminal = TRUE; 00428 if (cutpts[x - array_origin].index () + 00429 cutpts[x - array_origin].fake_count <= best_count + best_fake) { 00430 if (cutpts[x - array_origin].fake_count < best_fake 00431 || (cutpts[x - array_origin].fake_count == best_fake 00432 && cutpts[x - array_origin].cost_function () < best_cost)) { 00433 best_fake = cutpts[x - array_origin].fake_count; 00434 best_cost = cutpts[x - array_origin].cost_function (); 00435 best_left_x = x; 00436 best_right_x = x; 00437 best_count = cutpts[x - array_origin].index (); 00438 } 00439 else if (cutpts[x - array_origin].fake_count == best_fake 00440 && x == best_right_x + 1 00441 && cutpts[x - array_origin].cost_function () == best_cost) { 00442 //exactly equal 00443 best_right_x = x; 00444 } 00445 } 00446 x++; 00447 } 00448 ASSERT_HOST (best_fake < MAX_INT16); 00449 00450 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin]; 00451 if (this_box.right () == textord_test_x 00452 && this_box.top () == textord_test_y) { 00453 for (x = left_edge - pitch; x < right_edge + pitch; x++) { 00454 tprintf ("x=%d, C=%g, s=%g, sq=%g, prev=%d\n", 00455 x, cutpts[x - array_origin].cost_function (), 00456 cutpts[x - array_origin].sum (), 00457 cutpts[x - array_origin].squares (), 00458 cutpts[x - array_origin].previous ()->position ()); 00459 } 00460 } 00461 occupation_count = -1; 00462 do { 00463 for (x = best_end->position () - pitch + pitch_error; 00464 x < best_end->position () - pitch_error 00465 && projection->pile_count (x) == 0; x++); 00466 if (x < best_end->position () - pitch_error) 00467 occupation_count++; 00468 //copy it 00469 segpt = new FPSEGPT (best_end); 00470 seg_it.add_before_then_move (segpt); 00471 best_end = best_end->previous (); 00472 } 00473 while (best_end != NULL); 00474 seg_it.move_to_last (); 00475 mean_sum = seg_it.data ()->sum (); 00476 mean_sum = mean_sum * mean_sum / best_count; 00477 if (seg_it.data ()->squares () - mean_sum < 0) 00478 tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n", 00479 seg_it.data ()->squares (), seg_it.data ()->sum (), best_count); 00480 free_mem(cutpts); 00481 // tprintf("blob_count=%d, pitch=%d, sync=%g, occ=%d\n", 00482 // blob_count,pitch,seg_it.data()->squares()-mean_sum, 00483 // occupation_count); 00484 return seg_it.data ()->squares () - mean_sum; 00485 } 00486 00487 00488 /********************************************************************** 00489 * check_pitch_sync 00490 * 00491 * Construct the lattice of possible segmentation points and choose the 00492 * optimal path. Return the optimal path only. 00493 * The return value is a measure of goodness of the sync. 00494 **********************************************************************/ 00495 00496 double check_pitch_sync3( //find segmentation 00497 inT16 projection_left, //edges //to be considered 0 00498 inT16 projection_right, 00499 inT16 zero_count, 00500 inT16 pitch, //pitch estimate 00501 inT16 pitch_error, //tolerance 00502 STATS *projection, //vertical 00503 float projection_scale, //scale factor 00504 inT16 &occupation_count, //no of occupied cells 00505 FPSEGPT_LIST *seg_list, //output list 00506 inT16 start, //start of good range 00507 inT16 end //end of good range 00508 ) { 00509 BOOL8 faking; //illegal cut pt 00510 BOOL8 mid_cut; //cheap cut pt. 00511 inT16 left_edge; //of word 00512 inT16 right_edge; //of word 00513 inT16 x; //current coord 00514 inT16 array_origin; //x coord of array 00515 inT16 offset; //dist to legal area 00516 inT16 projection_offset; //from scaled projection 00517 inT16 prev_zero; //previous zero dist 00518 inT16 next_zero; //next zero dist 00519 inT16 zero_offset; //scan window 00520 inT16 best_left_x = 0; //for equals 00521 inT16 best_right_x = 0; //right edge 00522 FPSEGPT *segpt; //segment point 00523 FPCUTPT *cutpts; //array of points 00524 BOOL8 *mins; //local min results 00525 int minindex; //next input position 00526 int test_index; //index to mins 00527 double best_cost; //best path 00528 double mean_sum; //computes result 00529 FPCUTPT *best_end; //end of best path 00530 inT16 best_fake; //best fake level 00531 inT16 best_count; //no of cuts 00532 FPSEGPT_IT seg_it = seg_list; //output iterator 00533 00534 end = (end - start) % pitch; 00535 if (pitch < 3) 00536 pitch = 3; //nothing ludicrous 00537 if ((pitch - 3) / 2 < pitch_error) 00538 pitch_error = (pitch - 3) / 2; 00539 //min dist of zero 00540 zero_offset = (inT16) (pitch * pitsync_joined_edge); 00541 for (left_edge = projection_left; projection->pile_count (left_edge) == 0 00542 && left_edge < projection_right; left_edge++); 00543 for (right_edge = projection_right; projection->pile_count (right_edge) == 0 00544 && right_edge > left_edge; right_edge--); 00545 array_origin = left_edge - pitch; 00546 cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1) 00547 * sizeof (FPCUTPT)); 00548 mins = (BOOL8 *) alloc_mem ((pitch_error * 2 + 1) * sizeof (BOOL8)); 00549 for (x = array_origin; x < left_edge; x++) 00550 //free cuts 00551 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0); 00552 prev_zero = left_edge - 1; 00553 for (offset = 0; offset <= pitch_error; offset++, x++) 00554 //not quite free 00555 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset); 00556 00557 best_cost = MAX_FLOAT32; 00558 best_end = NULL; 00559 for (offset = -pitch_error, minindex = 0; offset < pitch_error; 00560 offset++, minindex++) 00561 mins[minindex] = projection->local_min (x + offset); 00562 next_zero = x + zero_offset + 1; 00563 for (offset = next_zero - 1; offset >= x; offset--) { 00564 if (projection->pile_count (offset) <= zero_count) { 00565 next_zero = offset; 00566 break; 00567 } 00568 } 00569 while (x < right_edge - pitch_error) { 00570 mins[minindex] = projection->local_min (x + pitch_error); 00571 minindex++; 00572 if (minindex > pitch_error * 2) 00573 minindex = 0; 00574 faking = FALSE; 00575 mid_cut = FALSE; 00576 offset = 0; 00577 if (projection->pile_count (x) <= zero_count) { 00578 prev_zero = x; 00579 } 00580 else { 00581 for (offset = 1; offset <= pitch_error; offset++) 00582 if (projection->pile_count (x + offset) <= zero_count 00583 || projection->pile_count (x - offset) <= zero_count) 00584 break; 00585 } 00586 if (offset > pitch_error) { 00587 if (x - prev_zero > zero_offset && next_zero - x > zero_offset) { 00588 for (offset = 0; offset <= pitch_error; offset++) { 00589 test_index = minindex + pitch_error + offset; 00590 if (test_index > pitch_error * 2) 00591 test_index -= pitch_error * 2 + 1; 00592 if (mins[test_index]) 00593 break; 00594 test_index = minindex + pitch_error - offset; 00595 if (test_index > pitch_error * 2) 00596 test_index -= pitch_error * 2 + 1; 00597 if (mins[test_index]) 00598 break; 00599 } 00600 } 00601 if (offset > pitch_error) { 00602 offset = projection->pile_count (x); 00603 faking = TRUE; 00604 } 00605 else { 00606 projection_offset = 00607 (inT16) (projection->pile_count (x) / projection_scale); 00608 if (projection_offset > offset) 00609 offset = projection_offset; 00610 mid_cut = TRUE; 00611 } 00612 } 00613 if ((start == 0 && end == 0) 00614 || !textord_fast_pitch_test 00615 || (x - projection_left - start) % pitch <= end) 00616 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00617 faking, mid_cut, offset, projection, 00618 projection_scale, zero_count, pitch, 00619 pitch_error); 00620 else 00621 cutpts[x - array_origin].assign_cheap (cutpts, array_origin, x, 00622 faking, mid_cut, offset, 00623 projection, projection_scale, 00624 zero_count, pitch, 00625 pitch_error); 00626 x++; 00627 if (next_zero < x || next_zero == x + zero_offset) 00628 next_zero = x + zero_offset + 1; 00629 if (projection->pile_count (x + zero_offset) <= zero_count) 00630 next_zero = x + zero_offset; 00631 } 00632 00633 best_fake = MAX_INT16; 00634 best_cost = MAX_INT32; 00635 best_count = MAX_INT16; 00636 while (x < right_edge + pitch) { 00637 offset = x < right_edge ? right_edge - x : 0; 00638 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00639 FALSE, FALSE, offset, projection, 00640 projection_scale, zero_count, pitch, 00641 pitch_error); 00642 cutpts[x - array_origin].terminal = TRUE; 00643 if (cutpts[x - array_origin].index () + 00644 cutpts[x - array_origin].fake_count <= best_count + best_fake) { 00645 if (cutpts[x - array_origin].fake_count < best_fake 00646 || (cutpts[x - array_origin].fake_count == best_fake 00647 && cutpts[x - array_origin].cost_function () < best_cost)) { 00648 best_fake = cutpts[x - array_origin].fake_count; 00649 best_cost = cutpts[x - array_origin].cost_function (); 00650 best_left_x = x; 00651 best_right_x = x; 00652 best_count = cutpts[x - array_origin].index (); 00653 } 00654 else if (cutpts[x - array_origin].fake_count == best_fake 00655 && x == best_right_x + 1 00656 && cutpts[x - array_origin].cost_function () == best_cost) { 00657 //exactly equal 00658 best_right_x = x; 00659 } 00660 } 00661 x++; 00662 } 00663 ASSERT_HOST (best_fake < MAX_INT16); 00664 00665 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin]; 00666 // for (x=left_edge-pitch;x<right_edge+pitch;x++) 00667 // { 00668 // tprintf("x=%d, C=%g, s=%g, sq=%g, prev=%d\n", 00669 // x,cutpts[x-array_origin].cost_function(), 00670 // cutpts[x-array_origin].sum(), 00671 // cutpts[x-array_origin].squares(), 00672 // cutpts[x-array_origin].previous()->position()); 00673 // } 00674 occupation_count = -1; 00675 do { 00676 for (x = best_end->position () - pitch + pitch_error; 00677 x < best_end->position () - pitch_error 00678 && projection->pile_count (x) == 0; x++); 00679 if (x < best_end->position () - pitch_error) 00680 occupation_count++; 00681 //copy it 00682 segpt = new FPSEGPT (best_end); 00683 seg_it.add_before_then_move (segpt); 00684 best_end = best_end->previous (); 00685 } 00686 while (best_end != NULL); 00687 seg_it.move_to_last (); 00688 mean_sum = seg_it.data ()->sum (); 00689 mean_sum = mean_sum * mean_sum / best_count; 00690 if (seg_it.data ()->squares () - mean_sum < 0) 00691 tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n", 00692 seg_it.data ()->squares (), seg_it.data ()->sum (), best_count); 00693 free_mem(mins); 00694 free_mem(cutpts); 00695 return seg_it.data ()->squares () - mean_sum; 00696 }