tesseract
3.03
|
00001 /********************************************************************** 00002 * File: polyblk.c (Formerly poly_block.c) 00003 * Description: Polygonal blocks 00004 * Author: Sheelagh Lloyd? 00005 * Created: 00006 * 00007 * (C) Copyright 1993, 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 <ctype.h> 00021 #include <math.h> 00022 #include <stdio.h> 00023 #include "elst.h" 00024 #include "polyblk.h" 00025 00026 // Include automatically generated configuration file if running autoconf. 00027 #ifdef HAVE_CONFIG_H 00028 #include "config_auto.h" 00029 #endif 00030 00031 #define PBLOCK_LABEL_SIZE 150 00032 #define INTERSECTING MAX_INT16 00033 00034 int lessthan(const void *first, const void *second); 00035 00036 POLY_BLOCK::POLY_BLOCK(ICOORDELT_LIST *points, PolyBlockType t) { 00037 ICOORDELT_IT v = &vertices; 00038 00039 vertices.clear(); 00040 v.move_to_first(); 00041 v.add_list_before(points); 00042 compute_bb(); 00043 type = t; 00044 } 00045 00046 // Initialize from box coordinates. 00047 POLY_BLOCK::POLY_BLOCK(const TBOX& box, PolyBlockType t) { 00048 vertices.clear(); 00049 ICOORDELT_IT v = &vertices; 00050 v.move_to_first(); 00051 v.add_to_end(new ICOORDELT(box.left(), box.top())); 00052 v.add_to_end(new ICOORDELT(box.left(), box.bottom())); 00053 v.add_to_end(new ICOORDELT(box.right(), box.bottom())); 00054 v.add_to_end(new ICOORDELT(box.right(), box.top())); 00055 compute_bb(); 00056 type = t; 00057 } 00058 00065 void POLY_BLOCK::compute_bb() { //constructor 00066 ICOORD ibl, itr; //integer bb 00067 ICOORD botleft; //bounding box 00068 ICOORD topright; 00069 ICOORD pos; //current pos; 00070 ICOORDELT_IT pts = &vertices; //iterator 00071 00072 botleft = *pts.data (); 00073 topright = botleft; 00074 do { 00075 pos = *pts.data (); 00076 if (pos.x () < botleft.x ()) 00077 //get bounding box 00078 botleft = ICOORD (pos.x (), botleft.y ()); 00079 if (pos.y () < botleft.y ()) 00080 botleft = ICOORD (botleft.x (), pos.y ()); 00081 if (pos.x () > topright.x ()) 00082 topright = ICOORD (pos.x (), topright.y ()); 00083 if (pos.y () > topright.y ()) 00084 topright = ICOORD (topright.x (), pos.y ()); 00085 pts.forward (); 00086 } 00087 while (!pts.at_first ()); 00088 ibl = ICOORD (botleft.x (), botleft.y ()); 00089 itr = ICOORD (topright.x (), topright.y ()); 00090 box = TBOX (ibl, itr); 00091 } 00092 00093 00101 inT16 POLY_BLOCK::winding_number(const ICOORD &point) { 00102 inT16 count; //winding count 00103 ICOORD pt; //current point 00104 ICOORD vec; //point to current point 00105 ICOORD vvec; //current point to next point 00106 inT32 cross; //cross product 00107 ICOORDELT_IT it = &vertices; //iterator 00108 00109 count = 0; 00110 do { 00111 pt = *it.data (); 00112 vec = pt - point; 00113 vvec = *it.data_relative (1) - pt; 00114 //crossing the line 00115 if (vec.y () <= 0 && vec.y () + vvec.y () > 0) { 00116 cross = vec * vvec; //cross product 00117 if (cross > 0) 00118 count++; //crossing right half 00119 else if (cross == 0) 00120 return INTERSECTING; //going through point 00121 } 00122 else if (vec.y () > 0 && vec.y () + vvec.y () <= 0) { 00123 cross = vec * vvec; 00124 if (cross < 0) 00125 count--; //crossing back 00126 else if (cross == 0) 00127 return INTERSECTING; //illegal 00128 } 00129 else if (vec.y () == 0 && vec.x () == 0) 00130 return INTERSECTING; 00131 it.forward (); 00132 } 00133 while (!it.at_first ()); 00134 return count; //winding number 00135 } 00136 00137 00139 bool POLY_BLOCK::contains(POLY_BLOCK *other) { 00140 inT16 count; // winding count 00141 ICOORDELT_IT it = &vertices; // iterator 00142 ICOORD vertex; 00143 00144 if (!box.overlap (*(other->bounding_box ()))) 00145 return false; // can't be contained 00146 00147 /* check that no vertex of this is inside other */ 00148 00149 do { 00150 vertex = *it.data (); 00151 // get winding number 00152 count = other->winding_number (vertex); 00153 if (count != INTERSECTING) 00154 if (count != 0) 00155 return false; 00156 it.forward (); 00157 } 00158 while (!it.at_first ()); 00159 00160 /* check that all vertices of other are inside this */ 00161 00162 //switch lists 00163 it.set_to_list (other->points ()); 00164 do { 00165 vertex = *it.data (); 00166 //try other way round 00167 count = winding_number (vertex); 00168 if (count != INTERSECTING) 00169 if (count == 0) 00170 return false; 00171 it.forward (); 00172 } 00173 while (!it.at_first ()); 00174 return true; 00175 } 00176 00177 00185 void POLY_BLOCK::rotate(FCOORD rotation) { 00186 FCOORD pos; //current pos; 00187 ICOORDELT *pt; //current point 00188 ICOORDELT_IT pts = &vertices; //iterator 00189 00190 do { 00191 pt = pts.data (); 00192 pos.set_x (pt->x ()); 00193 pos.set_y (pt->y ()); 00194 pos.rotate (rotation); 00195 pt->set_x ((inT16) (floor (pos.x () + 0.5))); 00196 pt->set_y ((inT16) (floor (pos.y () + 0.5))); 00197 pts.forward (); 00198 } 00199 while (!pts.at_first ()); 00200 compute_bb(); 00201 } 00202 00209 void POLY_BLOCK::reflect_in_y_axis() { 00210 ICOORDELT *pt; // current point 00211 ICOORDELT_IT pts = &vertices; // Iterator. 00212 00213 do { 00214 pt = pts.data(); 00215 pt->set_x(-pt->x()); 00216 pts.forward(); 00217 } 00218 while (!pts.at_first()); 00219 compute_bb(); 00220 } 00221 00222 00230 void POLY_BLOCK::move(ICOORD shift) { 00231 ICOORDELT *pt; //current point 00232 ICOORDELT_IT pts = &vertices; //iterator 00233 00234 do { 00235 pt = pts.data (); 00236 *pt += shift; 00237 pts.forward (); 00238 } 00239 while (!pts.at_first ()); 00240 compute_bb(); 00241 } 00242 00243 00244 #ifndef GRAPHICS_DISABLED 00245 void POLY_BLOCK::plot(ScrollView* window, inT32 num) { 00246 ICOORDELT_IT v = &vertices; 00247 00248 window->Pen(ColorForPolyBlockType(type)); 00249 00250 v.move_to_first (); 00251 00252 if (num > 0) { 00253 window->TextAttributes("Times", 80, false, false, false); 00254 char temp_buff[34]; 00255 #if defined(__UNIX__) || defined(MINGW) 00256 sprintf(temp_buff, INT32FORMAT, num); 00257 #else 00258 ltoa (num, temp_buff, 10); 00259 #endif 00260 window->Text(v.data ()->x (), v.data ()->y (), temp_buff); 00261 } 00262 00263 window->SetCursor(v.data ()->x (), v.data ()->y ()); 00264 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) { 00265 window->DrawTo(v.data ()->x (), v.data ()->y ()); 00266 } 00267 v.move_to_first (); 00268 window->DrawTo(v.data ()->x (), v.data ()->y ()); 00269 } 00270 00271 00272 void POLY_BLOCK::fill(ScrollView* window, ScrollView::Color colour) { 00273 inT16 y; 00274 inT16 width; 00275 PB_LINE_IT *lines; 00276 ICOORDELT_LIST *segments; 00277 ICOORDELT_IT s_it; 00278 00279 lines = new PB_LINE_IT (this); 00280 window->Pen(colour); 00281 00282 for (y = this->bounding_box ()->bottom (); 00283 y <= this->bounding_box ()->top (); y++) { 00284 segments = lines->get_line (y); 00285 if (!segments->empty ()) { 00286 s_it.set_to_list (segments); 00287 for (s_it.mark_cycle_pt (); !s_it.cycled_list (); s_it.forward ()) { 00288 // Note different use of ICOORDELT, x coord is x coord of pixel 00289 // at the start of line segment, y coord is length of line segment 00290 // Last pixel is start pixel + length. 00291 width = s_it.data ()->y (); 00292 window->SetCursor(s_it.data ()->x (), y); 00293 window->DrawTo(s_it.data ()->x () + (float) width, y); 00294 } 00295 } 00296 } 00297 } 00298 #endif 00299 00300 00302 bool POLY_BLOCK::overlap(POLY_BLOCK *other) { 00303 inT16 count; // winding count 00304 ICOORDELT_IT it = &vertices; // iterator 00305 ICOORD vertex; 00306 00307 if (!box.overlap(*(other->bounding_box()))) 00308 return false; // can't be any overlap. 00309 00310 /* see if a vertex of this is inside other */ 00311 00312 do { 00313 vertex = *it.data (); 00314 // get winding number 00315 count = other->winding_number (vertex); 00316 if (count != INTERSECTING) 00317 if (count != 0) 00318 return true; 00319 it.forward (); 00320 } 00321 while (!it.at_first ()); 00322 00323 /* see if a vertex of other is inside this */ 00324 00325 // switch lists 00326 it.set_to_list (other->points ()); 00327 do { 00328 vertex = *it.data(); 00329 // try other way round 00330 count = winding_number (vertex); 00331 if (count != INTERSECTING) 00332 if (count != 0) 00333 return true; 00334 it.forward (); 00335 } 00336 while (!it.at_first ()); 00337 return false; 00338 } 00339 00340 00341 ICOORDELT_LIST *PB_LINE_IT::get_line(inT16 y) { 00342 ICOORDELT_IT v, r; 00343 ICOORDELT_LIST *result; 00344 ICOORDELT *x, *current, *previous; 00345 float fy, fx; 00346 00347 fy = (float) (y + 0.5); 00348 result = new ICOORDELT_LIST (); 00349 r.set_to_list (result); 00350 v.set_to_list (block->points ()); 00351 00352 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) { 00353 if (((v.data_relative (-1)->y () > y) && (v.data ()->y () <= y)) 00354 || ((v.data_relative (-1)->y () <= y) && (v.data ()->y () > y))) { 00355 previous = v.data_relative (-1); 00356 current = v.data (); 00357 fx = (float) (0.5 + previous->x () + 00358 (current->x () - previous->x ()) * (fy - 00359 previous->y ()) / 00360 (current->y () - previous->y ())); 00361 x = new ICOORDELT ((inT16) fx, 0); 00362 r.add_to_end (x); 00363 } 00364 } 00365 00366 if (!r.empty ()) { 00367 r.sort (lessthan); 00368 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) 00369 x = r.data (); 00370 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) { 00371 r.data ()->set_y (r.data_relative (1)->x () - r.data ()->x ()); 00372 r.forward (); 00373 delete (r.extract ()); 00374 } 00375 } 00376 00377 return result; 00378 } 00379 00380 00381 int lessthan(const void *first, const void *second) { 00382 ICOORDELT *p1 = (*(ICOORDELT **) first); 00383 ICOORDELT *p2 = (*(ICOORDELT **) second); 00384 00385 if (p1->x () < p2->x ()) 00386 return (-1); 00387 else if (p1->x () > p2->x ()) 00388 return (1); 00389 else 00390 return (0); 00391 } 00392 00393 #ifndef GRAPHICS_DISABLED 00394 00395 ScrollView::Color POLY_BLOCK::ColorForPolyBlockType(PolyBlockType type) { 00396 // Keep kPBColors in sync with PolyBlockType. 00397 const ScrollView::Color kPBColors[PT_COUNT] = { 00398 ScrollView::WHITE, // Type is not yet known. Keep as the 1st element. 00399 ScrollView::BLUE, // Text that lives inside a column. 00400 ScrollView::CYAN, // Text that spans more than one column. 00401 ScrollView::MEDIUM_BLUE, // Text that is in a cross-column pull-out region. 00402 ScrollView::AQUAMARINE, // Partition belonging to an equation region. 00403 ScrollView::SKY_BLUE, // Partition belonging to an inline equation region. 00404 ScrollView::MAGENTA, // Partition belonging to a table region. 00405 ScrollView::GREEN, // Text-line runs vertically. 00406 ScrollView::LIGHT_BLUE, // Text that belongs to an image. 00407 ScrollView::RED, // Image that lives inside a column. 00408 ScrollView::YELLOW, // Image that spans more than one column. 00409 ScrollView::ORANGE, // Image in a cross-column pull-out region. 00410 ScrollView::BROWN, // Horizontal Line. 00411 ScrollView::DARK_GREEN, // Vertical Line. 00412 ScrollView::GREY // Lies outside of any column. 00413 }; 00414 if (type >= 0 && type < PT_COUNT) { 00415 return kPBColors[type]; 00416 } 00417 return ScrollView::WHITE; 00418 } 00419 #endif // GRAPHICS_DISABLED