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