/** * @name insert_seam * * Add another seam to a collection of seams at a particular location * in the seam array. */ void insert_seam(const TWERD* word, int index, SEAM *seam, GenericVector<SEAM*>* seam_array) { SEAM *test_seam; int list_length = seam_array->size(); for (int test_index = 0; test_index < index; ++test_index) { test_seam = seam_array->get(test_index); if (test_index + test_seam->widthp >= index) { test_seam->widthp++; /*got in the way */ } else if (test_seam->widthp + test_index == index - 1) { test_seam->widthp = account_splits(test_seam, word, test_index + 1, 1); if (test_seam->widthp < 0) { tprintf("Failed to find any right blob for a split!\n"); print_seam("New dud seam", seam); print_seam("Failed seam", test_seam); } } } for (int test_index = index; test_index < list_length; test_index++) { test_seam = seam_array->get(test_index); if (test_index - test_seam->widthn < index) { test_seam->widthn++; /*got in the way */ } else if (test_index - test_seam->widthn == index) { test_seam->widthn = account_splits(test_seam, word, test_index + 1, -1); if (test_seam->widthn < 0) { tprintf("Failed to find any left blob for a split!\n"); print_seam("New dud seam", seam); print_seam("Failed seam", test_seam); } } } seam_array->insert(seam, index); }
/** * @name insert_seam * * Add another seam to a collection of seams at a particular location * in the seam array. */ SEAMS insert_seam(SEAMS seam_list, int index, SEAM *seam, TBLOB *left_blob, TBLOB *first_blob) { SEAM *test_seam; TBLOB *blob; int test_index; int list_length; list_length = array_count(seam_list); for (test_index=0, blob=first_blob->next; test_index < index; test_index++, blob=blob->next) { test_seam = (SEAM *) array_value(seam_list, test_index); if (test_index + test_seam->widthp >= index) { test_seam->widthp++; /*got in the way */ } else if (test_seam->widthp + test_index == index - 1) { test_seam->widthp = account_splits_right(test_seam, blob); if (test_seam->widthp < 0) { cprintf("Failed to find any right blob for a split!\n"); print_seam("New dud seam", seam); print_seam("Failed seam", test_seam); } } } for (test_index=index, blob=left_blob->next; test_index < list_length; test_index++, blob=blob->next) { test_seam = (SEAM *) array_value(seam_list, test_index); if (test_index - test_seam->widthn < index) { test_seam->widthn++; /*got in the way */ } else if (test_index - test_seam->widthn == index) { test_seam->widthn = account_splits_left(test_seam, first_blob, blob); if (test_seam->widthn < 0) { cprintf("Failed to find any left blob for a split!\n"); print_seam("New dud seam", seam); print_seam("Failed seam", test_seam); } } } return (array_insert (seam_list, index, seam)); }
/** * @name print_seams * * Print a list of splits. Show the coordinates of both points in * each split. */ void print_seams(const char *label, const GenericVector<SEAM*>& seams) { char number[CHARS_PER_LINE]; if (!seams.empty()) { tprintf("%s\n", label); for (int x = 0; x < seams.size(); ++x) { sprintf(number, "%2d: ", x); print_seam(number, seams[x]); } tprintf("\n"); } }
/** * @name print_seams * * Print a list of splits. Show the coordinates of both points in * each split. */ void print_seams(const char *label, SEAMS seams) { int x; char number[CHARS_PER_LINE]; if (seams) { cprintf("%s\n", label); array_loop(seams, x) { sprintf(number, "%2d: ", x); print_seam(number, (SEAM *) array_value(seams, x)); } cprintf("\n"); }
SEAM *Wordrec::attempt_blob_chop(TWERD *word, TBLOB *blob, inT32 blob_number, bool italic_blob, const GenericVector<SEAM*>& seams) { if (repair_unchopped_blobs) preserve_outline_tree (blob->outlines); TBLOB *other_blob = TBLOB::ShallowCopy(*blob); /* Make new blob */ // Insert it into the word. word->blobs.insert(other_blob, blob_number + 1); SEAM *seam = NULL; if (prioritize_division) { TPOINT location; if (divisible_blob(blob, italic_blob, &location)) { seam = new SEAM(0.0f, location, NULL, NULL, NULL); } } if (seam == NULL) seam = pick_good_seam(blob); if (chop_debug) { if (seam != NULL) print_seam("Good seam picked=", seam); else tprintf("\n** no seam picked *** \n"); } if (seam) { apply_seam(blob, other_blob, italic_blob, seam); } seam = CheckSeam(chop_debug, blob_number, word, blob, other_blob, seams, seam); if (seam == NULL) { if (repair_unchopped_blobs) restore_outline_tree(blob->outlines); if (word->latin_script) { // If the blob can simply be divided into outlines, then do that. TPOINT location; if (divisible_blob(blob, italic_blob, &location)) { other_blob = TBLOB::ShallowCopy(*blob); /* Make new blob */ word->blobs.insert(other_blob, blob_number + 1); seam = new SEAM(0.0f, location, NULL, NULL, NULL); apply_seam(blob, other_blob, italic_blob, seam); seam = CheckSeam(chop_debug, blob_number, word, blob, other_blob, seams, seam); } } } return seam; }
/********************************************************************** * attempt_blob_chop * * Try to split the this blob after this one. Check to make sure that * it was successful. **********************************************************************/ SEAM *attempt_blob_chop(TWERD *word, INT32 blob_number, SEAMS seam_list) { TBLOB *blob; TBLOB *other_blob; SEAM *seam; TBLOB *last_blob; TBLOB *next_blob; INT16 x; if (first_pass) chops_attempted1++; else chops_attempted2++; last_blob = NULL; blob = word->blobs; for (x = 0; x < blob_number; x++) { last_blob = blob; blob = blob->next; } next_blob = blob->next; if (repair_unchopped_blobs) preserve_outline_tree (blob->outlines); other_blob = newblob (); /* Make new blob */ other_blob->next = blob->next; other_blob->outlines = NULL; blob->next = other_blob; seam = pick_good_seam (blob); if (chop_debug) { if (seam != NULL) { print_seam ("Good seam picked=", seam); } else cprintf ("\n** no seam picked *** \n"); } if (seam) { apply_seam(blob, other_blob, seam); } if ((seam == NULL) || (blob->outlines == NULL) || (other_blob->outlines == NULL) || total_containment (blob, other_blob) || check_blob (other_blob) || !(check_seam_order (blob, seam) && check_seam_order (other_blob, seam)) || any_shared_split_points (seam_list, seam) || !test_insert_seam(seam_list, blob_number, blob, word->blobs)) { blob->next = next_blob; if (seam) { undo_seam(blob, other_blob, seam); delete_seam(seam); #ifndef GRAPHICS_DISABLED if (chop_debug) { display_blob(blob, Red); cprintf ("\n** seam being removed ** \n"); } #endif } else { oldblob(other_blob); } if (repair_unchopped_blobs) restore_outline_tree (blob->outlines); return (NULL); } return (seam); }
SEAM *Wordrec::attempt_blob_chop(TWERD *word, inT32 blob_number, bool italic_blob, SEAMS seam_list) { TBLOB *blob; TBLOB *other_blob; SEAM *seam; TBLOB *last_blob; TBLOB *next_blob; inT16 x; last_blob = NULL; blob = word->blobs; for (x = 0; x < blob_number; x++) { last_blob = blob; blob = blob->next; } next_blob = blob->next; if (repair_unchopped_blobs) preserve_outline_tree (blob->outlines); other_blob = new TBLOB; /* Make new blob */ other_blob->next = blob->next; other_blob->outlines = NULL; blob->next = other_blob; seam = pick_good_seam(blob); if (seam == NULL && word->latin_script) { // If the blob can simply be divided into outlines, then do that. TPOINT location; if (divisible_blob(blob, italic_blob, &location)) { seam = new_seam(0.0f, location, NULL, NULL, NULL); } } if (chop_debug) { if (seam != NULL) { print_seam ("Good seam picked=", seam); } else cprintf ("\n** no seam picked *** \n"); } if (seam) { apply_seam(blob, other_blob, italic_blob, seam); } if ((seam == NULL) || (blob->outlines == NULL) || (other_blob->outlines == NULL) || total_containment (blob, other_blob) || check_blob (other_blob) || !(check_seam_order (blob, seam) && check_seam_order (other_blob, seam)) || any_shared_split_points (seam_list, seam) || !test_insert_seam(seam_list, blob_number, blob, word->blobs)) { blob->next = next_blob; if (seam) { undo_seam(blob, other_blob, seam); delete_seam(seam); #ifndef GRAPHICS_DISABLED if (chop_debug) { if (chop_debug >2) display_blob(blob, Red); cprintf ("\n** seam being removed ** \n"); } #endif } else { delete other_blob; } if (repair_unchopped_blobs) restore_outline_tree (blob->outlines); return (NULL); } return (seam); }
/********************************************************************** * combine_seam * * Find other seams to combine with this one. The new seams that result * from this union should be added to the seam queue. The return value * tells whether or not any additional seams were added to the queue. **********************************************************************/ void combine_seam(SEAM_QUEUE seam_queue, SEAM_PILE seam_pile, SEAM *seam) { register inT16 x; register inT16 dist; inT16 bottom1, top1; inT16 bottom2, top2; SEAM *new_one; SEAM *this_one; bottom1 = seam->split1->point1->pos.y; if (seam->split1->point2->pos.y >= bottom1) top1 = seam->split1->point2->pos.y; else { top1 = bottom1; bottom1 = seam->split1->point2->pos.y; } if (seam->split2 != NULL) { bottom2 = seam->split2->point1->pos.y; if (seam->split2->point2->pos.y >= bottom2) top2 = seam->split2->point2->pos.y; else { top2 = bottom2; bottom2 = seam->split2->point2->pos.y; } } else { bottom2 = bottom1; top2 = top1; } array_loop(seam_pile, x) { this_one = (SEAM *) array_value (seam_pile, x); dist = seam->location - this_one->location; if (-SPLIT_CLOSENESS < dist && dist < SPLIT_CLOSENESS && seam->priority + this_one->priority < chop_ok_split) { inT16 split1_point1_y = this_one->split1->point1->pos.y; inT16 split1_point2_y = this_one->split1->point2->pos.y; inT16 split2_point1_y = 0; inT16 split2_point2_y = 0; if (this_one->split2) { split2_point1_y = this_one->split2->point1->pos.y; split2_point2_y = this_one->split2->point2->pos.y; } if ( /*!tessedit_fix_sideways_chops || */ ( /* this_one->split1 always exists */ ( ((split1_point1_y >= top1 && split1_point2_y >= top1) || (split1_point1_y <= bottom1 && split1_point2_y <= bottom1)) && ((split1_point1_y >= top2 && split1_point2_y >= top2) || (split1_point1_y <= bottom2 && split1_point2_y <= bottom2)) ) ) && ( this_one->split2 == NULL || ( ((split2_point1_y >= top1 && split2_point2_y >= top1) || (split2_point1_y <= bottom1 && split2_point2_y <= bottom1)) && ((split2_point1_y >= top2 && split2_point2_y >= top2) || (split2_point1_y <= bottom2 && split2_point2_y <= bottom2)) ) ) ) { new_one = join_two_seams (seam, this_one); if (chop_debug > 1) print_seam ("Combo priority ", new_one); add_seam_to_queue (seam_queue, new_one, new_one->priority); } } }
/********************************************************************** * choose_best_seam * * Choose the best seam that can be created by assembling this a * collection of splits. A queue of all the possible seams is * maintained. Each new split received is placed in that queue with * its partial priority value. These values in the seam queue are * evaluated and combined until a good enough seam is found. If no * further good seams are being found then this function returns to the * caller, who will send more splits. If this function is called with * a split of NULL, then no further splits can be supplied by the * caller. **********************************************************************/ void choose_best_seam(SEAM_QUEUE seam_queue, SEAM_PILE *seam_pile, SPLIT *split, PRIORITY priority, SEAM **seam_result, TBLOB *blob) { SEAM *seam; TPOINT topleft; TPOINT botright; char str[80]; float my_priority; /* Add seam of split */ my_priority = priority; if (split != NULL) { seam = new_seam (my_priority, (split->point1->pos.x + split->point1->pos.x) / 2, split, NULL, NULL); if (chop_debug > 1) print_seam ("Partial priority ", seam); add_seam_to_queue (seam_queue, seam, (float) my_priority); if (my_priority > chop_good_split) return; } blob_bounding_box(blob, &topleft, &botright); /* Queue loop */ while (pop_next_seam (seam_queue, seam, my_priority)) { /* Set full priority */ my_priority = seam_priority (seam, topleft.x, botright.x); if (chop_debug) { sprintf (str, "Full my_priority %0.0f, ", my_priority); print_seam(str, seam); } if ((*seam_result == NULL || /* Replace answer */ (*seam_result)->priority > my_priority) && my_priority < chop_ok_split) { /* No crossing */ if (constrained_split (seam->split1, blob)) { delete_seam(*seam_result); clone_seam(*seam_result, seam); (*seam_result)->priority = my_priority; } else { delete_seam(seam); seam = NULL; my_priority = BAD_PRIORITY; } } if (my_priority < chop_good_split) { if (seam) delete_seam(seam); return; /* Made good answer */ } if (seam) { /* Combine with others */ if (array_count (*seam_pile) < MAX_NUM_SEAMS /*|| tessedit_truncate_chopper==0 */ ) { combine_seam(seam_queue, *seam_pile, seam); *seam_pile = array_push (*seam_pile, seam); } else delete_seam(seam); } my_priority = best_seam_priority (seam_queue); if ((my_priority > chop_ok_split) || (my_priority > chop_good_split && split)) return; } }