tesseract  5.0.0
intproto.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  ** Filename: intproto.c
3  ** Purpose: Definition of data structures for integer protos.
4  ** Author: Dan Johnson
5  **
6  ** (c) Copyright Hewlett-Packard Company, 1988.
7  ** Licensed under the Apache License, Version 2.0 (the "License");
8  ** you may not use this file except in compliance with the License.
9  ** You may obtain a copy of the License at
10  ** http://www.apache.org/licenses/LICENSE-2.0
11  ** Unless required by applicable law or agreed to in writing, software
12  ** distributed under the License is distributed on an "AS IS" BASIS,
13  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  ** See the License for the specific language governing permissions and
15  ** limitations under the License.
16  ******************************************************************************/
17 /*-----------------------------------------------------------------------------
18  Include Files and Type Defines
19 -----------------------------------------------------------------------------*/
20 
21 #define _USE_MATH_DEFINES // for M_PI
22 
23 // Include automatically generated configuration file if running autoconf.
24 #ifdef HAVE_CONFIG_H
25 # include "config_auto.h"
26 #endif
27 
28 #include "intproto.h"
29 
30 #include "classify.h"
31 #include "fontinfo.h"
32 #include "mfoutline.h"
33 #include "picofeat.h"
34 #include "points.h"
35 #include "shapetable.h"
36 #ifndef GRAPHICS_DISABLED
37 #include "svmnode.h"
38 #endif
39 
40 #include "helpers.h"
41 
42 #include <algorithm>
43 #include <cassert>
44 #include <cmath> // for M_PI, std::floor
45 #include <cstdio>
46 
47 namespace tesseract {
48 
49 /* match debug display constants*/
50 #define PROTO_PRUNER_SCALE (4.0)
51 
52 #define INT_DESCENDER (0.0 * INT_CHAR_NORM_RANGE)
53 #define INT_BASELINE (0.25 * INT_CHAR_NORM_RANGE)
54 #define INT_XHEIGHT (0.75 * INT_CHAR_NORM_RANGE)
55 #define INT_CAPHEIGHT (1.0 * INT_CHAR_NORM_RANGE)
56 
57 #define INT_XCENTER (0.5 * INT_CHAR_NORM_RANGE)
58 #define INT_YCENTER (0.5 * INT_CHAR_NORM_RANGE)
59 #define INT_XRADIUS (0.2 * INT_CHAR_NORM_RANGE)
60 #define INT_YRADIUS (0.2 * INT_CHAR_NORM_RANGE)
61 #define INT_MIN_X 0
62 #define INT_MIN_Y 0
63 #define INT_MAX_X INT_CHAR_NORM_RANGE
64 #define INT_MAX_Y INT_CHAR_NORM_RANGE
65 
67 #define HV_TOLERANCE (0.0025) /* approx 0.9 degrees */
68 
70 #define MAX_NUM_SWITCHES 3
71 
72 struct FILL_SWITCH {
74  int8_t X, Y;
75  int16_t YInit;
76  int16_t Delta;
77 };
78 
79 struct TABLE_FILLER {
80  uint8_t NextSwitch;
81  uint8_t AngleStart, AngleEnd;
82  int8_t X;
83  int16_t YStart, YEnd;
84  int16_t StartDelta, EndDelta;
86 };
87 
88 struct FILL_SPEC {
89  int8_t X;
90  int8_t YStart, YEnd;
91  uint8_t AngleStart, AngleEnd;
92 };
93 
94 /* constants for conversion from old inttemp format */
95 #define OLD_MAX_NUM_CONFIGS 32
96 #define OLD_WERDS_PER_CONFIG_VEC ((OLD_MAX_NUM_CONFIGS + BITS_PER_WERD - 1) / BITS_PER_WERD)
97 
98 /*-----------------------------------------------------------------------------
99  Macros
100 -----------------------------------------------------------------------------*/
102 #define CircularIncrement(i, r) (((i) < (r)-1) ? ((i)++) : ((i) = 0))
103 
105 #define MapParam(P, O, N) (std::floor(((P) + (O)) * (N)))
106 
107 /*---------------------------------------------------------------------------
108  Private Function Prototypes
109 ----------------------------------------------------------------------------*/
110 float BucketStart(int Bucket, float Offset, int NumBuckets);
111 
112 float BucketEnd(int Bucket, float Offset, int NumBuckets);
113 
114 void DoFill(FILL_SPEC *FillSpec, CLASS_PRUNER_STRUCT *Pruner, uint32_t ClassMask,
115  uint32_t ClassCount, uint32_t WordIndex);
116 
117 bool FillerDone(TABLE_FILLER *Filler);
118 
119 void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
120  float Center, float Spread, bool debug);
121 
122 void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
123  float Center, float Spread, bool debug);
124 
125 void GetCPPadsForLevel(int Level, float *EndPad, float *SidePad, float *AnglePad);
126 
127 ScrollView::Color GetMatchColorFor(float Evidence);
128 
129 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill);
130 
131 void InitTableFiller(float EndPad, float SidePad, float AnglePad, PROTO_STRUCT *Proto,
132  TABLE_FILLER *Filler);
133 
134 #ifndef GRAPHICS_DISABLED
135 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT *Feature,
136  ScrollView::Color color);
137 
138 void RenderIntProto(ScrollView *window, INT_CLASS_STRUCT *Class, PROTO_ID ProtoId, ScrollView::Color color);
139 #endif // !GRAPHICS_DISABLED
140 
141 /*-----------------------------------------------------------------------------
142  Global Data Definitions and Declarations
143 -----------------------------------------------------------------------------*/
144 
145 #ifndef GRAPHICS_DISABLED
146 /* global display lists used to display proto and feature match information*/
147 static ScrollView *IntMatchWindow = nullptr;
148 static ScrollView *FeatureDisplayWindow = nullptr;
149 static ScrollView *ProtoDisplayWindow = nullptr;
150 #endif
151 
152 /*-----------------------------------------------------------------------------
153  Variables
154 -----------------------------------------------------------------------------*/
155 
156 /* control knobs */
157 static INT_VAR(classify_num_cp_levels, 3, "Number of Class Pruner Levels");
158 static double_VAR(classify_cp_angle_pad_loose, 45.0, "Class Pruner Angle Pad Loose");
159 static double_VAR(classify_cp_angle_pad_medium, 20.0, "Class Pruner Angle Pad Medium");
160 static double_VAR(classify_cp_angle_pad_tight, 10.0, "CLass Pruner Angle Pad Tight");
161 static double_VAR(classify_cp_end_pad_loose, 0.5, "Class Pruner End Pad Loose");
162 static double_VAR(classify_cp_end_pad_medium, 0.5, "Class Pruner End Pad Medium");
163 static double_VAR(classify_cp_end_pad_tight, 0.5, "Class Pruner End Pad Tight");
164 static double_VAR(classify_cp_side_pad_loose, 2.5, "Class Pruner Side Pad Loose");
165 static double_VAR(classify_cp_side_pad_medium, 1.2, "Class Pruner Side Pad Medium");
166 static double_VAR(classify_cp_side_pad_tight, 0.6, "Class Pruner Side Pad Tight");
167 static double_VAR(classify_pp_angle_pad, 45.0, "Proto Pruner Angle Pad");
168 static double_VAR(classify_pp_end_pad, 0.5, "Proto Prune End Pad");
169 static double_VAR(classify_pp_side_pad, 2.5, "Proto Pruner Side Pad");
170 
180 static int TruncateParam(float Param, int Min, int Max) {
181  int result;
182  if (Param < Min) {
183  result = Min;
184  } else if (Param > Max) {
185  result = Max;
186  } else {
187  result = static_cast<int>(std::floor(Param));
188  }
189  return result;
190 }
191 
192 /*-----------------------------------------------------------------------------
193  Public Code
194 -----------------------------------------------------------------------------*/
198  : X(ClipToRange<int16_t>(static_cast<int16_t>(pos.x() + 0.5), 0, 255))
199  , Y(ClipToRange<int16_t>(static_cast<int16_t>(pos.y() + 0.5), 0, 255))
200  , Theta(theta)
201  , CP_misses(0) {}
204  : X(static_cast<uint8_t>(ClipToRange<int>(x, 0, UINT8_MAX)))
205  , Y(static_cast<uint8_t>(ClipToRange<int>(y, 0, UINT8_MAX)))
206  , Theta(static_cast<uint8_t>(ClipToRange<int>(theta, 0, UINT8_MAX)))
207  , CP_misses(0) {}
208 
220 void AddIntClass(INT_TEMPLATES_STRUCT *Templates, CLASS_ID ClassId, INT_CLASS_STRUCT *Class) {
221  int Pruner;
222 
223  assert(LegalClassId(ClassId));
224  if (static_cast<unsigned>(ClassId) != Templates->NumClasses) {
225  fprintf(stderr,
226  "Please make sure that classes are added to templates"
227  " in increasing order of ClassIds\n");
228  exit(1);
229  }
230  ClassForClassId(Templates, ClassId) = Class;
231  Templates->NumClasses++;
232 
233  if (Templates->NumClasses > MaxNumClassesIn(Templates)) {
234  Pruner = Templates->NumClassPruners++;
235  Templates->ClassPruners[Pruner] = new CLASS_PRUNER_STRUCT;
236  memset(Templates->ClassPruners[Pruner], 0, sizeof(CLASS_PRUNER_STRUCT));
237  }
238 } /* AddIntClass */
239 
251  int Index;
252 
253  assert(Class->NumConfigs < MAX_NUM_CONFIGS);
254 
255  Index = Class->NumConfigs++;
256  Class->ConfigLengths[Index] = 0;
257  return Index;
258 } /* AddIntConfig */
259 
271  if (Class->NumProtos >= MAX_NUM_PROTOS) {
272  return (NO_PROTO);
273  }
274 
275  int Index = Class->NumProtos++;
276 
277  if (Class->NumProtos > MaxNumIntProtosIn(Class)) {
278  int ProtoSetId = Class->NumProtoSets++;
279  auto ProtoSet = new PROTO_SET_STRUCT;
280  Class->ProtoSets[ProtoSetId] = ProtoSet;
281  memset(ProtoSet, 0, sizeof(*ProtoSet));
282 
283  /* reallocate space for the proto lengths and install in class */
284  Class->ProtoLengths.resize(MaxNumIntProtosIn(Class));
285  }
286 
287  /* initialize proto so its length is zero and it isn't in any configs */
288  Class->ProtoLengths[Index] = 0;
289  auto Proto = ProtoForProtoId(Class, Index);
290  for (uint32_t *Word = Proto->Configs; Word < Proto->Configs + WERDS_PER_CONFIG_VEC; *Word++ = 0) {
291  }
292 
293  return (Index);
294 }
295 
307 #define MAX_LEVEL 2
308 {
309  CLASS_PRUNER_STRUCT *Pruner;
310  uint32_t ClassMask;
311  uint32_t ClassCount;
312  uint32_t WordIndex;
313  int Level;
314  float EndPad, SidePad, AnglePad;
315  TABLE_FILLER TableFiller;
316  FILL_SPEC FillSpec;
317 
318  Pruner = CPrunerFor(Templates, ClassId);
319  WordIndex = CPrunerWordIndexFor(ClassId);
320  ClassMask = CPrunerMaskFor(MAX_LEVEL, ClassId);
321 
322  for (Level = classify_num_cp_levels - 1; Level >= 0; Level--) {
323  GetCPPadsForLevel(Level, &EndPad, &SidePad, &AnglePad);
324  ClassCount = CPrunerMaskFor(Level, ClassId);
325  InitTableFiller(EndPad, SidePad, AnglePad, Proto, &TableFiller);
326 
327  while (!FillerDone(&TableFiller)) {
328  GetNextFill(&TableFiller, &FillSpec);
329  DoFill(&FillSpec, Pruner, ClassMask, ClassCount, WordIndex);
330  }
331  }
332 } /* AddProtoToClassPruner */
333 
344 void AddProtoToProtoPruner(PROTO_STRUCT *Proto, int ProtoId, INT_CLASS_STRUCT *Class, bool debug) {
345  float X, Y, Length;
346  float Pad;
347 
348  if (ProtoId >= Class->NumProtos) {
349  tprintf("AddProtoToProtoPruner:assert failed: %d < %d", ProtoId, Class->NumProtos);
350  }
351  assert(ProtoId < Class->NumProtos);
352 
353  int Index = IndexForProto(ProtoId);
354  auto ProtoSet = Class->ProtoSets[SetForProto(ProtoId)];
355 
356  float Angle = Proto->Angle;
357 #ifndef _WIN32
358  assert(!std::isnan(Angle));
359 #endif
360 
361  FillPPCircularBits(ProtoSet->ProtoPruner[PRUNER_ANGLE], Index, Angle + ANGLE_SHIFT,
362  classify_pp_angle_pad / 360.0, debug);
363 
364  Angle *= 2.0 * M_PI;
365  Length = Proto->Length;
366 
367  X = Proto->X + X_SHIFT;
368  Pad = std::max(fabs(std::cos(Angle)) * (Length / 2.0 + classify_pp_end_pad * GetPicoFeatureLength()),
369  fabs(std::sin(Angle)) * (classify_pp_side_pad * GetPicoFeatureLength()));
370 
371  FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_X], Index, X, Pad, debug);
372 
373  Y = Proto->Y + Y_SHIFT;
374  Pad = std::max(fabs(std::sin(Angle)) * (Length / 2.0 + classify_pp_end_pad * GetPicoFeatureLength()),
375  fabs(std::cos(Angle)) * (classify_pp_side_pad * GetPicoFeatureLength()));
376 
377  FillPPLinearBits(ProtoSet->ProtoPruner[PRUNER_Y], Index, Y, Pad, debug);
378 } /* AddProtoToProtoPruner */
379 
385 uint8_t Bucket8For(float param, float offset, int num_buckets) {
386  int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
387  return static_cast<uint8_t>(ClipToRange<int>(bucket, 0, num_buckets - 1));
388 }
389 uint16_t Bucket16For(float param, float offset, int num_buckets) {
390  int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
391  return static_cast<uint16_t>(ClipToRange<int>(bucket, 0, num_buckets - 1));
392 }
393 
399 uint8_t CircBucketFor(float param, float offset, int num_buckets) {
400  int bucket = IntCastRounded(MapParam(param, offset, num_buckets));
401  return static_cast<uint8_t>(Modulo(bucket, num_buckets));
402 } /* CircBucketFor */
403 
404 #ifndef GRAPHICS_DISABLED
414  if (IntMatchWindow != nullptr) {
415  IntMatchWindow->Update();
416  }
417 } /* ClearMatchDisplay */
418 #endif
419 
430 void ConvertConfig(BIT_VECTOR Config, int ConfigId, INT_CLASS_STRUCT *Class) {
431  int ProtoId;
432  INT_PROTO_STRUCT *Proto;
433  int TotalLength;
434 
435  for (ProtoId = 0, TotalLength = 0; ProtoId < Class->NumProtos; ProtoId++) {
436  if (test_bit(Config, ProtoId)) {
437  Proto = ProtoForProtoId(Class, ProtoId);
438  SET_BIT(Proto->Configs, ConfigId);
439  TotalLength += Class->ProtoLengths[ProtoId];
440  }
441  }
442  Class->ConfigLengths[ConfigId] = TotalLength;
443 } /* ConvertConfig */
444 
452 void Classify::ConvertProto(PROTO_STRUCT *Proto, int ProtoId, INT_CLASS_STRUCT *Class) {
453  assert(ProtoId < Class->NumProtos);
454 
455  INT_PROTO_STRUCT *P = ProtoForProtoId(Class, ProtoId);
456 
457  float Param = Proto->A * 128;
458  P->A = TruncateParam(Param, -128, 127);
459 
460  Param = -Proto->B * 256;
461  P->B = TruncateParam(Param, 0, 255);
462 
463  Param = Proto->C * 128;
464  P->C = TruncateParam(Param, -128, 127);
465 
466  Param = Proto->Angle * 256;
467  if (Param < 0 || Param >= 256) {
468  P->Angle = 0;
469  } else {
470  P->Angle = static_cast<uint8_t>(Param);
471  }
472 
473  /* round proto length to nearest integer number of pico-features */
474  Param = (Proto->Length / GetPicoFeatureLength()) + 0.5;
475  Class->ProtoLengths[ProtoId] = TruncateParam(Param, 1, 255);
476  if (classify_learning_debug_level >= 2) {
477  tprintf("Converted ffeat to (A=%d,B=%d,C=%d,L=%d)", P->A, P->B, P->C,
478  Class->ProtoLengths[ProtoId]);
479  }
480 } /* ConvertProto */
481 
491  const UNICHARSET &target_unicharset) {
492  CLASS_TYPE FClass;
493  INT_CLASS_STRUCT *IClass;
494  int ProtoId;
495  int ConfigId;
496 
497  auto IntTemplates = new INT_TEMPLATES_STRUCT;
498 
499  for (unsigned ClassId = 0; ClassId < target_unicharset.size(); ClassId++) {
500  FClass = &(FloatProtos[ClassId]);
501  if (FClass->NumProtos == 0 && FClass->NumConfigs == 0 &&
502  strcmp(target_unicharset.id_to_unichar(ClassId), " ") != 0) {
503  tprintf("Warning: no protos/configs for %s in CreateIntTemplates()\n",
504  target_unicharset.id_to_unichar(ClassId));
505  }
506  assert(UnusedClassIdIn(IntTemplates, ClassId));
507  IClass = new INT_CLASS_STRUCT(FClass->NumProtos, FClass->NumConfigs);
508  FontSet fs{FClass->font_set.size()};
509  for (unsigned i = 0; i < fs.size(); ++i) {
510  fs[i] = FClass->font_set.at(i);
511  }
512  IClass->font_set_id = this->fontset_table_.push_back(fs);
513  AddIntClass(IntTemplates, ClassId, IClass);
514 
515  for (ProtoId = 0; ProtoId < FClass->NumProtos; ProtoId++) {
516  AddIntProto(IClass);
517  ConvertProto(ProtoIn(FClass, ProtoId), ProtoId, IClass);
518  AddProtoToProtoPruner(ProtoIn(FClass, ProtoId), ProtoId, IClass,
519  classify_learning_debug_level >= 2);
520  AddProtoToClassPruner(ProtoIn(FClass, ProtoId), ClassId, IntTemplates);
521  }
522 
523  for (ConfigId = 0; ConfigId < FClass->NumConfigs; ConfigId++) {
524  AddIntConfig(IClass);
525  ConvertConfig(FClass->Configurations[ConfigId], ConfigId, IClass);
526  }
527  }
528  return (IntTemplates);
529 } /* CreateIntTemplates */
530 
531 #ifndef GRAPHICS_DISABLED
541 void DisplayIntFeature(const INT_FEATURE_STRUCT *Feature, float Evidence) {
542  ScrollView::Color color = GetMatchColorFor(Evidence);
543  RenderIntFeature(IntMatchWindow, Feature, color);
544  if (FeatureDisplayWindow) {
545  RenderIntFeature(FeatureDisplayWindow, Feature, color);
546  }
547 } /* DisplayIntFeature */
548 
559 void DisplayIntProto(INT_CLASS_STRUCT *Class, PROTO_ID ProtoId, float Evidence) {
560  ScrollView::Color color = GetMatchColorFor(Evidence);
561  RenderIntProto(IntMatchWindow, Class, ProtoId, color);
562  if (ProtoDisplayWindow) {
563  RenderIntProto(ProtoDisplayWindow, Class, ProtoId, color);
564  }
565 } /* DisplayIntProto */
566 #endif
567 
573 INT_CLASS_STRUCT::INT_CLASS_STRUCT(int MaxNumProtos, int MaxNumConfigs) :
574  NumProtos(0),
575  NumProtoSets((MaxNumProtos + PROTOS_PER_PROTO_SET - 1) / PROTOS_PER_PROTO_SET),
576  NumConfigs(0),
577  ProtoLengths(MaxNumIntProtosIn(this))
578 {
579  assert(MaxNumConfigs <= MAX_NUM_CONFIGS);
580  assert(NumProtoSets <= MAX_NUM_PROTO_SETS);
581 
582  for (int i = 0; i < NumProtoSets; i++) {
583  /* allocate space for a proto set, install in class, and initialize */
584  auto ProtoSet = new PROTO_SET_STRUCT;
585  memset(ProtoSet, 0, sizeof(*ProtoSet));
586  ProtoSets[i] = ProtoSet;
587 
588  /* allocate space for the proto lengths and install in class */
589  }
590  memset(ConfigLengths, 0, sizeof(ConfigLengths));
591 }
592 
594  for (int i = 0; i < NumProtoSets; i++) {
595  delete ProtoSets[i];
596  }
597 }
598 
602  NumClasses = 0;
603  NumClassPruners = 0;
604 
605  for (int i = 0; i < MAX_NUM_CLASSES; i++) {
606  ClassForClassId(this, i) = nullptr;
607  }
608 }
609 
611  for (unsigned i = 0; i < NumClasses; i++) {
612  delete Class[i];
613  }
614  for (unsigned i = 0; i < NumClassPruners; i++) {
615  delete ClassPruners[i];
616  }
617 }
618 
628  int j, w, x, y, z;
629  INT_TEMPLATES_STRUCT *Templates;
630  CLASS_PRUNER_STRUCT *Pruner;
631  INT_CLASS_STRUCT *Class;
632 
633  /* variables for conversion from older inttemp formats */
634  int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
635  CLASS_ID class_id, max_class_id;
636  std::vector<CLASS_ID> ClassIdFor(MAX_NUM_CLASSES);
637  std::vector<CLASS_PRUNER_STRUCT *> TempClassPruner(MAX_NUM_CLASS_PRUNERS);
638  uint32_t SetBitsForMask = // word with NUM_BITS_PER_CLASS
639  (1 << NUM_BITS_PER_CLASS) - 1; // set starting at bit 0
640  uint32_t Mask, NewMask, ClassBits;
641  unsigned MaxNumConfigs = MAX_NUM_CONFIGS;
642  unsigned WerdsPerConfigVec = WERDS_PER_CONFIG_VEC;
643 
644  /* first read the high level template struct */
645  Templates = new INT_TEMPLATES_STRUCT;
646  // Read Templates in parts for 64 bit compatibility.
647  uint32_t unicharset_size;
648  if (fp->FReadEndian(&unicharset_size, sizeof(unicharset_size), 1) != 1) {
649  tprintf("Bad read of inttemp!\n");
650  }
651  int32_t version_id = 0;
652  if (fp->FReadEndian(&version_id, sizeof(version_id), 1) != 1 ||
653  fp->FReadEndian(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners), 1) != 1) {
654  tprintf("Bad read of inttemp!\n");
655  }
656  if (version_id < 0) {
657  // This file has a version id!
658  version_id = -version_id;
659  if (fp->FReadEndian(&Templates->NumClasses, sizeof(Templates->NumClasses), 1) != 1) {
660  tprintf("Bad read of inttemp!\n");
661  }
662  } else {
663  Templates->NumClasses = version_id;
664  }
665 
666  if (version_id < 3) {
667  MaxNumConfigs = OLD_MAX_NUM_CONFIGS;
668  WerdsPerConfigVec = OLD_WERDS_PER_CONFIG_VEC;
669  }
670 
671  if (version_id < 2) {
672  std::vector<int16_t> IndexFor(MAX_NUM_CLASSES);
673  if (fp->FReadEndian(&IndexFor[0], sizeof(IndexFor[0]), unicharset_size) != unicharset_size) {
674  tprintf("Bad read of inttemp!\n");
675  }
676  if (fp->FReadEndian(&ClassIdFor[0], sizeof(ClassIdFor[0]), Templates->NumClasses) !=
677  Templates->NumClasses) {
678  tprintf("Bad read of inttemp!\n");
679  }
680  }
681 
682  /* then read in the class pruners */
683  const unsigned kNumBuckets = NUM_CP_BUCKETS * NUM_CP_BUCKETS * NUM_CP_BUCKETS * WERDS_PER_CP_VECTOR;
684  for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
685  Pruner = new CLASS_PRUNER_STRUCT;
686  if (fp->FReadEndian(Pruner, sizeof(Pruner->p[0][0][0][0]), kNumBuckets) != kNumBuckets) {
687  tprintf("Bad read of inttemp!\n");
688  }
689  if (version_id < 2) {
690  TempClassPruner[i] = Pruner;
691  } else {
692  Templates->ClassPruners[i] = Pruner;
693  }
694  }
695 
696  /* fix class pruners if they came from an old version of inttemp */
697  if (version_id < 2) {
698  // Allocate enough class pruners to cover all the class ids.
699  max_class_id = 0;
700  for (unsigned i = 0; i < Templates->NumClasses; i++) {
701  if (ClassIdFor[i] > max_class_id) {
702  max_class_id = ClassIdFor[i];
703  }
704  }
705  for (int i = 0; i <= CPrunerIdFor(max_class_id); i++) {
706  Templates->ClassPruners[i] = new CLASS_PRUNER_STRUCT;
707  memset(Templates->ClassPruners[i], 0, sizeof(CLASS_PRUNER_STRUCT));
708  }
709  // Convert class pruners from the old format (indexed by class index)
710  // to the new format (indexed by class id).
711  last_cp_bit_number = NUM_BITS_PER_CLASS * Templates->NumClasses - 1;
712  for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
713  for (x = 0; x < NUM_CP_BUCKETS; x++) {
714  for (y = 0; y < NUM_CP_BUCKETS; y++) {
715  for (z = 0; z < NUM_CP_BUCKETS; z++) {
716  for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
717  if (TempClassPruner[i]->p[x][y][z][w] == 0) {
718  continue;
719  }
720  for (b = 0; b < BITS_PER_WERD; b += NUM_BITS_PER_CLASS) {
721  bit_number = i * BITS_PER_CP_VECTOR + w * BITS_PER_WERD + b;
722  if (bit_number > last_cp_bit_number) {
723  break; // the rest of the bits in this word are not used
724  }
725  class_id = ClassIdFor[bit_number / NUM_BITS_PER_CLASS];
726  // Single out NUM_BITS_PER_CLASS bits relating to class_id.
727  Mask = SetBitsForMask << b;
728  ClassBits = TempClassPruner[i]->p[x][y][z][w] & Mask;
729  // Move these bits to the new position in which they should
730  // appear (indexed corresponding to the class_id).
731  new_i = CPrunerIdFor(class_id);
732  new_w = CPrunerWordIndexFor(class_id);
733  new_b = CPrunerBitIndexFor(class_id) * NUM_BITS_PER_CLASS;
734  if (new_b > b) {
735  ClassBits <<= (new_b - b);
736  } else {
737  ClassBits >>= (b - new_b);
738  }
739  // Copy bits relating to class_id to the correct position
740  // in Templates->ClassPruner.
741  NewMask = SetBitsForMask << new_b;
742  Templates->ClassPruners[new_i]->p[x][y][z][new_w] &= ~NewMask;
743  Templates->ClassPruners[new_i]->p[x][y][z][new_w] |= ClassBits;
744  }
745  }
746  }
747  }
748  }
749  }
750  for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
751  delete TempClassPruner[i];
752  }
753  }
754 
755  /* then read in each class */
756  for (unsigned i = 0; i < Templates->NumClasses; i++) {
757  /* first read in the high level struct for the class */
758  Class = new INT_CLASS_STRUCT;
759  if (fp->FReadEndian(&Class->NumProtos, sizeof(Class->NumProtos), 1) != 1 ||
760  fp->FRead(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1) != 1 ||
761  fp->FRead(&Class->NumConfigs, sizeof(Class->NumConfigs), 1) != 1) {
762  tprintf("Bad read of inttemp!\n");
763  }
764  if (version_id == 0) {
765  // Only version 0 writes 5 pointless pointers to the file.
766  for (j = 0; j < 5; ++j) {
767  int32_t junk;
768  if (fp->FRead(&junk, sizeof(junk), 1) != 1) {
769  tprintf("Bad read of inttemp!\n");
770  }
771  }
772  }
773  unsigned num_configs = version_id < 4 ? MaxNumConfigs : Class->NumConfigs;
774  ASSERT_HOST(num_configs <= MaxNumConfigs);
775  if (fp->FReadEndian(Class->ConfigLengths, sizeof(uint16_t), num_configs) != num_configs) {
776  tprintf("Bad read of inttemp!\n");
777  }
778  if (version_id < 2) {
779  ClassForClassId(Templates, ClassIdFor[i]) = Class;
780  } else {
781  ClassForClassId(Templates, i) = Class;
782  }
783 
784  /* then read in the proto lengths */
785  Class->ProtoLengths.clear();
786  if (MaxNumIntProtosIn(Class) > 0) {
787  Class->ProtoLengths.resize(MaxNumIntProtosIn(Class));
788  if (fp->FRead(&Class->ProtoLengths[0], sizeof(uint8_t), MaxNumIntProtosIn(Class)) !=
789  MaxNumIntProtosIn(Class)) {
790  tprintf("Bad read of inttemp!\n");
791  }
792  }
793 
794  /* then read in the proto sets */
795  for (j = 0; j < Class->NumProtoSets; j++) {
796  auto ProtoSet = new PROTO_SET_STRUCT;
797  unsigned num_buckets = NUM_PP_PARAMS * NUM_PP_BUCKETS * WERDS_PER_PP_VECTOR;
798  if (fp->FReadEndian(&ProtoSet->ProtoPruner, sizeof(ProtoSet->ProtoPruner[0][0][0]),
799  num_buckets) != num_buckets) {
800  tprintf("Bad read of inttemp!\n");
801  }
802  for (x = 0; x < PROTOS_PER_PROTO_SET; x++) {
803  if (fp->FRead(&ProtoSet->Protos[x].A, sizeof(ProtoSet->Protos[x].A), 1) != 1 ||
804  fp->FRead(&ProtoSet->Protos[x].B, sizeof(ProtoSet->Protos[x].B), 1) != 1 ||
805  fp->FRead(&ProtoSet->Protos[x].C, sizeof(ProtoSet->Protos[x].C), 1) != 1 ||
806  fp->FRead(&ProtoSet->Protos[x].Angle, sizeof(ProtoSet->Protos[x].Angle), 1) != 1) {
807  tprintf("Bad read of inttemp!\n");
808  }
809  if (fp->FReadEndian(&ProtoSet->Protos[x].Configs, sizeof(ProtoSet->Protos[x].Configs[0]),
810  WerdsPerConfigVec) != WerdsPerConfigVec) {
811  tprintf("Bad read of inttemp!\n");
812  }
813  }
814  Class->ProtoSets[j] = ProtoSet;
815  }
816  if (version_id < 4) {
817  Class->font_set_id = -1;
818  } else {
819  fp->FReadEndian(&Class->font_set_id, sizeof(Class->font_set_id), 1);
820  }
821  }
822 
823  if (version_id < 2) {
824  /* add an empty nullptr class with class id 0 */
825  assert(UnusedClassIdIn(Templates, 0));
826  ClassForClassId(Templates, 0) = new INT_CLASS_STRUCT(1, 1);
827  ClassForClassId(Templates, 0)->font_set_id = -1;
828  Templates->NumClasses++;
829  /* make sure the classes are contiguous */
830  for (unsigned i = 0; i < MAX_NUM_CLASSES; i++) {
831  if (i < Templates->NumClasses) {
832  if (ClassForClassId(Templates, i) == nullptr) {
833  fprintf(stderr, "Non-contiguous class ids in inttemp\n");
834  exit(1);
835  }
836  } else {
837  if (ClassForClassId(Templates, i) != nullptr) {
838  fprintf(stderr, "Class id %u exceeds NumClassesIn (Templates) %u\n", i,
839  Templates->NumClasses);
840  exit(1);
841  }
842  }
843  }
844  }
845  if (version_id >= 4) {
846  using namespace std::placeholders; // for _1, _2
847  this->fontinfo_table_.read(fp, std::bind(read_info, _1, _2));
848  if (version_id >= 5) {
849  this->fontinfo_table_.read(fp, std::bind(read_spacing_info, _1, _2));
850  }
851  this->fontset_table_.read(fp, [](auto *f, auto *fs) { return f->DeSerialize(*fs); } );
852  }
853 
854  return (Templates);
855 } /* ReadIntTemplates */
856 
857 #ifndef GRAPHICS_DISABLED
868  if (ProtoDisplayWindow) {
869  ProtoDisplayWindow->Clear();
870  }
871  if (FeatureDisplayWindow) {
872  FeatureDisplayWindow->Clear();
873  }
874  ClearFeatureSpaceWindow(static_cast<NORM_METHOD>(static_cast<int>(classify_norm_method)),
875  IntMatchWindow);
877  if (ProtoDisplayWindow) {
878  ProtoDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y, INT_MAX_X, INT_MAX_Y);
879  }
880  if (FeatureDisplayWindow) {
881  FeatureDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y, INT_MAX_X, INT_MAX_Y);
882  }
883 } /* ShowMatchDisplay */
884 
887 void ClearFeatureSpaceWindow(NORM_METHOD norm_method, ScrollView *window) {
888  window->Clear();
889 
890  window->Pen(ScrollView::GREY);
891  // Draw the feature space limit rectangle.
892  window->Rectangle(0, 0, INT_MAX_X, INT_MAX_Y);
893  if (norm_method == baseline) {
894  window->SetCursor(0, INT_DESCENDER);
895  window->DrawTo(INT_MAX_X, INT_DESCENDER);
896  window->SetCursor(0, INT_BASELINE);
897  window->DrawTo(INT_MAX_X, INT_BASELINE);
898  window->SetCursor(0, INT_XHEIGHT);
899  window->DrawTo(INT_MAX_X, INT_XHEIGHT);
900  window->SetCursor(0, INT_CAPHEIGHT);
901  window->DrawTo(INT_MAX_X, INT_CAPHEIGHT);
902  } else {
905  }
906 }
907 #endif
908 
918  const UNICHARSET &target_unicharset) {
919  INT_CLASS_STRUCT *Class;
920  auto unicharset_size = target_unicharset.size();
921  int version_id = -5; // When negated by the reader -1 becomes +1 etc.
922 
923  if (Templates->NumClasses != unicharset_size) {
924  tprintf(
925  "Warning: executing WriteIntTemplates() with %d classes in"
926  " Templates, while target_unicharset size is %zu\n",
927  Templates->NumClasses, unicharset_size);
928  }
929 
930  /* first write the high level template struct */
931  fwrite(&unicharset_size, sizeof(unicharset_size), 1, File);
932  fwrite(&version_id, sizeof(version_id), 1, File);
933  fwrite(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners), 1, File);
934  fwrite(&Templates->NumClasses, sizeof(Templates->NumClasses), 1, File);
935 
936  /* then write out the class pruners */
937  for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
938  fwrite(Templates->ClassPruners[i], sizeof(CLASS_PRUNER_STRUCT), 1, File);
939  }
940 
941  /* then write out each class */
942  for (unsigned i = 0; i < Templates->NumClasses; i++) {
943  Class = Templates->Class[i];
944 
945  /* first write out the high level struct for the class */
946  fwrite(&Class->NumProtos, sizeof(Class->NumProtos), 1, File);
947  fwrite(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File);
948  ASSERT_HOST(Class->NumConfigs == this->fontset_table_.at(Class->font_set_id).size());
949  fwrite(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File);
950  for (int j = 0; j < Class->NumConfigs; ++j) {
951  fwrite(&Class->ConfigLengths[j], sizeof(uint16_t), 1, File);
952  }
953 
954  /* then write out the proto lengths */
955  if (MaxNumIntProtosIn(Class) > 0) {
956  fwrite(&Class->ProtoLengths[0], sizeof(uint8_t), MaxNumIntProtosIn(Class), File);
957  }
958 
959  /* then write out the proto sets */
960  for (int j = 0; j < Class->NumProtoSets; j++) {
961  fwrite(Class->ProtoSets[j], sizeof(PROTO_SET_STRUCT), 1, File);
962  }
963 
964  /* then write the fonts info */
965  fwrite(&Class->font_set_id, sizeof(int), 1, File);
966  }
967 
968  /* Write the fonts info tables */
969  using namespace std::placeholders; // for _1, _2
970  this->fontinfo_table_.write(File, std::bind(write_info, _1, _2));
971  this->fontinfo_table_.write(File, std::bind(write_spacing_info, _1, _2));
972  this->fontset_table_.write(File, std::bind(write_set, _1, _2));
973 } /* WriteIntTemplates */
974 
975 /*-----------------------------------------------------------------------------
976  Private Code
977 -----------------------------------------------------------------------------*/
989 float BucketStart(int Bucket, float Offset, int NumBuckets) {
990  return static_cast<float>(Bucket) / NumBuckets - Offset;
991 
992 } /* BucketStart */
993 
1005 float BucketEnd(int Bucket, float Offset, int NumBuckets) {
1006  return static_cast<float>(Bucket + 1) / NumBuckets - Offset;
1007 } /* BucketEnd */
1008 
1019 void DoFill(FILL_SPEC *FillSpec, CLASS_PRUNER_STRUCT *Pruner, uint32_t ClassMask,
1020  uint32_t ClassCount, uint32_t WordIndex) {
1021  int X, Y, Angle;
1022  uint32_t OldWord;
1023 
1024  X = FillSpec->X;
1025  if (X < 0) {
1026  X = 0;
1027  }
1028  if (X >= NUM_CP_BUCKETS) {
1029  X = NUM_CP_BUCKETS - 1;
1030  }
1031 
1032  if (FillSpec->YStart < 0) {
1033  FillSpec->YStart = 0;
1034  }
1035  if (FillSpec->YEnd >= NUM_CP_BUCKETS) {
1036  FillSpec->YEnd = NUM_CP_BUCKETS - 1;
1037  }
1038 
1039  for (Y = FillSpec->YStart; Y <= FillSpec->YEnd; Y++) {
1040  for (Angle = FillSpec->AngleStart;; CircularIncrement(Angle, NUM_CP_BUCKETS)) {
1041  OldWord = Pruner->p[X][Y][Angle][WordIndex];
1042  if (ClassCount > (OldWord & ClassMask)) {
1043  OldWord &= ~ClassMask;
1044  OldWord |= ClassCount;
1045  Pruner->p[X][Y][Angle][WordIndex] = OldWord;
1046  }
1047  if (Angle == FillSpec->AngleEnd) {
1048  break;
1049  }
1050  }
1051  }
1052 } /* DoFill */
1053 
1061 bool FillerDone(TABLE_FILLER *Filler) {
1062  FILL_SWITCH *Next;
1063 
1064  Next = &(Filler->Switch[Filler->NextSwitch]);
1065 
1066  return Filler->X > Next->X && Next->Type == LastSwitch;
1067 
1068 } /* FillerDone */
1069 
1083 void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
1084  float Center, float Spread, bool debug) {
1085  int i, FirstBucket, LastBucket;
1086 
1087  if (Spread > 0.5) {
1088  Spread = 0.5;
1089  }
1090 
1091  FirstBucket = static_cast<int>(std::floor((Center - Spread) * NUM_PP_BUCKETS));
1092  if (FirstBucket < 0) {
1093  FirstBucket += NUM_PP_BUCKETS;
1094  }
1095 
1096  LastBucket = static_cast<int>(std::floor((Center + Spread) * NUM_PP_BUCKETS));
1097  if (LastBucket >= NUM_PP_BUCKETS) {
1098  LastBucket -= NUM_PP_BUCKETS;
1099  }
1100  if (debug) {
1101  tprintf("Circular fill from %d to %d", FirstBucket, LastBucket);
1102  }
1103  for (i = FirstBucket; true; CircularIncrement(i, NUM_PP_BUCKETS)) {
1104  SET_BIT(ParamTable[i], Bit);
1105 
1106  /* exit loop after we have set the bit for the last bucket */
1107  if (i == LastBucket) {
1108  break;
1109  }
1110  }
1111 
1112 } /* FillPPCircularBits */
1113 
1128 void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
1129  float Center, float Spread, bool debug) {
1130  int i, FirstBucket, LastBucket;
1131 
1132  FirstBucket = static_cast<int>(std::floor((Center - Spread) * NUM_PP_BUCKETS));
1133  if (FirstBucket < 0) {
1134  FirstBucket = 0;
1135  }
1136 
1137  LastBucket = static_cast<int>(std::floor((Center + Spread) * NUM_PP_BUCKETS));
1138  if (LastBucket >= NUM_PP_BUCKETS) {
1139  LastBucket = NUM_PP_BUCKETS - 1;
1140  }
1141 
1142  if (debug) {
1143  tprintf("Linear fill from %d to %d", FirstBucket, LastBucket);
1144  }
1145  for (i = FirstBucket; i <= LastBucket; i++) {
1146  SET_BIT(ParamTable[i], Bit);
1147  }
1148 
1149 } /* FillPPLinearBits */
1150 
1151 /*---------------------------------------------------------------------------*/
1152 #ifndef GRAPHICS_DISABLED
1163 CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *pretrained_on,
1164  int *shape_id) {
1165  tprintf("%s\n", Prompt);
1166  SVEvent *ev;
1167  SVEventType ev_type;
1168  int unichar_id = INVALID_UNICHAR_ID;
1169  // Wait until a click or popup event.
1170  do {
1171  ev = IntMatchWindow->AwaitEvent(SVET_ANY);
1172  ev_type = ev->type;
1173  if (ev_type == SVET_POPUP) {
1174  if (ev->command_id == IDA_SHAPE_INDEX) {
1175  if (shape_table_ != nullptr) {
1176  *shape_id = atoi(ev->parameter);
1177  *adaptive_on = false;
1178  *pretrained_on = true;
1179  if (*shape_id >= 0 && static_cast<unsigned>(*shape_id) < shape_table_->NumShapes()) {
1180  int font_id;
1181  shape_table_->GetFirstUnicharAndFont(*shape_id, &unichar_id, &font_id);
1182  tprintf("Shape %d, first unichar=%d, font=%d\n", *shape_id, unichar_id, font_id);
1183  return unichar_id;
1184  }
1185  tprintf("Shape index '%s' not found in shape table\n", ev->parameter);
1186  } else {
1187  tprintf("No shape table loaded!\n");
1188  }
1189  } else {
1191  unichar_id = unicharset.unichar_to_id(ev->parameter);
1192  if (ev->command_id == IDA_ADAPTIVE) {
1193  *adaptive_on = true;
1194  *pretrained_on = false;
1195  *shape_id = -1;
1196  } else if (ev->command_id == IDA_STATIC) {
1197  *adaptive_on = false;
1198  *pretrained_on = true;
1199  } else {
1200  *adaptive_on = true;
1201  *pretrained_on = true;
1202  }
1203  if (ev->command_id == IDA_ADAPTIVE || shape_table_ == nullptr) {
1204  *shape_id = -1;
1205  return unichar_id;
1206  }
1207  for (unsigned s = 0; s < shape_table_->NumShapes(); ++s) {
1208  if (shape_table_->GetShape(s).ContainsUnichar(unichar_id)) {
1209  tprintf("%s\n", shape_table_->DebugStr(s).c_str());
1210  }
1211  }
1212  } else {
1213  tprintf("Char class '%s' not found in unicharset", ev->parameter);
1214  }
1215  }
1216  }
1217  delete ev;
1218  } while (ev_type != SVET_CLICK);
1219  return 0;
1220 } /* GetClassToDebug */
1221 
1222 #endif
1223 
1235 void GetCPPadsForLevel(int Level, float *EndPad, float *SidePad, float *AnglePad) {
1236  switch (Level) {
1237  case 0:
1238  *EndPad = classify_cp_end_pad_loose * GetPicoFeatureLength();
1239  *SidePad = classify_cp_side_pad_loose * GetPicoFeatureLength();
1240  *AnglePad = classify_cp_angle_pad_loose / 360.0;
1241  break;
1242 
1243  case 1:
1244  *EndPad = classify_cp_end_pad_medium * GetPicoFeatureLength();
1245  *SidePad = classify_cp_side_pad_medium * GetPicoFeatureLength();
1246  *AnglePad = classify_cp_angle_pad_medium / 360.0;
1247  break;
1248 
1249  case 2:
1250  *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength();
1251  *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength();
1252  *AnglePad = classify_cp_angle_pad_tight / 360.0;
1253  break;
1254 
1255  default:
1256  *EndPad = classify_cp_end_pad_tight * GetPicoFeatureLength();
1257  *SidePad = classify_cp_side_pad_tight * GetPicoFeatureLength();
1258  *AnglePad = classify_cp_angle_pad_tight / 360.0;
1259  break;
1260  }
1261  if (*AnglePad > 0.5) {
1262  *AnglePad = 0.5;
1263  }
1264 
1265 } /* GetCPPadsForLevel */
1266 
1273  assert(Evidence >= 0.0);
1274  assert(Evidence <= 1.0);
1275 
1276  if (Evidence >= 0.90) {
1277  return ScrollView::WHITE;
1278  } else if (Evidence >= 0.75) {
1279  return ScrollView::GREEN;
1280  } else if (Evidence >= 0.50) {
1281  return ScrollView::RED;
1282  } else {
1283  return ScrollView::BLUE;
1284  }
1285 } /* GetMatchColorFor */
1286 
1295 void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill) {
1296  FILL_SWITCH *Next;
1297 
1298  /* compute the fill assuming no switches will be encountered */
1299  Fill->AngleStart = Filler->AngleStart;
1300  Fill->AngleEnd = Filler->AngleEnd;
1301  Fill->X = Filler->X;
1302  Fill->YStart = Filler->YStart >> 8;
1303  Fill->YEnd = Filler->YEnd >> 8;
1304 
1305  /* update the fill info and the filler for ALL switches at this X value */
1306  Next = &(Filler->Switch[Filler->NextSwitch]);
1307  while (Filler->X >= Next->X) {
1308  Fill->X = Filler->X = Next->X;
1309  if (Next->Type == StartSwitch) {
1310  Fill->YStart = Next->Y;
1311  Filler->StartDelta = Next->Delta;
1312  Filler->YStart = Next->YInit;
1313  } else if (Next->Type == EndSwitch) {
1314  Fill->YEnd = Next->Y;
1315  Filler->EndDelta = Next->Delta;
1316  Filler->YEnd = Next->YInit;
1317  } else { /* Type must be LastSwitch */
1318  break;
1319  }
1320  Filler->NextSwitch++;
1321  Next = &(Filler->Switch[Filler->NextSwitch]);
1322  }
1323 
1324  /* prepare the filler for the next call to this routine */
1325  Filler->X++;
1326  Filler->YStart += Filler->StartDelta;
1327  Filler->YEnd += Filler->EndDelta;
1328 
1329 } /* GetNextFill */
1330 
1340 void InitTableFiller(float EndPad, float SidePad, float AnglePad, PROTO_STRUCT *Proto, TABLE_FILLER *Filler)
1341 #define XS X_SHIFT
1342 #define YS Y_SHIFT
1343 #define AS ANGLE_SHIFT
1344 #define NB NUM_CP_BUCKETS
1345 {
1346  float Angle;
1347  float X, Y, HalfLength;
1348  float Cos, Sin;
1349  float XAdjust, YAdjust;
1350  FPOINT Start, Switch1, Switch2, End;
1351  int S1 = 0;
1352  int S2 = 1;
1353 
1354  Angle = Proto->Angle;
1355  X = Proto->X;
1356  Y = Proto->Y;
1357  HalfLength = Proto->Length / 2.0;
1358 
1359  Filler->AngleStart = CircBucketFor(Angle - AnglePad, AS, NB);
1360  Filler->AngleEnd = CircBucketFor(Angle + AnglePad, AS, NB);
1361  Filler->NextSwitch = 0;
1362 
1363  if (fabs(Angle - 0.0) < HV_TOLERANCE || fabs(Angle - 0.5) < HV_TOLERANCE) {
1364  /* horizontal proto - handle as special case */
1365  Filler->X = Bucket8For(X - HalfLength - EndPad, XS, NB);
1366  Filler->YStart = Bucket16For(Y - SidePad, YS, NB * 256);
1367  Filler->YEnd = Bucket16For(Y + SidePad, YS, NB * 256);
1368  Filler->StartDelta = 0;
1369  Filler->EndDelta = 0;
1370  Filler->Switch[0].Type = LastSwitch;
1371  Filler->Switch[0].X = Bucket8For(X + HalfLength + EndPad, XS, NB);
1372  } else if (fabs(Angle - 0.25) < HV_TOLERANCE || fabs(Angle - 0.75) < HV_TOLERANCE) {
1373  /* vertical proto - handle as special case */
1374  Filler->X = Bucket8For(X - SidePad, XS, NB);
1375  Filler->YStart = Bucket16For(Y - HalfLength - EndPad, YS, NB * 256);
1376  Filler->YEnd = Bucket16For(Y + HalfLength + EndPad, YS, NB * 256);
1377  Filler->StartDelta = 0;
1378  Filler->EndDelta = 0;
1379  Filler->Switch[0].Type = LastSwitch;
1380  Filler->Switch[0].X = Bucket8For(X + SidePad, XS, NB);
1381  } else {
1382  /* diagonal proto */
1383 
1384  if ((Angle > 0.0 && Angle < 0.25) || (Angle > 0.5 && Angle < 0.75)) {
1385  /* rising diagonal proto */
1386  Angle *= 2.0 * M_PI;
1387  Cos = fabs(std::cos(Angle));
1388  Sin = fabs(std::sin(Angle));
1389 
1390  /* compute the positions of the corners of the acceptance region */
1391  Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1392  Start.y = Y - (HalfLength + EndPad) * Sin + SidePad * Cos;
1393  End.x = 2.0 * X - Start.x;
1394  End.y = 2.0 * Y - Start.y;
1395  Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1396  Switch1.y = Y - (HalfLength + EndPad) * Sin - SidePad * Cos;
1397  Switch2.x = 2.0 * X - Switch1.x;
1398  Switch2.y = 2.0 * Y - Switch1.y;
1399 
1400  if (Switch1.x > Switch2.x) {
1401  S1 = 1;
1402  S2 = 0;
1403  }
1404 
1405  /* translate into bucket positions and deltas */
1406  Filler->X = Bucket8For(Start.x, XS, NB);
1407  Filler->StartDelta = -static_cast<int16_t>((Cos / Sin) * 256);
1408  Filler->EndDelta = static_cast<int16_t>((Sin / Cos) * 256);
1409 
1410  XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
1411  YAdjust = XAdjust * Cos / Sin;
1412  Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
1413  YAdjust = XAdjust * Sin / Cos;
1414  Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
1415 
1416  Filler->Switch[S1].Type = StartSwitch;
1417  Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
1418  Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
1419  XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
1420  YAdjust = XAdjust * Sin / Cos;
1421  Filler->Switch[S1].YInit = Bucket16For(Switch1.y - YAdjust, YS, NB * 256);
1422  Filler->Switch[S1].Delta = Filler->EndDelta;
1423 
1424  Filler->Switch[S2].Type = EndSwitch;
1425  Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
1426  Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
1427  XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
1428  YAdjust = XAdjust * Cos / Sin;
1429  Filler->Switch[S2].YInit = Bucket16For(Switch2.y + YAdjust, YS, NB * 256);
1430  Filler->Switch[S2].Delta = Filler->StartDelta;
1431 
1432  Filler->Switch[2].Type = LastSwitch;
1433  Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
1434  } else {
1435  /* falling diagonal proto */
1436  Angle *= 2.0 * M_PI;
1437  Cos = fabs(std::cos(Angle));
1438  Sin = fabs(std::sin(Angle));
1439 
1440  /* compute the positions of the corners of the acceptance region */
1441  Start.x = X - (HalfLength + EndPad) * Cos - SidePad * Sin;
1442  Start.y = Y + (HalfLength + EndPad) * Sin - SidePad * Cos;
1443  End.x = 2.0 * X - Start.x;
1444  End.y = 2.0 * Y - Start.y;
1445  Switch1.x = X - (HalfLength + EndPad) * Cos + SidePad * Sin;
1446  Switch1.y = Y + (HalfLength + EndPad) * Sin + SidePad * Cos;
1447  Switch2.x = 2.0 * X - Switch1.x;
1448  Switch2.y = 2.0 * Y - Switch1.y;
1449 
1450  if (Switch1.x > Switch2.x) {
1451  S1 = 1;
1452  S2 = 0;
1453  }
1454 
1455  /* translate into bucket positions and deltas */
1456  Filler->X = Bucket8For(Start.x, XS, NB);
1457  Filler->StartDelta = static_cast<int16_t>(
1458  ClipToRange<int>(-IntCastRounded((Sin / Cos) * 256), INT16_MIN, INT16_MAX));
1459  Filler->EndDelta = static_cast<int16_t>(
1460  ClipToRange<int>(IntCastRounded((Cos / Sin) * 256), INT16_MIN, INT16_MAX));
1461 
1462  XAdjust = BucketEnd(Filler->X, XS, NB) - Start.x;
1463  YAdjust = XAdjust * Sin / Cos;
1464  Filler->YStart = Bucket16For(Start.y - YAdjust, YS, NB * 256);
1465  YAdjust = XAdjust * Cos / Sin;
1466  Filler->YEnd = Bucket16For(Start.y + YAdjust, YS, NB * 256);
1467 
1468  Filler->Switch[S1].Type = EndSwitch;
1469  Filler->Switch[S1].X = Bucket8For(Switch1.x, XS, NB);
1470  Filler->Switch[S1].Y = Bucket8For(Switch1.y, YS, NB);
1471  XAdjust = Switch1.x - BucketStart(Filler->Switch[S1].X, XS, NB);
1472  YAdjust = XAdjust * Sin / Cos;
1473  Filler->Switch[S1].YInit = Bucket16For(Switch1.y + YAdjust, YS, NB * 256);
1474  Filler->Switch[S1].Delta = Filler->StartDelta;
1475 
1476  Filler->Switch[S2].Type = StartSwitch;
1477  Filler->Switch[S2].X = Bucket8For(Switch2.x, XS, NB);
1478  Filler->Switch[S2].Y = Bucket8For(Switch2.y, YS, NB);
1479  XAdjust = Switch2.x - BucketStart(Filler->Switch[S2].X, XS, NB);
1480  YAdjust = XAdjust * Cos / Sin;
1481  Filler->Switch[S2].YInit = Bucket16For(Switch2.y - YAdjust, YS, NB * 256);
1482  Filler->Switch[S2].Delta = Filler->EndDelta;
1483 
1484  Filler->Switch[2].Type = LastSwitch;
1485  Filler->Switch[2].X = Bucket8For(End.x, XS, NB);
1486  }
1487  }
1488 } /* InitTableFiller */
1489 
1490 /*---------------------------------------------------------------------------*/
1491 #ifndef GRAPHICS_DISABLED
1500 void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT *Feature,
1501  ScrollView::Color color) {
1502  float X, Y, Dx, Dy, Length;
1503 
1504  window->Pen(color);
1505  assert(Feature != nullptr);
1506  assert(color != 0);
1507 
1508  X = Feature->X;
1509  Y = Feature->Y;
1510  Length = GetPicoFeatureLength() * 0.7 * INT_CHAR_NORM_RANGE;
1511  // The -PI has no significant effect here, but the value of Theta is computed
1512  // using BinaryAnglePlusPi in intfx.cpp.
1513  Dx = (Length / 2.0) * cos((Feature->Theta / 256.0) * 2.0 * M_PI - M_PI);
1514  Dy = (Length / 2.0) * sin((Feature->Theta / 256.0) * 2.0 * M_PI - M_PI);
1515 
1516  window->SetCursor(X, Y);
1517  window->DrawTo(X + Dx, Y + Dy);
1518 } /* RenderIntFeature */
1519 
1534 void RenderIntProto(ScrollView *window, INT_CLASS_STRUCT *Class, PROTO_ID ProtoId,
1535  ScrollView::Color color) {
1536  INT_PROTO_STRUCT *Proto;
1537  int ProtoSetIndex;
1538  int ProtoWordIndex;
1539  float Length;
1540  int Xmin, Xmax, Ymin, Ymax;
1541  float X, Y, Dx, Dy;
1542  uint32_t ProtoMask;
1543  int Bucket;
1544 
1545  assert(ProtoId >= 0);
1546  assert(Class != nullptr);
1547  assert(ProtoId < Class->NumProtos);
1548  assert(color != 0);
1549  window->Pen(color);
1550 
1551  auto ProtoSet = Class->ProtoSets[SetForProto(ProtoId)];
1552  ProtoSetIndex = IndexForProto(ProtoId);
1553  Proto = &(ProtoSet->Protos[ProtoSetIndex]);
1554  Length = (Class->ProtoLengths[ProtoId] * GetPicoFeatureLength() * INT_CHAR_NORM_RANGE);
1555  ProtoMask = PPrunerMaskFor(ProtoId);
1556  ProtoWordIndex = PPrunerWordIndexFor(ProtoId);
1557 
1558  // find the x and y extent of the proto from the proto pruning table
1559  Xmin = Ymin = NUM_PP_BUCKETS;
1560  Xmax = Ymax = 0;
1561  for (Bucket = 0; Bucket < NUM_PP_BUCKETS; Bucket++) {
1562  if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_X][Bucket][ProtoWordIndex]) {
1563  UpdateRange(Bucket, &Xmin, &Xmax);
1564  }
1565 
1566  if (ProtoMask & ProtoSet->ProtoPruner[PRUNER_Y][Bucket][ProtoWordIndex]) {
1567  UpdateRange(Bucket, &Ymin, &Ymax);
1568  }
1569  }
1570  X = (Xmin + Xmax + 1) / 2.0 * PROTO_PRUNER_SCALE;
1571  Y = (Ymin + Ymax + 1) / 2.0 * PROTO_PRUNER_SCALE;
1572  // The -PI has no significant effect here, but the value of Theta is computed
1573  // using BinaryAnglePlusPi in intfx.cpp.
1574  Dx = (Length / 2.0) * cos((Proto->Angle / 256.0) * 2.0 * M_PI - M_PI);
1575  Dy = (Length / 2.0) * sin((Proto->Angle / 256.0) * 2.0 * M_PI - M_PI);
1576 
1577  window->SetCursor(X - Dx, Y - Dy);
1578  window->DrawTo(X + Dx, Y + Dy);
1579 } /* RenderIntProto */
1580 #endif
1581 
1582 #ifndef GRAPHICS_DISABLED
1588  if (IntMatchWindow == nullptr) {
1589  IntMatchWindow = CreateFeatureSpaceWindow("IntMatchWindow", 50, 200);
1590  auto *popup_menu = new SVMenuNode();
1591 
1592  popup_menu->AddChild("Debug Adapted classes", IDA_ADAPTIVE, "x", "Class to debug");
1593  popup_menu->AddChild("Debug Static classes", IDA_STATIC, "x", "Class to debug");
1594  popup_menu->AddChild("Debug Both", IDA_BOTH, "x", "Class to debug");
1595  popup_menu->AddChild("Debug Shape Index", IDA_SHAPE_INDEX, "0", "Index to debug");
1596  popup_menu->BuildMenu(IntMatchWindow, false);
1597  }
1598 }
1599 
1605  if (ProtoDisplayWindow == nullptr) {
1606  ProtoDisplayWindow = CreateFeatureSpaceWindow("ProtoDisplayWindow", 550, 200);
1607  }
1608 }
1609 
1615  if (FeatureDisplayWindow == nullptr) {
1616  FeatureDisplayWindow = CreateFeatureSpaceWindow("FeatureDisplayWindow", 50, 700);
1617  }
1618 }
1619 
1622 ScrollView *CreateFeatureSpaceWindow(const char *name, int xpos, int ypos) {
1623  return new ScrollView(name, xpos, ypos, 520, 520, 260, 260, true);
1624 }
1625 #endif // !GRAPHICS_DISABLED
1626 
1627 } // namespace tesseract
#define ASSERT_HOST(x)
Definition: errcode.h:59
#define INT_VAR(name, val, comment)
Definition: params.h:356
#define double_VAR(name, val, comment)
Definition: params.h:365
#define OLD_MAX_NUM_CONFIGS
Definition: intproto.cpp:95
#define CircularIncrement(i, r)
Definition: intproto.cpp:102
#define INT_YRADIUS
Definition: intproto.cpp:60
#define XS
#define INT_MAX_Y
Definition: intproto.cpp:64
#define NB
#define MAX_LEVEL
#define INT_DESCENDER
Definition: intproto.cpp:52
#define INT_MIN_Y
Definition: intproto.cpp:62
#define INT_YCENTER
Definition: intproto.cpp:58
#define HV_TOLERANCE
Definition: intproto.cpp:67
#define INT_XHEIGHT
Definition: intproto.cpp:54
#define MapParam(P, O, N)
Definition: intproto.cpp:105
#define INT_XCENTER
Definition: intproto.cpp:57
#define AS
#define INT_MIN_X
Definition: intproto.cpp:61
#define YS
#define PROTO_PRUNER_SCALE
Definition: intproto.cpp:50
#define INT_MAX_X
Definition: intproto.cpp:63
#define MAX_NUM_SWITCHES
Definition: intproto.cpp:70
#define OLD_WERDS_PER_CONFIG_VEC
Definition: intproto.cpp:96
#define INT_BASELINE
Definition: intproto.cpp:53
#define INT_XRADIUS
Definition: intproto.cpp:59
#define INT_CAPHEIGHT
Definition: intproto.cpp:55
#define PPrunerWordIndexFor(I)
Definition: intproto.h:149
#define ANGLE_SHIFT
Definition: intproto.h:40
#define BITS_PER_CP_VECTOR
Definition: intproto.h:59
#define MaxNumIntProtosIn(C)
Definition: intproto.h:145
#define MAX_NUM_PROTO_SETS
Definition: intproto.h:50
#define NUM_PP_PARAMS
Definition: intproto.h:51
#define UnusedClassIdIn(T, c)
Definition: intproto.h:155
#define MAX_NUM_PROTOS
Definition: intproto.h:48
#define IndexForProto(P)
Definition: intproto.h:147
#define WERDS_PER_PP_VECTOR
Definition: intproto.h:62
#define INT_CHAR_NORM_RANGE
Definition: intproto.h:117
#define MAX_NUM_CONFIGS
Definition: intproto.h:47
#define BITS_PER_WERD
Definition: intproto.h:45
#define ClassForClassId(T, c)
Definition: intproto.h:156
#define LegalClassId(c)
Definition: intproto.h:154
#define X_SHIFT
Definition: intproto.h:41
#define PRUNER_Y
Definition: intproto.h:36
#define MaxNumClassesIn(T)
Definition: intproto.h:153
#define WERDS_PER_CONFIG_VEC
Definition: intproto.h:65
#define CPrunerWordIndexFor(c)
Definition: intproto.h:160
#define CPrunerIdFor(c)
Definition: intproto.h:158
#define PRUNER_ANGLE
Definition: intproto.h:37
#define SetForProto(P)
Definition: intproto.h:146
#define CPrunerBitIndexFor(c)
Definition: intproto.h:161
#define PPrunerMaskFor(I)
Definition: intproto.h:151
#define NUM_CP_BUCKETS
Definition: intproto.h:53
#define MAX_NUM_CLASS_PRUNERS
Definition: intproto.h:60
#define WERDS_PER_CP_VECTOR
Definition: intproto.h:61
#define Y_SHIFT
Definition: intproto.h:42
#define PROTOS_PER_PROTO_SET
Definition: intproto.h:49
#define NUM_PP_BUCKETS
Definition: intproto.h:52
#define NUM_BITS_PER_CLASS
Definition: intproto.h:55
#define CPrunerMaskFor(L, c)
Definition: intproto.h:162
#define CPrunerFor(T, c)
Definition: intproto.h:159
#define PRUNER_X
Definition: intproto.h:35
#define ProtoForProtoId(C, P)
Definition: intproto.h:148
#define GetPicoFeatureLength()
Definition: picofeat.h:56
#define ProtoIn(Class, Pid)
Definition: protos.h:70
uint32_t * BIT_VECTOR
Definition: bitvec.h:28
#define test_bit(array, bit)
Definition: bitvec.h:59
#define SET_BIT(array, bit)
Definition: bitvec.h:55
#define NO_PROTO
Definition: matchdefs.h:41
#define MAX_NUM_CLASSES
Definition: matchdefs.h:31
bool FillerDone(TABLE_FILLER *Filler)
Definition: intproto.cpp:1061
void AddIntClass(INT_TEMPLATES_STRUCT *Templates, CLASS_ID ClassId, INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:220
void AddProtoToProtoPruner(PROTO_STRUCT *Proto, int ProtoId, INT_CLASS_STRUCT *Class, bool debug)
Definition: intproto.cpp:344
void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill)
Definition: intproto.cpp:1295
void InitTableFiller(float EndPad, float SidePad, float AnglePad, PROTO_STRUCT *Proto, TABLE_FILLER *Filler)
Definition: intproto.cpp:1340
uint8_t Bucket8For(float param, float offset, int num_buckets)
Definition: intproto.cpp:385
void ConvertConfig(BIT_VECTOR Config, int ConfigId, INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:430
void DoFill(FILL_SPEC *FillSpec, CLASS_PRUNER_STRUCT *Pruner, uint32_t ClassMask, uint32_t ClassCount, uint32_t WordIndex)
Definition: intproto.cpp:1019
void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit, float Center, float Spread, bool debug)
Definition: intproto.cpp:1083
bool write_set(FILE *f, const FontSet &fs)
Definition: fontinfo.cpp:222
bool write_info(FILE *f, const FontInfo &fi)
Definition: fontinfo.cpp:157
void DisplayIntFeature(const INT_FEATURE_STRUCT *Feature, float Evidence)
Definition: intproto.cpp:541
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
int IntCastRounded(double x)
Definition: helpers.h:175
bool write_spacing_info(FILE *f, const FontInfo &fi)
Definition: fontinfo.cpp:194
@ SVET_POPUP
Definition: scrollview.h:61
@ SVET_CLICK
Definition: scrollview.h:55
float BucketEnd(int Bucket, float Offset, int NumBuckets)
Definition: intproto.cpp:1005
@ baseline
Definition: mfoutline.h:53
uint8_t CircBucketFor(float param, float offset, int num_buckets)
Definition: intproto.cpp:399
ScrollView::Color GetMatchColorFor(float Evidence)
Definition: intproto.cpp:1272
ScrollView * CreateFeatureSpaceWindow(const char *name, int xpos, int ypos)
Definition: intproto.cpp:1622
void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT *Feature, ScrollView::Color color)
Definition: intproto.cpp:1500
std::vector< int > FontSet
Definition: fontinfo.h:154
CLUSTERCONFIG Config
float BucketStart(int Bucket, float Offset, int NumBuckets)
Definition: intproto.cpp:989
void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit, float Center, float Spread, bool debug)
Definition: intproto.cpp:1128
void InitIntMatchWindowIfReqd()
Definition: intproto.cpp:1587
void InitFeatureDisplayWindowIfReqd()
Definition: intproto.cpp:1614
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:110
int16_t PROTO_ID
Definition: matchdefs.h:40
uint16_t Bucket16For(float param, float offset, int num_buckets)
Definition: intproto.cpp:389
bool read_info(TFile *f, FontInfo *fi)
Definition: fontinfo.cpp:143
@ IDA_BOTH
Definition: intproto.h:139
@ IDA_SHAPE_INDEX
Definition: intproto.h:139
@ IDA_ADAPTIVE
Definition: intproto.h:139
@ IDA_STATIC
Definition: intproto.h:139
void DisplayIntProto(INT_CLASS_STRUCT *Class, PROTO_ID ProtoId, float Evidence)
Definition: intproto.cpp:559
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
Definition: helpers.h:122
@ LastSwitch
Definition: intproto.cpp:69
@ StartSwitch
Definition: intproto.cpp:69
void GetCPPadsForLevel(int Level, float *EndPad, float *SidePad, float *AnglePad)
Definition: intproto.cpp:1235
void AddProtoToClassPruner(PROTO_STRUCT *Proto, CLASS_ID ClassId, INT_TEMPLATES_STRUCT *Templates)
Definition: intproto.cpp:306
void InitProtoDisplayWindowIfReqd()
Definition: intproto.cpp:1604
void UpdateMatchDisplay()
Definition: intproto.cpp:413
void ClearFeatureSpaceWindow(NORM_METHOD norm_method, ScrollView *window)
Definition: intproto.cpp:887
void RenderIntProto(ScrollView *window, INT_CLASS_STRUCT *Class, PROTO_ID ProtoId, ScrollView::Color color)
Definition: intproto.cpp:1534
int AddIntConfig(INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:250
bool read_spacing_info(TFile *f, FontInfo *fi)
Definition: fontinfo.cpp:163
UNICHAR_ID CLASS_ID
Definition: matchdefs.h:34
int Modulo(int a, int b)
Definition: helpers.h:158
int AddIntProto(INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:270
int size() const
Return the size used.
Definition: unicity_table.h:51
int push_back(T object)
Add an element in the table.
Definition: unicity_table.h:73
bool write(FILE *f, std::function< bool(FILE *, const T &)> cb) const
const T & at(int id) const
Return the object from an id.
Definition: unicity_table.h:56
bool read(tesseract::TFile *f, std::function< bool(tesseract::TFile *, T *)> cb)
UNICHARSET unicharset
Definition: ccutil.h:61
size_t FReadEndian(void *buffer, size_t size, size_t count)
Definition: serialis.cpp:210
bool DeSerialize(std::string &data)
Definition: serialis.cpp:94
size_t FRead(void *buffer, size_t size, size_t count)
Definition: serialis.cpp:221
const char * id_to_unichar(UNICHAR_ID id) const
Definition: unicharset.cpp:279
bool contains_unichar(const char *const unichar_repr) const
Definition: unicharset.cpp:695
UNICHAR_ID unichar_to_id(const char *const unichar_repr) const
Definition: unicharset.cpp:186
size_t size() const
Definition: unicharset.h:355
INT_TEMPLATES_STRUCT * CreateIntTemplates(CLASSES FloatProtos, const UNICHARSET &target_unicharset)
Definition: intproto.cpp:490
void WriteIntTemplates(FILE *File, INT_TEMPLATES_STRUCT *Templates, const UNICHARSET &target_unicharset)
Definition: intproto.cpp:917
ShapeTable * shape_table_
Definition: classify.h:452
void ConvertProto(PROTO_STRUCT *Proto, int ProtoId, INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:452
UnicityTable< FontSet > fontset_table_
Definition: classify.h:443
CLASS_ID GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *pretrained_on, int *shape_id)
Definition: intproto.cpp:1163
INT_TEMPLATES_STRUCT * ReadIntTemplates(TFile *fp)
Definition: intproto.cpp:627
UnicityTable< FontInfo > fontinfo_table_
Definition: classify.h:435
Definition: fpoint.h:29
float y
Definition: fpoint.h:30
float x
Definition: fpoint.h:30
FILL_SWITCH Switch[MAX_NUM_SWITCHES]
Definition: intproto.cpp:85
uint32_t p[NUM_CP_BUCKETS][NUM_CP_BUCKETS][NUM_CP_BUCKETS][WERDS_PER_CP_VECTOR]
Definition: intproto.h:73
uint32_t Configs[WERDS_PER_CONFIG_VEC]
Definition: intproto.h:81
PROTO_SET_STRUCT * ProtoSets[MAX_NUM_PROTO_SETS]
Definition: intproto.h:100
uint16_t ConfigLengths[MAX_NUM_CONFIGS]
Definition: intproto.h:102
std::vector< uint8_t > ProtoLengths
Definition: intproto.h:101
CLASS_PRUNER_STRUCT * ClassPruners[MAX_NUM_CLASS_PRUNERS]
Definition: intproto.h:112
INT_CLASS_STRUCT * Class[MAX_NUM_CLASSES]
Definition: intproto.h:111
std::vector< BIT_VECTOR > Configurations
Definition: protos.h:46
UnicityTable< int > font_set
Definition: protos.h:47
bool ContainsUnichar(int unichar_id) const
Definition: shapetable.cpp:150
std::string DebugStr(unsigned shape_id) const
Definition: shapetable.cpp:292
const Shape & GetShape(unsigned shape_id) const
Definition: shapetable.h:292
unsigned NumShapes() const
Definition: shapetable.h:248
void GetFirstUnicharAndFont(unsigned shape_id, int *unichar_id, int *font_id) const
Definition: shapetable.cpp:420
SVEventType type
Definition: scrollview.h:73
void void ZoomToRectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:759
void Pen(Color color)
Definition: scrollview.cpp:723
static void Update()
Definition: scrollview.cpp:713
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:589
void SetCursor(int x, int y)
Definition: scrollview.cpp:498
void DrawTo(int x, int y)
Definition: scrollview.cpp:504
SVEvent * AwaitEvent(SVEventType type)
Definition: scrollview.cpp:445