• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  **	Filename:    intproto.c
3  **	Purpose:     Definition of data structures for integer protos.
4  **	Author:      Dan Johnson
5  **	History:     Thu Feb  7 14:38:16 1991, DSJ, Created.
6  **
7  **	(c) Copyright Hewlett-Packard Company, 1988.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  ******************************************************************************/
18 /**----------------------------------------------------------------------------
19           Include Files and Type Defines
20 ----------------------------------------------------------------------------**/
21 #include "intproto.h"
22 #include "picofeat.h"
23 #include "mfoutline.h"
24 #include "emalloc.h"
25 #include "const.h"
26 #include "ndminx.h"
27 #include "svmnode.h"
28 #include "adaptmatch.h"
29 #include "globals.h"
30 #include "classify.h"
31 #include "genericvector.h"
32 
33 //extern GetPicoFeatureLength();
34 
35 #include <math.h>
36 #include <stdio.h>
37 #include <assert.h>
38 #ifdef __UNIX__
39 #include <unistd.h>
40 #endif
41 
42 /* match debug display constants*/
43 #define DISPLAY_OFFSET  (0.5  * INT_CHAR_NORM_RANGE)
44 #define PROTO_PRUNER_SCALE  (4.0)
45 
46 #define INT_DESCENDER (0.0  * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
47 #define INT_BASELINE  (0.25 * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
48 #define INT_XHEIGHT (0.75 * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
49 #define INT_CAPHEIGHT (1.0  * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
50 
51 #define INT_XCENTER (0.5  * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
52 #define INT_YCENTER (0.5  * INT_CHAR_NORM_RANGE - DISPLAY_OFFSET)
53 #define INT_XRADIUS (0.2  * INT_CHAR_NORM_RANGE)
54 #define INT_YRADIUS (0.2  * INT_CHAR_NORM_RANGE)
55 #define INT_MIN_X (- DISPLAY_OFFSET)
56 #define INT_MIN_Y (- DISPLAY_OFFSET)
57 #define INT_MAX_X (  DISPLAY_OFFSET)
58 #define INT_MAX_Y (  DISPLAY_OFFSET)
59 #define DOUBLE_OFFSET 0.095
60 
61 /* define pad used to snap near horiz/vertical protos to horiz/vertical */
62 #define HV_TOLERANCE  (0.0025)   /* approx 0.9 degrees */
63 
64 typedef enum
65 { StartSwitch, EndSwitch, LastSwitch }
66 SWITCH_TYPE;
67 #define MAX_NUM_SWITCHES  3
68 
69 typedef struct
70 {
71   SWITCH_TYPE Type;
72   inT8 X, Y;
73   inT16 YInit;
74   inT16 Delta;
75 }
76 
77 
78 FILL_SWITCH;
79 
80 typedef struct
81 {
82   uinT8 NextSwitch;
83   uinT8 AngleStart, AngleEnd;
84   inT8 X;
85   inT16 YStart, YEnd;
86   inT16 StartDelta, EndDelta;
87   FILL_SWITCH Switch[MAX_NUM_SWITCHES];
88 }
89 
90 
91 TABLE_FILLER;
92 
93 typedef struct
94 {
95   inT8 X;
96   inT8 YStart, YEnd;
97   uinT8 AngleStart, AngleEnd;
98 }
99 
100 
101 FILL_SPEC;
102 
103 
104 /* constants for conversion from old inttemp format */
105 #define OLD_MAX_NUM_CONFIGS      32
106 #define OLD_WERDS_PER_CONFIG_VEC ((OLD_MAX_NUM_CONFIGS + BITS_PER_WERD - 1) /\
107                                   BITS_PER_WERD)
108 
109 /**----------------------------------------------------------------------------
110             Macros
111 ----------------------------------------------------------------------------**/
112 /* macro for performing circular increments of bucket indices */
113 #define CircularIncrement(i,r)  (((i) < (r) - 1)?((i)++):((i) = 0))
114 
115 /* macro for mapping floats to ints without bounds checking */
116 #define MapParam(P,O,N)   (floor (((P) + (O)) * (N)))
117 
118 /*---------------------------------------------------------------------------
119             Private Function Prototypes
120 ----------------------------------------------------------------------------*/
121 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets);
122 
123 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets);
124 
125 void DoFill(FILL_SPEC *FillSpec,
126             CLASS_PRUNER Pruner,
127             register uinT32 ClassMask,
128             register uinT32 ClassCount,
129             register uinT32 WordIndex);
130 
131 BOOL8 FillerDone(TABLE_FILLER *Filler);
132 
133 void FillPPCircularBits (uinT32
134                          ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
135                          int Bit, FLOAT32 Center, FLOAT32 Spread);
136 
137 void FillPPLinearBits (uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
138                        int Bit, FLOAT32 Center, FLOAT32 Spread);
139 
140 #ifndef GRAPHICS_DISABLED
141 CLASS_ID GetClassToDebug(const char *Prompt);
142 #endif
143 
144 void GetCPPadsForLevel(int Level,
145                        FLOAT32 *EndPad,
146                        FLOAT32 *SidePad,
147                        FLOAT32 *AnglePad);
148 
149 C_COL GetMatchColorFor(FLOAT32 Evidence);
150 
151 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill);
152 
153 void InitTableFiller(FLOAT32 EndPad,
154                      FLOAT32 SidePad,
155                      FLOAT32 AnglePad,
156                      PROTO Proto,
157                      TABLE_FILLER *Filler);
158 
159 #ifndef GRAPHICS_DISABLED
160 void RenderIntFeature(void *window, INT_FEATURE Feature, C_COL Color);
161 
162 void RenderIntProto(void *window,
163                     INT_CLASS Class,
164                     PROTO_ID ProtoId,
165                     C_COL Color);
166 #endif
167 
168 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id);
169 
170 /**----------------------------------------------------------------------------
171         Global Data Definitions and Declarations
172 ----------------------------------------------------------------------------**/
173 
174 /* global display lists used to display proto and feature match information*/
175 ScrollView *IntMatchWindow = NULL;
176 ScrollView *FeatureDisplayWindow = NULL;
177 ScrollView *ProtoDisplayWindow = NULL;
178 
179 /**----------------------------------------------------------------------------
180         Variables
181 ----------------------------------------------------------------------------**/
182 
183 /* control knobs */
184 INT_VAR(classify_num_cp_levels, 3, "Number of Class Pruner Levels");
185 double_VAR(classify_cp_angle_pad_loose, 45.0,
186            "Class Pruner Angle Pad Loose");
187 double_VAR(classify_cp_angle_pad_medium, 20.0,
188            "Class Pruner Angle Pad Medium");
189 double_VAR(classify_cp_angle_pad_tight, 10.0,
190            "CLass Pruner Angle Pad Tight");
191 double_VAR(classify_cp_end_pad_loose, 0.5, "Class Pruner End Pad Loose");
192 double_VAR(classify_cp_end_pad_medium, 0.5, "Class Pruner End Pad Medium");
193 double_VAR(classify_cp_end_pad_tight, 0.5, "Class Pruner End Pad Tight");
194 double_VAR(classify_cp_side_pad_loose, 2.5, "Class Pruner Side Pad Loose");
195 double_VAR(classify_cp_side_pad_medium, 1.2, "Class Pruner Side Pad Medium");
196 double_VAR(classify_cp_side_pad_tight, 0.6, "Class Pruner Side Pad Tight");
197 double_VAR(classify_pp_angle_pad, 45.0, "Proto Pruner Angle Pad");
198 double_VAR(classify_pp_end_pad, 0.5, "Proto Prune End Pad");
199 double_VAR(classify_pp_side_pad, 2.5, "Proto Pruner Side Pad");
200 
201 /**----------------------------------------------------------------------------
202               Public Code
203 ----------------------------------------------------------------------------**/
204 /*---------------------------------------------------------------------------*/
AddIntClass(INT_TEMPLATES Templates,CLASS_ID ClassId,INT_CLASS Class)205 void AddIntClass(INT_TEMPLATES Templates, CLASS_ID ClassId, INT_CLASS Class) {
206 /*
207  **	Parameters:
208  **		Templates	templates to add new class to
209  **		ClassId		class id to associate new class with
210  **		Class		class data structure to add to templates
211  **	Globals: none
212  **	Operation: This routine adds a new class structure to a set of
213  **                templates. Classes have to be added to Templates in
214  **                the order of increasing ClassIds.
215  **	Return: none
216  **	Exceptions: none
217  **	History: Mon Feb 11 11:52:08 1991, DSJ, Created.
218  */
219   int Pruner;
220   uinT32 *Word;
221 
222   assert (LegalClassId (ClassId));
223   if (ClassId != Templates->NumClasses) {
224     fprintf(stderr, "Please make sure that classes are added to templates");
225     fprintf(stderr, " in increasing order of ClassIds\n");
226     exit(1);
227   }
228   ClassForClassId (Templates, ClassId) = Class;
229   Templates->NumClasses++;
230 
231   if (Templates->NumClasses > MaxNumClassesIn (Templates)) {
232     Pruner = Templates->NumClassPruners++;
233     Templates->ClassPruner[Pruner] =
234       (CLASS_PRUNER) Emalloc (sizeof (CLASS_PRUNER_STRUCT));
235 
236     for (Word = reinterpret_cast<uinT32*>(Templates->ClassPruner[Pruner]);
237          Word < reinterpret_cast<uinT32*>(Templates->ClassPruner[Pruner]) +
238                 WERDS_PER_CP;
239          *Word++ = 0);
240   }
241 }                                /* AddIntClass */
242 
243 
244 /*---------------------------------------------------------------------------*/
AddIntConfig(INT_CLASS Class)245 int AddIntConfig(INT_CLASS Class) {
246 /*
247  **	Parameters:
248  **		Class	class to add new configuration to
249  **	Globals: none
250  **	Operation: This routine returns the index of the next free config
251  **		in Class.
252  **	Return: Index of next free config.
253  **	Exceptions: none
254  **	History: Mon Feb 11 14:44:40 1991, DSJ, Created.
255  */
256   int Index;
257 
258   assert(Class->NumConfigs < MAX_NUM_CONFIGS);
259 
260   Index = Class->NumConfigs++;
261   Class->ConfigLengths[Index] = 0;
262   return Index;
263 }                                /* AddIntConfig */
264 
265 
266 /*---------------------------------------------------------------------------*/
AddIntProto(INT_CLASS Class)267 int AddIntProto(INT_CLASS Class) {
268 /*
269  **	Parameters:
270  **		Class	class to add new proto to
271  **	Globals: none
272  **	Operation: This routine allocates the next free proto in Class and
273  **		returns its index.
274  **	Return: Proto index of new proto.
275  **	Exceptions: none
276  **	History: Mon Feb 11 13:26:41 1991, DSJ, Created.
277  */
278   int Index;
279   int ProtoSetId;
280   PROTO_SET ProtoSet;
281   INT_PROTO Proto;
282   register uinT32 *Word;
283 
284   if (Class->NumProtos >= MAX_NUM_PROTOS)
285     return (NO_PROTO);
286 
287   Index = Class->NumProtos++;
288 
289   if (Class->NumProtos > MaxNumIntProtosIn(Class)) {
290     ProtoSetId = Class->NumProtoSets++;
291 
292     ProtoSet = (PROTO_SET) Emalloc (sizeof (PROTO_SET_STRUCT));
293     Class->ProtoSets[ProtoSetId] = ProtoSet;
294     for (Word = reinterpret_cast<uinT32*>(ProtoSet->ProtoPruner);
295          Word < reinterpret_cast<uinT32*>(ProtoSet->ProtoPruner) + WERDS_PER_PP;
296          *Word++ = 0);
297 
298     /* reallocate space for the proto lengths and install in class */
299     Class->ProtoLengths =
300       (uinT8 *)Erealloc(Class->ProtoLengths,
301                         MaxNumIntProtosIn(Class) * sizeof(uinT8));
302   }
303 
304   /* initialize proto so its length is zero and it isn't in any configs */
305   Class->ProtoLengths[Index] = 0;
306   Proto = ProtoForProtoId (Class, Index);
307   for (Word = Proto->Configs;
308        Word < Proto->Configs + WERDS_PER_CONFIG_VEC; *Word++ = 0);
309 
310   return (Index);
311 
312 }                                /* AddIntProto */
313 
314 
315 /*---------------------------------------------------------------------------*/
AddProtoToClassPruner(PROTO Proto,CLASS_ID ClassId,INT_TEMPLATES Templates)316 void AddProtoToClassPruner (PROTO Proto, CLASS_ID ClassId,
317                             INT_TEMPLATES Templates)
318 /*
319  **	Parameters:
320  **		Proto		floating-pt proto to add to class pruner
321  **		ClassId		class id corresponding to Proto
322  **		Templates	set of templates containing class pruner
323  **	Globals:
324  **   classify_num_cp_levels number of levels used in the class pruner
325  **	Operation: This routine adds Proto to the class pruning tables
326  **		for the specified class in Templates.
327  **	Return: none
328  **	Exceptions: none
329  **	History: Wed Feb 13 08:49:54 1991, DSJ, Created.
330  */
331 #define MAX_LEVEL     2
332 {
333   CLASS_PRUNER Pruner;
334   uinT32 ClassMask;
335   uinT32 ClassCount;
336   uinT32 WordIndex;
337   int Level;
338   FLOAT32 EndPad, SidePad, AnglePad;
339   TABLE_FILLER TableFiller;
340   FILL_SPEC FillSpec;
341 
342   Pruner = CPrunerFor (Templates, ClassId);
343   WordIndex = CPrunerWordIndexFor (ClassId);
344   ClassMask = CPrunerMaskFor (MAX_LEVEL, ClassId);
345 
346   for (Level = classify_num_cp_levels - 1; Level >= 0; Level--) {
347     GetCPPadsForLevel(Level, &EndPad, &SidePad, &AnglePad);
348     ClassCount = CPrunerMaskFor (Level, ClassId);
349     InitTableFiller(EndPad, SidePad, AnglePad, Proto, &TableFiller);
350 
351     while (!FillerDone (&TableFiller)) {
352       GetNextFill(&TableFiller, &FillSpec);
353       DoFill(&FillSpec, Pruner, ClassMask, ClassCount, WordIndex);
354     }
355   }
356 }                                /* AddProtoToClassPruner */
357 
358 
359 /*---------------------------------------------------------------------------*/
AddProtoToProtoPruner(PROTO Proto,int ProtoId,INT_CLASS Class)360 void AddProtoToProtoPruner(PROTO Proto, int ProtoId, INT_CLASS Class) {
361 /*
362  **	Parameters:
363  **		Proto	floating-pt proto to be added to proto pruner
364  **		ProtoId	id of proto
365  **		Class	integer class that contains desired proto pruner
366  **	Globals: none
367  **	Operation: This routine updates the proto pruner lookup tables
368  **		for Class to include a new proto identified by ProtoId
369  **		and described by Proto.
370  **	Return: none
371  **	Exceptions: none
372  **	History: Fri Feb  8 13:07:19 1991, DSJ, Created.
373  */
374   FLOAT32 Angle, X, Y, Length;
375   FLOAT32 Pad;
376   int Index;
377   PROTO_SET ProtoSet;
378 
379   if (ProtoId >= Class->NumProtos)
380     cprintf ("AddProtoToProtoPruner:assert failed: %d < %d",
381             ProtoId, Class->NumProtos);
382   assert(ProtoId < Class->NumProtos);
383 
384   Index = IndexForProto (ProtoId);
385   ProtoSet = Class->ProtoSets[SetForProto (ProtoId)];
386 
387   Angle = Proto->Angle;
388 #ifndef __MSW32__
389   assert (!isnan(Angle));
390 #endif
391 
392   FillPPCircularBits (ProtoSet->ProtoPruner[PRUNER_ANGLE], Index,
393                       Angle + ANGLE_SHIFT, classify_pp_angle_pad / 360.0);
394 
395   Angle *= 2.0 * PI;
396   Length = Proto->Length;
397 
398   X = Proto->X + X_SHIFT;
399   Pad = MAX (fabs (cos (Angle)) * (Length / 2.0 +
400                                    classify_pp_end_pad *
401                                    GetPicoFeatureLength ()),
402              fabs (sin (Angle)) * (classify_pp_side_pad *
403                                    GetPicoFeatureLength ()));
404 
405   FillPPLinearBits (ProtoSet->ProtoPruner[PRUNER_X], Index, X, Pad);
406 
407   Y = Proto->Y + Y_SHIFT;
408   Pad = MAX (fabs (sin (Angle)) * (Length / 2.0 +
409                                    classify_pp_end_pad *
410                                    GetPicoFeatureLength ()),
411              fabs (cos (Angle)) * (classify_pp_side_pad *
412                                    GetPicoFeatureLength ()));
413 
414   FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_Y], Index, Y, Pad);
415 }                                /* AddProtoToProtoPruner */
416 
417 
418 /*---------------------------------------------------------------------------*/
BucketFor(FLOAT32 Param,FLOAT32 Offset,int NumBuckets)419 int BucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
420 /*
421  **	Parameters:
422  **		Param		parameter value to map into a bucket number
423  **		Offset		amount to shift param before mapping it
424  **		NumBuckets	number of buckets to map param into
425  **	Globals: none
426  **	Operation: This routine maps a parameter value into a bucket between
427  **		0 and NumBuckets-1.  Offset is added to the parameter
428  **		before mapping it.  Values which map to buckets outside
429  **		the range are truncated to fit within the range.  Mapping
430  **		is done by truncating rather than rounding.
431  **	Return: Bucket number corresponding to Param + Offset.
432  **	Exceptions: none
433  **	History: Thu Feb 14 13:24:33 1991, DSJ, Created.
434  */
435   int Bucket;
436 
437   Bucket = static_cast<int>(MapParam(Param, Offset, NumBuckets));
438   if (Bucket < 0)
439     Bucket = 0;
440   else if (Bucket >= NumBuckets)
441     Bucket = NumBuckets - 1;
442   return (Bucket);
443 }                                /* BucketFor */
444 
445 
446 /*---------------------------------------------------------------------------*/
CircBucketFor(FLOAT32 Param,FLOAT32 Offset,int NumBuckets)447 int CircBucketFor(FLOAT32 Param, FLOAT32 Offset, int NumBuckets) {
448 /*
449  **	Parameters:
450  **		Param		parameter value to map into a circular bucket
451  **		Offset		amount to shift param before mapping it
452  **		NumBuckets	number of buckets to map param into
453  **	Globals: none
454  **	Operation: This routine maps a parameter value into a bucket between
455  **		0 and NumBuckets-1.  Offset is added to the parameter
456  **		before mapping it.  Values which map to buckets outside
457  **		the range are wrapped to a new value in a circular fashion.
458  **		Mapping is done by truncating rather than rounding.
459  **	Return: Bucket number corresponding to Param + Offset.
460  **	Exceptions: none
461  **	History: Thu Feb 14 13:24:33 1991, DSJ, Created.
462  */
463   int Bucket;
464 
465   Bucket = static_cast<int>(MapParam(Param, Offset, NumBuckets));
466   if (Bucket < 0)
467     Bucket += NumBuckets;
468   else if (Bucket >= NumBuckets)
469     Bucket -= NumBuckets;
470   return Bucket;
471 }                                /* CircBucketFor */
472 
473 
474 /*---------------------------------------------------------------------------*/
475 #ifndef GRAPHICS_DISABLED
UpdateMatchDisplay()476 void UpdateMatchDisplay() {
477 /*
478  **	Parameters: none
479  **	Globals:
480  **		FeatureShapes	display list for features
481  **		ProtoShapes	display list for protos
482  **	Operation: This routine clears the global feature and proto
483  **		display lists.
484  **	Return: none
485  **	Exceptions: none
486  **	History: Thu Mar 21 15:40:19 1991, DSJ, Created.
487  */
488   if (IntMatchWindow != NULL)
489     c_make_current(IntMatchWindow);
490 }                                /* ClearMatchDisplay */
491 #endif
492 
493 /*---------------------------------------------------------------------------*/
ConvertConfig(BIT_VECTOR Config,int ConfigId,INT_CLASS Class)494 void ConvertConfig(BIT_VECTOR Config, int ConfigId, INT_CLASS Class) {
495 /*
496  **	Parameters:
497  **		Config		config to be added to class
498  **		ConfigId	id to be used for new config
499  **		Class		class to add new config to
500  **	Globals: none
501  **	Operation: This operation updates the config vectors of all protos
502  **		in Class to indicate that the protos with 1's in Config
503  **		belong to a new configuration identified by ConfigId.
504  **		It is assumed that the length of the Config bit vector is
505  **		equal to the number of protos in Class.
506  **	Return: none
507  **	Exceptions: none
508  **	History: Mon Feb 11 14:57:31 1991, DSJ, Created.
509  */
510   int ProtoId;
511   INT_PROTO Proto;
512   int TotalLength;
513 
514   for (ProtoId = 0, TotalLength = 0;
515     ProtoId < Class->NumProtos; ProtoId++) {
516     if (test_bit (Config, ProtoId)) {
517       Proto = ProtoForProtoId (Class, ProtoId);
518       SET_BIT (Proto->Configs, ConfigId);
519       TotalLength += Class->ProtoLengths[ProtoId];
520     }
521   }
522   Class->ConfigLengths[ConfigId] = TotalLength;
523 }                                /* ConvertConfig */
524 
525 
526 /*---------------------------------------------------------------------------*/
ConvertProto(PROTO Proto,int ProtoId,INT_CLASS Class)527 void ConvertProto(PROTO Proto, int ProtoId, INT_CLASS Class) {
528 /*
529  **	Parameters:
530  **		Proto	floating-pt proto to be converted to integer format
531  **		ProtoId	id of proto
532  **		Class	integer class to add converted proto to
533  **	Globals: none
534  **	Operation: This routine converts Proto to integer format and
535  **		installs it as ProtoId in Class.
536  **	Return: none
537  **	Exceptions: none
538  **	History: Fri Feb  8 11:22:43 1991, DSJ, Created.
539  */
540   INT_PROTO P;
541   FLOAT32 Param;
542 
543   assert(ProtoId < Class->NumProtos);
544 
545   P = ProtoForProtoId (Class, ProtoId);
546 
547   Param = Proto->A * 128;
548   P->A = TruncateParam (Param, -128, 127, NULL);
549 
550   Param = -Proto->B * 256;
551   P->B = TruncateParam (Param, 0, 255, NULL);
552 
553   Param = Proto->C * 128;
554   P->C = TruncateParam (Param, -128, 127, NULL);
555 
556   Param = Proto->Angle * 256;
557   if (Param < 0 || Param >= 256)
558     P->Angle = 0;
559   else
560     P->Angle = (uinT8) Param;
561 
562   /* round proto length to nearest integer number of pico-features */
563   Param = (Proto->Length / GetPicoFeatureLength()) + 0.5;
564   Class->ProtoLengths[ProtoId] = TruncateParam(Param, 1, 255, NULL);
565   if (classify_learning_debug_level >= 2)
566     cprintf ("Converted ffeat to (A=%d,B=%d,C=%d,L=%d)",
567             P->A, P->B, P->C, Class->ProtoLengths[ProtoId]);
568 }                                /* ConvertProto */
569 
570 
571 /*---------------------------------------------------------------------------*/
572 namespace tesseract {
CreateIntTemplates(CLASSES FloatProtos,const UNICHARSET & target_unicharset)573 INT_TEMPLATES Classify::CreateIntTemplates(CLASSES FloatProtos,
574                                            const UNICHARSET&
575                                            target_unicharset) {
576 /*
577  **	Parameters:
578  **		FloatProtos	prototypes in old floating pt format
579  **	Globals: none
580  **	Operation: This routine converts from the old floating point format
581  **		to the new integer format.
582  **	Return: New set of training templates in integer format.
583  **	Exceptions: none
584  **	History: Thu Feb  7 14:40:42 1991, DSJ, Created.
585  */
586   INT_TEMPLATES IntTemplates;
587   CLASS_TYPE FClass;
588   INT_CLASS IClass;
589   int ClassId;
590   int ProtoId;
591   int ConfigId;
592 
593   IntTemplates = NewIntTemplates ();
594 
595   for (ClassId = 0; ClassId < target_unicharset.size(); ClassId++) {
596     FClass = &(FloatProtos[ClassId]);
597     if (FClass->NumProtos == 0 && FClass->NumConfigs == 0 &&
598         strcmp(target_unicharset.id_to_unichar(ClassId), " ") != 0) {
599       cprintf("Warning: no protos/configs for %s in CreateIntTemplates()\n",
600               target_unicharset.id_to_unichar(ClassId));
601     }
602     assert (UnusedClassIdIn (IntTemplates, ClassId));
603     IClass = NewIntClass(FClass->NumProtos, FClass->NumConfigs);
604     FontSet fs;
605     fs.size = FClass->font_set.size();
606     fs.configs = new int[fs.size];
607     for (int i = 0; i < fs.size; ++i) {
608       fs.configs[i] = FClass->font_set.get(i);
609     }
610     if (this->fontset_table_.contains(fs)) {
611       IClass->font_set_id = this->fontset_table_.get_id(fs);
612       delete[] fs.configs;
613     } else {
614       IClass->font_set_id = this->fontset_table_.push_back(fs);
615     }
616     AddIntClass(IntTemplates, ClassId, IClass);
617 
618     for (ProtoId = 0; ProtoId < FClass->NumProtos; ProtoId++) {
619       AddIntProto(IClass);
620       ConvertProto (ProtoIn (FClass, ProtoId), ProtoId, IClass);
621       AddProtoToProtoPruner (ProtoIn (FClass, ProtoId), ProtoId, IClass);
622       AddProtoToClassPruner (ProtoIn (FClass, ProtoId), ClassId, IntTemplates);
623     }
624 
625     for (ConfigId = 0; ConfigId < FClass->NumConfigs; ConfigId++) {
626       AddIntConfig(IClass);
627       ConvertConfig(FClass->Configurations[ConfigId], ConfigId, IClass);
628     }
629   }
630   return (IntTemplates);
631 }                                /* CreateIntTemplates */
632 }  // namespace tesseract
633 
634 
635 /*---------------------------------------------------------------------------*/
636 #ifndef GRAPHICS_DISABLED
DisplayIntFeature(INT_FEATURE Feature,FLOAT32 Evidence)637 void DisplayIntFeature(INT_FEATURE Feature, FLOAT32 Evidence) {
638 /*
639  **	Parameters:
640  **		Feature		pico-feature to be displayed
641  **		Evidence	best evidence for this feature (0-1)
642  **	Globals:
643  **		FeatureShapes	global display list for features
644  **	Operation: This routine renders the specified feature into a
645  **		global display list.
646  **	Return: none
647  **	Exceptions: none
648  **	History: Thu Mar 21 14:45:04 1991, DSJ, Created.
649  */
650   C_COL Color;
651 
652   Color = GetMatchColorFor (Evidence);
653   RenderIntFeature(IntMatchWindow, Feature, Color);
654   if (FeatureDisplayWindow) {
655     RenderIntFeature(FeatureDisplayWindow, Feature, Color);
656   }
657 }                                /* DisplayIntFeature */
658 
659 
660 /*---------------------------------------------------------------------------*/
DisplayIntProto(INT_CLASS Class,PROTO_ID ProtoId,FLOAT32 Evidence)661 void DisplayIntProto(INT_CLASS Class, PROTO_ID ProtoId, FLOAT32 Evidence) {
662 /*
663  **	Parameters:
664  **		Class		class to take proto from
665  **		ProtoId		id of proto in Class to be displayed
666  **		Evidence	total evidence for proto (0-1)
667  **	Globals:
668  **		ProtoShapes	global display list for protos
669  **	Operation: This routine renders the specified proto into a
670  **		global display list.
671  **	Return: none
672  **	Exceptions: none
673  **	History: Thu Mar 21 14:45:04 1991, DSJ, Created.
674  */
675   C_COL Color;
676 
677   Color = GetMatchColorFor (Evidence);
678   RenderIntProto(IntMatchWindow, Class, ProtoId, Color);
679   if (ProtoDisplayWindow) {
680     RenderIntProto(ProtoDisplayWindow, Class, ProtoId, Color);
681   }
682 }                                /* DisplayIntProto */
683 #endif
684 
685 /*---------------------------------------------------------------------------*/
NewIntClass(int MaxNumProtos,int MaxNumConfigs)686 INT_CLASS NewIntClass(int MaxNumProtos, int MaxNumConfigs) {
687 /*
688  **	Parameters:
689  **		MaxNumProtos	number of protos to allocate space for
690  **		MaxNumConfigs	number of configs to allocate space for
691  **	Globals: none
692  **	Operation: This routine creates a new integer class data structure
693  **		and returns it.  Sufficient space is allocated
694  **		to handle the specified number of protos and configs.
695  **	Return: New class created.
696  **	Exceptions: none
697  **	History: Fri Feb  8 10:51:23 1991, DSJ, Created.
698  */
699   INT_CLASS Class;
700   PROTO_SET ProtoSet;
701   int i;
702   register uinT32 *Word;
703 
704   assert (MaxNumConfigs <= MAX_NUM_CONFIGS);
705 
706   Class = (INT_CLASS) Emalloc (sizeof (INT_CLASS_STRUCT));
707   Class->NumProtoSets = ((MaxNumProtos + PROTOS_PER_PROTO_SET - 1) /
708                             PROTOS_PER_PROTO_SET);
709 
710   assert(Class->NumProtoSets <= MAX_NUM_PROTO_SETS);
711 
712   Class->NumProtos = 0;
713   Class->NumConfigs = 0;
714 
715   for (i = 0; i < Class->NumProtoSets; i++) {
716     /* allocate space for a proto set, install in class, and initialize */
717     ProtoSet = (PROTO_SET) Emalloc (sizeof (PROTO_SET_STRUCT));
718     Class->ProtoSets[i] = ProtoSet;
719     for (Word = reinterpret_cast<uinT32*>(ProtoSet->ProtoPruner);
720          Word < reinterpret_cast<uinT32*>(ProtoSet->ProtoPruner) + WERDS_PER_PP;
721          *Word++ = 0);
722 
723     /* allocate space for the proto lengths and install in class */
724   }
725   if (MaxNumIntProtosIn (Class) > 0) {
726     Class->ProtoLengths =
727       (uinT8 *)Emalloc(MaxNumIntProtosIn (Class) * sizeof (uinT8));
728   }
729 
730   return (Class);
731 
732 }                                /* NewIntClass */
733 
734 
735 /*-------------------------------------------------------------------------*/
free_int_class(INT_CLASS int_class)736 void free_int_class(INT_CLASS int_class) {
737     int i;
738 
739   for (i = 0; i < int_class->NumProtoSets; i++) {
740     Efree (int_class->ProtoSets[i]);
741     }
742     if (int_class->ProtoLengths != NULL) {
743       Efree (int_class->ProtoLengths);
744     }
745     Efree(int_class);
746   }
747 
748 
749 /*---------------------------------------------------------------------------*/
NewIntTemplates()750 INT_TEMPLATES NewIntTemplates() {
751 /*
752  **	Parameters: none
753  **	Globals: none
754  **	Operation: This routine allocates a new set of integer templates
755  **		initialized to hold 0 classes.
756  **	Return: The integer templates created.
757  **	Exceptions: none
758  **	History: Fri Feb  8 08:38:51 1991, DSJ, Created.
759  */
760   INT_TEMPLATES T;
761   int i;
762 
763   T = (INT_TEMPLATES) Emalloc (sizeof (INT_TEMPLATES_STRUCT));
764   T->NumClasses = 0;
765   T->NumClassPruners = 0;
766 
767   for (i = 0; i < MAX_NUM_CLASSES; i++)
768     ClassForClassId (T, i) = NULL;
769 
770   return (T);
771 }                                /* NewIntTemplates */
772 
773 
774 /*---------------------------------------------------------------------------*/
free_int_templates(INT_TEMPLATES templates)775 void free_int_templates(INT_TEMPLATES templates) {
776   int i;
777 
778   for (i = 0; i < templates->NumClasses; i++)
779     free_int_class(templates->Class[i]);
780   for (i = 0; i < templates->NumClassPruners; i++)
781     Efree (templates->ClassPruner[i]);
782   Efree(templates);
783 }
784 
785 
786 /*---------------------------------------------------------------------------*/
787 // Code to read/write Classify::font*table structures.
788 namespace {
read_info(FILE * f,FontInfo * fi,bool swap)789 void read_info(FILE* f, FontInfo* fi, bool swap) {
790   inT32 size;
791   fread(&size, sizeof(inT32), 1, f);
792   if (swap)
793     reverse32(&size);
794   fi->name = new char[size + 1];
795   fread(fi->name, sizeof(char), size, f);
796   fi->name[size] = '\0';
797   fread(&fi->properties, sizeof(fi->properties), 1, f);
798   if (swap)
799     reverse32(&fi->properties);
800 }
801 
write_info(FILE * f,const FontInfo & fi)802 void write_info(FILE* f, const FontInfo& fi) {
803   inT32 size = strlen(fi.name);
804   fwrite(&size, sizeof(inT32), 1, f);
805   fwrite(fi.name, sizeof(char), size, f);
806   fwrite(&fi.properties, sizeof(inT32), 1, f);
807 }
808 
read_set(FILE * f,FontSet * fs,bool swap)809 void read_set(FILE* f, FontSet* fs, bool swap) {
810   fread(&fs->size, sizeof(inT32), 1, f);
811   if (swap)
812     reverse32(&fs->size);
813   fs->configs = new int[fs->size];
814   for (int i = 0; i < fs->size; ++i) {
815     fread(&fs->configs[i], sizeof(inT32), 1, f);
816     if (swap)
817       reverse32(&fs->configs[i]);
818   }
819 }
820 
write_set(FILE * f,const FontSet & fs)821 void write_set(FILE* f, const FontSet& fs) {
822   fwrite(&fs.size, sizeof(inT32), 1, f);
823   for (int i = 0; i < fs.size; ++i) {
824     fwrite(&fs.configs[i], sizeof(inT32), 1, f);
825   }
826 }
827 }
828 
829 namespace tesseract {
ReadIntTemplates(FILE * File)830 INT_TEMPLATES Classify::ReadIntTemplates(FILE *File) {
831 /*
832  **	Parameters:
833  **		File		open file to read templates from
834  **	Globals: none
835  **	Operation: This routine reads a set of integer templates from
836  **		File.  File must already be open and must be in the
837  **		correct binary format.
838  **	Return: Pointer to integer templates read from File.
839  **	Exceptions: none
840  **	History: Wed Feb 27 11:48:46 1991, DSJ, Created.
841  */
842   int i, j, w, x, y, z;
843   BOOL8 swap;
844   int nread;
845   int unicharset_size;
846   int version_id = 0;
847   INT_TEMPLATES Templates;
848   CLASS_PRUNER Pruner;
849   INT_CLASS Class;
850   uinT8 *Lengths;
851   PROTO_SET ProtoSet;
852 
853   /* variables for conversion from older inttemp formats */
854   int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
855   CLASS_ID class_id, max_class_id;
856   inT16 *IndexFor = new inT16[MAX_NUM_CLASSES];
857   CLASS_ID *ClassIdFor = new CLASS_ID[MAX_NUM_CLASSES];
858   CLASS_PRUNER *TempClassPruner = new CLASS_PRUNER[MAX_NUM_CLASS_PRUNERS];
859   uinT32 SetBitsForMask =           // word with NUM_BITS_PER_CLASS
860     (1 << NUM_BITS_PER_CLASS) - 1;  // set starting at bit 0
861   uinT32 Mask, NewMask, ClassBits;
862   uinT32 *Word;
863   int MaxNumConfigs = MAX_NUM_CONFIGS;
864   int WerdsPerConfigVec = WERDS_PER_CONFIG_VEC;
865 
866   /* first read the high level template struct */
867   Templates = NewIntTemplates ();
868   // Read Templates in parts for 64 bit compatibility.
869   if (fread(&unicharset_size, sizeof(int), 1, File) != 1)
870     cprintf ("Bad read of inttemp!\n");
871   if (fread(&Templates->NumClasses,
872             sizeof(Templates->NumClasses), 1, File) != 1 ||
873       fread(&Templates->NumClassPruners,
874             sizeof(Templates->NumClassPruners), 1, File) != 1)
875     cprintf ("Bad read of inttemp!\n");
876   // Swap status is determined automatically.
877   swap = Templates->NumClassPruners < 0 ||
878     Templates->NumClassPruners > MAX_NUM_CLASS_PRUNERS;
879   if (swap) {
880     reverse32 (&Templates->NumClassPruners);
881     reverse32 (&Templates->NumClasses);
882     reverse32 (&unicharset_size);
883   }
884   if (Templates->NumClasses < 0) {
885     // This file has a version id!
886     version_id = -Templates->NumClasses;
887     if (fread(&Templates->NumClasses, sizeof(Templates->NumClasses),
888               1, File) != 1)
889       cprintf("Bad read of inttemp!\n");
890     if (swap)
891       reverse32 (&Templates->NumClasses);
892   }
893 
894   if (version_id < 3) {
895     MaxNumConfigs = OLD_MAX_NUM_CONFIGS;
896     WerdsPerConfigVec = OLD_WERDS_PER_CONFIG_VEC;
897   }
898 
899   if (version_id < 2) {
900     for (i = 0; i < unicharset_size; ++i) {
901       if (fread(&IndexFor[i], sizeof(inT16), 1, File) != 1)
902         cprintf("Bad read of inttemp!\n");
903     }
904     for (i = 0; i < Templates->NumClasses; ++i) {
905       if (fread(&ClassIdFor[i], sizeof(CLASS_ID), 1, File) != 1)
906         cprintf("Bad read of inttemp!\n");
907     }
908     if (swap) {
909       for (i = 0; i < Templates->NumClasses; i++)
910         reverse16 (IndexFor[i]);
911       for (i = 0; i < Templates->NumClasses; i++)
912         reverse32 (ClassIdFor[i]);
913     }
914   }
915 
916   /* then read in the class pruners */
917   for (i = 0; i < Templates->NumClassPruners; i++) {
918     Pruner = (CLASS_PRUNER) Emalloc (sizeof (CLASS_PRUNER_STRUCT));
919     if ((nread =
920          fread ((char *) Pruner, 1, sizeof (CLASS_PRUNER_STRUCT),
921                 File)) != sizeof (CLASS_PRUNER_STRUCT))
922       cprintf ("Bad read of inttemp!\n");
923     if (swap) {
924       for (x = 0; x < NUM_CP_BUCKETS; x++) {
925         for (y = 0; y < NUM_CP_BUCKETS; y++) {
926           for (z = 0; z < NUM_CP_BUCKETS; z++) {
927             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
928               reverse32 (&Pruner[x][y][z][w]);
929             }
930           }
931         }
932       }
933     }
934     if (version_id < 2) {
935       TempClassPruner[i] = Pruner;
936     } else {
937       Templates->ClassPruner[i] = Pruner;
938     }
939   }
940 
941   /* fix class pruners if they came from an old version of inttemp */
942   if (version_id < 2) {
943     // Allocate enough class pruners to cover all the class ids.
944     max_class_id = 0;
945     for (i = 0; i < Templates->NumClasses; i++)
946       if (ClassIdFor[i] > max_class_id)
947         max_class_id = ClassIdFor[i];
948     for (i = 0; i <= CPrunerIdFor(max_class_id); i++) {
949       Templates->ClassPruner[i] =
950         (CLASS_PRUNER) Emalloc (sizeof (CLASS_PRUNER_STRUCT));
951       for (Word = (uinT32 *) (Templates->ClassPruner[i]);
952            Word < (uinT32 *) (Templates->ClassPruner[i]) + WERDS_PER_CP;
953            *Word++ = 0);
954     }
955     // Convert class pruners from the old format (indexed by class index)
956     // to the new format (indexed by class id).
957     last_cp_bit_number = NUM_BITS_PER_CLASS * Templates->NumClasses - 1;
958     for (i = 0; i < Templates->NumClassPruners; i++) {
959       for (x = 0; x < NUM_CP_BUCKETS; x++)
960         for (y = 0; y < NUM_CP_BUCKETS; y++)
961           for (z = 0; z < NUM_CP_BUCKETS; z++)
962             for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
963               if (TempClassPruner[i][x][y][z][w] == 0)
964                 continue;
965               for (b = 0; b < BITS_PER_WERD; b += NUM_BITS_PER_CLASS) {
966                 bit_number = i * BITS_PER_CP_VECTOR + w * BITS_PER_WERD + b;
967                 if (bit_number > last_cp_bit_number)
968                   break; // the rest of the bits in this word are not used
969                 class_id = ClassIdFor[bit_number / NUM_BITS_PER_CLASS];
970                 // Single out NUM_BITS_PER_CLASS bits relating to class_id.
971                 Mask = SetBitsForMask << b;
972                 ClassBits = TempClassPruner[i][x][y][z][w] & Mask;
973                 // Move these bits to the new position in which they should
974                 // appear (indexed corresponding to the class_id).
975                 new_i = CPrunerIdFor(class_id);
976                 new_w = CPrunerWordIndexFor(class_id);
977                 new_b = CPrunerBitIndexFor(class_id) * NUM_BITS_PER_CLASS;
978                 if (new_b > b) {
979                   ClassBits <<= (new_b - b);
980                 } else {
981                   ClassBits >>= (b - new_b);
982                 }
983                 // Copy bits relating to class_id to the correct position
984                 // in Templates->ClassPruner.
985                 NewMask = SetBitsForMask << new_b;
986                 Templates->ClassPruner[new_i][x][y][z][new_w] &= ~NewMask;
987                 Templates->ClassPruner[new_i][x][y][z][new_w] |= ClassBits;
988               }
989             }
990     }
991     for (i = 0; i < Templates->NumClassPruners; i++) {
992       Efree (TempClassPruner[i]);
993     }
994   }
995 
996   /* then read in each class */
997   for (i = 0; i < Templates->NumClasses; i++) {
998     /* first read in the high level struct for the class */
999     Class = (INT_CLASS) Emalloc (sizeof (INT_CLASS_STRUCT));
1000     if (fread(&Class->NumProtos, sizeof(Class->NumProtos), 1, File) != 1 ||
1001         fread(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File) != 1 ||
1002         fread(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File) != 1)
1003       cprintf ("Bad read of inttemp!\n");
1004     if (version_id == 0) {
1005       // Only version 0 writes 5 pointless pointers to the file.
1006       for (j = 0; j < 5; ++j) {
1007         int junk;
1008         if (fread(&junk, sizeof(junk), 1, File) != 1)
1009           cprintf ("Bad read of inttemp!\n");
1010       }
1011     }
1012     if (version_id < 4) {
1013       for (j = 0; j < MaxNumConfigs; ++j) {
1014         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
1015           cprintf ("Bad read of inttemp!\n");
1016       }
1017       if (swap) {
1018         reverse16 (&Class->NumProtos);
1019         for (j = 0; j < MaxNumConfigs; j++)
1020           reverse16 (&Class->ConfigLengths[j]);
1021       }
1022     } else {
1023       ASSERT_HOST(Class->NumConfigs < MaxNumConfigs);
1024       for (j = 0; j < Class->NumConfigs; ++j) {
1025         if (fread(&Class->ConfigLengths[j], sizeof(uinT16), 1, File) != 1)
1026           cprintf ("Bad read of inttemp!\n");
1027       }
1028       if (swap) {
1029         reverse16 (&Class->NumProtos);
1030         for (j = 0; j < MaxNumConfigs; j++)
1031           reverse16 (&Class->ConfigLengths[j]);
1032       }
1033     }
1034     if (version_id < 2) {
1035       ClassForClassId (Templates, ClassIdFor[i]) = Class;
1036     } else {
1037       ClassForClassId (Templates, i) = Class;
1038     }
1039 
1040     /* then read in the proto lengths */
1041     Lengths = NULL;
1042     if (MaxNumIntProtosIn (Class) > 0) {
1043       Lengths = (uinT8 *)Emalloc(sizeof(uinT8) * MaxNumIntProtosIn(Class));
1044       if ((nread =
1045            fread((char *)Lengths, sizeof(uinT8),
1046                  MaxNumIntProtosIn(Class), File)) != MaxNumIntProtosIn (Class))
1047         cprintf ("Bad read of inttemp!\n");
1048     }
1049     Class->ProtoLengths = Lengths;
1050 
1051     /* then read in the proto sets */
1052     for (j = 0; j < Class->NumProtoSets; j++) {
1053       ProtoSet = (PROTO_SET)Emalloc(sizeof(PROTO_SET_STRUCT));
1054       if (version_id < 3) {
1055         if ((nread =
1056              fread((char *) &ProtoSet->ProtoPruner, 1,
1057                     sizeof(PROTO_PRUNER), File)) != sizeof(PROTO_PRUNER))
1058           cprintf("Bad read of inttemp!\n");
1059         for (x = 0; x < PROTOS_PER_PROTO_SET; x++) {
1060           if ((nread = fread((char *) &ProtoSet->Protos[x].A, 1,
1061                              sizeof(inT8), File)) != sizeof(inT8) ||
1062               (nread = fread((char *) &ProtoSet->Protos[x].B, 1,
1063                              sizeof(uinT8), File)) != sizeof(uinT8) ||
1064               (nread = fread((char *) &ProtoSet->Protos[x].C, 1,
1065                              sizeof(inT8), File)) != sizeof(inT8) ||
1066               (nread = fread((char *) &ProtoSet->Protos[x].Angle, 1,
1067                              sizeof(uinT8), File)) != sizeof(uinT8))
1068             cprintf("Bad read of inttemp!\n");
1069           for (y = 0; y < WerdsPerConfigVec; y++)
1070             if ((nread = fread((char *) &ProtoSet->Protos[x].Configs[y], 1,
1071                                sizeof(uinT32), File)) != sizeof(uinT32))
1072               cprintf("Bad read of inttemp!\n");
1073         }
1074       } else {
1075         if ((nread =
1076              fread((char *) ProtoSet, 1, sizeof(PROTO_SET_STRUCT),
1077                    File)) != sizeof(PROTO_SET_STRUCT))
1078           cprintf("Bad read of inttemp!\n");
1079       }
1080       if (swap) {
1081         for (x = 0; x < NUM_PP_PARAMS; x++)
1082           for (y = 0; y < NUM_PP_BUCKETS; y++)
1083             for (z = 0; z < WERDS_PER_PP_VECTOR; z++)
1084               reverse32 (&ProtoSet->ProtoPruner[x][y][z]);
1085         for (x = 0; x < PROTOS_PER_PROTO_SET; x++)
1086           for (y = 0; y < WerdsPerConfigVec; y++)
1087             reverse32 (&ProtoSet->Protos[x].Configs[y]);
1088       }
1089       Class->ProtoSets[j] = ProtoSet;
1090     }
1091     if (version_id < 4)
1092       Class->font_set_id = -1;
1093     else {
1094       fread(&Class->font_set_id, sizeof(int), 1, File);
1095       if (swap)
1096         reverse32(&Class->font_set_id);
1097     }
1098   }
1099 
1100   if (version_id < 2) {
1101     /* add an empty NULL class with class id 0 */
1102     assert(UnusedClassIdIn (Templates, 0));
1103     ClassForClassId (Templates, 0) = NewIntClass (1, 1);
1104     ClassForClassId (Templates, 0)->font_set_id = -1;
1105     Templates->NumClasses++;
1106     /* make sure the classes are contiguous */
1107     for (i = 0; i < MAX_NUM_CLASSES; i++) {
1108       if (i < Templates->NumClasses) {
1109         if (ClassForClassId (Templates, i) == NULL) {
1110           fprintf(stderr, "Non-contiguous class ids in inttemp\n");
1111           exit(1);
1112         }
1113       } else {
1114         if (ClassForClassId (Templates, i) != NULL) {
1115           fprintf(stderr, "Class id %d exceeds NumClassesIn (Templates) %d\n",
1116                   i, Templates->NumClasses);
1117           exit(1);
1118         }
1119       }
1120     }
1121   }
1122   if (version_id >= 4) {
1123     this->fontinfo_table_.read(File, NewPermanentCallback(read_info), swap);
1124     this->fontset_table_.read(File, NewPermanentCallback(read_set), swap);
1125   }
1126 
1127   // Clean up.
1128   delete[] IndexFor;
1129   delete[] ClassIdFor;
1130   delete[] TempClassPruner;
1131 
1132   return (Templates);
1133 }                                /* ReadIntTemplates */
1134 
1135 } // namespace tesseract
1136 
1137 
1138 /*---------------------------------------------------------------------------*/
1139 #ifndef GRAPHICS_DISABLED
ShowMatchDisplay()1140 void ShowMatchDisplay() {
1141 /*
1142  **	Parameters: none
1143  **	Globals:
1144  **		FeatureShapes	display list containing feature matches
1145  **		ProtoShapes	display list containing proto matches
1146  **	Operation: This routine sends the shapes in the global display
1147  **		lists to the match debugger window.
1148  **	Return: none
1149  **	Exceptions: none
1150  **	History: Thu Mar 21 15:47:33 1991, DSJ, Created.
1151  */
1152   void *window;
1153   /* Size of drawable */
1154   InitIntMatchWindowIfReqd();
1155     c_clear_window(IntMatchWindow);
1156   if (ProtoDisplayWindow) {
1157     c_clear_window(ProtoDisplayWindow);
1158   }
1159   if (FeatureDisplayWindow) {
1160     c_clear_window(FeatureDisplayWindow);
1161   }
1162 
1163   window = IntMatchWindow;
1164   c_line_color_index(window, Grey);
1165   /* Default size of drawing */
1166   if (classify_norm_method == baseline) {
1167     c_move (window, -1000.0, INT_BASELINE);
1168     c_draw (window, 1000.0, INT_BASELINE);
1169     c_move (window, -1000.0, INT_DESCENDER);
1170     c_draw (window, 1000.0, INT_DESCENDER);
1171     c_move (window, -1000.0, INT_XHEIGHT);
1172     c_draw (window, 1000.0, INT_XHEIGHT);
1173     c_move (window, -1000.0, INT_CAPHEIGHT);
1174     c_draw (window, 1000.0, INT_CAPHEIGHT);
1175     c_move (window, INT_MIN_X, -1000.0);
1176     c_draw (window, INT_MIN_X, 1000.0);
1177     c_move (window, INT_MAX_X, -1000.0);
1178     c_draw (window, INT_MAX_X, 1000.0);
1179   }
1180   else {
1181     c_move (window, INT_XCENTER - INT_XRADIUS, INT_YCENTER - INT_YRADIUS);
1182     c_draw (window, INT_XCENTER + INT_XRADIUS, INT_YCENTER - INT_YRADIUS);
1183     c_move (window, INT_XCENTER - INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
1184     c_draw (window, INT_XCENTER + INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
1185     c_move (window, INT_XCENTER - INT_XRADIUS, INT_YCENTER - INT_YRADIUS);
1186     c_draw (window, INT_XCENTER - INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
1187     c_move (window, INT_XCENTER + INT_XRADIUS, INT_YCENTER - INT_YRADIUS);
1188     c_draw (window, INT_XCENTER + INT_XRADIUS, INT_YCENTER + INT_YRADIUS);
1189     c_move(window, INT_MIN_X, INT_MIN_Y);
1190     c_draw(window, INT_MIN_X, INT_MAX_Y);
1191     c_move(window, INT_MIN_X, INT_MIN_Y);
1192     c_draw(window, INT_MAX_X, INT_MIN_Y);
1193     c_move(window, INT_MAX_X, INT_MAX_Y);
1194     c_draw(window, INT_MIN_X, INT_MAX_Y);
1195     c_move(window, INT_MAX_X, INT_MAX_Y);
1196     c_draw(window, INT_MAX_X, INT_MIN_Y);
1197   }
1198   IntMatchWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
1199                                   INT_MAX_X, INT_MAX_Y);
1200   if (ProtoDisplayWindow) {
1201     ProtoDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
1202                                         INT_MAX_X, INT_MAX_Y);
1203   }
1204   if (FeatureDisplayWindow) {
1205     FeatureDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y,
1206                                           INT_MAX_X, INT_MAX_Y);
1207   }
1208 }                                /* ShowMatchDisplay */
1209 #endif
1210 
1211 /*---------------------------------------------------------------------------*/
1212 namespace tesseract {
WriteIntTemplates(FILE * File,INT_TEMPLATES Templates,const UNICHARSET & target_unicharset)1213 void Classify::WriteIntTemplates(FILE *File, INT_TEMPLATES Templates,
1214                                  const UNICHARSET& target_unicharset) {
1215 /*
1216  **	Parameters:
1217  **		File		open file to write templates to
1218  **		Templates	templates to save into File
1219  **	Globals: none
1220  **	Operation: This routine writes Templates to File.  The format
1221  **		is an efficient binary format.  File must already be open
1222  **		for writing.
1223  **	Return: none
1224  **	Exceptions: none
1225  **	History: Wed Feb 27 11:48:46 1991, DSJ, Created.
1226  */
1227   int i, j;
1228   INT_CLASS Class;
1229   int unicharset_size = target_unicharset.size();
1230   int version_id = -4;  // When negated by the reader -1 becomes +1 etc.
1231 
1232   if (Templates->NumClasses != unicharset_size) {
1233     cprintf("Warning: executing WriteIntTemplates() with %d classes in"
1234             " Templates, while target_unicharset size is %d\n",
1235             Templates->NumClasses, unicharset_size);
1236   }
1237 
1238   /* first write the high level template struct */
1239   fwrite(&unicharset_size, sizeof(unicharset_size), 1, File);
1240   fwrite(&version_id, sizeof(version_id), 1, File);
1241   fwrite(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners),
1242          1, File);
1243   fwrite(&Templates->NumClasses, sizeof(Templates->NumClasses), 1, File);
1244 
1245   /* then write out the class pruners */
1246   for (i = 0; i < Templates->NumClassPruners; i++)
1247     fwrite(Templates->ClassPruner[i],
1248            sizeof(CLASS_PRUNER_STRUCT), 1, File);
1249 
1250   /* then write out each class */
1251   for (i = 0; i < Templates->NumClasses; i++) {
1252     Class = Templates->Class[i];
1253 
1254     /* first write out the high level struct for the class */
1255     fwrite(&Class->NumProtos, sizeof(Class->NumProtos), 1, File);
1256     fwrite(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File);
1257     ASSERT_HOST(Class->NumConfigs == this->fontset_table_.get(Class->font_set_id).size);
1258     fwrite(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File);
1259     for (j = 0; j < Class->NumConfigs; ++j) {
1260       fwrite(&Class->ConfigLengths[j], sizeof(uinT16), 1, File);
1261     }
1262 
1263     /* then write out the proto lengths */
1264     if (MaxNumIntProtosIn (Class) > 0) {
1265       fwrite ((char *) (Class->ProtoLengths), sizeof (uinT8),
1266               MaxNumIntProtosIn (Class), File);
1267     }
1268 
1269     /* then write out the proto sets */
1270     for (j = 0; j < Class->NumProtoSets; j++)
1271       fwrite ((char *) Class->ProtoSets[j],
1272               sizeof (PROTO_SET_STRUCT), 1, File);
1273 
1274     /* then write the fonts info */
1275     fwrite(&Class->font_set_id, sizeof(int), 1, File);
1276   }
1277 
1278   /* Write the fonts info tables */
1279   this->fontinfo_table_.write(File, NewPermanentCallback(write_info));
1280   this->fontset_table_.write(File, NewPermanentCallback(write_set));
1281 }                                /* WriteIntTemplates */
1282 } // namespace tesseract
1283 
1284 
1285 /**----------------------------------------------------------------------------
1286               Private Code
1287 ----------------------------------------------------------------------------**/
1288 /*---------------------------------------------------------------------------*/
BucketStart(int Bucket,FLOAT32 Offset,int NumBuckets)1289 FLOAT32 BucketStart(int Bucket, FLOAT32 Offset, int NumBuckets) {
1290 /*
1291  **	Parameters:
1292  **		Bucket		bucket whose start is to be computed
1293  **		Offset		offset used to map params to buckets
1294  **		NumBuckets	total number of buckets
1295  **	Globals: none
1296  **	Operation: This routine returns the parameter value which
1297  **		corresponds to the beginning of the specified bucket.
1298  **		The bucket number should have been generated using the
1299  **		BucketFor() function with parameters Offset and NumBuckets.
1300  **	Return: Param value corresponding to start position of Bucket.
1301  **	Exceptions: none
1302  **	History: Thu Feb 14 13:24:33 1991, DSJ, Created.
1303  */
1304   return (((FLOAT32) Bucket / NumBuckets) - Offset);
1305 
1306 }                                /* BucketStart */
1307 
1308 
1309 /*---------------------------------------------------------------------------*/
BucketEnd(int Bucket,FLOAT32 Offset,int NumBuckets)1310 FLOAT32 BucketEnd(int Bucket, FLOAT32 Offset, int NumBuckets) {
1311 /*
1312  **	Parameters:
1313  **		Bucket		bucket whose end is to be computed
1314  **		Offset		offset used to map params to buckets
1315  **		NumBuckets	total number of buckets
1316  **	Globals: none
1317  **	Operation: This routine returns the parameter value which
1318  **		corresponds to the end of the specified bucket.
1319  **		The bucket number should have been generated using the
1320  **		BucketFor() function with parameters Offset and NumBuckets.
1321  **	Return: Param value corresponding to end position of Bucket.
1322  **	Exceptions: none
1323  **	History: Thu Feb 14 13:24:33 1991, DSJ, Created.
1324  */
1325   return (((FLOAT32) (Bucket + 1) / NumBuckets) - Offset);
1326 }                                /* BucketEnd */
1327 
1328 
1329 /*---------------------------------------------------------------------------*/
DoFill(FILL_SPEC * FillSpec,CLASS_PRUNER Pruner,register uinT32 ClassMask,register uinT32 ClassCount,register uinT32 WordIndex)1330 void DoFill(FILL_SPEC *FillSpec,
1331             CLASS_PRUNER Pruner,
1332             register uinT32 ClassMask,
1333             register uinT32 ClassCount,
1334             register uinT32 WordIndex) {
1335 /*
1336  **	Parameters:
1337  **		FillSpec	specifies which bits to fill in pruner
1338  **		Pruner		class pruner to be filled
1339  **		ClassMask	indicates which bits to change in each word
1340  **		ClassCount	indicates what to change bits to
1341  **		WordIndex	indicates which word to change
1342  **	Globals: none
1343  **	Operation: This routine fills in the section of a class pruner
1344  **		corresponding to a single x value for a single proto of
1345  **		a class.
1346  **	Return: none
1347  **	Exceptions: none
1348  **	History: Tue Feb 19 11:11:29 1991, DSJ, Created.
1349  */
1350   register int X, Y, Angle;
1351   register uinT32 OldWord;
1352 
1353   X = FillSpec->X;
1354   if (X < 0)
1355     X = 0;
1356   if (X >= NUM_CP_BUCKETS)
1357     X = NUM_CP_BUCKETS - 1;
1358 
1359   if (FillSpec->YStart < 0)
1360     FillSpec->YStart = 0;
1361   if (FillSpec->YEnd >= NUM_CP_BUCKETS)
1362     FillSpec->YEnd = NUM_CP_BUCKETS - 1;
1363 
1364   for (Y = FillSpec->YStart; Y <= FillSpec->YEnd; Y++)
1365     for (Angle = FillSpec->AngleStart;
1366          TRUE; CircularIncrement (Angle, NUM_CP_BUCKETS)) {
1367       OldWord = Pruner[X][Y][Angle][WordIndex];
1368       if (ClassCount > (OldWord & ClassMask)) {
1369         OldWord &= ~ClassMask;
1370         OldWord |= ClassCount;
1371         Pruner[X][Y][Angle][WordIndex] = OldWord;
1372       }
1373       if (Angle == FillSpec->AngleEnd)
1374         break;
1375     }
1376 }                                /* DoFill */
1377 
1378 
1379 /*---------------------------------------------------------------------------*/
FillerDone(TABLE_FILLER * Filler)1380 BOOL8 FillerDone(TABLE_FILLER *Filler) {
1381 /*
1382  **	Parameters:
1383  **		Filler		table filler to check if done
1384  **	Globals: none
1385  **	Operation: Return TRUE if the specified table filler is done, i.e.
1386  **		if it has no more lines to fill.
1387  **	Return: TRUE if no more lines to fill, FALSE otherwise.
1388  **	Exceptions: none
1389  **	History: Tue Feb 19 10:08:05 1991, DSJ, Created.
1390  */
1391   FILL_SWITCH *Next;
1392 
1393   Next = &(Filler->Switch[Filler->NextSwitch]);
1394 
1395   if (Filler->X > Next->X && Next->Type == LastSwitch)
1396     return (TRUE);
1397   else
1398     return (FALSE);
1399 
1400 }                                /* FillerDone */
1401 
1402 
1403 /*---------------------------------------------------------------------------*/
1404 void
FillPPCircularBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],int Bit,FLOAT32 Center,FLOAT32 Spread)1405 FillPPCircularBits (uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
1406                     int Bit, FLOAT32 Center, FLOAT32 Spread) {
1407 /*
1408  **	Parameters:
1409  **		ParamTable	table of bit vectors, one per param bucket
1410  **		Bit		bit position in vectors to be filled
1411  **		Center		center of filled area
1412  **		Spread		spread of filled area
1413  **	Globals: none
1414  **	Operation: This routine sets Bit in each bit vector whose
1415  **		bucket lies within the range Center +- Spread.  The fill
1416  **		is done for a circular dimension, i.e. bucket 0 is adjacent
1417  **		to the last bucket.  It is assumed that Center and Spread
1418  **		are expressed in a circular coordinate system whose range
1419  **		is 0 to 1.
1420  **	Return: none
1421  **	Exceptions: none
1422  **	History: Tue Oct 16 09:26:54 1990, DSJ, Created.
1423  */
1424   int i, FirstBucket, LastBucket;
1425 
1426   if (Spread > 0.5)
1427     Spread = 0.5;
1428 
1429   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
1430   if (FirstBucket < 0)
1431     FirstBucket += NUM_PP_BUCKETS;
1432 
1433   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
1434   if (LastBucket >= NUM_PP_BUCKETS)
1435     LastBucket -= NUM_PP_BUCKETS;
1436   if (classify_learning_debug_level >= 2)
1437     cprintf ("Circular fill from %d to %d", FirstBucket, LastBucket);
1438   for (i = FirstBucket; TRUE; CircularIncrement (i, NUM_PP_BUCKETS)) {
1439     SET_BIT (ParamTable[i], Bit);
1440 
1441     /* exit loop after we have set the bit for the last bucket */
1442     if (i == LastBucket)
1443       break;
1444   }
1445 
1446 }                                /* FillPPCircularBits */
1447 
1448 
1449 /*---------------------------------------------------------------------------*/
1450 void
FillPPLinearBits(uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],int Bit,FLOAT32 Center,FLOAT32 Spread)1451 FillPPLinearBits (uinT32 ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR],
1452                   int Bit, FLOAT32 Center, FLOAT32 Spread) {
1453 /*
1454  **	Parameters:
1455  **		ParamTable	table of bit vectors, one per param bucket
1456  **		Bit		bit number being filled
1457  **		Center		center of filled area
1458  **		Spread		spread of filled area
1459  **	Globals: none
1460  **	Operation: This routine sets Bit in each bit vector whose
1461  **		bucket lies within the range Center +- Spread.  The fill
1462  **		is done for a linear dimension, i.e. there is no wrap-around
1463  **		for this dimension.  It is assumed that Center and Spread
1464  **		are expressed in a linear coordinate system whose range
1465  **		is approximately 0 to 1.  Values outside this range will
1466  **		be clipped.
1467  **	Return: none
1468  **	Exceptions: none
1469  **	History: Tue Oct 16 09:26:54 1990, DSJ, Created.
1470  */
1471   int i, FirstBucket, LastBucket;
1472 
1473   FirstBucket = (int) floor ((Center - Spread) * NUM_PP_BUCKETS);
1474   if (FirstBucket < 0)
1475     FirstBucket = 0;
1476 
1477   LastBucket = (int) floor ((Center + Spread) * NUM_PP_BUCKETS);
1478   if (LastBucket >= NUM_PP_BUCKETS)
1479     LastBucket = NUM_PP_BUCKETS - 1;
1480 
1481   if (classify_learning_debug_level >= 2)
1482     cprintf ("Linear fill from %d to %d", FirstBucket, LastBucket);
1483   for (i = FirstBucket; i <= LastBucket; i++)
1484     SET_BIT (ParamTable[i], Bit);
1485 
1486 }                                /* FillPPLinearBits */
1487 
1488 
1489 /*---------------------------------------------------------------------------*/
1490 #ifndef GRAPHICS_DISABLED
1491 namespace tesseract {
GetClassToDebug(const char * Prompt)1492 CLASS_ID Classify::GetClassToDebug(const char *Prompt) {
1493 /*
1494  **	Parameters:
1495  **		Prompt	prompt to print while waiting for input from window
1496  **	Globals: none
1497  **	Operation: This routine prompts the user with Prompt and waits
1498  **		for the user to enter something in the debug window.
1499  **	Return: Character entered in the debug window.
1500  **	Exceptions: none
1501  **	History: Thu Mar 21 16:55:13 1991, DSJ, Created.
1502  */
1503   tprintf("%s\n", Prompt);
1504   SVEvent* ev;
1505   SVEventType ev_type;
1506   // Wait until a click or popup event.
1507   do {
1508     ev = IntMatchWindow->AwaitEvent(SVET_ANY);
1509     ev_type = ev->type;
1510     if (ev_type == SVET_POPUP) {
1511       // TODO(rays) must return which menu item was selected, but
1512       // that can't be done in this CL without dragging in a lot of
1513       // other changes.
1514       if (unicharset.contains_unichar(ev->parameter))
1515         return unicharset.unichar_to_id(ev->parameter);
1516       tprintf("Char class '%s' not found in unicharset",
1517               ev->parameter);
1518     }
1519     delete ev;
1520   } while (ev_type != SVET_CLICK);
1521   return 0;
1522 }                                /* GetClassToDebug */
1523 
1524 }  // namespace tesseract
1525 #endif
1526 
1527 /*---------------------------------------------------------------------------*/
GetCPPadsForLevel(int Level,FLOAT32 * EndPad,FLOAT32 * SidePad,FLOAT32 * AnglePad)1528 void GetCPPadsForLevel(int Level,
1529                        FLOAT32 *EndPad,
1530                        FLOAT32 *SidePad,
1531                        FLOAT32 *AnglePad) {
1532 /*
1533  **	Parameters:
1534  **		Level		"tightness" level to return pads for
1535  **		EndPad		place to put end pad for Level
1536  **		SidePad		place to put side pad for Level
1537  **		AnglePad	place to put angle pad for Level
1538  **	Globals: none
1539  **	Operation: This routine copies the appropriate global pad variables
1540  **		into EndPad, SidePad, and AnglePad.  This is a kludge used
1541  **		to get around the fact that global control variables cannot
1542  **		be arrays.  If the specified level is illegal, the tightest
1543  **		possible pads are returned.
1544  **	Return: none (results are returned in EndPad, SidePad, and AnglePad.
1545  **	Exceptions: none
1546  **	History: Thu Feb 14 08:26:49 1991, DSJ, Created.
1547  */
1548   switch (Level) {
1549     case 0:
1550       *EndPad = classify_cp_end_pad_loose * GetPicoFeatureLength ();
1551       *SidePad = classify_cp_side_pad_loose * GetPicoFeatureLength ();
1552       *AnglePad = classify_cp_angle_pad_loose / 360.0;
1553       break;
1554 
1555     case 1:
1556       *EndPad = classify_cp_end_pad_medium * GetPicoFeatureLength ();
1557       *SidePad = classify_cp_side_pad_medium * GetPicoFeatureLength ();
1558       *AnglePad = classify_cp_angle_pad_medium / 360.0;
1559       break;
1560 
1561     case 2:
1562       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
1563       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
1564       *AnglePad = classify_cp_angle_pad_tight / 360.0;
1565       break;
1566 
1567     default:
1568       *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength ();
1569       *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength ();
1570       *AnglePad = classify_cp_angle_pad_tight / 360.0;
1571       break;
1572   }
1573   if (*AnglePad > 0.5)
1574     *AnglePad = 0.5;
1575 
1576 }                                /* GetCPPadsForLevel */
1577 
1578 
1579 /*---------------------------------------------------------------------------*/
GetMatchColorFor(FLOAT32 Evidence)1580 C_COL GetMatchColorFor(FLOAT32 Evidence) {
1581 /*
1582  **	Parameters:
1583  **		Evidence	evidence value to return color for
1584  **	Globals: none
1585  **	Operation:
1586  **	Return: Color which corresponds to specified Evidence value.
1587  **	Exceptions: none
1588  **	History: Thu Mar 21 15:24:52 1991, DSJ, Created.
1589  */
1590 
1591   assert (Evidence >= 0.0);
1592   assert (Evidence <= 1.0);
1593 
1594   if (Evidence >= 0.90)
1595     return White;
1596   else if (Evidence >= 0.75)
1597     return Green;
1598   else if (Evidence >= 0.50)
1599     return Red;
1600   else
1601     return Blue;
1602 }                                /* GetMatchColorFor */
1603 
1604 
1605 /*---------------------------------------------------------------------------*/
GetNextFill(TABLE_FILLER * Filler,FILL_SPEC * Fill)1606 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill) {
1607 /*
1608  **	Parameters:
1609  **		Filler		filler to get next fill spec from
1610  **		Fill		place to put spec for next fill
1611  **	Globals: none
1612  **	Operation: This routine returns (in Fill) the specification of
1613  **		the next line to be filled from Filler.  FillerDone() should
1614  **		always be called before GetNextFill() to ensure that we
1615  **		do not run past the end of the fill table.
1616  **	Return: none (results are returned in Fill)
1617  **	Exceptions: none
1618  **	History: Tue Feb 19 10:17:42 1991, DSJ, Created.
1619  */
1620   FILL_SWITCH *Next;
1621 
1622   /* compute the fill assuming no switches will be encountered */
1623   Fill->AngleStart = Filler->AngleStart;
1624   Fill->AngleEnd = Filler->AngleEnd;
1625   Fill->X = Filler->X;
1626   Fill->YStart = Filler->YStart >> 8;
1627   Fill->YEnd = Filler->YEnd >> 8;
1628 
1629   /* update the fill info and the filler for ALL switches at this X value */
1630   Next = &(Filler->Switch[Filler->NextSwitch]);
1631   while (Filler->X >= Next->X) {
1632     Fill->X = Filler->X = Next->X;
1633     if (Next->Type == StartSwitch) {
1634       Fill->YStart = Next->Y;
1635       Filler->StartDelta = Next->Delta;
1636       Filler->YStart = Next->YInit;
1637     }
1638     else if (Next->Type == EndSwitch) {
1639       Fill->YEnd = Next->Y;
1640       Filler->EndDelta = Next->Delta;
1641       Filler->YEnd = Next->YInit;
1642     }
1643     else {                       /* Type must be LastSwitch */
1644       break;
1645     }
1646     Filler->NextSwitch++;
1647     Next = &(Filler->Switch[Filler->NextSwitch]);
1648   }
1649 
1650   /* prepare the filler for the next call to this routine */
1651   Filler->X++;
1652   Filler->YStart += Filler->StartDelta;
1653   Filler->YEnd += Filler->EndDelta;
1654 
1655 }                                /* GetNextFill */
1656 
1657 
1658 /*---------------------------------------------------------------------------*/
InitTableFiller(FLOAT32 EndPad,FLOAT32 SidePad,FLOAT32 AnglePad,PROTO Proto,TABLE_FILLER * Filler)1659 void InitTableFiller (FLOAT32 EndPad, FLOAT32 SidePad,
1660                       FLOAT32 AnglePad, PROTO Proto, TABLE_FILLER * Filler)
1661 /*
1662  **	Parameters:
1663  **		EndPad, SidePad, AnglePad	padding to add to proto
1664  **		Proto				proto to create a filler for
1665  **		Filler				place to put table filler
1666  **	Globals: none
1667  **	Operation: This routine computes a data structure (Filler)
1668  **		which can be used to fill in a rectangle surrounding
1669  **		the specified Proto.
1670  **	Return: none (results are returned in Filler)
1671  **	Exceptions: none
1672  **	History: Thu Feb 14 09:27:05 1991, DSJ, Created.
1673  */
1674 #define XS          X_SHIFT
1675 #define YS          Y_SHIFT
1676 #define AS          ANGLE_SHIFT
1677 #define NB          NUM_CP_BUCKETS
1678 {
1679   FLOAT32 Angle;
1680   FLOAT32 X, Y, HalfLength;
1681   FLOAT32 Cos, Sin;
1682   FLOAT32 XAdjust, YAdjust;
1683   FPOINT Start, Switch1, Switch2, End;
1684   int S1 = 0;
1685   int S2 = 1;
1686 
1687   Angle = Proto->Angle;
1688   X = Proto->X;
1689   Y = Proto->Y;
1690   HalfLength = Proto->Length / 2.0;
1691 
1692   Filler->AngleStart = CircBucketFor (Angle - AnglePad, AS, NB);
1693   Filler->AngleEnd = CircBucketFor (Angle + AnglePad, AS, NB);
1694   Filler->NextSwitch = 0;
1695 
1696   if (fabs (Angle - 0.0) < HV_TOLERANCE || fabs (Angle - 0.5) < HV_TOLERANCE) {
1697     /* horizontal proto - handle as special case */
1698     Filler->X = BucketFor (X - HalfLength - EndPad, XS, NB);
1699     Filler->YStart = BucketFor (Y - SidePad, YS, NB * 256);
1700     Filler->YEnd = BucketFor (Y + SidePad, YS, NB * 256);
1701     Filler->StartDelta = 0;
1702     Filler->EndDelta = 0;
1703     Filler->Switch[0].Type = LastSwitch;
1704     Filler->Switch[0].X = BucketFor (X + HalfLength + EndPad, XS, NB);
1705   } else if (fabs(Angle - 0.25) < HV_TOLERANCE ||
1706            fabs (Angle - 0.75) < HV_TOLERANCE) {
1707     /* vertical proto - handle as special case */
1708     Filler->X = BucketFor (X - SidePad, XS, NB);
1709     Filler->YStart = BucketFor (Y - HalfLength - EndPad, YS, NB * 256);
1710     Filler->YEnd = BucketFor (Y + HalfLength + EndPad, YS, NB * 256);
1711     Filler->StartDelta = 0;
1712     Filler->EndDelta = 0;
1713     Filler->Switch[0].Type = LastSwitch;
1714     Filler->Switch[0].X = BucketFor (X + SidePad, XS, NB);
1715   } else {
1716     /* diagonal proto */
1717 
1718     if ((Angle > 0.0 && Angle < 0.25) || (Angle > 0.5 && Angle < 0.75)) {
1719       /* rising diagonal proto */
1720       Angle *= 2.0 * PI;
1721       Cos = fabs (cos (Angle));
1722       Sin = fabs (sin (Angle));
1723 
1724       /* compute the positions of the corners of the acceptance region */
1725       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1726       Start.y = Y - (HalfLength + EndPad) * Sin + SidePad * Cos;
1727       End.x = 2.0 * X - Start.x;
1728       End.y = 2.0 * Y - Start.y;
1729       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1730       Switch1.y = Y - (HalfLength + EndPad) * Sin - SidePad * Cos;
1731       Switch2.x = 2.0 * X - Switch1.x;
1732       Switch2.y = 2.0 * Y - Switch1.y;
1733 
1734       if (Switch1.x > Switch2.x) {
1735         S1 = 1;
1736         S2 = 0;
1737       }
1738 
1739       /* translate into bucket positions and deltas */
1740       Filler->X = (inT8) MapParam (Start.x, XS, NB);
1741       Filler->StartDelta = -(inT16) ((Cos / Sin) * 256);
1742       Filler->EndDelta = (inT16) ((Sin / Cos) * 256);
1743 
1744       XAdjust = BucketEnd (Filler->X, XS, NB) - Start.x;
1745       YAdjust = XAdjust * Cos / Sin;
1746       Filler->YStart = (inT16) MapParam (Start.y - YAdjust, YS, NB * 256);
1747       YAdjust = XAdjust * Sin / Cos;
1748       Filler->YEnd = (inT16) MapParam (Start.y + YAdjust, YS, NB * 256);
1749 
1750       Filler->Switch[S1].Type = StartSwitch;
1751       Filler->Switch[S1].X = (inT8) MapParam (Switch1.x, XS, NB);
1752       Filler->Switch[S1].Y = (inT8) MapParam (Switch1.y, YS, NB);
1753       XAdjust = Switch1.x - BucketStart (Filler->Switch[S1].X, XS, NB);
1754       YAdjust = XAdjust * Sin / Cos;
1755       Filler->Switch[S1].YInit =
1756         (inT16) MapParam (Switch1.y - YAdjust, YS, NB * 256);
1757       Filler->Switch[S1].Delta = Filler->EndDelta;
1758 
1759       Filler->Switch[S2].Type = EndSwitch;
1760       Filler->Switch[S2].X = (inT8) MapParam (Switch2.x, XS, NB);
1761       Filler->Switch[S2].Y = (inT8) MapParam (Switch2.y, YS, NB);
1762       XAdjust = Switch2.x - BucketStart (Filler->Switch[S2].X, XS, NB);
1763       YAdjust = XAdjust * Cos / Sin;
1764       Filler->Switch[S2].YInit =
1765         (inT16) MapParam (Switch2.y + YAdjust, YS, NB * 256);
1766       Filler->Switch[S2].Delta = Filler->StartDelta;
1767 
1768       Filler->Switch[2].Type = LastSwitch;
1769       Filler->Switch[2].X = (inT8) MapParam (End.x, XS, NB);
1770     } else {
1771       /* falling diagonal proto */
1772       Angle *= 2.0 * PI;
1773       Cos = fabs (cos (Angle));
1774       Sin = fabs (sin (Angle));
1775 
1776       /* compute the positions of the corners of the acceptance region */
1777       Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1778       Start.y = Y + (HalfLength + EndPad) * Sin - SidePad * Cos;
1779       End.x = 2.0 * X - Start.x;
1780       End.y = 2.0 * Y - Start.y;
1781       Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1782       Switch1.y = Y + (HalfLength + EndPad) * Sin + SidePad * Cos;
1783       Switch2.x = 2.0 * X - Switch1.x;
1784       Switch2.y = 2.0 * Y - Switch1.y;
1785 
1786       if (Switch1.x > Switch2.x) {
1787         S1 = 1;
1788         S2 = 0;
1789       }
1790 
1791       /* translate into bucket positions and deltas */
1792       Filler->X = (inT8) MapParam (Start.x, XS, NB);
1793       Filler->StartDelta = -(inT16) ((Sin / Cos) * 256);
1794       Filler->EndDelta = (inT16) ((Cos / Sin) * 256);
1795 
1796       XAdjust = BucketEnd (Filler->X, XS, NB) - Start.x;
1797       YAdjust = XAdjust * Sin / Cos;
1798       Filler->YStart = (inT16) MapParam (Start.y - YAdjust, YS, NB * 256);
1799       YAdjust = XAdjust * Cos / Sin;
1800       Filler->YEnd = (inT16) MapParam (Start.y + YAdjust, YS, NB * 256);
1801 
1802       Filler->Switch[S1].Type = EndSwitch;
1803       Filler->Switch[S1].X = (inT8) MapParam (Switch1.x, XS, NB);
1804       Filler->Switch[S1].Y = (inT8) MapParam (Switch1.y, YS, NB);
1805       XAdjust = Switch1.x - BucketStart (Filler->Switch[S1].X, XS, NB);
1806       YAdjust = XAdjust * Sin / Cos;
1807       Filler->Switch[S1].YInit =
1808         (inT16) MapParam (Switch1.y + YAdjust, YS, NB * 256);
1809       Filler->Switch[S1].Delta = Filler->StartDelta;
1810 
1811       Filler->Switch[S2].Type = StartSwitch;
1812       Filler->Switch[S2].X = (inT8) MapParam (Switch2.x, XS, NB);
1813       Filler->Switch[S2].Y = (inT8) MapParam (Switch2.y, YS, NB);
1814       XAdjust = Switch2.x - BucketStart (Filler->Switch[S2].X, XS, NB);
1815       YAdjust = XAdjust * Cos / Sin;
1816       Filler->Switch[S2].YInit =
1817         (inT16) MapParam (Switch2.y - YAdjust, YS, NB * 256);
1818       Filler->Switch[S2].Delta = Filler->EndDelta;
1819 
1820       Filler->Switch[2].Type = LastSwitch;
1821       Filler->Switch[2].X = (inT8) MapParam (End.x, XS, NB);
1822     }
1823   }
1824 }                                /* InitTableFiller */
1825 
1826 
1827 /*---------------------------------------------------------------------------*/
1828 #ifndef GRAPHICS_DISABLED
RenderIntFeature(void * window,INT_FEATURE Feature,C_COL Color)1829 void RenderIntFeature(void *window, INT_FEATURE Feature, C_COL Color) {
1830 /*
1831  **	Parameters:
1832  **		ShapeList	shape list to add feature rendering to
1833  **		Feature		feature to be rendered
1834  **		Color		color to use for feature rendering
1835  **	Globals: none
1836  **	Operation: This routine renders the specified feature into ShapeList.
1837  **	Return: New shape list with rendering of Feature added.
1838  **	Exceptions: none
1839  **	History: Thu Mar 21 14:57:41 1991, DSJ, Created.
1840  */
1841   FLOAT32 X, Y, Dx, Dy, Length;
1842 
1843   c_line_color_index(window, Color);
1844   assert (Feature != NULL);
1845   assert (Color != 0);
1846 
1847   X = Feature->X - DISPLAY_OFFSET;
1848   Y = Feature->Y - DISPLAY_OFFSET;
1849   Length = GetPicoFeatureLength () * 0.7 * INT_CHAR_NORM_RANGE;
1850   Dx = (Length / 2.0) * cos ((Feature->Theta / 256.0) * 2.0 * PI);
1851   Dy = (Length / 2.0) * sin ((Feature->Theta / 256.0) * 2.0 * PI);
1852 
1853   c_move (window, X - Dx, Y - Dy);
1854   c_draw (window, X + Dx, Y + Dy);
1855   c_move (window, X - Dx - Dy * DOUBLE_OFFSET, Y - Dy + Dx * DOUBLE_OFFSET);
1856   c_draw (window, X + Dx - Dy * DOUBLE_OFFSET, Y + Dy + Dx * DOUBLE_OFFSET);
1857 }                                /* RenderIntFeature */
1858 
1859 
1860 /*---------------------------------------------------------------------------*/
RenderIntProto(void * window,INT_CLASS Class,PROTO_ID ProtoId,C_COL Color)1861 void RenderIntProto(void *window,
1862                     INT_CLASS Class,
1863                     PROTO_ID ProtoId,
1864                     C_COL Color) {
1865 /*
1866  **	Parameters:
1867  **		ShapeList	shape list to append proto rendering onto
1868  **		Class		class that proto is contained in
1869  **		ProtoId		id of proto to be rendered
1870  **		Color		color to render proto in
1871  **	Globals: none
1872  **	Operation: This routine extracts the parameters of the specified
1873  **		proto from the class description and adds a rendering of
1874  **		the proto onto the ShapeList.
1875  **	Return: New shape list with a rendering of one proto added.
1876  **	Exceptions: none
1877  **	History: Thu Mar 21 10:21:09 1991, DSJ, Created.
1878  */
1879   PROTO_SET ProtoSet;
1880   INT_PROTO Proto;
1881   int ProtoSetIndex;
1882   int ProtoWordIndex;
1883   FLOAT32 Length;
1884   int Xmin, Xmax, Ymin, Ymax;
1885   FLOAT32 X, Y, Dx, Dy;
1886   uinT32 ProtoMask;
1887   int Bucket;
1888 
1889   assert (ProtoId >= 0);
1890   assert (Class != NULL);
1891   assert(ProtoId < Class->NumProtos);
1892   assert (Color != 0);
1893   c_line_color_index(window, Color);
1894 
1895   ProtoSet = Class->ProtoSets[SetForProto(ProtoId)];
1896   ProtoSetIndex = IndexForProto (ProtoId);
1897   Proto = &(ProtoSet->Protos[ProtoSetIndex]);
1898   Length = (Class->ProtoLengths[ProtoId] *
1899             GetPicoFeatureLength () * INT_CHAR_NORM_RANGE);
1900   ProtoMask = PPrunerMaskFor (ProtoId);
1901   ProtoWordIndex = PPrunerWordIndexFor (ProtoId);
1902 
1903   // find the x and y extent of the proto from the proto pruning table
1904   Xmin = Ymin = NUM_PP_BUCKETS;
1905   Xmax = Ymax = 0;
1906   for (Bucket = 0; Bucket < NUM_PP_BUCKETS; Bucket++) {
1907     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_X][Bucket][ProtoWordIndex]) {
1908       if (Bucket < Xmin)
1909         Xmin = Bucket;
1910       else if (Bucket > Xmax)
1911         Xmax = Bucket;
1912     }
1913 
1914     if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_Y][Bucket][ProtoWordIndex]) {
1915       if (Bucket < Ymin)
1916         Ymin = Bucket;
1917       else if (Bucket > Ymax)
1918         Ymax = Bucket;
1919     }
1920   }
1921   X = (Xmin + Xmax + 1) / 2.0 * PROTO_PRUNER_SCALE - DISPLAY_OFFSET;
1922   Y = (Ymin + Ymax + 1) / 2.0 * PROTO_PRUNER_SCALE - DISPLAY_OFFSET;
1923   Dx = (Length / 2.0) * cos ((Proto->Angle / 256.0) * 2.0 * PI);
1924   Dy = (Length / 2.0) * sin ((Proto->Angle / 256.0) * 2.0 * PI);
1925 
1926   c_move (window, X - Dx, Y - Dy);
1927   c_draw (window, X + Dx, Y + Dy);
1928 }                                /* RenderIntProto */
1929 #endif
1930 
1931 /*---------------------------------------------------------------------------*/
TruncateParam(FLOAT32 Param,int Min,int Max,char * Id)1932 int TruncateParam(FLOAT32 Param, int Min, int Max, char *Id) {
1933 /*
1934  **	Parameters:
1935  **		Param		parameter value to be truncated
1936  **		Min, Max	parameter limits (inclusive)
1937  **		Id		string id of parameter for error messages
1938  **	Globals: none
1939  **	Operation: This routine truncates Param to lie within the range
1940  **		of Min-Max inclusive.  If a truncation is performed, and
1941  **		Id is not null, an warning message is printed.
1942  **	Return: Truncated parameter.
1943  **	Exceptions: none
1944  **	History: Fri Feb  8 11:54:28 1991, DSJ, Created.
1945  */
1946   if (Param < Min) {
1947     if (Id)
1948       cprintf ("Warning: Param %s truncated from %f to %d!\n",
1949                Id, Param, Min);
1950     Param = Min;
1951   } else if (Param > Max) {
1952     if (Id)
1953       cprintf ("Warning: Param %s truncated from %f to %d!\n",
1954                Id, Param, Max);
1955     Param = Max;
1956   }
1957   return static_cast<int>(floor(Param));
1958 }                                /* TruncateParam */
1959 
1960 
1961 /*---------------------------------------------------------------------------*/
1962 
InitIntMatchWindowIfReqd()1963 void InitIntMatchWindowIfReqd() {
1964 #ifndef GRAPHICS_DISABLED
1965 /*
1966  **     Operation: Initializes the int matcher window if it is not already
1967  **     initialized.
1968  */
1969   if (IntMatchWindow == NULL) {
1970     IntMatchWindow = c_create_window("IntMatchWindow", 50, 200,
1971                                      520, 520,
1972                                      -130.0, 130.0, -130.0, 130.0);
1973     SVMenuNode* popup_menu = new SVMenuNode();
1974 
1975     popup_menu->AddChild("Debug Adapted classes", IDA_ADAPTIVE,
1976                          "x", "Class to debug");
1977     popup_menu->AddChild("Debug Static classes", IDA_STATIC,
1978                          "x", "Class to debug");
1979     popup_menu->AddChild("Debug Both", IDA_BOTH,
1980                          "x", "Class to debug");
1981     popup_menu->BuildMenu(IntMatchWindow, false);
1982   }
1983 #endif
1984 }
1985 
InitProtoDisplayWindowIfReqd()1986 void InitProtoDisplayWindowIfReqd() {
1987 #ifndef GRAPHICS_DISABLED
1988 /*
1989  **     Operation: Initializes the proto display window if it is not already
1990  **     initialized.
1991  */
1992   if (ProtoDisplayWindow == NULL) {
1993     ProtoDisplayWindow = c_create_window("ProtoDisplayWindow", 50, 200,
1994                                          520, 520,
1995                                          -130.0, 130.0, -130.0, 130.0);
1996   }
1997 #endif
1998 }
1999 
InitFeatureDisplayWindowIfReqd()2000 void InitFeatureDisplayWindowIfReqd() {
2001 #ifndef GRAPHICS_DISABLED
2002 /*
2003  **     Operation: Initializes the feature display window if it is not already
2004  **     initialized.
2005  */
2006   if (FeatureDisplayWindow == NULL) {
2007     FeatureDisplayWindow = c_create_window("FeatureDisplayWindow", 50, 200,
2008                                            520, 520,
2009                                            -130.0, 130.0, -130.0, 130.0);
2010   }
2011 #endif
2012 }
2013