1 /**********************************************************************
2 * File: polyblob.cpp (Formerly blob.c)
3 * Description: Code for PBLOB class.
4 * Author: Ray Smith
5 * Created: Wed Oct 23 15:17:41 BST 1991
6 *
7 * (C) Copyright 1991, 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 #include "mfcpch.h"
21 #include "varable.h"
22 #include "ocrrow.h"
23 #include "polyblob.h"
24 //#include "lapoly.h"
25 #include "polyaprx.h"
26
27 #define EXTERN
28
29 EXTERN BOOL_VAR (polygon_tess_approximation, TRUE,
30 "Do tess poly instead of greyscale");
31
ELISTIZE_S(PBLOB)32 ELISTIZE_S (PBLOB)
33 /**********************************************************************
34 * position_outline
35 *
36 * Position the outline in the given list at the relevant place
37 * according to its nesting.
38 **********************************************************************/
39 static void position_outline( //put in place
40 OUTLINE *outline, //thing to place
41 OUTLINE_LIST *destlist //desstination list
42 ) {
43 OUTLINE *dest_outline; //outline from dest list
44 OUTLINE_IT it = destlist; //iterator
45 //iterator on children
46 OUTLINE_IT child_it = outline->child ();
47
48 if (!it.empty ()) {
49 do {
50 dest_outline = it.data (); //get destination
51 //encloses dest
52 if (*dest_outline < *outline) {
53 //take off list
54 dest_outline = it.extract ();
55 //put this in place
56 it.add_after_then_move (outline);
57 //make it a child
58 child_it.add_to_end (dest_outline);
59 while (!it.at_last ()) {
60 it.forward (); //do rest of list
61 //check for other children
62 dest_outline = it.data ();
63 if (*dest_outline < *outline) {
64 //take off list
65 dest_outline = it.extract ();
66 child_it.add_to_end (dest_outline);
67 //make it a child
68 if (it.empty ())
69 break;
70 }
71 }
72 return; //finished
73 }
74 //enclosed by dest
75 else if (*outline < *dest_outline) {
76 position_outline (outline, dest_outline->child ());
77 //place in child list
78 return; //finished
79 }
80 it.forward ();
81 }
82 while (!it.at_first ());
83 }
84 it.add_to_end (outline); //at outer level
85 }
86
87
88 /**********************************************************************
89 * plot_outline_list
90 *
91 * Draw a list of outlines in the given colour and their children
92 * in the child colour.
93 **********************************************************************/
94
95 #ifndef GRAPHICS_DISABLED
plot_outline_list(OUTLINE_LIST * list,ScrollView * window,ScrollView::Color colour,ScrollView::Color child_colour)96 static void plot_outline_list( //draw outlines
97 OUTLINE_LIST *list, //outline to draw
98 ScrollView* window, //window to draw in
99 ScrollView::Color colour, //colour to use
100 ScrollView::Color child_colour //colour of children
101 ) {
102 OUTLINE *outline; //current outline
103 OUTLINE_IT it = list; //iterator
104
105 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
106 outline = it.data ();
107 //draw it
108 outline->plot (window, colour);
109 if (!outline->child ()->empty ())
110 plot_outline_list (outline->child (), window,
111 child_colour, child_colour);
112 }
113 }
114 #endif
115
116
117 /**********************************************************************
118 * PBLOB::PBLOB
119 *
120 * Constructor to build a PBLOB from a list of OUTLINEs.
121 * The OUTLINEs are not copied so the source list is emptied.
122 * The OUTLINEs are nested correctly in the blob.
123 **********************************************************************/
124
PBLOB(OUTLINE_LIST * outline_list)125 PBLOB::PBLOB( //constructor
126 OUTLINE_LIST *outline_list //in random order
127 ) {
128 OUTLINE *outline; //current outline
129 OUTLINE_IT it = outline_list; //iterator
130
131 while (!it.empty ()) { //grab the list
132 outline = it.extract (); //get off the list
133 //put it in place
134 position_outline(outline, &outlines);
135 if (!it.empty ())
136 it.forward ();
137 }
138 }
139
140
141 /**********************************************************************
142 * approximate_outline_list
143 *
144 * Convert a list of outlines to polygonal form.
145 **********************************************************************/
146
approximate_outline_list(C_OUTLINE_LIST * srclist,OUTLINE_LIST * destlist,float xheight)147 static void approximate_outline_list( //do list of outlines
148 C_OUTLINE_LIST *srclist, //list to convert
149 OUTLINE_LIST *destlist, //desstination list
150 float xheight //height of line
151 ) {
152 C_OUTLINE *src_outline; //outline from src list
153 OUTLINE *dest_outline; //result
154 C_OUTLINE_IT src_it = srclist; //source iterator
155 OUTLINE_IT dest_it = destlist; //iterator
156
157 do {
158 src_outline = src_it.data ();
159 // if (polygon_tess_approximation)
160 dest_outline = tesspoly_outline (src_outline, xheight);
161 // else
162 // dest_outline=greypoly_outline(src_outline,xheight);
163 if (dest_outline != NULL) {
164 dest_it.add_after_then_move (dest_outline);
165 if (!src_outline->child ()->empty ())
166 //do child list
167 approximate_outline_list (src_outline->child (), dest_outline->child (), xheight);
168 }
169 src_it.forward ();
170 }
171 while (!src_it.at_first ());
172 }
173
174
175 /**********************************************************************
176 * PBLOB::PBLOB
177 *
178 * Constructor to build a PBLOB from a C_BLOB by polygonal approximation.
179 **********************************************************************/
180
PBLOB(C_BLOB * cblob,float xheight)181 PBLOB::PBLOB( //constructor
182 C_BLOB *cblob, //compact blob
183 float xheight //height of line
184 ) {
185 TBOX bbox; //bounding box
186
187 if (!cblob->out_list ()->empty ()) {
188 //get bounding box
189 bbox = cblob->bounding_box ();
190 if (bbox.height () > xheight)
191 xheight = bbox.height (); //max of line and blob
192 //copy it
193 approximate_outline_list (cblob->out_list (), &outlines, xheight);
194 }
195 }
196
197
198 /**********************************************************************
199 * PBLOB::bounding_box
200 *
201 * Return the bounding box of the blob.
202 **********************************************************************/
203
bounding_box()204 TBOX PBLOB::bounding_box() { //bounding box
205 OUTLINE *outline; //current outline
206 OUTLINE_IT it = &outlines; //outlines of blob
207 TBOX box; //bounding box
208
209 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
210 outline = it.data ();
211 box += outline->bounding_box ();
212 }
213 return box;
214 }
215
216
217 /**********************************************************************
218 * PBLOB::area
219 *
220 * Return the area of the blob.
221 **********************************************************************/
222
area()223 float PBLOB::area() { //area
224 OUTLINE *outline; //current outline
225 OUTLINE_IT it = &outlines; //outlines of blob
226 float total; //total area
227
228 total = 0.0f;
229 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
230 outline = it.data ();
231 total += outline->area ();
232 }
233 return total;
234 }
235
236
237 /**********************************************************************
238 * PBLOB::baseline_normalise
239 *
240 * Baseline normalize a blob
241 **********************************************************************/
242
baseline_normalise(ROW * row,DENORM * denorm)243 PBLOB *PBLOB::baseline_normalise( //normalize blob
244 ROW *row, //row it came from
245 DENORM *denorm //inverse mapping
246 ) {
247 TBOX blob_box = bounding_box ();
248 float x_centre = (blob_box.left () + blob_box.right ()) / 2.0;
249 PBLOB *bn_blob; //copied blob
250
251 *denorm = DENORM (x_centre, bln_x_height / row->x_height (), row);
252 bn_blob = new PBLOB; //get one
253 *bn_blob = *this; //deep copy
254 bn_blob->move (FCOORD (-denorm->origin (), -row->base_line (x_centre)));
255 bn_blob->scale (denorm->scale ());
256 bn_blob->move (FCOORD (0.0, bln_baseline_offset));
257 return bn_blob;
258 }
259
260
261 /**********************************************************************
262 * PBLOB::baseline_denormalise
263 *
264 * DeBaseline Normalise the blob properly with the given denorm.
265 **********************************************************************/
266
baseline_denormalise(const DENORM * denorm)267 void PBLOB::baseline_denormalise( // Tess style BL Norm
268 const DENORM *denorm //antidote
269 ) {
270 float blob_x_left; // Left edge of blob.
271 TBOX blob_box; //blob bounding box
272
273 move(FCOORD (0.0f, 0.0f - bln_baseline_offset));
274 blob_box = bounding_box ();
275 blob_x_left = blob_box.left ();
276 scale (1.0 / denorm->scale_at_x (blob_x_left));
277 move (FCOORD (denorm->origin (),
278 denorm->yshift_at_x (blob_x_left)));
279 }
280
281
282 /**********************************************************************
283 * PBLOB::move
284 *
285 * Move PBLOB by vector
286 **********************************************************************/
287
move(const FCOORD vec)288 void PBLOB::move( // reposition blob
289 const FCOORD vec // by vector
290 ) {
291 OUTLINE_IT it(&outlines); // iterator
292
293 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
294 it.data ()->move (vec); // move each outline
295 }
296
297
298 /**********************************************************************
299 * PBLOB::scale
300 *
301 * Scale PBLOB by float multiplier
302 **********************************************************************/
303
scale(const float f)304 void PBLOB::scale( // scale blob
305 const float f // by multiplier
306 ) {
307 OUTLINE_IT it(&outlines); // iterator
308
309 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
310 it.data ()->scale (f); // scale each outline
311 }
312
313
314 /**********************************************************************
315 * PBLOB::scale
316 *
317 * Scale PBLOB by float multiplier
318 **********************************************************************/
319
scale(const FCOORD vec)320 void PBLOB::scale( // scale blob
321 const FCOORD vec // by multiplier
322 ) {
323 OUTLINE_IT it(&outlines); // iterator
324
325 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
326 it.data ()->scale (vec); // scale each outline
327 }
328
329 /**********************************************************************
330 * PBLOB::rotate
331 *
332 * Rotate PBLOB 90 deg anticlockwise about the origin.
333 **********************************************************************/
334
rotate()335 void PBLOB::rotate() { // Rotate 90 deg anti
336 rotate(FCOORD(0.0f, 1.0f));
337 }
338
339 /**********************************************************************
340 * PBLOB::rotate
341 *
342 * Rotate PBLOB by the given rotation about the origin.
343 * The rotation is defined to be (cos a, sin a) where a is the anticlockwise
344 * rotation angle (in units appropriate for cos, sin).
345 * Alternatively think of multiplication by the complex number
346 * rotation = z = (x + iy), with |z| = 1.
347 **********************************************************************/
rotate(const FCOORD & rotation)348 void PBLOB::rotate(const FCOORD& rotation) { // Rotate by given rotation.
349 OUTLINE_IT it(&outlines);
350
351 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
352 it.data()->rotate(rotation); // Rotate each outline.
353 }
354 }
355
356 /**********************************************************************
357 * PBLOB::plot
358 *
359 * Draw the PBLOB in the given colour.
360 **********************************************************************/
361
362 #ifndef GRAPHICS_DISABLED
plot(ScrollView * window,ScrollView::Color blob_colour,ScrollView::Color child_colour)363 void PBLOB::plot( //draw it
364 ScrollView* window, //window to draw in
365 ScrollView::Color blob_colour, //main colour
366 ScrollView::Color child_colour //for holes
367 ) {
368 plot_outline_list(&outlines, window, blob_colour, child_colour);
369 }
370 #endif
371