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