tesseract 4.1.1
Loading...
Searching...
No Matches
fpchop.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * File: fpchop.cpp (Formerly fp_chop.c)
3 * Description: Code to chop fixed pitch text into character cells.
4 * Author: Ray Smith
5 *
6 * (C) Copyright 1993, Hewlett-Packard Ltd.
7 ** Licensed under the Apache License, Version 2.0 (the "License");
8 ** you may not use this file except in compliance with the License.
9 ** You may obtain a copy of the License at
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 *
17 **********************************************************************/
18
19#include "blobbox.h"
20#include "statistc.h"
21#include "drawtord.h"
22#include "tovars.h"
23#include "topitch.h"
24#include "fpchop.h"
25
26// Include automatically generated configuration file if running autoconf.
27#ifdef HAVE_CONFIG_H
28#include "config_auto.h"
29#endif
30
32"Max allowed bending of chop cells");
34"Max distance of chop pt from vertex");
35
37//#undef ASSERT_HOST
38//#define ASSERT_HOST(x) if (!(x)) AfxMessageBox(#x);
39/**********************************************************************
40 * fixed_pitch_words
41 *
42 * Make a ROW from a fixed pitch TO_ROW.
43 **********************************************************************/
44ROW *fixed_pitch_words( //find lines
45 TO_ROW *row, //row to do
46 FCOORD rotation //for drawing
47 ) {
48 bool bol; //start of line
49 uint8_t blanks; //in front of word
50 uint8_t new_blanks; //blanks in empty cell
51 int16_t chop_coord; //chop boundary
52 int16_t prev_chop_coord; //start of cell
53 int16_t rep_left; //left edge of rep word
54 ROW *real_row; //output row
55 C_OUTLINE_LIST left_coutlines;
56 C_OUTLINE_LIST right_coutlines;
57 C_BLOB_LIST cblobs;
58 C_BLOB_IT cblob_it = &cblobs;
59 WERD_LIST words;
60 WERD_IT word_it = &words; //new words
61 //repeated blobs
62 WERD_IT rep_it = &row->rep_words;
63 WERD *word; //new word
64 int32_t xstarts[2]; //row ends
65 int32_t prev_x; //end of prev blob
66 //iterator
67 BLOBNBOX_IT box_it = row->blob_list ();
68 //boundaries
69 ICOORDELT_IT cell_it = &row->char_cells;
70
71#ifndef GRAPHICS_DISABLED
72 if (textord_show_page_cuts && to_win != nullptr) {
73 plot_row_cells (to_win, ScrollView::RED, row, 0, &row->char_cells);
74 }
75#endif
76
77 prev_x = -INT16_MAX;
78 bol = true;
79 blanks = 0;
80 if (rep_it.empty ())
81 rep_left = INT16_MAX;
82 else
83 rep_left = rep_it.data ()->bounding_box ().left ();
84 if (box_it.empty ())
85 return nullptr; //empty row
86 xstarts[0] = box_it.data ()->bounding_box ().left ();
87 if (rep_left < xstarts[0]) {
88 xstarts[0] = rep_left;
89 }
90 if (cell_it.empty () || row->char_cells.singleton ()) {
91 tprintf ("Row without enough char cells!\n");
92 tprintf ("Leftmost blob is at (%d,%d)\n",
93 box_it.data ()->bounding_box ().left (),
94 box_it.data ()->bounding_box ().bottom ());
95 return nullptr;
96 }
97 ASSERT_HOST (!cell_it.empty () && !row->char_cells.singleton ());
98 prev_chop_coord = cell_it.data ()->x ();
99 word = nullptr;
100 while (rep_left < cell_it.data ()->x ()) {
101 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord,
102 blanks, row->fixed_pitch, &word_it);
103 }
104 cell_it.mark_cycle_pt ();
105 if (prev_chop_coord >= cell_it.data ()->x ())
106 cell_it.forward ();
107 for (; !cell_it.cycled_list (); cell_it.forward ()) {
108 chop_coord = cell_it.data ()->x ();
109 while (!box_it.empty ()
110 && box_it.data ()->bounding_box ().left () <= chop_coord) {
111 if (box_it.data ()->bounding_box ().right () > prev_x)
112 prev_x = box_it.data ()->bounding_box ().right ();
113 split_to_blob (box_it.extract (), chop_coord,
115 &left_coutlines,
116 &right_coutlines);
117 box_it.forward ();
118 while (!box_it.empty() && box_it.data()->cblob() == nullptr) {
119 delete box_it.extract();
120 box_it.forward();
121 }
122 }
123 if (!right_coutlines.empty() && left_coutlines.empty())
124 split_to_blob (nullptr, chop_coord,
126 &left_coutlines,
127 &right_coutlines);
128 if (!left_coutlines.empty()) {
129 cblob_it.add_after_then_move(new C_BLOB(&left_coutlines));
130 } else {
131 if (rep_left < chop_coord) {
132 if (rep_left > prev_chop_coord)
133 new_blanks = static_cast<uint8_t>(floor ((rep_left - prev_chop_coord)
134 / row->fixed_pitch + 0.5));
135 else
136 new_blanks = 0;
137 }
138 else {
139 if (chop_coord > prev_chop_coord)
140 new_blanks = static_cast<uint8_t>(floor ((chop_coord - prev_chop_coord)
141 / row->fixed_pitch + 0.5));
142 else
143 new_blanks = 0;
144 }
145 if (!cblob_it.empty()) {
146 if (blanks < 1 && word != nullptr && !word->flag (W_REP_CHAR))
147 blanks = 1;
148 word = new WERD (&cblobs, blanks, nullptr);
149 cblob_it.set_to_list (&cblobs);
150 word->set_flag (W_DONT_CHOP, true);
151 word_it.add_after_then_move (word);
152 if (bol) {
153 word->set_flag (W_BOL, true);
154 bol = false;
155 }
156 blanks = new_blanks;
157 }
158 else
159 blanks += new_blanks;
160 while (rep_left < chop_coord) {
161 word = add_repeated_word (&rep_it, rep_left, prev_chop_coord,
162 blanks, row->fixed_pitch, &word_it);
163 }
164 }
165 if (prev_chop_coord < chop_coord)
166 prev_chop_coord = chop_coord;
167 }
168 if (!cblob_it.empty()) {
169 word = new WERD(&cblobs, blanks, nullptr);
170 word->set_flag (W_DONT_CHOP, true);
171 word_it.add_after_then_move (word);
172 if (bol)
173 word->set_flag (W_BOL, true);
174 }
175 ASSERT_HOST (word != nullptr);
176 while (!rep_it.empty ()) {
177 add_repeated_word (&rep_it, rep_left, prev_chop_coord,
178 blanks, row->fixed_pitch, &word_it);
179 }
180 //at end of line
181 word_it.data ()->set_flag (W_EOL, true);
182 if (prev_chop_coord > prev_x)
183 prev_x = prev_chop_coord;
184 xstarts[1] = prev_x + 1;
185 real_row = new ROW (row, static_cast<int16_t>(row->kern_size), static_cast<int16_t>(row->space_size));
186 word_it.set_to_list (real_row->word_list ());
187 //put words in row
188 word_it.add_list_after (&words);
189 real_row->recalc_bounding_box ();
190 return real_row;
191}
192
193
194/**********************************************************************
195 * add_repeated_word
196 *
197 * Add repeated word into the row at the given point.
198 **********************************************************************/
199
200WERD *add_repeated_word( //move repeated word
201 WERD_IT *rep_it, //repeated words
202 int16_t &rep_left, //left edge of word
203 int16_t &prev_chop_coord, //previous word end
204 uint8_t &blanks, //no of blanks
205 float pitch, //char cell size
206 WERD_IT *word_it //list of words
207 ) {
208 WERD *word; //word to move
209 int16_t new_blanks; //extra blanks
210
211 if (rep_left > prev_chop_coord) {
212 new_blanks = static_cast<uint8_t>(floor ((rep_left - prev_chop_coord) / pitch + 0.5));
213 blanks += new_blanks;
214 }
215 word = rep_it->extract ();
216 prev_chop_coord = word->bounding_box ().right ();
217 word_it->add_after_then_move (word);
218 word->set_blanks (blanks);
219 rep_it->forward ();
220 if (rep_it->empty ())
221 rep_left = INT16_MAX;
222 else
223 rep_left = rep_it->data ()->bounding_box ().left ();
224 blanks = 0;
225 return word;
226}
227
228
229/**********************************************************************
230 * split_to_blob
231 *
232 * Split a BLOBNBOX across a vertical chop line and put the pieces
233 * into a left outline list and a right outline list.
234 **********************************************************************/
235
236void split_to_blob( //split the blob
237 BLOBNBOX *blob, //blob to split
238 int16_t chop_coord, //place to chop
239 float pitch_error, //allowed deviation
240 C_OUTLINE_LIST *left_coutlines, //for cblobs
241 C_OUTLINE_LIST *right_coutlines) {
242 C_BLOB *real_cblob; //cblob to chop
243
244 if (blob != nullptr) {
245 real_cblob = blob->cblob();
246 } else {
247 real_cblob = nullptr;
248 }
249 if (!right_coutlines->empty() || real_cblob != nullptr)
250 fixed_chop_cblob(real_cblob,
251 chop_coord,
252 pitch_error,
253 left_coutlines,
254 right_coutlines);
255
256 delete blob;
257}
258
259/**********************************************************************
260 * fixed_chop_cblob
261 *
262 * Chop the given cblob (if any) and the existing right outlines to
263 * produce a list of outlines left of the chop point and more to the right.
264 **********************************************************************/
265
266void fixed_chop_cblob( //split the blob
267 C_BLOB *blob, //blob to split
268 int16_t chop_coord, //place to chop
269 float pitch_error, //allowed deviation
270 C_OUTLINE_LIST *left_outlines, //left half of chop
271 C_OUTLINE_LIST *right_outlines //right half of chop
272 ) {
273 C_OUTLINE *old_right; //already there
274 C_OUTLINE_LIST new_outlines; //new right ones
275 //output iterator
276 C_OUTLINE_IT left_it = left_outlines;
277 //in/out iterator
278 C_OUTLINE_IT right_it = right_outlines;
279 C_OUTLINE_IT new_it = &new_outlines;
280 C_OUTLINE_IT blob_it; //outlines in blob
281
282 if (!right_it.empty ()) {
283 while (!right_it.empty ()) {
284 old_right = right_it.extract ();
285 right_it.forward ();
286 fixed_split_coutline(old_right,
287 chop_coord,
288 pitch_error,
289 &left_it,
290 &new_it);
291 }
292 right_it.add_list_before (&new_outlines);
293 }
294 if (blob != nullptr) {
295 blob_it.set_to_list (blob->out_list ());
296 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list ();
297 blob_it.forward ())
298 fixed_split_coutline (blob_it.extract (), chop_coord, pitch_error,
299 &left_it, &right_it);
300 delete blob;
301 }
302}
303
304
305/**********************************************************************
306 * fixed_split_outline
307 *
308 * Chop the given outline (if necessary) placing the fragments which
309 * fall either side of the chop line into the appropriate list.
310 **********************************************************************/
311
312void fixed_split_coutline( //chop the outline
313 C_OUTLINE *srcline, //source outline
314 int16_t chop_coord, //place to chop
315 float pitch_error, //allowed deviation
316 C_OUTLINE_IT *left_it, //left half of chop
317 C_OUTLINE_IT *right_it //right half of chop
318 ) {
319 C_OUTLINE *child; //child outline
320 TBOX srcbox; //box of outline
321 C_OUTLINE_LIST left_ch; //left children
322 C_OUTLINE_LIST right_ch; //right children
323 C_OUTLINE_FRAG_LIST left_frags;//chopped fragments
324 C_OUTLINE_FRAG_LIST right_frags;;
325 C_OUTLINE_IT left_ch_it = &left_ch;
326 //for whole children
327 C_OUTLINE_IT right_ch_it = &right_ch;
328 //for holes
329 C_OUTLINE_IT child_it = srcline->child ();
330
331 srcbox = srcline->bounding_box();
332 if (srcbox.left() + srcbox.right() <= chop_coord * 2
333 && srcbox.right() < chop_coord + pitch_error) {
334 // Whole outline is in the left side or not far over the chop_coord,
335 // so put the whole thing on the left.
336 left_it->add_after_then_move(srcline);
337 } else if (srcbox.left() + srcbox.right() > chop_coord * 2
338 && srcbox.left () > chop_coord - pitch_error) {
339 // Whole outline is in the right side or not far over the chop_coord,
340 // so put the whole thing on the right.
341 right_it->add_before_stay_put(srcline);
342 } else {
343 // Needs real chopping.
344 if (fixed_chop_coutline(srcline, chop_coord, pitch_error,
345 &left_frags, &right_frags)) {
346 for (child_it.mark_cycle_pt(); !child_it.cycled_list();
347 child_it.forward()) {
348 child = child_it.extract();
349 srcbox = child->bounding_box();
350 if (srcbox.right() < chop_coord) {
351 // Whole child is on the left.
352 left_ch_it.add_after_then_move(child);
353 } else if (srcbox.left() > chop_coord) {
354 // Whole child is on the right.
355 right_ch_it.add_after_then_move (child);
356 } else {
357 // No pitch_error is allowed when chopping children to prevent
358 // impossible outlines from being created.
359 if (fixed_chop_coutline(child, chop_coord, 0.0f,
360 &left_frags, &right_frags)) {
361 delete child;
362 } else {
363 if (srcbox.left() + srcbox.right() <= chop_coord * 2)
364 left_ch_it.add_after_then_move(child);
365 else
366 right_ch_it.add_after_then_move(child);
367 }
368 }
369 }
370 close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it);
371 close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it);
372 ASSERT_HOST(left_ch.empty() && right_ch.empty());
373 // No children left.
374 delete srcline; // Smashed up.
375 } else {
376 // Chop failed. Just use middle coord.
377 if (srcbox.left() + srcbox.right() <= chop_coord * 2)
378 left_it->add_after_then_move(srcline); // Stick whole in left.
379 else
380 right_it->add_before_stay_put(srcline);
381 }
382 }
383}
384
385
386/**********************************************************************
387 * fixed_chop_coutline
388 *
389 * Chop the given coutline (if necessary) placing the fragments which
390 * fall either side of the chop line into the appropriate list.
391 * If the coutline lies too heavily to one side to chop, false is returned.
392 **********************************************************************/
393
394bool fixed_chop_coutline( //chop the outline
395 C_OUTLINE* srcline, //source outline
396 int16_t chop_coord, //place to chop
397 float pitch_error, //allowed deviation
398 C_OUTLINE_FRAG_LIST* left_frags, //left half of chop
399 C_OUTLINE_FRAG_LIST* right_frags //right half of chop
400) {
401 bool first_frag; //fragment
402 int16_t left_edge; //of outline
403 int16_t startindex; //in first fragment
404 int32_t length; //of outline
405 int16_t stepindex; //into outline
406 int16_t head_index; //start of fragment
407 ICOORD head_pos; //start of fragment
408 int16_t tail_index; //end of fragment
409 ICOORD tail_pos; //end of fragment
410 ICOORD pos; //current point
411 int16_t first_index = 0; //first tail
412 ICOORD first_pos; //first tail
413
414 length = srcline->pathlength ();
415 pos = srcline->start_pos ();
416 left_edge = pos.x ();
417 tail_index = 0;
418 tail_pos = pos;
419 for (stepindex = 0; stepindex < length; stepindex++) {
420 if (pos.x () < left_edge) {
421 left_edge = pos.x ();
422 tail_index = stepindex;
423 tail_pos = pos;
424 }
425 pos += srcline->step (stepindex);
426 }
427 if (left_edge >= chop_coord - pitch_error)
428 return false; //not worth it
429
430 startindex = tail_index;
431 first_frag = true;
432 head_index = tail_index;
433 head_pos = tail_pos;
434 do {
435 do {
436 tail_pos += srcline->step (tail_index);
437 tail_index++;
438 if (tail_index == length)
439 tail_index = 0;
440 }
441 while (tail_pos.x () != chop_coord && tail_index != startindex);
442 if (tail_index == startindex) {
443 if (first_frag)
444 return false; //doesn't cross line
445 else
446 break;
447 }
448 ASSERT_HOST (head_index != tail_index);
449 if (!first_frag) {
450 save_chop_cfragment(head_index,
451 head_pos,
452 tail_index,
453 tail_pos,
454 srcline,
455 left_frags);
456 }
457 else {
458 first_index = tail_index;
459 first_pos = tail_pos;
460 first_frag = false;
461 }
462 while (srcline->step (tail_index).x () == 0) {
463 tail_pos += srcline->step (tail_index);
464 tail_index++;
465 if (tail_index == length)
466 tail_index = 0;
467 }
468 head_index = tail_index;
469 head_pos = tail_pos;
470 while (srcline->step (tail_index).x () > 0) {
471 do {
472 tail_pos += srcline->step (tail_index);
473 tail_index++;
474 if (tail_index == length)
475 tail_index = 0;
476 }
477 while (tail_pos.x () != chop_coord);
478 ASSERT_HOST (head_index != tail_index);
479 save_chop_cfragment(head_index,
480 head_pos,
481 tail_index,
482 tail_pos,
483 srcline,
484 right_frags);
485 while (srcline->step (tail_index).x () == 0) {
486 tail_pos += srcline->step (tail_index);
487 tail_index++;
488 if (tail_index == length)
489 tail_index = 0;
490 }
491 head_index = tail_index;
492 head_pos = tail_pos;
493 }
494 }
495 while (tail_index != startindex);
496 save_chop_cfragment(head_index,
497 head_pos,
498 first_index,
499 first_pos,
500 srcline,
501 left_frags);
502 return true; //did some chopping
503}
504
505/**********************************************************************
506 * save_chop_cfragment
507 *
508 * Store the given fragment in the given fragment list.
509 **********************************************************************/
510
511void save_chop_cfragment( //chop the outline
512 int16_t head_index, //head of fragment
513 ICOORD head_pos, //head of fragment
514 int16_t tail_index, //tail of fragment
515 ICOORD tail_pos, //tail of fragment
516 C_OUTLINE *srcline, //source of edgesteps
517 C_OUTLINE_FRAG_LIST *frags //fragment list
518 ) {
519 int16_t jump; //gap across end
520 int16_t stepcount; //total steps
521 C_OUTLINE_FRAG *head; //head of fragment
522 C_OUTLINE_FRAG *tail; //tail of fragment
523 int16_t tail_y; //ycoord of tail
524
525 ASSERT_HOST (tail_pos.x () == head_pos.x ());
526 ASSERT_HOST (tail_index != head_index);
527 stepcount = tail_index - head_index;
528 if (stepcount < 0)
529 stepcount += srcline->pathlength ();
530 jump = tail_pos.y () - head_pos.y ();
531 if (jump < 0)
532 jump = -jump;
533 if (jump == stepcount)
534 return; //its a nop
535 tail_y = tail_pos.y ();
536 head = new C_OUTLINE_FRAG (head_pos, tail_pos, srcline,
537 head_index, tail_index);
538 tail = new C_OUTLINE_FRAG (head, tail_y);
539 head->other_end = tail;
540 add_frag_to_list(head, frags);
541 add_frag_to_list(tail, frags);
542}
543
544
545/**********************************************************************
546 * C_OUTLINE_FRAG::C_OUTLINE_FRAG
547 *
548 * Constructors for C_OUTLINE_FRAG.
549 **********************************************************************/
550
552 ICOORD start_pt, //start coord
553 ICOORD end_pt, //end coord
554 C_OUTLINE *outline, //source of steps
555 int16_t start_index,
556 int16_t end_index) {
557 start = start_pt;
558 end = end_pt;
559 ycoord = start_pt.y ();
560 stepcount = end_index - start_index;
561 if (stepcount < 0)
562 stepcount += outline->pathlength ();
564 steps = new DIR128[stepcount];
565 if (end_index > start_index) {
566 for (int i = start_index; i < end_index; ++i)
567 steps[i - start_index] = outline->step_dir(i);
568 }
569 else {
570 int len = outline->pathlength();
571 int i = start_index;
572 for (; i < len; ++i)
573 steps[i - start_index] = outline->step_dir(i);
574 if (end_index > 0)
575 for (; i < end_index + len; ++i)
576 steps[i - start_index] = outline->step_dir(i - len);
577 }
578 other_end = nullptr;
579 delete close();
580}
581
582
584 C_OUTLINE_FRAG *head, //other end
585 int16_t tail_y) {
586 ycoord = tail_y;
587 other_end = head;
588 start = head->start;
589 end = head->end;
590 steps = nullptr;
591 stepcount = 0;
592}
593
594
595/**********************************************************************
596 * add_frag_to_list
597 *
598 * Insert the fragment in the list at the appropriate place to keep
599 * them in ascending ycoord order.
600 **********************************************************************/
601
602void add_frag_to_list( //ordered add
603 C_OUTLINE_FRAG *frag, //fragment to add
604 C_OUTLINE_FRAG_LIST *frags //fragment list
605 ) {
606 //output list
607 C_OUTLINE_FRAG_IT frag_it = frags;
608
609 if (!frags->empty ()) {
610 for (frag_it.mark_cycle_pt (); !frag_it.cycled_list ();
611 frag_it.forward ()) {
612 if (frag_it.data ()->ycoord > frag->ycoord
613 || (frag_it.data ()->ycoord == frag->ycoord
614 && frag->other_end->ycoord < frag->ycoord)) {
615 frag_it.add_before_then_move (frag);
616 return;
617 }
618 }
619 }
620 frag_it.add_to_end (frag);
621}
622
623
624/**********************************************************************
625 * close_chopped_cfragments
626 *
627 * Clear the given list of fragments joining them up into outlines.
628 * Each outline made soaks up any of the child outlines which it encloses.
629 **********************************************************************/
630
631void close_chopped_cfragments( //chop the outline
632 C_OUTLINE_FRAG_LIST *frags, //list to clear
633 C_OUTLINE_LIST *children, //potential children
634 float pitch_error, //allowed shrinkage
635 C_OUTLINE_IT *dest_it //output list
636 ) {
637 //iterator
638 C_OUTLINE_FRAG_IT frag_it = frags;
639 C_OUTLINE_FRAG *bottom_frag; //bottom of cut
640 C_OUTLINE_FRAG *top_frag; //top of cut
641 C_OUTLINE *outline; //new outline
642 C_OUTLINE *child; //current child
643 C_OUTLINE_IT child_it = children;
644 C_OUTLINE_IT olchild_it; //children of outline
645
646 while (!frag_it.empty()) {
647 frag_it.move_to_first();
648 // get bottom one
649 bottom_frag = frag_it.extract();
650 frag_it.forward();
651 top_frag = frag_it.data(); // look at next
652 if ((bottom_frag->steps == nullptr && top_frag->steps == nullptr)
653 || (bottom_frag->steps != nullptr && top_frag->steps != nullptr)) {
654 if (frag_it.data_relative(1)->ycoord == top_frag->ycoord)
655 frag_it.forward();
656 }
657 top_frag = frag_it.extract();
658 if (top_frag->other_end != bottom_frag) {
659 outline = join_chopped_fragments(bottom_frag, top_frag);
660 ASSERT_HOST(outline == nullptr);
661 } else {
662 outline = join_chopped_fragments(bottom_frag, top_frag);
663 if (outline != nullptr) {
664 olchild_it.set_to_list(outline->child());
665 for (child_it.mark_cycle_pt(); !child_it.cycled_list();
666 child_it.forward()) {
667 child = child_it.data();
668 if (*child < *outline)
669 olchild_it.add_to_end(child_it.extract());
670 }
671 if (outline->bounding_box().width() > pitch_error)
672 dest_it->add_after_then_move(outline);
673 else
674 delete outline; // Make it disappear.
675 }
676 }
677 }
678 while (!child_it.empty ()) {
679 dest_it->add_after_then_move (child_it.extract ());
680 child_it.forward ();
681 }
682}
683
684
685/**********************************************************************
686 * join_chopped_fragments
687 *
688 * Join the two lists of POLYPTs such that neither OUTLINE_FRAG
689 * operand keeps responsibility for the fragment.
690 **********************************************************************/
691
693 C_OUTLINE_FRAG *bottom, //bottom of cut
694 C_OUTLINE_FRAG *top //top of cut
695 ) {
696 C_OUTLINE *outline; //closed loop
697
698 if (bottom->other_end == top) {
699 if (bottom->steps == nullptr)
700 outline = top->close (); //turn to outline
701 else
702 outline = bottom->close ();
703 delete top;
704 delete bottom;
705 return outline;
706 }
707 if (bottom->steps == nullptr) {
708 ASSERT_HOST (top->steps != nullptr);
709 join_segments (bottom->other_end, top);
710 }
711 else {
712 ASSERT_HOST (top->steps == nullptr);
713 join_segments (top->other_end, bottom);
714 }
715 top->other_end->other_end = bottom->other_end;
716 bottom->other_end->other_end = top->other_end;
717 delete bottom;
718 delete top;
719 return nullptr;
720}
721
722/**********************************************************************
723 * join_segments
724 *
725 * Join the two edgestep fragments such that the second comes after
726 * the first and the gap between them is closed.
727 **********************************************************************/
728
729void join_segments( //join pieces
730 C_OUTLINE_FRAG *bottom, //bottom of cut
731 C_OUTLINE_FRAG *top //top of cut
732 ) {
733 DIR128 *steps; //new steps
734 int32_t stepcount; //no of steps
735 int16_t fake_count; //fake steps
736 DIR128 fake_step; //step entry
737
738 ASSERT_HOST (bottom->end.x () == top->start.x ());
739 fake_count = top->start.y () - bottom->end.y ();
740 if (fake_count < 0) {
741 fake_count = -fake_count;
742 fake_step = 32;
743 }
744 else
745 fake_step = 96;
746
747 stepcount = bottom->stepcount + fake_count + top->stepcount;
748 steps = new DIR128[stepcount];
749 memmove (steps, bottom->steps, bottom->stepcount);
750 memset (steps + bottom->stepcount, fake_step.get_dir(), fake_count);
751 memmove (steps + bottom->stepcount + fake_count, top->steps,
752 top->stepcount);
753 delete [] bottom->steps;
754 bottom->steps = steps;
755 bottom->stepcount = stepcount;
756 bottom->end = top->end;
757 bottom->other_end->end = top->end;
758}
759
760
761/**********************************************************************
762 * C_OUTLINE_FRAG::close
763 *
764 * Join the ends of this fragment and turn it into an outline.
765 **********************************************************************/
766
768 DIR128 *new_steps; //new steps
769 int32_t new_stepcount; //no of steps
770 int16_t fake_count; //fake steps
771 DIR128 fake_step; //step entry
772
773 ASSERT_HOST (start.x () == end.x ());
774 fake_count = start.y () - end.y ();
775 if (fake_count < 0) {
776 fake_count = -fake_count;
777 fake_step = 32;
778 }
779 else
780 fake_step = 96;
781
782 new_stepcount = stepcount + fake_count;
783 if (new_stepcount > C_OUTLINE::kMaxOutlineLength)
784 return nullptr; // Can't join them
785 new_steps = new DIR128[new_stepcount];
786 memmove(new_steps, steps, stepcount);
787 memset (new_steps + stepcount, fake_step.get_dir(), fake_count);
788 auto* result = new C_OUTLINE (start, new_steps, new_stepcount);
789 delete [] new_steps;
790 return result;
791}
792
793
794/**********************************************************************
795 * C_OUTLINE_FRAG::operator=
796 *
797 * Copy this fragment.
798 **********************************************************************/
799
800 //join pieces
802const C_OUTLINE_FRAG & src //fragment to copy
803) {
804 delete [] steps;
805
806 stepcount = src.stepcount;
807 steps = new DIR128[stepcount];
808 memmove (steps, src.steps, stepcount);
809 start = src.start;
810 end = src.end;
811 ycoord = src.ycoord;
812 return *this;
813}
@ W_EOL
end of line
Definition: werd.h:33
@ W_REP_CHAR
repeated character
Definition: werd.h:38
@ W_DONT_CHOP
fixed pitch chopped
Definition: werd.h:37
@ W_BOL
start of line
Definition: werd.h:32
#define ELISTIZE(CLASSNAME)
Definition: elst.h:931
#define ASSERT_HOST(x)
Definition: errcode.h:88
#define INT_VAR(name, val, comment)
Definition: params.h:303
#define double_VAR(name, val, comment)
Definition: params.h:312
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
void plot_row_cells(ScrollView *win, ScrollView::Color colour, TO_ROW *row, float xshift, ICOORDELT_LIST *cells)
Definition: drawtord.cpp:394
ScrollView * to_win
Definition: drawtord.cpp:35
double textord_fp_chop_snap
Definition: fpchop.cpp:34
C_OUTLINE * join_chopped_fragments(C_OUTLINE_FRAG *bottom, C_OUTLINE_FRAG *top)
Definition: fpchop.cpp:692
void add_frag_to_list(C_OUTLINE_FRAG *frag, C_OUTLINE_FRAG_LIST *frags)
Definition: fpchop.cpp:602
void fixed_chop_cblob(C_BLOB *blob, int16_t chop_coord, float pitch_error, C_OUTLINE_LIST *left_outlines, C_OUTLINE_LIST *right_outlines)
Definition: fpchop.cpp:266
void fixed_split_coutline(C_OUTLINE *srcline, int16_t chop_coord, float pitch_error, C_OUTLINE_IT *left_it, C_OUTLINE_IT *right_it)
Definition: fpchop.cpp:312
int textord_fp_chop_error
Definition: fpchop.cpp:32
ROW * fixed_pitch_words(TO_ROW *row, FCOORD rotation)
Definition: fpchop.cpp:44
WERD * add_repeated_word(WERD_IT *rep_it, int16_t &rep_left, int16_t &prev_chop_coord, uint8_t &blanks, float pitch, WERD_IT *word_it)
Definition: fpchop.cpp:200
void split_to_blob(BLOBNBOX *blob, int16_t chop_coord, float pitch_error, C_OUTLINE_LIST *left_coutlines, C_OUTLINE_LIST *right_coutlines)
Definition: fpchop.cpp:236
void save_chop_cfragment(int16_t head_index, ICOORD head_pos, int16_t tail_index, ICOORD tail_pos, C_OUTLINE *srcline, C_OUTLINE_FRAG_LIST *frags)
Definition: fpchop.cpp:511
void close_chopped_cfragments(C_OUTLINE_FRAG_LIST *frags, C_OUTLINE_LIST *children, float pitch_error, C_OUTLINE_IT *dest_it)
Definition: fpchop.cpp:631
bool fixed_chop_coutline(C_OUTLINE *srcline, int16_t chop_coord, float pitch_error, C_OUTLINE_FRAG_LIST *left_frags, C_OUTLINE_FRAG_LIST *right_frags)
Definition: fpchop.cpp:394
void join_segments(C_OUTLINE_FRAG *bottom, C_OUTLINE_FRAG *top)
Definition: fpchop.cpp:729
bool textord_show_page_cuts
Definition: topitch.cpp:47
C_BLOB * cblob() const
Definition: blobbox.h:268
C_OUTLINE_LIST * child()
Definition: coutln.h:108
ICOORD step(int index) const
Definition: coutln.h:144
const TBOX & bounding_box() const
Definition: coutln.h:113
DIR128 step_dir(int index) const
Definition: coutln.h:139
const ICOORD & start_pos() const
Definition: coutln.h:148
static const int kMaxOutlineLength
Definition: coutln.h:273
int32_t pathlength() const
Definition: coutln.h:135
Definition: mod128.h:30
int8_t get_dir() const
Definition: mod128.h:76
Definition: ocrrow.h:37
WERD_LIST * word_list()
Definition: ocrrow.h:55
void recalc_bounding_box()
Definition: ocrrow.cpp:100
integer coordinate
Definition: points.h:32
int16_t y() const
access_function
Definition: points.h:56
int16_t x() const
access function
Definition: points.h:52
Definition: points.h:189
Definition: rect.h:34
int16_t width() const
Definition: rect.h:115
int16_t left() const
Definition: rect.h:72
int16_t right() const
Definition: rect.h:79
C_OUTLINE_LIST * out_list()
Definition: stepblob.h:70
Definition: werd.h:56
void set_blanks(uint8_t new_blanks)
Definition: werd.h:102
void set_flag(WERD_FLAGS mask, bool value)
Definition: werd.h:118
TBOX bounding_box() const
Definition: werd.cpp:148
int32_t stepcount
Definition: fpchop.h:50
ICOORD end
Definition: fpchop.h:48
C_OUTLINE * close()
Definition: fpchop.cpp:767
DIR128 * steps
Definition: fpchop.h:49
ICOORD start
Definition: fpchop.h:47
C_OUTLINE_FRAG()
Definition: fpchop.h:28
int16_t ycoord
Definition: fpchop.h:52
C_OUTLINE_FRAG * other_end
Definition: fpchop.h:51
C_OUTLINE_FRAG & operator=(const C_OUTLINE_FRAG &src)
Definition: fpchop.cpp:801