tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/ccstruct/polyblk.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines