1
by tmbdev
top-skimming import from sf.net |
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 |
||
351
by joregan
move include of config_auto.h to not conflict with local types. Not finished |
31 |
// Include automatically generated configuration file if running autoconf.
|
32 |
#ifdef HAVE_CONFIG_H
|
|
33 |
#include "config_auto.h" |
|
34 |
#endif
|
|
35 |
||
1
by tmbdev
top-skimming import from sf.net |
36 |
#define EXTERN
|
37 |
||
38 |
EXTERN INT_VAR (textord_fp_chop_error, 2, |
|
39 |
"Max allowed bending of chop cells"); |
|
40 |
EXTERN double_VAR (textord_fp_chop_snap, 0.5, |
|
41 |
"Max distance of chop pt from vertex"); |
|
42 |
||
415
by theraysmith
Deleted lots of dead code, including PBLOB |
43 |
ELISTIZE(C_OUTLINE_FRAG) |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
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 |
|
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
71 |
inT32 xstarts[2]; //row ends |
72 |
inT32 prev_x; //end of prev blob |
|
1
by tmbdev
top-skimming import from sf.net |
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
|
|
101
by theraysmith
Updated graphics output for new java-based display |
79 |
if (textord_show_page_cuts && to_win != NULL) { |
80 |
plot_row_cells (to_win, ScrollView::RED, row, 0, &row->char_cells); |
|
1
by tmbdev
top-skimming import from sf.net |
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, |
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
122 |
&left_coutlines, |
123 |
&right_coutlines); |
|
1
by tmbdev
top-skimming import from sf.net |
124 |
box_it.forward (); |
415
by theraysmith
Deleted lots of dead code, including PBLOB |
125 |
while (!box_it.empty() && box_it.data()->cblob() == NULL) { |
126 |
delete box_it.extract(); |
|
127 |
box_it.forward(); |
|
1
by tmbdev
top-skimming import from sf.net |
128 |
}
|
129 |
}
|
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
130 |
if (!right_coutlines.empty() && left_coutlines.empty()) |
1
by tmbdev
top-skimming import from sf.net |
131 |
split_to_blob (NULL, chop_coord, |
132 |
textord_fp_chop_error + 0.5f, |
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
133 |
&left_coutlines, |
134 |
&right_coutlines); |
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
135 |
if (!left_coutlines.empty()) { |
136 |
cblob_it.add_after_then_move(new C_BLOB(&left_coutlines)); |
|
137 |
} else { |
|
1
by tmbdev
top-skimming import from sf.net |
138 |
if (rep_left < chop_coord) { |
139 |
if (rep_left > prev_chop_coord) |
|
112
by theraysmith
Fixed name collision with jpeg library |
140 |
new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) |
1
by tmbdev
top-skimming import from sf.net |
141 |
/ row->fixed_pitch + 0.5); |
142 |
else
|
|
143 |
new_blanks = 0; |
|
144 |
}
|
|
145 |
else { |
|
146 |
if (chop_coord > prev_chop_coord) |
|
112
by theraysmith
Fixed name collision with jpeg library |
147 |
new_blanks = (uinT8) floor ((chop_coord - prev_chop_coord) |
1
by tmbdev
top-skimming import from sf.net |
148 |
/ row->fixed_pitch + 0.5); |
149 |
else
|
|
150 |
new_blanks = 0; |
|
151 |
}
|
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
152 |
if (!cblob_it.empty()) { |
1
by tmbdev
top-skimming import from sf.net |
153 |
if (blanks < 1 && word != NULL && !word->flag (W_REP_CHAR)) |
154 |
blanks = 1; |
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
155 |
word = new WERD (&cblobs, blanks, NULL); |
156 |
cblob_it.set_to_list (&cblobs); |
|
1
by tmbdev
top-skimming import from sf.net |
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 |
}
|
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
175 |
if (!cblob_it.empty()) { |
176 |
word = new WERD(&cblobs, blanks, NULL); |
|
1
by tmbdev
top-skimming import from sf.net |
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; |
|
112
by theraysmith
Fixed name collision with jpeg library |
192 |
real_row = new ROW (row, (inT16) row->kern_size, (inT16) row->space_size); |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
209 |
inT16 &rep_left, //left edge of word |
210 |
inT16 &prev_chop_coord, //previous word end |
|
211 |
uinT8 &blanks, //no of blanks |
|
1
by tmbdev
top-skimming import from sf.net |
212 |
float pitch, //char cell size |
213 |
WERD_IT *word_it //list of words |
|
214 |
) { |
|
215 |
WERD *word; //word to move |
|
112
by theraysmith
Fixed name collision with jpeg library |
216 |
inT16 new_blanks; //extra blanks |
1
by tmbdev
top-skimming import from sf.net |
217 |
|
218 |
if (rep_left > prev_chop_coord) { |
|
112
by theraysmith
Fixed name collision with jpeg library |
219 |
new_blanks = (uinT8) floor ((rep_left - prev_chop_coord) / pitch + 0.5); |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
245 |
inT16 chop_coord, //place to chop |
1
by tmbdev
top-skimming import from sf.net |
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) { |
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
252 |
real_cblob = blob->cblob(); |
253 |
} else { |
|
1
by tmbdev
top-skimming import from sf.net |
254 |
real_cblob = NULL; |
255 |
}
|
|
415
by theraysmith
Deleted lots of dead code, including PBLOB |
256 |
if (!right_coutlines->empty() || real_cblob != NULL) |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
275 |
inT16 chop_coord, //place to chop |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
321 |
inT16 chop_coord, //place to chop |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
327 |
TBOX srcbox; //box of outline |
1
by tmbdev
top-skimming import from sf.net |
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 |
||
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
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.
|
|
1
by tmbdev
top-skimming import from sf.net |
362 |
right_ch_it.add_after_then_move (child); |
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
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)) { |
|
1
by tmbdev
top-skimming import from sf.net |
368 |
delete child; |
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
369 |
} else { |
370 |
if (srcbox.left() + srcbox.right() <= chop_coord * 2) |
|
371 |
left_ch_it.add_after_then_move(child); |
|
1
by tmbdev
top-skimming import from sf.net |
372 |
else
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
373 |
right_ch_it.add_after_then_move(child); |
1
by tmbdev
top-skimming import from sf.net |
374 |
}
|
375 |
}
|
|
376 |
}
|
|
112
by theraysmith
Fixed name collision with jpeg library |
377 |
close_chopped_cfragments(&left_frags, &left_ch, pitch_error, left_it); |
378 |
close_chopped_cfragments(&right_frags, &right_ch, pitch_error, right_it); |
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
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. |
|
1
by tmbdev
top-skimming import from sf.net |
386 |
else
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
387 |
right_it->add_before_stay_put(srcline); |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
403 |
inT16 chop_coord, //place to chop |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
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 |
|
1
by tmbdev
top-skimming import from sf.net |
414 |
ICOORD head_pos; //start of fragment |
112
by theraysmith
Fixed name collision with jpeg library |
415 |
inT16 tail_index; //end of fragment |
1
by tmbdev
top-skimming import from sf.net |
416 |
ICOORD tail_pos; //end of fragment |
417 |
ICOORD pos; //current point |
|
112
by theraysmith
Fixed name collision with jpeg library |
418 |
inT16 first_index = 0; //first tail |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
523 |
inT16 head_index, //head of fragment |
1
by tmbdev
top-skimming import from sf.net |
524 |
ICOORD head_pos, //head of fragment |
112
by theraysmith
Fixed name collision with jpeg library |
525 |
inT16 tail_index, //tail of fragment |
1
by tmbdev
top-skimming import from sf.net |
526 |
ICOORD tail_pos, //tail of fragment |
527 |
C_OUTLINE *srcline, //source of edgesteps |
|
528 |
C_OUTLINE_FRAG_LIST *frags //fragment list |
|
529 |
) { |
|
112
by theraysmith
Fixed name collision with jpeg library |
530 |
inT16 jump; //gap across end |
531 |
inT16 stepcount; //total steps |
|
1
by tmbdev
top-skimming import from sf.net |
532 |
C_OUTLINE_FRAG *head; //head of fragment |
533 |
C_OUTLINE_FRAG *tail; //tail of fragment |
|
112
by theraysmith
Fixed name collision with jpeg library |
534 |
inT16 tail_y; //ycoord of tail |
1
by tmbdev
top-skimming import from sf.net |
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; |
|
112
by theraysmith
Fixed name collision with jpeg library |
551 |
add_frag_to_list(head, frags); |
552 |
add_frag_to_list(tail, frags); |
|
1
by tmbdev
top-skimming import from sf.net |
553 |
}
|
554 |
||
555 |
||
556 |
/**********************************************************************
|
|
557 |
* C_OUTLINE_FRAG::C_OUTLINE_FRAG
|
|
558 |
*
|
|
559 |
* Constructors for C_OUTLINE_FRAG.
|
|
560 |
**********************************************************************/
|
|
561 |
||
562 |
C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment |
|
563 |
ICOORD start_pt, //start coord |
|
564 |
ICOORD end_pt, //end coord |
|
565 |
C_OUTLINE *outline, //source of steps |
|
112
by theraysmith
Fixed name collision with jpeg library |
566 |
inT16 start_index, |
567 |
inT16 end_index) { |
|
1
by tmbdev
top-skimming import from sf.net |
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]; |
|
101
by theraysmith
Updated graphics output for new java-based display |
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); |
|
1
by tmbdev
top-skimming import from sf.net |
579 |
}
|
101
by theraysmith
Updated graphics output for new java-based display |
580 |
else { |
581 |
int len = outline->pathlength(); |
|
582 |
int i = start_index; |
|
583 |
for (; i < len; ++i) |
|
1
by tmbdev
top-skimming import from sf.net |
584 |
steps[i - start_index] = outline->step_dir(i); |
101
by theraysmith
Updated graphics output for new java-based display |
585 |
if (end_index > 0) |
586 |
for (; i < end_index + len; ++i) |
|
1
by tmbdev
top-skimming import from sf.net |
587 |
steps[i - start_index] = outline->step_dir(i - len); |
588 |
}
|
|
589 |
other_end = NULL; |
|
112
by theraysmith
Fixed name collision with jpeg library |
590 |
delete close(); |
1
by tmbdev
top-skimming import from sf.net |
591 |
}
|
592 |
||
593 |
||
594 |
C_OUTLINE_FRAG::C_OUTLINE_FRAG( //record fragment |
|
595 |
C_OUTLINE_FRAG *head, //other end |
|
112
by theraysmith
Fixed name collision with jpeg library |
596 |
inT16 tail_y) { |
1
by tmbdev
top-skimming import from sf.net |
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 |
|
101
by theraysmith
Updated graphics output for new java-based display |
624 |
|| (frag_it.data ()->ycoord == frag->ycoord |
625 |
&& frag->other_end->ycoord < frag->ycoord)) { |
|
1
by tmbdev
top-skimming import from sf.net |
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 |
||
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
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 |
|
101
by theraysmith
Updated graphics output for new java-based display |
663 |
if ((bottom_frag->steps == 0 && top_frag->steps == 0) |
664 |
|| (bottom_frag->steps != 0 && top_frag->steps != 0)) { |
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
665 |
if (frag_it.data_relative(1)->ycoord == top_frag->ycoord) |
666 |
frag_it.forward(); |
|
1
by tmbdev
top-skimming import from sf.net |
667 |
}
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
668 |
top_frag = frag_it.extract(); |
1
by tmbdev
top-skimming import from sf.net |
669 |
if (top_frag->other_end != bottom_frag) { |
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
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. |
|
1
by tmbdev
top-skimming import from sf.net |
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 |
||
703 |
C_OUTLINE *join_chopped_fragments( //join pieces |
|
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 |
|
112
by theraysmith
Fixed name collision with jpeg library |
746 |
inT32 stepcount; //no of steps |
747 |
inT16 fake_count; //fake steps |
|
1
by tmbdev
top-skimming import from sf.net |
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 |
||
779 |
C_OUTLINE *C_OUTLINE_FRAG::close() { //join pieces |
|
780 |
DIR128 *new_steps; //new steps |
|
112
by theraysmith
Fixed name collision with jpeg library |
781 |
inT32 new_stepcount; //no of steps |
782 |
inT16 fake_count; //fake steps |
|
1
by tmbdev
top-skimming import from sf.net |
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; |
|
668
by theraysmith at gmail
Major refactor of beam search, elimination of dead code, misc bug fixes, updates to Makefile.am, Changelog etc. |
795 |
if (new_stepcount > C_OUTLINE::kMaxOutlineLength) |
796 |
return NULL; // Can't join them |
|
1
by tmbdev
top-skimming import from sf.net |
797 |
new_steps = new DIR128[new_stepcount]; |
112
by theraysmith
Fixed name collision with jpeg library |
798 |
memmove(new_steps, steps, stepcount); |
101
by theraysmith
Updated graphics output for new java-based display |
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; |
|
1
by tmbdev
top-skimming import from sf.net |
802 |
return result; |
803 |
}
|
|
804 |
||
805 |
||
806 |
/**********************************************************************
|
|
807 |
* C_OUTLINE_FRAG::operator=
|
|
808 |
*
|
|
809 |
* Copy this fragment.
|
|
810 |
**********************************************************************/
|
|
811 |
||
812 |
//join pieces
|
|
813 |
C_OUTLINE_FRAG & C_OUTLINE_FRAG::operator= ( |
|
814 |
const C_OUTLINE_FRAG & src //fragment to copy |
|
815 |
) { |
|
816 |
if (steps != NULL) |
|
112
by theraysmith
Fixed name collision with jpeg library |
817 |
delete [] steps; |
1
by tmbdev
top-skimming import from sf.net |
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 |
}
|