Tesseract  3.02
tesseract-ocr/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 "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 }