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