tesseract
3.03
|
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