Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
stepblob.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: stepblob.cpp (Formerly cblob.c)
3  * Description: Code for C_BLOB class.
4  * Author: Ray Smith
5  * Created: Tue Oct 08 10:41:13 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 "stepblob.h"
22 #include "allheaders.h"
23 
24 // Include automatically generated configuration file if running autoconf.
25 #ifdef HAVE_CONFIG_H
26 #include "config_auto.h"
27 #endif
28 
30 /**********************************************************************
31  * position_outline
32  *
33  * Position the outline in the given list at the relevant place
34  * according to its nesting.
35  **********************************************************************/
36 static void position_outline( //put in place
37  C_OUTLINE *outline, //thing to place
38  C_OUTLINE_LIST *destlist //desstination list
39  ) {
40  C_OUTLINE *dest_outline; //outline from dest list
41  C_OUTLINE_IT it = destlist; //iterator
42  //iterator on children
43  C_OUTLINE_IT child_it = outline->child ();
44 
45  if (!it.empty ()) {
46  do {
47  dest_outline = it.data (); //get destination
48  //encloses dest
49  if (*dest_outline < *outline) {
50  //take off list
51  dest_outline = it.extract ();
52  //put this in place
53  it.add_after_then_move (outline);
54  //make it a child
55  child_it.add_to_end (dest_outline);
56  while (!it.at_last ()) {
57  it.forward (); //do rest of list
58  //check for other children
59  dest_outline = it.data ();
60  if (*dest_outline < *outline) {
61  //take off list
62  dest_outline = it.extract ();
63  child_it.add_to_end (dest_outline);
64  //make it a child
65  if (it.empty ())
66  break;
67  }
68  }
69  return; //finished
70  }
71  //enclosed by dest
72  else if (*outline < *dest_outline) {
73  position_outline (outline, dest_outline->child ());
74  //place in child list
75  return; //finished
76  }
77  it.forward ();
78  }
79  while (!it.at_first ());
80  }
81  it.add_to_end (outline); //at outer level
82 }
83 
84 
85 /**********************************************************************
86  * plot_outline_list
87  *
88  * Draw a list of outlines in the given colour and their children
89  * in the child colour.
90  **********************************************************************/
91 
92 #ifndef GRAPHICS_DISABLED
93 static void plot_outline_list( //draw outlines
94  C_OUTLINE_LIST *list, //outline to draw
95  ScrollView* window, //window to draw in
96  ScrollView::Color colour, //colour to use
97  ScrollView::Color child_colour //colour of children
98  ) {
99  C_OUTLINE *outline; //current outline
100  C_OUTLINE_IT it = list; //iterator
101 
102  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
103  outline = it.data ();
104  //draw it
105  outline->plot (window, colour);
106  if (!outline->child ()->empty ())
107  plot_outline_list (outline->child (), window,
108  child_colour, child_colour);
109  }
110 }
111 #endif
112 
113 
114 /**********************************************************************
115  * reverse_outline_list
116  *
117  * Reverse a list of outlines and their children.
118  **********************************************************************/
119 
120 static void reverse_outline_list( //reverse outlines
121  C_OUTLINE_LIST *list //outline to reverse
122  ) {
123  C_OUTLINE *outline; //current outline
124  C_OUTLINE_IT it = list; //iterator
125 
126  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
127  outline = it.data ();
128  outline->reverse (); //reverse it
129  if (!outline->child ()->empty ())
130  reverse_outline_list (outline->child ());
131  }
132 }
133 
134 
135 /**********************************************************************
136  * C_BLOB::C_BLOB
137  *
138  * Constructor to build a C_BLOB from a list of C_OUTLINEs.
139  * The C_OUTLINEs are not copied so the source list is emptied.
140  * The C_OUTLINEs are nested correctly in the blob.
141  **********************************************************************/
142 
143 C_BLOB::C_BLOB( //constructor
144  C_OUTLINE_LIST *outline_list //in random order
145  ) {
146  C_OUTLINE *outline; //current outline
147  C_OUTLINE_IT it = outline_list;//iterator
148 
149  while (!it.empty ()) { //grab the list
150  outline = it.extract (); //get off the list
151  //put it in place
152  position_outline(outline, &outlines);
153  if (!it.empty ())
154  it.forward ();
155  }
156  it.set_to_list (&outlines);
157  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
158  outline = it.data ();
159  if (outline->turn_direction () < 0) {
160  outline->reverse ();
161  reverse_outline_list (outline->child ());
162  outline->set_flag (COUT_INVERSE, TRUE);
163  }
164  else {
165  outline->set_flag (COUT_INVERSE, FALSE);
166  }
167  }
168 }
169 
170 // Simpler constructor to build a blob from a single outline that has
171 // already been fully initialized.
173  C_OUTLINE_IT it(&outlines);
174  it.add_to_end(outline);
175 }
176 
177 
178 // Build and return a fake blob containing a single fake outline with no
179 // steps.
181  C_OUTLINE_LIST outlines;
182  C_OUTLINE::FakeOutline(box, &outlines);
183  return new C_BLOB(&outlines);
184 }
185 
186 /**********************************************************************
187  * C_BLOB::bounding_box
188  *
189  * Return the bounding box of the blob.
190  **********************************************************************/
191 
192 TBOX C_BLOB::bounding_box() { //bounding box
193  C_OUTLINE *outline; //current outline
194  C_OUTLINE_IT it = &outlines; //outlines of blob
195  TBOX box; //bounding box
196 
197  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
198  outline = it.data ();
199  box += outline->bounding_box ();
200  }
201  return box;
202 }
203 
204 
205 /**********************************************************************
206  * C_BLOB::area
207  *
208  * Return the area of the blob.
209  **********************************************************************/
210 
211 inT32 C_BLOB::area() { //area
212  C_OUTLINE *outline; //current outline
213  C_OUTLINE_IT it = &outlines; //outlines of blob
214  inT32 total; //total area
215 
216  total = 0;
217  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
218  outline = it.data ();
219  total += outline->area ();
220  }
221  return total;
222 }
223 
224 /**********************************************************************
225  * C_BLOB::perimeter
226  *
227  * Return the perimeter of the top and 2nd level outlines.
228  **********************************************************************/
229 
231  C_OUTLINE *outline; // current outline
232  C_OUTLINE_IT it = &outlines; // outlines of blob
233  inT32 total; // total perimeter
234 
235  total = 0;
236  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
237  outline = it.data();
238  total += outline->perimeter();
239  }
240  return total;
241 }
242 
243 
244 /**********************************************************************
245  * C_BLOB::outer_area
246  *
247  * Return the area of the blob.
248  **********************************************************************/
249 
251  C_OUTLINE *outline; //current outline
252  C_OUTLINE_IT it = &outlines; //outlines of blob
253  inT32 total; //total area
254 
255  total = 0;
256  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
257  outline = it.data ();
258  total += outline->outer_area ();
259  }
260  return total;
261 }
262 
263 
264 /**********************************************************************
265  * C_BLOB::count_transitions
266  *
267  * Return the total x and y maxes and mins in the blob.
268  * Chlid outlines are not counted.
269  **********************************************************************/
270 
272  inT32 threshold //on size
273  ) {
274  C_OUTLINE *outline; //current outline
275  C_OUTLINE_IT it = &outlines; //outlines of blob
276  inT32 total; //total area
277 
278  total = 0;
279  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
280  outline = it.data ();
281  total += outline->count_transitions (threshold);
282  }
283  return total;
284 }
285 
286 
287 /**********************************************************************
288  * C_BLOB::move
289  *
290  * Move C_BLOB by vector
291  **********************************************************************/
292 
293 void C_BLOB::move( // reposition blob
294  const ICOORD vec // by vector
295  ) {
296  C_OUTLINE_IT it(&outlines); // iterator
297 
298  for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
299  it.data ()->move (vec); // move each outline
300 }
301 
302 // Static helper for C_BLOB::rotate to allow recursion of child outlines.
303 void RotateOutlineList(const FCOORD& rotation, C_OUTLINE_LIST* outlines) {
304  C_OUTLINE_LIST new_outlines;
305  C_OUTLINE_IT src_it(outlines);
306  C_OUTLINE_IT dest_it(&new_outlines);
307  while (!src_it.empty()) {
308  C_OUTLINE* old_outline = src_it.extract();
309  src_it.forward();
310  C_OUTLINE* new_outline = new C_OUTLINE(old_outline, rotation);
311  if (!old_outline->child()->empty()) {
312  RotateOutlineList(rotation, old_outline->child());
313  C_OUTLINE_IT child_it(new_outline->child());
314  child_it.add_list_after(old_outline->child());
315  }
316  delete old_outline;
317  dest_it.add_to_end(new_outline);
318  }
319  src_it.add_list_after(&new_outlines);
320 }
321 
322 /**********************************************************************
323  * C_BLOB::rotate
324  *
325  * Rotate C_BLOB by rotation.
326  * Warning! has to rebuild all the C_OUTLINEs.
327  **********************************************************************/
328 void C_BLOB::rotate(const FCOORD& rotation) {
329  RotateOutlineList(rotation, &outlines);
330 }
331 
332 static void render_outline_list(C_OUTLINE_LIST *list,
333  int left, int top, Pix* pix) {
334  C_OUTLINE_IT it(list);
335  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
336  C_OUTLINE* outline = it.data();
337  outline->render(left, top, pix);
338  if (!outline->child()->empty())
339  render_outline_list(outline->child(), left, top, pix);
340  }
341 }
342 
343 static void render_outline_list_outline(C_OUTLINE_LIST *list,
344  int left, int top, Pix* pix) {
345  C_OUTLINE_IT it(list);
346  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
347  C_OUTLINE* outline = it.data();
348  outline->render_outline(left, top, pix);
349  }
350 }
351 
352 // Returns a Pix rendering of the blob. pixDestroy after use.
354  TBOX box = bounding_box();
355  Pix* pix = pixCreate(box.width(), box.height(), 1);
356  render_outline_list(&outlines, box.left(), box.top(), pix);
357  return pix;
358 }
359 
360 // Returns a Pix rendering of the outline of the blob. (no fill).
361 // pixDestroy after use.
363  TBOX box = bounding_box();
364  Pix* pix = pixCreate(box.width(), box.height(), 1);
365  render_outline_list_outline(&outlines, box.left(), box.top(), pix);
366  return pix;
367 }
368 
369 /**********************************************************************
370  * C_BLOB::plot
371  *
372  * Draw the C_BLOB in the given colour.
373  **********************************************************************/
374 
375 #ifndef GRAPHICS_DISABLED
376 void C_BLOB::plot( //draw it
377  ScrollView* window, //window to draw in
378  ScrollView::Color blob_colour, //main colour
379  ScrollView::Color child_colour //for holes
380  ) {
381  plot_outline_list(&outlines, window, blob_colour, child_colour);
382 }
383 #endif