tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/classify/intproto.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  ** Filename:    intproto.c
00003  ** Purpose:     Definition of data structures for integer protos.
00004  ** Author:      Dan Johnson
00005  ** History:     Thu Feb  7 14:38:16 1991, DSJ, Created.
00006  **
00007  ** (c) Copyright Hewlett-Packard Company, 1988.
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           Include Files and Type Defines
00020 -----------------------------------------------------------------------------*/
00021 
00022 #include <math.h>
00023 #include <stdio.h>
00024 #include <assert.h>
00025 #ifdef __UNIX__
00026 #include <unistd.h>
00027 #endif
00028 
00029 #include "classify.h"
00030 #include "const.h"
00031 #include "emalloc.h"
00032 #include "fontinfo.h"
00033 #include "genericvector.h"
00034 #include "globals.h"
00035 #include "helpers.h"
00036 #include "intproto.h"
00037 #include "mfoutline.h"
00038 #include "ndminx.h"
00039 #include "picofeat.h"
00040 #include "points.h"
00041 #include "shapetable.h"
00042 #include "svmnode.h"
00043 
00044 // Include automatically generated configuration file if running autoconf.
00045 #ifdef HAVE_CONFIG_H
00046 #include "config_auto.h"
00047 #endif
00048 
00049 using tesseract::FontInfo;
00050 using tesseract::FontSet;
00051 using tesseract::FontSpacingInfo;
00052 
00053 /* match debug display constants*/
00054 #define PROTO_PRUNER_SCALE  (4.0)
00055 
00056 #define INT_DESCENDER (0.0  * INT_CHAR_NORM_RANGE)
00057 #define INT_BASELINE  (0.25 * INT_CHAR_NORM_RANGE)
00058 #define INT_XHEIGHT (0.75 * INT_CHAR_NORM_RANGE)
00059 #define INT_CAPHEIGHT (1.0  * INT_CHAR_NORM_RANGE)
00060 
00061 #define INT_XCENTER (0.5  * INT_CHAR_NORM_RANGE)
00062 #define INT_YCENTER (0.5  * INT_CHAR_NORM_RANGE)
00063 #define INT_XRADIUS (0.2  * INT_CHAR_NORM_RANGE)
00064 #define INT_YRADIUS (0.2  * INT_CHAR_NORM_RANGE)
00065 #define INT_MIN_X 0
00066 #define INT_MIN_Y 0
00067 #define INT_MAX_X INT_CHAR_NORM_RANGE
00068 #define INT_MAX_Y INT_CHAR_NORM_RANGE
00069 
00071 #define HV_TOLERANCE  (0.0025)   /* approx 0.9 degrees */
00072 
00073 typedef enum
00074 { StartSwitch, EndSwitch, LastSwitch }
00075 SWITCH_TYPE;
00076 #define MAX_NUM_SWITCHES  3
00077 
00078 typedef struct
00079 {
00080   SWITCH_TYPE Type;
00081   inT8 X, Y;
00082   inT16 YInit;
00083   inT16 Delta;
00084 }
00085 
00086 
00087 FILL_SWITCH;
00088 
00089 typedef struct
00090 {
00091   uinT8 NextSwitch;
00092   uinT8 AngleStart, AngleEnd;
00093   inT8 X;
00094   inT16 YStart, YEnd;
00095   inT16 StartDelta, EndDelta;
00096   FILL_SWITCH Switch[MAX_NUM_SWITCHES];
00097 }
00098 
00099 
00100 TABLE_FILLER;
00101 
00102 typedef struct
00103 {
00104   inT8 X;
00105   inT8 YStart, YEnd;
00106   uinT8 AngleStart, AngleEnd;
00107 }
00108 
00109 
00110 FILL_SPEC;
00111 
00112 
00113 /* constants for conversion from old inttemp format */
00114 #define OLD_MAX_NUM_CONFIGS      32
00115 #define OLD_WERDS_PER_CONFIG_VEC ((OLD_MAX_NUM_CONFIGS + BITS_PER_WERD - 1) /\
00116                                   BITS_PER_WERD)
00117 
00118 /*-----------------------------------------------------------------------------
00119             Macros
00120 -----------------------------------------------------------------------------*/
00122 #define CircularIncrement(i,r)  (((i) < (r) - 1)?((i)++):((i) = 0))
00123 
00125 #define MapParam(P,O,N)   (floor (((P) + (O)) * (N)))
00126 
00127 /*---------------------------------------------------------------------------
00128             Private Function Prototypes
00129 ----------------------------------------------------------------------------*/
00130 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets);
00131 
00132 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets);
00133 
00134 void DoFill(FILL_SPEC *FillSpec,
00135             CLASS_PRUNER_STRUCT* Pruner,
00136             register uinT32 ClassMask,
00137             register uinT32 ClassCount,
00138             register uinT32 WordIndex);
00139 
00140 BOOL8 FillerDone(TABLE_FILLER *Filler);
00141 
00142 void FillPPCircularBits(uinT32
00143                         ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
00144                         int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug);
00145 
00146 void FillPPLinearBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
00147                       int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug);
00148 
00149 void GetCPPadsForLevel(int Level,
00150                        FLOAT32 *EndPad,
00151                        FLOAT32 *SidePad,
00152                        FLOAT32 *AnglePad);
00153 
00154 ScrollView::Color GetMatchColorFor(FLOAT32 Evidence);
00155 
00156 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill);
00157 
00158 void InitTableFiller(FLOAT32 EndPad,
00159                      FLOAT32 SidePad,
00160                      FLOAT32 AnglePad,
00161                      PROTO Proto,
00162                      TABLE_FILLER *Filler);
00163 
00164 #ifndef GRAPHICS_DISABLED
00165 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT* Feature,
00166                       ScrollView::Color color);
00167 
00168 void RenderIntProto(ScrollView *window,
00169                     INT_CLASS Class,
00170                     PROTO_ID ProtoId,
00171                     ScrollView::Color color);
00172 #endif  // GRAPHICS_DISABLED
00173 
00174 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id);
00175 
00176 /*-----------------------------------------------------------------------------
00177         Global Data Definitions and Declarations
00178 -----------------------------------------------------------------------------*/
00179 
00180 /* global display lists used to display proto and feature match information*/
00181 ScrollView *IntMatchWindow = NULL;
00182 ScrollView *FeatureDisplayWindow = NULL;
00183 ScrollView *ProtoDisplayWindow = NULL;
00184 
00185 /*-----------------------------------------------------------------------------
00186         Variables
00187 -----------------------------------------------------------------------------*/
00188 
00189 /* control knobs */
00190 INT_VAR(classify_num_cp_levels, 3, "Number of Class Pruner Levels");
00191 double_VAR(classify_cp_angle_pad_loose, 45.0,
00192            "Class Pruner Angle Pad Loose");
00193 double_VAR(classify_cp_angle_pad_medium, 20.0,
00194            "Class Pruner Angle Pad Medium");
00195 double_VAR(classify_cp_angle_pad_tight, 10.0,
00196            "CLass Pruner Angle Pad Tight");
00197 double_VAR(classify_cp_end_pad_loose, 0.5, "Class Pruner End Pad Loose");
00198 double_VAR(classify_cp_end_pad_medium, 0.5, "Class Pruner End Pad Medium");
00199 double_VAR(classify_cp_end_pad_tight, 0.5, "Class Pruner End Pad Tight");
00200 double_VAR(classify_cp_side_pad_loose, 2.5, "Class Pruner Side Pad Loose");
00201 double_VAR(classify_cp_side_pad_medium, 1.2, "Class Pruner Side Pad Medium");
00202 double_VAR(classify_cp_side_pad_tight, 0.6, "Class Pruner Side Pad Tight");
00203 double_VAR(classify_pp_angle_pad, 45.0, "Proto Pruner Angle Pad");
00204 double_VAR(classify_pp_end_pad, 0.5, "Proto Prune End Pad");
00205 double_VAR(classify_pp_side_pad, 2.5, "Proto Pruner Side Pad");
00206 
00207 /*-----------------------------------------------------------------------------
00208               Public Code
00209 -----------------------------------------------------------------------------*/
00210 // Builds a feature from an FCOORD for position with all the necessary
00211 // clipping and rounding.
00212 INT_FEATURE_STRUCT::INT_FEATURE_STRUCT(const FCOORD& pos, uinT8 theta)
00213   : X(ClipToRange<inT16>(static_cast<inT16>(pos.x() + 0.5), 0, 255)),
00214     Y(ClipToRange<inT16>(static_cast<inT16>(pos.y() + 0.5), 0, 255)),
00215     Theta(theta),
00216     CP_misses(0) {
00217 }
00218 // Builds a feature from ints with all the necessary clipping and casting.
00219 INT_FEATURE_STRUCT::INT_FEATURE_STRUCT(int x, int y, int theta)
00220   : X(static_cast<uinT8>(ClipToRange(x, 0, MAX_UINT8))),
00221     Y(static_cast<uinT8>(ClipToRange(y, 0, MAX_UINT8))),
00222     Theta(static_cast<uinT8>(ClipToRange(theta, 0, MAX_UINT8))),
00223     CP_misses(0) {
00224 }
00225 
00226 /*---------------------------------------------------------------------------*/
00241 void AddIntClass(INT_TEMPLATES Templates, CLASS_ID ClassId, INT_CLASS Class) {
00242   int Pruner;
00243 
00244   assert (LegalClassId (ClassId));
00245   if (ClassId != Templates->NumClasses) {
00246     fprintf(stderr, "Please make sure that classes are added to templates");
00247     fprintf(stderr, " in increasing order of ClassIds\n");
00248     exit(1);
00249   }
00250   ClassForClassId (Templates, ClassId) = Class;
00251   Templates->NumClasses++;
00252 
00253   if (Templates->NumClasses > MaxNumClassesIn (Templates)) {
00254     Pruner = Templates->NumClassPruners++;
00255     Templates->ClassPruners[Pruner] = new CLASS_PRUNER_STRUCT;
00256     memset(Templates->ClassPruners[Pruner], 0, sizeof(CLASS_PRUNER_STRUCT));
00257   }
00258 }                                /* AddIntClass */
00259 
00260 
00261 /*---------------------------------------------------------------------------*/
00274 int AddIntConfig(INT_CLASS Class) {
00275   int Index;
00276 
00277   assert(Class->NumConfigs < MAX_NUM_CONFIGS);
00278 
00279   Index = Class->NumConfigs++;
00280   Class->ConfigLengths[Index] = 0;
00281   return Index;
00282 }                                /* AddIntConfig */
00283 
00284 
00285 /*---------------------------------------------------------------------------*/
00298 int AddIntProto(INT_CLASS Class) {
00299   int Index;
00300   int ProtoSetId;
00301   PROTO_SET ProtoSet;
00302   INT_PROTO Proto;
00303   register uinT32 *Word;
00304 
00305   if (Class->NumProtos >= MAX_NUM_PROTOS)
00306     return (NO_PROTO);
00307 
00308   Index = Class->NumProtos++;
00309 
00310   if (Class->NumProtos > MaxNumIntProtosIn(Class)) {
00311     ProtoSetId = Class->NumProtoSets++;
00312 
00313     ProtoSet = (PROTO_SET) Emalloc(sizeof(PROTO_SET_STRUCT));
00314     Class->ProtoSets[ProtoSetId] = ProtoSet;
00315     memset(ProtoSet, 0, sizeof(*ProtoSet));
00316 
00317     /* reallocate space for the proto lengths and install in class */
00318     Class->ProtoLengths =
00319       (uinT8 *)Erealloc(Class->ProtoLengths,
00320                         MaxNumIntProtosIn(Class) * sizeof(uinT8));
00321     memset(&Class->ProtoLengths[Index], 0,
00322            sizeof(*Class->ProtoLengths) * (MaxNumIntProtosIn(Class) - Index));
00323   }
00324 
00325   /* initialize proto so its length is zero and it isn't in any configs */
00326   Class->ProtoLengths[Index] = 0;
00327   Proto = ProtoForProtoId (Class, Index);
00328   for (Word = Proto->Configs;
00329        Word < Proto->Configs + WERDS_PER_CONFIG_VEC; *Word++ = 0);
00330 
00331   return (Index);
00332 
00333 }                                /* AddIntProto */
00334 
00335 
00336 /*---------------------------------------------------------------------------*/
00337 void AddProtoToClassPruner (PROTO Proto, CLASS_ID ClassId,
00338                             INT_TEMPLATES Templates)
00339 /*
00340  ** Parameters:
00341  **   Proto   floating-pt proto to add to class pruner
00342  **   ClassId   class id corresponding to Proto
00343  **   Templates set of templates containing class pruner
00344  ** Globals:
00345  **   classify_num_cp_levels number of levels used in the class pruner
00346  ** Operation: This routine adds Proto to the class pruning tables
00347  **   for the specified class in Templates.
00348  ** Return: none
00349  ** Exceptions: none
00350  ** History: Wed Feb 13 08:49:54 1991, DSJ, Created.
00351  */
00352 #define MAX_LEVEL     2
00353 {
00354   CLASS_PRUNER_STRUCT* Pruner;
00355   uinT32 ClassMask;
00356   uinT32 ClassCount;
00357   uinT32 WordIndex;
00358   int Level;
00359   FLOAT32 EndPad, SidePad, AnglePad;
00360   TABLE_FILLER TableFiller;
00361   FILL_SPEC FillSpec;
00362 
00363   Pruner = CPrunerFor (Templates, ClassId);
00364   WordIndex = CPrunerWordIndexFor (ClassId);
00365   ClassMask = CPrunerMaskFor (MAX_LEVEL, ClassId);
00366 
00367   for (Level = classify_num_cp_levels - 1; Level >= 0; Level--) {
00368     GetCPPadsForLevel(Level, &EndPad, &SidePad, &AnglePad);
00369     ClassCount = CPrunerMaskFor (Level, ClassId);
00370     InitTableFiller(EndPad, SidePad, AnglePad, Proto, &TableFiller);
00371 
00372     while (!FillerDone (&TableFiller)) {
00373       GetNextFill(&TableFiller, &FillSpec);
00374       DoFill(&FillSpec, Pruner, ClassMask, ClassCount, WordIndex);
00375     }
00376   }
00377 }                                /* AddProtoToClassPruner */
00378 
00379 
00380 /*---------------------------------------------------------------------------*/
00381 void AddProtoToProtoPruner(PROTO Proto, int ProtoId,
00382                            INT_CLASS Class, bool debug) {
00383 /*
00384  ** Parameters:
00385  **   Proto floating-pt proto to be added to proto pruner
00386  **   ProtoId id of proto
00387  **   Class integer class that contains desired proto pruner
00388  ** Globals: none
00389  ** Operation: This routine updates the proto pruner lookup tables
00390  **   for Class to include a new proto identified by ProtoId
00391  **   and described by Proto.
00392  ** Return: none
00393  ** Exceptions: none
00394  ** History: Fri Feb  8 13:07:19 1991, DSJ, Created.
00395  */
00396   FLOAT32 Angle, X, Y, Length;
00397   FLOAT32 Pad;
00398   int Index;
00399   PROTO_SET ProtoSet;
00400 
00401   if (ProtoId >= Class->NumProtos)
00402     cprintf("AddProtoToProtoPruner:assert failed: %d < %d",
00403             ProtoId, Class->NumProtos);
00404   assert(ProtoId < Class->NumProtos);
00405 
00406   Index = IndexForProto (ProtoId);
00407   ProtoSet = Class->ProtoSets[SetForProto (ProtoId)];
00408 
00409   Angle = Proto->Angle;
00410 #ifndef _WIN32
00411   assert(!isnan(Angle));
00412 #endif
00413 
00414   FillPPCircularBits (ProtoSet->ProtoPruner[PRUNER_ANGLE], Index,
00415                       Angle + ANGLE_SHIFT, classify_pp_angle_pad / 360.0,
00416                       debug);
00417 
00418   Angle *= 2.0 * PI;
00419   Length = Proto->Length;
00420 
00421   X = Proto->X + X_SHIFT;
00422   Pad = MAX (fabs (cos (Angle)) * (Length / 2.0 +
00423                                    classify_pp_end_pad *
00424                                    GetPicoFeatureLength ()),
00425              fabs (sin (Angle)) * (classify_pp_side_pad *
00426                                    GetPicoFeatureLength ()));
00427 
00428   FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_X], Index, X, Pad, debug);
00429 
00430   Y = Proto->Y + Y_SHIFT;
00431   Pad = MAX (fabs (sin (Angle)) * (Length / 2.0 +
00432                                    classify_pp_end_pad *
00433                                    GetPicoFeatureLength ()),
00434              fabs (cos (Angle)) * (classify_pp_side_pad *
00435                                    GetPicoFeatureLength ()));
00436 
00437   FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_Y], Index, Y, Pad, debug);
00438 }                                /* AddProtoToProtoPruner */
00439 
00440 
00441 /*---------------------------------------------------------------------------*/
00442 int BucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
00443 /*
00444  ** Parameters:
00445  **   Param   parameter value to map into a bucket number
00446  **   Offset    amount to shift param before mapping it
00447  **   NumBuckets  number of buckets to map param into
00448  ** Globals: none
00449  ** Operation: This routine maps a parameter value into a bucket between
00450  **   0 and NumBuckets-1.  Offset is added to the parameter
00451  **   before mapping it.  Values which map to buckets outside
00452  **   the range are truncated to fit within the range.  Mapping
00453  **   is done by truncating rather than rounding.
00454  ** Return: Bucket number corresponding to Param + Offset.
00455  ** Exceptions: none
00456  ** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
00457  */
00458   return ClipToRange(static_cast<int>(MapParam(Param, Offset, NumBuckets)),
00459                      0, NumBuckets - 1);
00460 }                                /* BucketFor */
00461 
00462 
00463 /*---------------------------------------------------------------------------*/
00464 int CircBucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
00465 /*
00466  ** Parameters:
00467  **   Param   parameter value to map into a circular bucket
00468  **   Offset    amount to shift param before mapping it
00469  **   NumBuckets  number of buckets to map param into
00470  ** Globals: none
00471  ** Operation: This routine maps a parameter value into a bucket between
00472  **   0 and NumBuckets-1.  Offset is added to the parameter
00473  **   before mapping it.  Values which map to buckets outside
00474  **   the range are wrapped to a new value in a circular fashion.
00475  **   Mapping is done by truncating rather than rounding.
00476  ** Return: Bucket number corresponding to Param + Offset.
00477  ** Exceptions: none
00478  ** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
00479  */
00480   int Bucket;
00481 
00482   Bucket = static_cast<int>(MapParam(Param, Offset, NumBuckets));
00483   if (Bucket < 0)
00484     Bucket += NumBuckets;
00485   else if (Bucket >= NumBuckets)
00486     Bucket -= NumBuckets;
00487   return Bucket;
00488 }                                /* CircBucketFor */
00489 
00490 
00491 /*---------------------------------------------------------------------------*/
00492 #ifndef GRAPHICS_DISABLED
00493 void UpdateMatchDisplay() {
00494 /*
00495  ** Parameters: none
00496  ** Globals:
00497  **   FeatureShapes display list for features
00498  **   ProtoShapes display list for protos
00499  ** Operation: This routine clears the global feature and proto
00500  **   display lists.
00501  ** Return: none
00502  ** Exceptions: none
00503  ** History: Thu Mar 21 15:40:19 1991, DSJ, Created.
00504  */
00505   if (IntMatchWindow != NULL)
00506     IntMatchWindow->Update();
00507 }                                /* ClearMatchDisplay */
00508 #endif
00509 
00510 /*---------------------------------------------------------------------------*/
00511 void ConvertConfig(BIT_VECTOR Config, int ConfigId, INT_CLASS Class) {
00512 /*
00513  ** Parameters:
00514  **   Config    config to be added to class
00515  **   ConfigId  id to be used for new config
00516  **   Class   class to add new config to
00517  ** Globals: none
00518  ** Operation: This operation updates the config vectors of all protos
00519  **   in Class to indicate that the protos with 1's in Config
00520  **   belong to a new configuration identified by ConfigId.
00521  **   It is assumed that the length of the Config bit vector is
00522  **   equal to the number of protos in Class.
00523  ** Return: none
00524  ** Exceptions: none
00525  ** History: Mon Feb 11 14:57:31 1991, DSJ, Created.
00526  */
00527   int ProtoId;
00528   INT_PROTO Proto;
00529   int TotalLength;
00530 
00531   for (ProtoId = 0, TotalLength = 0;
00532     ProtoId < Class->NumProtos; ProtoId++) {
00533     if (test_bit(Config, ProtoId)) {
00534       Proto = ProtoForProtoId(Class, ProtoId);
00535       SET_BIT(Proto->Configs, ConfigId);
00536       TotalLength += Class->ProtoLengths[ProtoId];
00537     }
00538   }
00539   Class->ConfigLengths[ConfigId] = TotalLength;
00540 }                                /* ConvertConfig */
00541 
00542 
00543 namespace tesseract {
00544 /*---------------------------------------------------------------------------*/
00545 void Classify::ConvertProto(PROTO Proto, int ProtoId, INT_CLASS Class) {
00546 /*
00547  ** Parameters:
00548  **   Proto floating-pt proto to be converted to integer format
00549  **   ProtoId id of proto
00550  **   Class integer class to add converted proto to
00551  ** Globals: none
00552  ** Operation: This routine converts Proto to integer format and
00553  **   installs it as ProtoId in Class.
00554  ** Return: none
00555  ** Exceptions: none
00556  ** History: Fri Feb  8 11:22:43 1991, DSJ, Created.
00557  */
00558   INT_PROTO P;
00559   FLOAT32 Param;
00560 
00561   assert(ProtoId < Class->NumProtos);
00562 
00563   P = ProtoForProtoId(Class, ProtoId);
00564 
00565   Param = Proto->A * 128;
00566   P->A = TruncateParam(Param, -128, 127, NULL);
00567 
00568   Param = -Proto->B * 256;
00569   P->B = TruncateParam(Param, 0, 255, NULL);
00570 
00571   Param = Proto->C * 128;
00572   P->C = TruncateParam(Param, -128, 127, NULL);
00573 
00574   Param = Proto->Angle * 256;
00575   if (Param < 0 || Param >= 256)
00576     P->Angle = 0;
00577   else
00578     P->Angle = (uinT8) Param;
00579 
00580   /* round proto length to nearest integer number of pico-features */
00581   Param = (Proto->Length / GetPicoFeatureLength()) + 0.5;
00582   Class->ProtoLengths[ProtoId] = TruncateParam(Param, 1, 255, NULL);
00583   if (classify_learning_debug_level >= 2)
00584     cprintf("Converted ffeat to (A=%d,B=%d,C=%d,L=%d)",
00585             P->A, P->B, P->C, Class->ProtoLengths[ProtoId]);
00586 }                                /* ConvertProto */
00587 
00588 
00589 /*---------------------------------------------------------------------------*/
00590 INT_TEMPLATES Classify::CreateIntTemplates(CLASSES FloatProtos,
00591                                            const UNICHARSET&
00592                                            target_unicharset) {
00593 /*
00594  ** Parameters:
00595  **   FloatProtos prototypes in old floating pt format
00596  ** Globals: none
00597  ** Operation: This routine converts from the old floating point format
00598  **   to the new integer format.
00599  ** Return: New set of training templates in integer format.
00600  ** Exceptions: none
00601  ** History: Thu Feb  7 14:40:42 1991, DSJ, Created.
00602  */
00603   INT_TEMPLATES IntTemplates;
00604   CLASS_TYPE FClass;
00605   INT_CLASS IClass;
00606   int ClassId;
00607   int ProtoId;
00608   int ConfigId;
00609 
00610   IntTemplates = NewIntTemplates();
00611 
00612   for (ClassId = 0; ClassId < target_unicharset.size(); ClassId++) {
00613     FClass = &(FloatProtos[ClassId]);
00614     if (FClass->NumProtos == 0 && FClass->NumConfigs == 0 &&
00615         strcmp(target_unicharset.id_to_unichar(ClassId), " ") != 0) {
00616       cprintf("Warning: no protos/configs for %s in CreateIntTemplates()\n",
00617               target_unicharset.id_to_unichar(ClassId));
00618     }
00619     assert(UnusedClassIdIn(IntTemplates, ClassId));
00620     IClass = NewIntClass(FClass->NumProtos, FClass->NumConfigs);
00621     FontSet fs;
00622     fs.size = FClass->font_set.size();
00623     fs.configs = new int[fs.size];
00624     for (int i = 0; i < fs.size; ++i) {
00625       fs.configs[i] = FClass->font_set.get(i);
00626     }
00627     if (this->fontset_table_.contains(fs)) {
00628       IClass->font_set_id = this->fontset_table_.get_id(fs);
00629       delete[] fs.configs;
00630     } else {
00631       IClass->font_set_id = this->fontset_table_.push_back(fs);
00632     }
00633     AddIntClass(IntTemplates, ClassId, IClass);
00634 
00635     for (ProtoId = 0; ProtoId < FClass->NumProtos; ProtoId++) {
00636       AddIntProto(IClass);
00637       ConvertProto(ProtoIn(FClass, ProtoId), ProtoId, IClass);
00638       AddProtoToProtoPruner(ProtoIn(FClass, ProtoId), ProtoId, IClass,
00639                             classify_learning_debug_level >= 2);
00640       AddProtoToClassPruner(ProtoIn(FClass, ProtoId), ClassId, IntTemplates);
00641     }
00642 
00643     for (ConfigId = 0; ConfigId < FClass->NumConfigs; ConfigId++) {
00644       AddIntConfig(IClass);
00645       ConvertConfig(FClass->Configurations[ConfigId], ConfigId, IClass);
00646     }
00647   }
00648   return (IntTemplates);
00649 }                                /* CreateIntTemplates */
00650 }  // namespace tesseract
00651 
00652 
00653 /*---------------------------------------------------------------------------*/
00654 #ifndef GRAPHICS_DISABLED
00655 void DisplayIntFeature(const INT_FEATURE_STRUCT* Feature, FLOAT32 Evidence) {
00656 /*
00657  ** Parameters:
00658  **   Feature   pico-feature to be displayed
00659  **   Evidence  best evidence for this feature (0-1)
00660  ** Globals:
00661  **   FeatureShapes global display list for features
00662  ** Operation: This routine renders the specified feature into a
00663  **   global display list.
00664  ** Return: none
00665  ** Exceptions: none
00666  ** History: Thu Mar 21 14:45:04 1991, DSJ, Created.
00667  */
00668   ScrollView::Color color = GetMatchColorFor(Evidence);
00669   RenderIntFeature(IntMatchWindow, Feature, color);
00670   if (FeatureDisplayWindow) {
00671     RenderIntFeature(FeatureDisplayWindow, Feature, color);
00672   }
00673 }                                /* DisplayIntFeature */
00674 
00675 
00676 /*---------------------------------------------------------------------------*/
00677 void DisplayIntProto(INT_CLASS Class, PROTO_ID ProtoId, FLOAT32 Evidence) {
00678 /*
00679  ** Parameters:
00680  **   Class   class to take proto from
00681  **   ProtoId   id of proto in Class to be displayed
00682  **   Evidence  total evidence for proto (0-1)
00683  ** Globals:
00684  **   ProtoShapes global display list for protos
00685  ** Operation: This routine renders the specified proto into a
00686  **   global display list.
00687  ** Return: none
00688  ** Exceptions: none
00689  ** History: Thu Mar 21 14:45:04 1991, DSJ, Created.
00690  */
00691   ScrollView::Color color = GetMatchColorFor(Evidence);
00692   RenderIntProto(IntMatchWindow, Class, ProtoId, color);
00693   if (ProtoDisplayWindow) {
00694     RenderIntProto(ProtoDisplayWindow, Class, ProtoId, color);
00695   }
00696 }                                /* DisplayIntProto */
00697 #endif
00698 
00699 /*---------------------------------------------------------------------------*/
00700 INT_CLASS NewIntClass(int MaxNumProtos, int MaxNumConfigs) {
00701 /*
00702  ** Parameters:
00703  **   MaxNumProtos  number of protos to allocate space for
00704  **   MaxNumConfigs number of configs to allocate space for
00705  ** Globals: none
00706  ** Operation: This routine creates a new integer class data structure
00707  **   and returns it.  Sufficient space is allocated
00708  **   to handle the specified number of protos and configs.
00709  ** Return: New class created.
00710  ** Exceptions: none
00711  ** History: Fri Feb  8 10:51:23 1991, DSJ, Created.
00712  */
00713   INT_CLASS Class;
00714   PROTO_SET ProtoSet;
00715   int i;
00716 
00717   assert(MaxNumConfigs <= MAX_NUM_CONFIGS);
00718 
00719   Class = (INT_CLASS) Emalloc(sizeof(INT_CLASS_STRUCT));
00720   Class->NumProtoSets = ((MaxNumProtos + PROTOS_PER_PROTO_SET - 1) /
00721                             PROTOS_PER_PROTO_SET);
00722 
00723   assert(Class->NumProtoSets <= MAX_NUM_PROTO_SETS);
00724 
00725   Class->NumProtos = 0;
00726   Class->NumConfigs = 0;
00727 
00728   for (i = 0; i < Class->NumProtoSets; i++) {
00729     /* allocate space for a proto set, install in class, and initialize */
00730     ProtoSet = (PROTO_SET) Emalloc(sizeof(PROTO_SET_STRUCT));
00731     memset(ProtoSet, 0, sizeof(*ProtoSet));
00732     Class->ProtoSets[i] = ProtoSet;
00733 
00734     /* allocate space for the proto lengths and install in class */
00735   }
00736   if (MaxNumIntProtosIn (Class) > 0) {
00737     Class->ProtoLengths =
00738       (uinT8 *)Emalloc(MaxNumIntProtosIn (Class) * sizeof (uinT8));
00739     memset(Class->ProtoLengths, 0,
00740            MaxNumIntProtosIn(Class) * sizeof(*Class->ProtoLengths));
00741   } else {
00742     Class->ProtoLengths = NULL;
00743   }
00744   memset(Class->ConfigLengths, 0, sizeof(Class->ConfigLengths));
00745 
00746   return (Class);
00747 
00748 }                                /* NewIntClass */
00749 
00750 
00751 /*-------------------------------------------------------------------------*/
00752 void free_int_class(INT_CLASS int_class) {
00753   int i;
00754 
00755   for (i = 0; i < int_class->NumProtoSets; i++) {
00756     Efree (int_class->ProtoSets[i]);
00757   }
00758   if (int_class->ProtoLengths != NULL) {
00759     Efree (int_class->ProtoLengths);
00760   }
00761   Efree(int_class);
00762 }
00763 
00764 
00765 /*---------------------------------------------------------------------------*/
00766 INT_TEMPLATES NewIntTemplates() {
00767 /*
00768  ** Parameters: none
00769  ** Globals: none
00770  ** Operation: This routine allocates a new set of integer templates
00771  **   initialized to hold 0 classes.
00772  ** Return: The integer templates created.
00773  ** Exceptions: none
00774  ** History: Fri Feb  8 08:38:51 1991, DSJ, Created.
00775  */
00776   INT_TEMPLATES T;
00777   int i;
00778 
00779   T = (INT_TEMPLATES) Emalloc (sizeof (INT_TEMPLATES_STRUCT));
00780   T->NumClasses = 0;
00781   T->NumClassPruners = 0;
00782 
00783   for (i = 0; i < MAX_NUM_CLASSES; i++)
00784     ClassForClassId (T, i) = NULL;
00785 
00786   return (T);
00787 }                                /* NewIntTemplates */
00788 
00789 
00790 /*---------------------------------------------------------------------------*/
00791 void free_int_templates(INT_TEMPLATES templates) {
00792   int i;
00793 
00794   for (i = 0; i < templates->NumClasses; i++)
00795     free_int_class(templates->Class[i]);
00796   for (i = 0; i < templates->NumClassPruners; i++)
00797     delete templates->ClassPruners[i];
00798   Efree(templates);
00799 }
00800 
00801 
00802 namespace tesseract {
00803 INT_TEMPLATES Classify::ReadIntTemplates(FILE *File) {
00804 /*
00805  ** Parameters:
00806  **   File    open file to read templates from
00807  ** Globals: none
00808  ** Operation: This routine reads a set of integer templates from
00809  **   File.  File must already be open and must be in the
00810  **   correct binary format.
00811  ** Return: Pointer to integer templates read from File.
00812  ** Exceptions: none
00813  ** History: Wed Feb 27 11:48:46 1991, DSJ, Created.
00814  */
00815   int i, j, w, x, y, z;
00816   BOOL8 swap;
00817   int nread;
00818   int unicharset_size;
00819   int version_id = 0;
00820   INT_TEMPLATES Templates;
00821   CLASS_PRUNER_STRUCT* Pruner;
00822   INT_CLASS Class;
00823   uinT8 *Lengths;
00824   PROTO_SET ProtoSet;
00825 
00826   /* variables for conversion from older inttemp formats */
00827   int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
00828   CLASS_ID class_id, max_class_id;
00829   inT16 *IndexFor = new inT16[MAX_NUM_CLASSES];
00830   CLASS_ID *ClassIdFor = new CLASS_ID[MAX_NUM_CLASSES];
00831   CLASS_PRUNER_STRUCT **TempClassPruner =
00832       new CLASS_PRUNER_STRUCT*[MAX_NUM_CLASS_PRUNERS];
00833   uinT32 SetBitsForMask =           // word with NUM_BITS_PER_CLASS
00834     (1 << NUM_BITS_PER_CLASS) - 1;  // set starting at bit 0
00835   uinT32 Mask, NewMask, ClassBits;
00836   int MaxNumConfigs = MAX_NUM_CONFIGS;
00837   int WerdsPerConfigVec = WERDS_PER_CONFIG_VEC;
00838 
00839   /* first read the high level template struct */
00840   Templates = NewIntTemplates();
00841   // Read Templates in parts for 64 bit compatibility.
00842   if (fread(&unicharset_size, sizeof(int), 1, File) != 1)
00843     cprintf("Bad read of inttemp!\n");
00844   if (fread(&Templates->NumClasses,
00845             sizeof(Templates->NumClasses), 1, File) != 1 ||
00846       fread(&Templates->NumClassPruners,
00847             sizeof(Templates->NumClassPruners), 1, File) != 1)
00848     cprintf("Bad read of inttemp!\n");
00849   // Swap status is determined automatically.
00850   swap = Templates->NumClassPruners < 0 ||
00851     Templates->NumClassPruners > MAX_NUM_CLASS_PRUNERS;
00852   if (swap) {
00853     Reverse32(&Templates->NumClassPruners);
00854     Reverse32(&Templates->NumClasses);
00855     Reverse32(&unicharset_size);
00856   }
00857   if (Templates->NumClasses < 0) {
00858     // This file has a version id!
00859     version_id = -Templates->NumClasses;
00860     if (fread(&Templates->NumClasses, sizeof(Templates->NumClasses),
00861               1, File) != 1)
00862       cprintf("Bad read of inttemp!\n");
00863     if (swap)
00864       Reverse32(&Templates->NumClasses);
00865   }
00866 
00867   if (version_id < 3) {
00868     MaxNumConfigs = OLD_MAX_NUM_CONFIGS;
00869     WerdsPerConfigVec = OLD_WERDS_PER_CONFIG_VEC;
00870   }
00871 
00872   if (version_id < 2) {
00873     for (i = 0; i < unicharset_size; ++i) {
00874       if (fread(&IndexFor[i], sizeof(inT16), 1, File) != 1)
00875         cprintf("Bad read of inttemp!\n");
00876     }
00877     for (i = 0; i < Templates->NumClasses; ++i) {
00878       if (fread(&ClassIdFor[i], sizeof(CLASS_ID), 1, File) != 1)
00879         cprintf("Bad read of inttemp!\n");
00880     }
00881     if (swap) {
00882       for (i = 0; i < Templates->NumClasses; i++)
00883         Reverse16(&IndexFor[i]);
00884       for (i = 0; i < Templates->NumClasses; i++)
00885         Reverse32(&ClassIdFor[i]);
00886     }
00887   }
00888 
00889   /* then read in the class pruners */
00890   for (i = 0; i < Templates->NumClassPruners; i++) {
00891     Pruner = new CLASS_PRUNER_STRUCT;
00892     if ((nread =
00893          fread(Pruner, 1, sizeof(CLASS_PRUNER_STRUCT),
00894                 File)) != sizeof(CLASS_PRUNER_STRUCT))
00895       cprintf("Bad read of inttemp!\n");
00896     if (swap) {
00897       for (x = 0; x < NUM_CP_BUCKETS; x++) {
00898         for (y = 0; y < NUM_CP_BUCKETS; y++) {
00899           for (z = 0; z < NUM_CP_BUCKETS; z++) {
00900             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
00901               Reverse32(&Pruner->p[x][y][z][w]);
00902             }
00903           }
00904         }
00905       }
00906     }
00907     if (version_id < 2) {
00908       TempClassPruner[i] = Pruner;
00909     } else {
00910       Templates->ClassPruners[i] = Pruner;
00911     }
00912   }
00913 
00914   /* fix class pruners if they came from an old version of inttemp */
00915   if (version_id < 2) {
00916     // Allocate enough class pruners to cover all the class ids.
00917     max_class_id = 0;
00918     for (i = 0; i < Templates->NumClasses; i++)
00919       if (ClassIdFor[i] > max_class_id)
00920         max_class_id = ClassIdFor[i];
00921     for (i = 0; i <= CPrunerIdFor(max_class_id); i++) {
00922       Templates->ClassPruners[i] = new CLASS_PRUNER_STRUCT;
00923       memset(Templates->ClassPruners[i], 0, sizeof(CLASS_PRUNER_STRUCT));
00924     }
00925     // Convert class pruners from the old format (indexed by class index)
00926     // to the new format (indexed by class id).
00927     last_cp_bit_number = NUM_BITS_PER_CLASS * Templates->NumClasses - 1;
00928     for (i = 0; i < Templates->NumClassPruners; i++) {
00929       for (x = 0; x < NUM_CP_BUCKETS; x++)
00930         for (y = 0; y < NUM_CP_BUCKETS; y++)
00931           for (z = 0; z < NUM_CP_BUCKETS; z++)
00932             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
00933               if (TempClassPruner[i]->p[x][y][z][w] == 0)
00934                 continue;
00935               for (b = 0; b < BITS_PER_WERD; b += NUM_BITS_PER_CLASS) {
00936                 bit_number = i * BITS_PER_CP_VECTOR + w * BITS_PER_WERD + b;
00937                 if (bit_number > last_cp_bit_number)
00938                   break; // the rest of the bits in this word are not used
00939                 class_id = ClassIdFor[bit_number / NUM_BITS_PER_CLASS];
00940                 // Single out NUM_BITS_PER_CLASS bits relating to class_id.
00941                 Mask = SetBitsForMask << b;
00942                 ClassBits = TempClassPruner[i]->p[x][y][z][w] & Mask;
00943                 // Move these bits to the new position in which they should
00944                 // appear (indexed corresponding to the class_id).
00945                 new_i = CPrunerIdFor(class_id);
00946                 new_w = CPrunerWordIndexFor(class_id);
00947                 new_b = CPrunerBitIndexFor(class_id) * NUM_BITS_PER_CLASS;
00948                 if (new_b > b) {
00949                   ClassBits <<= (new_b - b);
00950                 } else {
00951                   ClassBits >>= (b - new_b);
00952                 }
00953                 // Copy bits relating to class_id to the correct position
00954                 // in Templates->ClassPruner.
00955                 NewMask = SetBitsForMask << new_b;
00956                 Templates->ClassPruners[new_i]->p[x][y][z][new_w] &= ~NewMask;
00957                 Templates->ClassPruners[new_i]->p[x][y][z][new_w] |= ClassBits;
00958               }
00959             }
00960     }
00961     for (i = 0; i < Templates->NumClassPruners; i++) {
00962       delete TempClassPruner[i];
00963     }
00964   }
00965 
00966   /* then read in each class */
00967   for (i = 0; i < Templates->NumClasses; i++) {
00968     /* first read in the high level struct for the class */
00969     Class = (INT_CLASS) Emalloc (sizeof (INT_CLASS_STRUCT));
00970     if (fread(&Class->NumProtos, sizeof(Class->NumProtos), 1, File) != 1 ||
00971         fread(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File) != 1 ||
00972         fread(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File) != 1)
00973       cprintf ("Bad read of inttemp!\n");
00974     if (version_id == 0) {
00975       // Only version 0 writes 5 pointless pointers to the file.
00976       for (j = 0; j < 5; ++j) {
00977         int junk;
00978         if (fread(&junk, sizeof(junk), 1, File) != 1)
00979           cprintf ("Bad read of inttemp!\n");
00980       }
00981     }
00982     if (version_id < 4) {
00983       for (j = 0; j < MaxNumConfigs; ++j) {
00984         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
00985           cprintf ("Bad read of inttemp!\n");
00986       }
00987       if (swap) {
00988         Reverse16(&Class->NumProtos);
00989         for (j = 0; j < MaxNumConfigs; j++)
00990           Reverse16(&Class->ConfigLengths[j]);
00991       }
00992     } else {
00993       ASSERT_HOST(Class->NumConfigs < MaxNumConfigs);
00994       for (j = 0; j < Class->NumConfigs; ++j) {
00995         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
00996           cprintf ("Bad read of inttemp!\n");
00997       }
00998       if (swap) {
00999         Reverse16(&Class->NumProtos);
01000         for (j = 0; j < MaxNumConfigs; j++)
01001           Reverse16(&Class->ConfigLengths[j]);
01002       }
01003     }
01004     if (version_id < 2) {
01005       ClassForClassId (Templates, ClassIdFor[i]) = Class;
01006     } else {
01007       ClassForClassId (Templates, i) = Class;
01008     }
01009 
01010     /* then read in the proto lengths */
01011     Lengths = NULL;
01012     if (MaxNumIntProtosIn (Class) > 0) {
01013       Lengths = (uinT8 *)Emalloc(sizeof(uinT8) * MaxNumIntProtosIn(Class));
01014       if ((nread =
01015            fread((char *)Lengths, sizeof(uinT8),
01016                  MaxNumIntProtosIn(Class), File)) != MaxNumIntProtosIn (Class))
01017         cprintf ("Bad read of inttemp!\n");
01018     }
01019     Class->ProtoLengths = Lengths;
01020 
01021     /* then read in the proto sets */
01022     for (j = 0; j < Class->NumProtoSets; j++) {
01023       ProtoSet = (PROTO_SET)Emalloc(sizeof(PROTO_SET_STRUCT));
01024       if (version_id < 3) {
01025         if ((nread =
01026              fread((char *) &ProtoSet->ProtoPruner, 1,
01027                     sizeof(PROTO_PRUNER), File)) != sizeof(PROTO_PRUNER))
01028           cprintf("Bad read of inttemp!\n");
01029         for (x = 0; x < PROTOS_PER_PROTO_SET; x++) {
01030           if ((nread = fread((char *) &ProtoSet->Protos[x].A, 1,
01031                              sizeof(inT8), File)) != sizeof(inT8) ||
01032               (nread = fread((char *) &ProtoSet->Protos[x].B, 1,
01033                              sizeof(uinT8), File)) != sizeof(uinT8) ||
01034               (nread = fread((char *) &ProtoSet->Protos[x].C, 1,
01035                              sizeof(inT8), File)) != sizeof(inT8) ||
01036               (nread = fread((char *) &ProtoSet->Protos[x].Angle, 1,
01037                              sizeof(uinT8), File)) != sizeof(uinT8))
01038             cprintf("Bad read of inttemp!\n");
01039           for (y = 0; y < WerdsPerConfigVec; y++)
01040             if ((nread = fread((char *) &ProtoSet->Protos[x].Configs[y], 1,
01041                                sizeof(uinT32), File)) != sizeof(uinT32))
01042               cprintf("Bad read of inttemp!\n");
01043         }
01044       } else {
01045         if ((nread =
01046              fread((char *) ProtoSet, 1, sizeof(PROTO_SET_STRUCT),
01047                    File)) != sizeof(PROTO_SET_STRUCT))
01048           cprintf("Bad read of inttemp!\n");
01049       }
01050       if (swap) {
01051         for (x = 0; x < NUM_PP_PARAMS; x++)
01052           for (y = 0; y < NUM_PP_BUCKETS; y++)
01053             for (z = 0; z < WERDS_PER_PP_VECTOR; z++)
01054               Reverse32(&ProtoSet->ProtoPruner[x][y][z]);
01055         for (x = 0; x < PROTOS_PER_PROTO_SET; x++)
01056           for (y = 0; y < WerdsPerConfigVec; y++)
01057             Reverse32(&ProtoSet->Protos[x].Configs[y]);
01058       }
01059       Class->ProtoSets[j] = ProtoSet;
01060     }
01061     if (version_id < 4)
01062       Class->font_set_id = -1;
01063     else {
01064       fread(&Class->font_set_id, sizeof(int), 1, File);
01065       if (swap)
01066         Reverse32(&Class->font_set_id);
01067     }
01068   }
01069 
01070   if (version_id < 2) {
01071     /* add an empty NULL class with class id 0 */
01072     assert(UnusedClassIdIn (Templates, 0));
01073     ClassForClassId (Templates, 0) = NewIntClass (1, 1);
01074     ClassForClassId (Templates, 0)->font_set_id = -1;
01075     Templates->NumClasses++;
01076     /* make sure the classes are contiguous */
01077     for (i = 0; i < MAX_NUM_CLASSES; i++) {
01078       if (i < Templates->NumClasses) {
01079         if (ClassForClassId (Templates, i) == NULL) {
01080           fprintf(stderr, "Non-contiguous class ids in inttemp\n");
01081           exit(1);
01082         }
01083       } else {
01084         if (ClassForClassId (Templates, i) != NULL) {
01085           fprintf(stderr, "Class id %d exceeds NumClassesIn (Templates) %d\n",
01086                   i, Templates->NumClasses);
01087           exit(1);
01088         }
01089       }
01090     }
01091   }
01092   if (version_id >= 4) {
01093     this->fontinfo_table_.read(File, NewPermanentTessCallback(read_info), swap);
01094     if (version_id >= 5) {
01095       this->fontinfo_table_.read(File,
01096                                  NewPermanentTessCallback(read_spacing_info),
01097                                  swap);
01098     }
01099     this->fontset_table_.read(File, NewPermanentTessCallback(read_set), swap);
01100   }
01101 
01102   // Clean up.
01103   delete[] IndexFor;
01104   delete[] ClassIdFor;
01105   delete[] TempClassPruner;
01106 
01107   return (Templates);
01108 }                                /* ReadIntTemplates */
01109 
01110 
01111 /*---------------------------------------------------------------------------*/
01112 #ifndef GRAPHICS_DISABLED
01113 void Classify::ShowMatchDisplay() {
01114 /*
01115  ** Parameters: none
01116  ** Globals:
01117  **   FeatureShapes display list containing feature matches
01118  **   ProtoShapes display list containing proto matches
01119  ** Operation: This routine sends the shapes in the global display
01120  **   lists to the match debugger window.
01121  ** Return: none
01122  ** Exceptions: none
01123  ** History: Thu Mar 21 15:47:33 1991, DSJ, Created.
01124  */
01125   InitIntMatchWindowIfReqd();
01126   if (ProtoDisplayWindow) {
01127     ProtoDisplayWindow->Clear();
01128   }
01129   if (FeatureDisplayWindow) {
01130     FeatureDisplayWindow->Clear();
01131   }
01132   ClearFeatureSpaceWindow(
01133       static_cast<NORM_METHOD>(static_cast<int>(classify_norm_method)),
01134       IntMatchWindow);
01135   IntMatchWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01136                                   INT_MAX_X, INT_MAX_Y);
01137   if (ProtoDisplayWindow) {
01138     ProtoDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01139                                         INT_MAX_X, INT_MAX_Y);
01140   }
01141   if (FeatureDisplayWindow) {
01142     FeatureDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
01143                                           INT_MAX_X, INT_MAX_Y);
01144   }
01145 }                                /* ShowMatchDisplay */
01146 
01147 // Clears the given window and draws the featurespace guides for the
01148 // appropriate normalization method.
01149 void ClearFeatureSpaceWindow(NORM_METHOD norm_method, ScrollView* window) {
01150   window->Clear();
01151 
01152   window->Pen(ScrollView::GREY);
01153   // Draw the feature space limit rectangle.
01154   window->Rectangle(0, 0, INT_MAX_X, INT_MAX_Y);
01155   if (norm_method == baseline) {
01156     window->SetCursor(0, INT_DESCENDER);
01157     window->DrawTo(INT_MAX_X, INT_DESCENDER);
01158     window->SetCursor(0, INT_BASELINE);
01159     window->DrawTo(INT_MAX_X, INT_BASELINE);
01160     window->SetCursor(0, INT_XHEIGHT);
01161     window->DrawTo(INT_MAX_X, INT_XHEIGHT);
01162     window->SetCursor(0, INT_CAPHEIGHT);
01163     window->DrawTo(INT_MAX_X, INT_CAPHEIGHT);
01164   } else {
01165     window->Rectangle(INT_XCENTER - INT_XRADIUS, INT_YCENTER - INT_YRADIUS,
01166                       INT_XCENTER + INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
01167   }
01168 }
01169 #endif
01170 
01171 /*---------------------------------------------------------------------------*/
01172 void Classify::WriteIntTemplates(FILE *File, INT_TEMPLATES Templates,
01173                                  const UNICHARSET& target_unicharset) {
01174 /*
01175  ** Parameters:
01176  **   File    open file to write templates to
01177  **   Templates templates to save into File
01178  ** Globals: none
01179  ** Operation: This routine writes Templates to File.  The format
01180  **   is an efficient binary format.  File must already be open
01181  **   for writing.
01182  ** Return: none
01183  ** Exceptions: none
01184  ** History: Wed Feb 27 11:48:46 1991, DSJ, Created.
01185  */
01186   int i, j;
01187   INT_CLASS Class;
01188   int unicharset_size = target_unicharset.size();
01189   int version_id = -5;  // When negated by the reader -1 becomes +1 etc.
01190 
01191   if (Templates->NumClasses != unicharset_size) {
01192     cprintf("Warning: executing WriteIntTemplates() with %d classes in"
01193             " Templates, while target_unicharset size is %d\n",
01194             Templates->NumClasses, unicharset_size);
01195   }
01196 
01197   /* first write the high level template struct */
01198   fwrite(&unicharset_size, sizeof(unicharset_size), 1, File);
01199   fwrite(&version_id, sizeof(version_id), 1, File);
01200   fwrite(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners),
01201          1, File);
01202   fwrite(&Templates->NumClasses, sizeof(Templates->NumClasses), 1, File);
01203 
01204   /* then write out the class pruners */
01205   for (i = 0; i < Templates->NumClassPruners; i++)
01206     fwrite(Templates->ClassPruners[i],
01207            sizeof(CLASS_PRUNER_STRUCT), 1, File);
01208 
01209   /* then write out each class */
01210   for (i = 0; i < Templates->NumClasses; i++) {
01211     Class = Templates->Class[i];
01212 
01213     /* first write out the high level struct for the class */
01214     fwrite(&Class->NumProtos, sizeof(Class->NumProtos), 1, File);
01215     fwrite(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File);
01216     ASSERT_HOST(Class->NumConfigs == this->fontset_table_.get(Class->font_set_id).size);
01217     fwrite(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File);
01218     for (j = 0; j < Class->NumConfigs; ++j) {
01219       fwrite(&Class->ConfigLengths[j], sizeof(uinT16), 1, File);
01220     }
01221 
01222     /* then write out the proto lengths */
01223     if (MaxNumIntProtosIn (Class) > 0) {
01224       fwrite ((char *) (Class->ProtoLengths), sizeof (uinT8),
01225               MaxNumIntProtosIn (Class), File);
01226     }
01227 
01228     /* then write out the proto sets */
01229     for (j = 0; j < Class->NumProtoSets; j++)
01230       fwrite ((char *) Class->ProtoSets[j],
01231               sizeof (PROTO_SET_STRUCT), 1, File);
01232 
01233     /* then write the fonts info */
01234     fwrite(&Class->font_set_id, sizeof(int), 1, File);
01235   }
01236 
01237   /* Write the fonts info tables */
01238   this->fontinfo_table_.write(File, NewPermanentTessCallback(write_info));
01239   this->fontinfo_table_.write(File,
01240                               NewPermanentTessCallback(write_spacing_info));
01241   this->fontset_table_.write(File, NewPermanentTessCallback(write_set));
01242 }                                /* WriteIntTemplates */
01243 } // namespace tesseract
01244 
01245 
01246 /*-----------------------------------------------------------------------------
01247               Private Code
01248 -----------------------------------------------------------------------------*/
01249 /*---------------------------------------------------------------------------*/
01250 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets) {
01251 /*
01252  ** Parameters:
01253  **   Bucket    bucket whose start is to be computed
01254  **   Offset    offset used to map params to buckets
01255  **   NumBuckets  total number of buckets
01256  ** Globals: none
01257  ** Operation: This routine returns the parameter value which
01258  **   corresponds to the beginning of the specified bucket.
01259  **   The bucket number should have been generated using the
01260  **   BucketFor() function with parameters Offset and NumBuckets.
01261  ** Return: Param value corresponding to start position of Bucket.
01262  ** Exceptions: none
01263  ** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
01264  */
01265   return (((FLOAT32) Bucket / NumBuckets) - Offset);
01266 
01267 }                                /* BucketStart */
01268 
01269 
01270 /*---------------------------------------------------------------------------*/
01271 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets) {
01272 /*
01273  ** Parameters:
01274  **   Bucket    bucket whose end is to be computed
01275  **   Offset    offset used to map params to buckets
01276  **   NumBuckets  total number of buckets
01277  ** Globals: none
01278  ** Operation: This routine returns the parameter value which
01279  **   corresponds to the end of the specified bucket.
01280  **   The bucket number should have been generated using the
01281  **   BucketFor() function with parameters Offset and NumBuckets.
01282  ** Return: Param value corresponding to end position of Bucket.
01283  ** Exceptions: none
01284  ** History: Thu Feb 14 13:24:33 1991, DSJ, Created.
01285  */
01286   return (((FLOAT32) (Bucket + 1) / NumBuckets) - Offset);
01287 }                                /* BucketEnd */
01288 
01289 
01290 /*---------------------------------------------------------------------------*/
01291 void DoFill(FILL_SPEC *FillSpec,
01292             CLASS_PRUNER_STRUCT* Pruner,
01293             register uinT32 ClassMask,
01294             register uinT32 ClassCount,
01295             register uinT32 WordIndex) {
01296 /*
01297  ** Parameters:
01298  **   FillSpec  specifies which bits to fill in pruner
01299  **   Pruner    class pruner to be filled
01300  **   ClassMask indicates which bits to change in each word
01301  **   ClassCount  indicates what to change bits to
01302  **   WordIndex indicates which word to change
01303  ** Globals: none
01304  ** Operation: This routine fills in the section of a class pruner
01305  **   corresponding to a single x value for a single proto of
01306  **   a class.
01307  ** Return: none
01308  ** Exceptions: none
01309  ** History: Tue Feb 19 11:11:29 1991, DSJ, Created.
01310  */
01311   register int X, Y, Angle;
01312   register uinT32 OldWord;
01313 
01314   X = FillSpec->X;
01315   if (X < 0)
01316     X = 0;
01317   if (X >= NUM_CP_BUCKETS)
01318     X = NUM_CP_BUCKETS - 1;
01319 
01320   if (FillSpec->YStart < 0)
01321     FillSpec->YStart = 0;
01322   if (FillSpec->YEnd >= NUM_CP_BUCKETS)
01323     FillSpec->YEnd = NUM_CP_BUCKETS - 1;
01324 
01325   for (Y = FillSpec->YStart; Y <= FillSpec->YEnd; Y++)
01326     for (Angle = FillSpec->AngleStart;
01327          TRUE; CircularIncrement (Angle, NUM_CP_BUCKETS)) {
01328       OldWord = Pruner->p[X][Y][Angle][WordIndex];
01329       if (ClassCount > (OldWord & ClassMask)) {
01330         OldWord &= ~ClassMask;
01331         OldWord |= ClassCount;
01332         Pruner->p[X][Y][Angle][WordIndex] = OldWord;
01333       }
01334       if (Angle == FillSpec->AngleEnd)
01335         break;
01336     }
01337 }                                /* DoFill */
01338 
01339 
01340 /*---------------------------------------------------------------------------*/
01341 BOOL8 FillerDone(TABLE_FILLER *Filler) {
01342 /*
01343  ** Parameters:
01344  **   Filler    table filler to check if done
01345  ** Globals: none
01346  ** Operation: Return TRUE if the specified table filler is done, i.e.
01347  **   if it has no more lines to fill.
01348  ** Return: TRUE if no more lines to fill, FALSE otherwise.
01349  ** Exceptions: none
01350  ** History: Tue Feb 19 10:08:05 1991, DSJ, Created.
01351  */
01352   FILL_SWITCH *Next;
01353 
01354   Next = &(Filler->Switch[Filler->NextSwitch]);
01355 
01356   if (Filler->X > Next->X && Next->Type == LastSwitch)
01357     return (TRUE);
01358   else
01359     return (FALSE);
01360 
01361 }                                /* FillerDone */
01362 
01363 
01364 /*---------------------------------------------------------------------------*/
01365 void FillPPCircularBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
01366                         int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug) {
01367 /*
01368  ** Parameters:
01369  **   ParamTable  table of bit vectors, one per param bucket
01370  **   Bit   bit position in vectors to be filled
01371  **   Center    center of filled area
01372  **   Spread    spread of filled area
01373  ** Globals: none
01374  ** Operation: This routine sets Bit in each bit vector whose
01375  **   bucket lies within the range Center +- Spread.  The fill
01376  **   is done for a circular dimension, i.e. bucket 0 is adjacent
01377  **   to the last bucket.  It is assumed that Center and Spread
01378  **   are expressed in a circular coordinate system whose range
01379  **   is 0 to 1.
01380  ** Return: none
01381  ** Exceptions: none
01382  ** History: Tue Oct 16 09:26:54 1990, DSJ, Created.
01383  */
01384   int i, FirstBucket, LastBucket;
01385 
01386   if (Spread > 0.5)
01387     Spread = 0.5;
01388 
01389   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
01390   if (FirstBucket < 0)
01391     FirstBucket += NUM_PP_BUCKETS;
01392 
01393   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
01394   if (LastBucket >= NUM_PP_BUCKETS)
01395     LastBucket -= NUM_PP_BUCKETS;
01396   if (debug) tprintf("Circular fill from %d to %d", FirstBucket, LastBucket);
01397   for (i = FirstBucket; TRUE; CircularIncrement (i, NUM_PP_BUCKETS)) {
01398     SET_BIT (ParamTable[i], Bit);
01399 
01400     /* exit loop after we have set the bit for the last bucket */
01401     if (i == LastBucket)
01402       break;
01403   }
01404 
01405 }                                /* FillPPCircularBits */
01406 
01407 
01408 /*---------------------------------------------------------------------------*/
01409 void FillPPLinearBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
01410                       int Bit, FLOAT32 Center, FLOAT32 Spread, bool debug) {
01411 /*
01412  ** Parameters:
01413  **   ParamTable  table of bit vectors, one per param bucket
01414  **   Bit   bit number being filled
01415  **   Center    center of filled area
01416  **   Spread    spread of filled area
01417  ** Globals: none
01418  ** Operation: This routine sets Bit in each bit vector whose
01419  **   bucket lies within the range Center +- Spread.  The fill
01420  **   is done for a linear dimension, i.e. there is no wrap-around
01421  **   for this dimension.  It is assumed that Center and Spread
01422  **   are expressed in a linear coordinate system whose range
01423  **   is approximately 0 to 1.  Values outside this range will
01424  **   be clipped.
01425  ** Return: none
01426  ** Exceptions: none
01427  ** History: Tue Oct 16 09:26:54 1990, DSJ, Created.
01428  */
01429   int i, FirstBucket, LastBucket;
01430 
01431   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
01432   if (FirstBucket < 0)
01433     FirstBucket = 0;
01434 
01435   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
01436   if (LastBucket >= NUM_PP_BUCKETS)
01437     LastBucket = NUM_PP_BUCKETS - 1;
01438 
01439   if (debug) tprintf("Linear fill from %d to %d", FirstBucket, LastBucket);
01440   for (i = FirstBucket; i <= LastBucket; i++)
01441     SET_BIT (ParamTable[i], Bit);
01442 
01443 }                                /* FillPPLinearBits */
01444 
01445 
01446 /*---------------------------------------------------------------------------*/
01447 #ifndef GRAPHICS_DISABLED
01448 namespace tesseract {
01449 CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool* adaptive_on,
01450                                    bool* pretrained_on, int* shape_id) {
01451 /*
01452  ** Parameters:
01453  **   Prompt  prompt to print while waiting for input from window
01454  ** Globals: none
01455  ** Operation: This routine prompts the user with Prompt and waits
01456  **   for the user to enter something in the debug window.
01457  ** Return: Character entered in the debug window.
01458  ** Exceptions: none
01459  ** History: Thu Mar 21 16:55:13 1991, DSJ, Created.
01460  */
01461   tprintf("%s\n", Prompt);
01462   SVEvent* ev;
01463   SVEventType ev_type;
01464   int unichar_id = INVALID_UNICHAR_ID;
01465   // Wait until a click or popup event.
01466   do {
01467     ev = IntMatchWindow->AwaitEvent(SVET_ANY);
01468     ev_type = ev->type;
01469     if (ev_type == SVET_POPUP) {
01470       if (ev->command_id == IDA_SHAPE_INDEX) {
01471         if (shape_table_ != NULL) {
01472           *shape_id = atoi(ev->parameter);
01473           *adaptive_on = false;
01474           *pretrained_on = true;
01475           if (*shape_id >= 0 && *shape_id < shape_table_->NumShapes()) {
01476             int font_id;
01477             shape_table_->GetFirstUnicharAndFont(*shape_id, &unichar_id,
01478                                                  &font_id);
01479             tprintf("Shape %d, first unichar=%d, font=%d\n",
01480                     *shape_id, unichar_id, font_id);
01481             return unichar_id;
01482           }
01483           tprintf("Shape index '%s' not found in shape table\n", ev->parameter);
01484         } else {
01485           tprintf("No shape table loaded!\n");
01486         }
01487       } else {
01488         if (unicharset.contains_unichar(ev->parameter)) {
01489           unichar_id = unicharset.unichar_to_id(ev->parameter);
01490           if (ev->command_id == IDA_ADAPTIVE) {
01491             *adaptive_on = true;
01492             *pretrained_on = false;
01493             *shape_id = -1;
01494           } else if (ev->command_id == IDA_STATIC) {
01495             *adaptive_on = false;
01496             *pretrained_on = true;
01497           } else {
01498             *adaptive_on = true;
01499             *pretrained_on = true;
01500           }
01501           if (ev->command_id == IDA_ADAPTIVE || shape_table_ == NULL) {
01502             *shape_id = -1;
01503             return unichar_id;
01504           }
01505           for (int s = 0; s < shape_table_->NumShapes(); ++s) {
01506             if (shape_table_->GetShape(s).ContainsUnichar(unichar_id)) {
01507               tprintf("%s\n", shape_table_->DebugStr(s).string());
01508             }
01509           }
01510         } else {
01511           tprintf("Char class '%s' not found in unicharset",
01512                   ev->parameter);
01513         }
01514       }
01515     }
01516     delete ev;
01517   } while (ev_type != SVET_CLICK);
01518   return 0;
01519 }                                /* GetClassToDebug */
01520 
01521 }  // namespace tesseract
01522 #endif
01523 
01524 /*---------------------------------------------------------------------------*/
01525 void GetCPPadsForLevel(int Level,
01526                        FLOAT32 *EndPad,
01527                        FLOAT32 *SidePad,
01528                        FLOAT32 *AnglePad) {
01529 /*
01530  ** Parameters:
01531  **   Level   "tightness" level to return pads for
01532  **   EndPad    place to put end pad for Level
01533  **   SidePad   place to put side pad for Level
01534  **   AnglePad  place to put angle pad for Level
01535  ** Globals: none
01536  ** Operation: This routine copies the appropriate global pad variables
01537  **   into EndPad, SidePad, and AnglePad.  This is a kludge used
01538  **   to get around the fact that global control variables cannot
01539  **   be arrays.  If the specified level is illegal, the tightest
01540  **   possible pads are returned.
01541  ** Return: none (results are returned in EndPad, SidePad, and AnglePad.
01542  ** Exceptions: none
01543  ** History: Thu Feb 14 08:26:49 1991, DSJ, Created.
01544  */
01545   switch (Level) {
01546     case 0:
01547       *EndPad = classify_cp_end_pad_loose * GetPicoFeatureLength ();
01548       *SidePad = classify_cp_side_pad_loose * GetPicoFeatureLength ();
01549       *AnglePad = classify_cp_angle_pad_loose / 360.0;
01550       break;
01551 
01552     case 1:
01553       *EndPad = classify_cp_end_pad_medium * GetPicoFeatureLength ();
01554       *SidePad = classify_cp_side_pad_medium * GetPicoFeatureLength ();
01555       *AnglePad = classify_cp_angle_pad_medium / 360.0;
01556       break;
01557 
01558     case 2:
01559       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
01560       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
01561       *AnglePad = classify_cp_angle_pad_tight / 360.0;
01562       break;
01563 
01564     default:
01565       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
01566       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
01567       *AnglePad = classify_cp_angle_pad_tight / 360.0;
01568       break;
01569   }
01570   if (*AnglePad > 0.5)
01571     *AnglePad = 0.5;
01572 
01573 }                                /* GetCPPadsForLevel */
01574 
01575 
01576 /*---------------------------------------------------------------------------*/
01577 ScrollView::Color GetMatchColorFor(FLOAT32 Evidence) {
01578 /*
01579  ** Parameters:
01580  **   Evidence  evidence value to return color for
01581  ** Globals: none
01582  ** Operation:
01583  ** Return: Color which corresponds to specified Evidence value.
01584  ** Exceptions: none
01585  ** History: Thu Mar 21 15:24:52 1991, DSJ, Created.
01586  */
01587 
01588   assert (Evidence >= 0.0);
01589   assert (Evidence <= 1.0);
01590 
01591   if (Evidence >= 0.90)
01592     return ScrollView::WHITE;
01593   else if (Evidence >= 0.75)
01594     return ScrollView::GREEN;
01595   else if (Evidence >= 0.50)
01596     return ScrollView::RED;
01597   else
01598     return ScrollView::BLUE;
01599 }                                /* GetMatchColorFor */
01600 
01601 
01602 /*---------------------------------------------------------------------------*/
01603 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill) {
01604 /*
01605  ** Parameters:
01606  **   Filler    filler to get next fill spec from
01607  **   Fill    place to put spec for next fill
01608  ** Globals: none
01609  ** Operation: This routine returns (in Fill) the specification of
01610  **   the next line to be filled from Filler.  FillerDone() should
01611  **   always be called before GetNextFill() to ensure that we
01612  **   do not run past the end of the fill table.
01613  ** Return: none (results are returned in Fill)
01614  ** Exceptions: none
01615  ** History: Tue Feb 19 10:17:42 1991, DSJ, Created.
01616  */
01617   FILL_SWITCH *Next;
01618 
01619   /* compute the fill assuming no switches will be encountered */
01620   Fill->AngleStart = Filler->AngleStart;
01621   Fill->AngleEnd = Filler->AngleEnd;
01622   Fill->X = Filler->X;
01623   Fill->YStart = Filler->YStart >> 8;
01624   Fill->YEnd = Filler->YEnd >> 8;
01625 
01626   /* update the fill info and the filler for ALL switches at this X value */
01627   Next = &(Filler->Switch[Filler->NextSwitch]);
01628   while (Filler->X >= Next->X) {
01629     Fill->X = Filler->X = Next->X;
01630     if (Next->Type == StartSwitch) {
01631       Fill->YStart = Next->Y;
01632       Filler->StartDelta = Next->Delta;
01633       Filler->YStart = Next->YInit;
01634     }
01635     else if (Next->Type == EndSwitch) {
01636       Fill->YEnd = Next->Y;
01637       Filler->EndDelta = Next->Delta;
01638       Filler->YEnd = Next->YInit;
01639     }
01640     else {                       /* Type must be LastSwitch */
01641       break;
01642     }
01643     Filler->NextSwitch++;
01644     Next = &(Filler->Switch[Filler->NextSwitch]);
01645   }
01646 
01647   /* prepare the filler for the next call to this routine */
01648   Filler->X++;
01649   Filler->YStart += Filler->StartDelta;
01650   Filler->YEnd += Filler->EndDelta;
01651 
01652 }                                /* GetNextFill */
01653 
01654 
01655 /*---------------------------------------------------------------------------*/
01671 void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
01672                       FLOAT32 AnglePad, PROTO Proto, TABLE_FILLER * Filler)
01673 #define XS          X_SHIFT
01674 #define YS          Y_SHIFT
01675 #define AS          ANGLE_SHIFT
01676 #define NB          NUM_CP_BUCKETS
01677 {
01678   FLOAT32 Angle;
01679   FLOAT32 X, Y, HalfLength;
01680   FLOAT32 Cos, Sin;
01681   FLOAT32 XAdjust, YAdjust;
01682   FPOINT Start, Switch1, Switch2, End;
01683   int S1 = 0;
01684   int S2 = 1;
01685 
01686   Angle = Proto->Angle;
01687   X = Proto->X;
01688   Y = Proto->Y;
01689   HalfLength = Proto->Length / 2.0;
01690 
01691   Filler->AngleStart = CircBucketFor(Angle - AnglePad, AS, NB);
01692   Filler->AngleEnd = CircBucketFor(Angle + AnglePad, AS, NB);
01693   Filler->NextSwitch = 0;
01694 
01695   if (fabs (Angle - 0.0) < HV_TOLERANCE || fabs (Angle - 0.5) < HV_TOLERANCE) {
01696     /* horizontal proto - handle as special case */
01697     Filler->X = BucketFor(X - HalfLength - EndPad, XS, NB);
01698     Filler->YStart = BucketFor(Y - SidePad, YS, NB * 256);
01699     Filler->YEnd = BucketFor(Y + SidePad, YS, NB * 256);
01700     Filler->StartDelta = 0;
01701     Filler->EndDelta = 0;
01702     Filler->Switch[0].Type = LastSwitch;
01703     Filler->Switch[0].X = BucketFor(X + HalfLength + EndPad, XS, NB);
01704   } else if (fabs(Angle - 0.25) < HV_TOLERANCE ||
01705            fabs(Angle - 0.75) < HV_TOLERANCE) {
01706     /* vertical proto - handle as special case */
01707     Filler->X = BucketFor(X - SidePad, XS, NB);
01708     Filler->YStart = BucketFor(Y - HalfLength - EndPad, YS, NB * 256);
01709     Filler->YEnd = BucketFor(Y + HalfLength + EndPad, YS, NB * 256);
01710     Filler->StartDelta = 0;
01711     Filler->EndDelta = 0;
01712     Filler->Switch[0].Type = LastSwitch;
01713     Filler->Switch[0].X = BucketFor(X + SidePad, XS, NB);
01714   } else {
01715     /* diagonal proto */
01716 
01717     if ((Angle > 0.0 && Angle < 0.25) || (Angle > 0.5 && Angle < 0.75)) {
01718       /* rising diagonal proto */
01719       Angle *= 2.0 * PI;
01720       Cos = fabs(cos(Angle));
01721       Sin = fabs(sin(Angle));
01722 
01723       /* compute the positions of the corners of the acceptance region */
01724       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
01725       Start.y = Y - (HalfLength + EndPad) * Sin + SidePad * Cos;
01726       End.x = 2.0 * X - Start.x;
01727       End.y = 2.0 * Y - Start.y;
01728       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
01729       Switch1.y = Y - (HalfLength + EndPad) * Sin - SidePad * Cos;
01730       Switch2.x = 2.0 * X - Switch1.x;
01731       Switch2.y = 2.0 * Y - Switch1.y;
01732 
01733       if (Switch1.x > Switch2.x) {
01734         S1 = 1;
01735         S2 = 0;
01736       }
01737 
01738       /* translate into bucket positions and deltas */
01739       Filler->X = (inT8) MapParam(Start.x, XS, NB);
01740       Filler->StartDelta = -(inT16) ((Cos / Sin) * 256);
01741       Filler->EndDelta = (inT16) ((Sin / Cos) * 256);
01742 
01743       XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
01744       YAdjust = XAdjust * Cos / Sin;
01745       Filler->YStart = (inT16) MapParam(Start.y - YAdjust, YS, NB * 256);
01746       YAdjust = XAdjust * Sin / Cos;
01747       Filler->YEnd = (inT16) MapParam(Start.y + YAdjust, YS, NB * 256);
01748 
01749       Filler->Switch[S1].Type = StartSwitch;
01750       Filler->Switch[S1].X = (inT8) MapParam(Switch1.x, XS, NB);
01751       Filler->Switch[S1].Y = (inT8) MapParam(Switch1.y, YS, NB);
01752       XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
01753       YAdjust = XAdjust * Sin / Cos;
01754       Filler->Switch[S1].YInit =
01755         (inT16) MapParam(Switch1.y - YAdjust, YS, NB * 256);
01756       Filler->Switch[S1].Delta = Filler->EndDelta;
01757 
01758       Filler->Switch[S2].Type = EndSwitch;
01759       Filler->Switch[S2].X = (inT8) MapParam(Switch2.x, XS, NB);
01760       Filler->Switch[S2].Y = (inT8) MapParam(Switch2.y, YS, NB);
01761       XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
01762       YAdjust = XAdjust * Cos / Sin;
01763       Filler->Switch[S2].YInit =
01764         (inT16) MapParam(Switch2.y + YAdjust, YS, NB * 256);
01765       Filler->Switch[S2].Delta = Filler->StartDelta;
01766 
01767       Filler->Switch[2].Type = LastSwitch;
01768       Filler->Switch[2].X = (inT8)MapParam(End.x, XS, NB);
01769     } else {
01770       /* falling diagonal proto */
01771       Angle *= 2.0 * PI;
01772       Cos = fabs(cos(Angle));
01773       Sin = fabs(sin(Angle));
01774 
01775       /* compute the positions of the corners of the acceptance region */
01776       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
01777       Start.y = Y + (HalfLength + EndPad) * Sin - SidePad * Cos;
01778       End.x = 2.0 * X - Start.x;
01779       End.y = 2.0 * Y - Start.y;
01780       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
01781       Switch1.y = Y + (HalfLength + EndPad) * Sin + SidePad * Cos;
01782       Switch2.x = 2.0 * X - Switch1.x;
01783       Switch2.y = 2.0 * Y - Switch1.y;
01784 
01785       if (Switch1.x > Switch2.x) {
01786         S1 = 1;
01787         S2 = 0;
01788       }
01789 
01790       /* translate into bucket positions and deltas */
01791       Filler->X = (inT8) MapParam(Start.x, XS, NB);
01792       Filler->StartDelta = -(inT16) ((Sin / Cos) * 256);
01793       Filler->EndDelta = (inT16) ((Cos / Sin) * 256);
01794 
01795       XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
01796       YAdjust = XAdjust * Sin / Cos;
01797       Filler->YStart = (inT16) MapParam(Start.y - YAdjust, YS, NB * 256);
01798       YAdjust = XAdjust * Cos / Sin;
01799       Filler->YEnd = (inT16) MapParam(Start.y + YAdjust, YS, NB * 256);
01800 
01801       Filler->Switch[S1].Type = EndSwitch;
01802       Filler->Switch[S1].X = (inT8) MapParam(Switch1.x, XS, NB);
01803       Filler->Switch[S1].Y = (inT8) MapParam(Switch1.y, YS, NB);
01804       XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
01805       YAdjust = XAdjust * Sin / Cos;
01806       Filler->Switch[S1].YInit =
01807         (inT16) MapParam(Switch1.y + YAdjust, YS, NB * 256);
01808       Filler->Switch[S1].Delta = Filler->StartDelta;
01809 
01810       Filler->Switch[S2].Type = StartSwitch;
01811       Filler->Switch[S2].X = (inT8) MapParam(Switch2.x, XS, NB);
01812       Filler->Switch[S2].Y = (inT8) MapParam(Switch2.y, YS, NB);
01813       XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
01814       YAdjust = XAdjust * Cos / Sin;
01815       Filler->Switch[S2].YInit =
01816         (inT16) MapParam(Switch2.y - YAdjust, YS, NB * 256);
01817       Filler->Switch[S2].Delta = Filler->EndDelta;
01818 
01819       Filler->Switch[2].Type = LastSwitch;
01820       Filler->Switch[2].X = (inT8) MapParam(End.x, XS, NB);
01821     }
01822   }
01823 }                                /* InitTableFiller */
01824 
01825 
01826 /*---------------------------------------------------------------------------*/
01827 #ifndef GRAPHICS_DISABLED
01828 /*
01829  * Parameters:
01830  *   ShapeList shape list to add feature rendering to
01831  *   Feature   feature to be rendered
01832  *   Color   color to use for feature rendering
01833  * Globals: none
01834  * Operation: This routine renders the specified feature into ShapeList.
01835  * Return: New shape list with rendering of Feature added.
01836  * @note Exceptions: none
01837  * @note History: Thu Mar 21 14:57:41 1991, DSJ, Created.
01838  */
01839 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT* Feature,
01840                       ScrollView::Color color) {
01841   FLOAT32 X, Y, Dx, Dy, Length;
01842 
01843   window->Pen(color);
01844   assert(Feature != NULL);
01845   assert(color != 0);
01846 
01847   X = Feature->X;
01848   Y = Feature->Y;
01849   Length = GetPicoFeatureLength() * 0.7 * INT_CHAR_NORM_RANGE;
01850   // The -PI has no significant effect here, but the value of Theta is computed
01851   // using BinaryAnglePlusPi in intfx.cpp.
01852   Dx = (Length / 2.0) * cos((Feature->Theta / 256.0) * 2.0 * PI - PI);
01853   Dy = (Length / 2.0) * sin((Feature->Theta / 256.0) * 2.0 * PI - PI);
01854 
01855   window->SetCursor(X, Y);
01856   window->DrawTo(X + Dx, Y + Dy);
01857 }                                /* RenderIntFeature */
01858 
01859 
01860 /*---------------------------------------------------------------------------*/
01861 /*
01862  * This routine extracts the parameters of the specified
01863  * proto from the class description and adds a rendering of
01864  * the proto onto the ShapeList.
01865  *
01866  * @param Class   class that proto is contained in
01867  * @param ProtoId   id of proto to be rendered
01868  * @param color   color to render proto in
01869  *
01870  * Globals: none
01871  *
01872  * @return New shape list with a rendering of one proto added.
01873  * @note Exceptions: none
01874  * @note History: Thu Mar 21 10:21:09 1991, DSJ, Created.
01875  */
01876 void RenderIntProto(ScrollView *window,
01877                     INT_CLASS Class,
01878                     PROTO_ID ProtoId,
01879                     ScrollView::Color color) {
01880   PROTO_SET ProtoSet;
01881   INT_PROTO Proto;
01882   int ProtoSetIndex;
01883   int ProtoWordIndex;
01884   FLOAT32 Length;
01885   int Xmin, Xmax, Ymin, Ymax;
01886   FLOAT32 X, Y, Dx, Dy;
01887   uinT32 ProtoMask;
01888   int Bucket;
01889 
01890   assert(ProtoId >= 0);
01891   assert(Class != NULL);
01892   assert(ProtoId < Class->NumProtos);
01893   assert(color != 0);
01894   window->Pen(color);
01895 
01896   ProtoSet = Class->ProtoSets[SetForProto(ProtoId)];
01897   ProtoSetIndex = IndexForProto(ProtoId);
01898   Proto = &(ProtoSet->Protos[ProtoSetIndex]);
01899   Length = (Class->ProtoLengths[ProtoId] *
01900     GetPicoFeatureLength() * INT_CHAR_NORM_RANGE);
01901   ProtoMask = PPrunerMaskFor(ProtoId);
01902   ProtoWordIndex = PPrunerWordIndexFor(ProtoId);
01903 
01904   // find the x and y extent of the proto from the proto pruning table
01905   Xmin = Ymin = NUM_PP_BUCKETS;
01906   Xmax = Ymax = 0;
01907   for (Bucket = 0; Bucket < NUM_PP_BUCKETS; Bucket++) {
01908     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_X][Bucket][ProtoWordIndex]) {
01909       UpdateRange(Bucket, &Xmin, &Xmax);
01910     }
01911 
01912     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_Y][Bucket][ProtoWordIndex]) {
01913       UpdateRange(Bucket, &Ymin, &Ymax);
01914     }
01915   }
01916   X = (Xmin + Xmax + 1) / 2.0 * PROTO_PRUNER_SCALE;
01917   Y = (Ymin + Ymax + 1) / 2.0 * PROTO_PRUNER_SCALE;
01918   // The -PI has no significant effect here, but the value of Theta is computed
01919   // using BinaryAnglePlusPi in intfx.cpp.
01920   Dx = (Length / 2.0) * cos((Proto->Angle / 256.0) * 2.0 * PI - PI);
01921   Dy = (Length / 2.0) * sin((Proto->Angle / 256.0) * 2.0 * PI - PI);
01922 
01923   window->SetCursor(X - Dx, Y - Dy);
01924   window->DrawTo(X + Dx, Y + Dy);
01925 }                                /* RenderIntProto */
01926 #endif
01927 
01928 /*---------------------------------------------------------------------------*/
01944 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id) {
01945   if (Param < Min) {
01946     if (Id)
01947       cprintf("Warning: Param %s truncated from %f to %d!\n",
01948               Id, Param, Min);
01949     Param = Min;
01950   } else if (Param > Max) {
01951     if (Id)
01952       cprintf("Warning: Param %s truncated from %f to %d!\n",
01953               Id, Param, Max);
01954     Param = Max;
01955   }
01956   return static_cast<int>(floor(Param));
01957 }                                /* TruncateParam */
01958 
01959 
01960 /*---------------------------------------------------------------------------*/
01961 #ifndef GRAPHICS_DISABLED
01962 
01966 void InitIntMatchWindowIfReqd() {
01967   if (IntMatchWindow == NULL) {
01968     IntMatchWindow = CreateFeatureSpaceWindow("IntMatchWindow", 50, 200);
01969     SVMenuNode* popup_menu = new SVMenuNode();
01970 
01971     popup_menu->AddChild("Debug Adapted classes", IDA_ADAPTIVE,
01972                          "x", "Class to debug");
01973     popup_menu->AddChild("Debug Static classes", IDA_STATIC,
01974                          "x", "Class to debug");
01975     popup_menu->AddChild("Debug Both", IDA_BOTH,
01976                          "x", "Class to debug");
01977     popup_menu->AddChild("Debug Shape Index", IDA_SHAPE_INDEX,
01978                          "0", "Index to debug");
01979     popup_menu->BuildMenu(IntMatchWindow, false);
01980   }
01981 }
01982 
01987 void InitProtoDisplayWindowIfReqd() {
01988   if (ProtoDisplayWindow == NULL) {
01989     ProtoDisplayWindow = CreateFeatureSpaceWindow("ProtoDisplayWindow",
01990                                                   550, 200);
01991  }
01992 }
01993 
01998 void InitFeatureDisplayWindowIfReqd() {
01999   if (FeatureDisplayWindow == NULL) {
02000     FeatureDisplayWindow = CreateFeatureSpaceWindow("FeatureDisplayWindow",
02001                                                     50, 700);
02002   }
02003 }
02004 
02005 // Creates a window of the appropriate size for displaying elements
02006 // in feature space.
02007 ScrollView* CreateFeatureSpaceWindow(const char* name, int xpos, int ypos) {
02008   return new ScrollView(name, xpos, ypos, 520, 520, 260, 260, true);
02009 }
02010 #endif  // GRAPHICS_DISABLED
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines