Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: stepblob.cpp (Formerly cblob.c) 00003 * Description: Code for C_BLOB class. 00004 * Author: Ray Smith 00005 * Created: Tue Oct 08 10:41:13 BST 1991 00006 * 00007 * (C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #include "mfcpch.h" 00021 #include "stepblob.h" 00022 #include "allheaders.h" 00023 00024 // Include automatically generated configuration file if running autoconf. 00025 #ifdef HAVE_CONFIG_H 00026 #include "config_auto.h" 00027 #endif 00028 00029 ELISTIZE (C_BLOB) 00030 /********************************************************************** 00031 * position_outline 00032 * 00033 * Position the outline in the given list at the relevant place 00034 * according to its nesting. 00035 **********************************************************************/ 00036 static void position_outline( //put in place 00037 C_OUTLINE *outline, //thing to place 00038 C_OUTLINE_LIST *destlist //desstination list 00039 ) { 00040 C_OUTLINE *dest_outline; //outline from dest list 00041 C_OUTLINE_IT it = destlist; //iterator 00042 //iterator on children 00043 C_OUTLINE_IT child_it = outline->child (); 00044 00045 if (!it.empty ()) { 00046 do { 00047 dest_outline = it.data (); //get destination 00048 //encloses dest 00049 if (*dest_outline < *outline) { 00050 //take off list 00051 dest_outline = it.extract (); 00052 //put this in place 00053 it.add_after_then_move (outline); 00054 //make it a child 00055 child_it.add_to_end (dest_outline); 00056 while (!it.at_last ()) { 00057 it.forward (); //do rest of list 00058 //check for other children 00059 dest_outline = it.data (); 00060 if (*dest_outline < *outline) { 00061 //take off list 00062 dest_outline = it.extract (); 00063 child_it.add_to_end (dest_outline); 00064 //make it a child 00065 if (it.empty ()) 00066 break; 00067 } 00068 } 00069 return; //finished 00070 } 00071 //enclosed by dest 00072 else if (*outline < *dest_outline) { 00073 position_outline (outline, dest_outline->child ()); 00074 //place in child list 00075 return; //finished 00076 } 00077 it.forward (); 00078 } 00079 while (!it.at_first ()); 00080 } 00081 it.add_to_end (outline); //at outer level 00082 } 00083 00084 00085 /********************************************************************** 00086 * plot_outline_list 00087 * 00088 * Draw a list of outlines in the given colour and their children 00089 * in the child colour. 00090 **********************************************************************/ 00091 00092 #ifndef GRAPHICS_DISABLED 00093 static void plot_outline_list( //draw outlines 00094 C_OUTLINE_LIST *list, //outline to draw 00095 ScrollView* window, //window to draw in 00096 ScrollView::Color colour, //colour to use 00097 ScrollView::Color child_colour //colour of children 00098 ) { 00099 C_OUTLINE *outline; //current outline 00100 C_OUTLINE_IT it = list; //iterator 00101 00102 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00103 outline = it.data (); 00104 //draw it 00105 outline->plot (window, colour); 00106 if (!outline->child ()->empty ()) 00107 plot_outline_list (outline->child (), window, 00108 child_colour, child_colour); 00109 } 00110 } 00111 #endif 00112 00113 00114 /********************************************************************** 00115 * reverse_outline_list 00116 * 00117 * Reverse a list of outlines and their children. 00118 **********************************************************************/ 00119 00120 static void reverse_outline_list( //reverse outlines 00121 C_OUTLINE_LIST *list //outline to reverse 00122 ) { 00123 C_OUTLINE *outline; //current outline 00124 C_OUTLINE_IT it = list; //iterator 00125 00126 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00127 outline = it.data (); 00128 outline->reverse (); //reverse it 00129 if (!outline->child ()->empty ()) 00130 reverse_outline_list (outline->child ()); 00131 } 00132 } 00133 00134 00135 /********************************************************************** 00136 * C_BLOB::C_BLOB 00137 * 00138 * Constructor to build a C_BLOB from a list of C_OUTLINEs. 00139 * The C_OUTLINEs are not copied so the source list is emptied. 00140 * The C_OUTLINEs are nested correctly in the blob. 00141 **********************************************************************/ 00142 00143 C_BLOB::C_BLOB( //constructor 00144 C_OUTLINE_LIST *outline_list //in random order 00145 ) { 00146 C_OUTLINE *outline; //current outline 00147 C_OUTLINE_IT it = outline_list;//iterator 00148 00149 while (!it.empty ()) { //grab the list 00150 outline = it.extract (); //get off the list 00151 //put it in place 00152 position_outline(outline, &outlines); 00153 if (!it.empty ()) 00154 it.forward (); 00155 } 00156 it.set_to_list (&outlines); 00157 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00158 outline = it.data (); 00159 if (outline->turn_direction () < 0) { 00160 outline->reverse (); 00161 reverse_outline_list (outline->child ()); 00162 outline->set_flag (COUT_INVERSE, TRUE); 00163 } 00164 else { 00165 outline->set_flag (COUT_INVERSE, FALSE); 00166 } 00167 } 00168 } 00169 00170 // Simpler constructor to build a blob from a single outline that has 00171 // already been fully initialized. 00172 C_BLOB::C_BLOB(C_OUTLINE* outline) { 00173 C_OUTLINE_IT it(&outlines); 00174 it.add_to_end(outline); 00175 } 00176 00177 00178 // Build and return a fake blob containing a single fake outline with no 00179 // steps. 00180 C_BLOB* C_BLOB::FakeBlob(const TBOX& box) { 00181 C_OUTLINE_LIST outlines; 00182 C_OUTLINE::FakeOutline(box, &outlines); 00183 return new C_BLOB(&outlines); 00184 } 00185 00186 /********************************************************************** 00187 * C_BLOB::bounding_box 00188 * 00189 * Return the bounding box of the blob. 00190 **********************************************************************/ 00191 00192 TBOX C_BLOB::bounding_box() { //bounding box 00193 C_OUTLINE *outline; //current outline 00194 C_OUTLINE_IT it = &outlines; //outlines of blob 00195 TBOX box; //bounding box 00196 00197 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00198 outline = it.data (); 00199 box += outline->bounding_box (); 00200 } 00201 return box; 00202 } 00203 00204 00205 /********************************************************************** 00206 * C_BLOB::area 00207 * 00208 * Return the area of the blob. 00209 **********************************************************************/ 00210 00211 inT32 C_BLOB::area() { //area 00212 C_OUTLINE *outline; //current outline 00213 C_OUTLINE_IT it = &outlines; //outlines of blob 00214 inT32 total; //total area 00215 00216 total = 0; 00217 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00218 outline = it.data (); 00219 total += outline->area (); 00220 } 00221 return total; 00222 } 00223 00224 /********************************************************************** 00225 * C_BLOB::perimeter 00226 * 00227 * Return the perimeter of the top and 2nd level outlines. 00228 **********************************************************************/ 00229 00230 inT32 C_BLOB::perimeter() { 00231 C_OUTLINE *outline; // current outline 00232 C_OUTLINE_IT it = &outlines; // outlines of blob 00233 inT32 total; // total perimeter 00234 00235 total = 0; 00236 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { 00237 outline = it.data(); 00238 total += outline->perimeter(); 00239 } 00240 return total; 00241 } 00242 00243 00244 /********************************************************************** 00245 * C_BLOB::outer_area 00246 * 00247 * Return the area of the blob. 00248 **********************************************************************/ 00249 00250 inT32 C_BLOB::outer_area() { //area 00251 C_OUTLINE *outline; //current outline 00252 C_OUTLINE_IT it = &outlines; //outlines of blob 00253 inT32 total; //total area 00254 00255 total = 0; 00256 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00257 outline = it.data (); 00258 total += outline->outer_area (); 00259 } 00260 return total; 00261 } 00262 00263 00264 /********************************************************************** 00265 * C_BLOB::count_transitions 00266 * 00267 * Return the total x and y maxes and mins in the blob. 00268 * Chlid outlines are not counted. 00269 **********************************************************************/ 00270 00271 inT32 C_BLOB::count_transitions( //area 00272 inT32 threshold //on size 00273 ) { 00274 C_OUTLINE *outline; //current outline 00275 C_OUTLINE_IT it = &outlines; //outlines of blob 00276 inT32 total; //total area 00277 00278 total = 0; 00279 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) { 00280 outline = it.data (); 00281 total += outline->count_transitions (threshold); 00282 } 00283 return total; 00284 } 00285 00286 00287 /********************************************************************** 00288 * C_BLOB::move 00289 * 00290 * Move C_BLOB by vector 00291 **********************************************************************/ 00292 00293 void C_BLOB::move( // reposition blob 00294 const ICOORD vec // by vector 00295 ) { 00296 C_OUTLINE_IT it(&outlines); // iterator 00297 00298 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) 00299 it.data ()->move (vec); // move each outline 00300 } 00301 00302 // Static helper for C_BLOB::rotate to allow recursion of child outlines. 00303 void RotateOutlineList(const FCOORD& rotation, C_OUTLINE_LIST* outlines) { 00304 C_OUTLINE_LIST new_outlines; 00305 C_OUTLINE_IT src_it(outlines); 00306 C_OUTLINE_IT dest_it(&new_outlines); 00307 while (!src_it.empty()) { 00308 C_OUTLINE* old_outline = src_it.extract(); 00309 src_it.forward(); 00310 C_OUTLINE* new_outline = new C_OUTLINE(old_outline, rotation); 00311 if (!old_outline->child()->empty()) { 00312 RotateOutlineList(rotation, old_outline->child()); 00313 C_OUTLINE_IT child_it(new_outline->child()); 00314 child_it.add_list_after(old_outline->child()); 00315 } 00316 delete old_outline; 00317 dest_it.add_to_end(new_outline); 00318 } 00319 src_it.add_list_after(&new_outlines); 00320 } 00321 00322 /********************************************************************** 00323 * C_BLOB::rotate 00324 * 00325 * Rotate C_BLOB by rotation. 00326 * Warning! has to rebuild all the C_OUTLINEs. 00327 **********************************************************************/ 00328 void C_BLOB::rotate(const FCOORD& rotation) { 00329 RotateOutlineList(rotation, &outlines); 00330 } 00331 00332 static void render_outline_list(C_OUTLINE_LIST *list, 00333 int left, int top, Pix* pix) { 00334 C_OUTLINE_IT it(list); 00335 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { 00336 C_OUTLINE* outline = it.data(); 00337 outline->render(left, top, pix); 00338 if (!outline->child()->empty()) 00339 render_outline_list(outline->child(), left, top, pix); 00340 } 00341 } 00342 00343 static void render_outline_list_outline(C_OUTLINE_LIST *list, 00344 int left, int top, Pix* pix) { 00345 C_OUTLINE_IT it(list); 00346 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { 00347 C_OUTLINE* outline = it.data(); 00348 outline->render_outline(left, top, pix); 00349 } 00350 } 00351 00352 // Returns a Pix rendering of the blob. pixDestroy after use. 00353 Pix* C_BLOB::render() { 00354 TBOX box = bounding_box(); 00355 Pix* pix = pixCreate(box.width(), box.height(), 1); 00356 render_outline_list(&outlines, box.left(), box.top(), pix); 00357 return pix; 00358 } 00359 00360 // Returns a Pix rendering of the outline of the blob. (no fill). 00361 // pixDestroy after use. 00362 Pix* C_BLOB::render_outline() { 00363 TBOX box = bounding_box(); 00364 Pix* pix = pixCreate(box.width(), box.height(), 1); 00365 render_outline_list_outline(&outlines, box.left(), box.top(), pix); 00366 return pix; 00367 } 00368 00369 /********************************************************************** 00370 * C_BLOB::plot 00371 * 00372 * Draw the C_BLOB in the given colour. 00373 **********************************************************************/ 00374 00375 #ifndef GRAPHICS_DISABLED 00376 void C_BLOB::plot( //draw it 00377 ScrollView* window, //window to draw in 00378 ScrollView::Color blob_colour, //main colour 00379 ScrollView::Color child_colour //for holes 00380 ) { 00381 plot_outline_list(&outlines, window, blob_colour, child_colour); 00382 } 00383 #endif