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