tesseract 5.2.0
Loading...
Searching...
No Matches
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
47namespace 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
74 int8_t X, Y;
75 int16_t YInit;
76 int16_t Delta;
77};
78
80 uint8_t NextSwitch;
82 int8_t X;
83 int16_t YStart, YEnd;
86};
87
88struct FILL_SPEC {
89 int8_t X;
90 int8_t YStart, YEnd;
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----------------------------------------------------------------------------*/
110float BucketStart(int Bucket, float Offset, int NumBuckets);
111
112float BucketEnd(int Bucket, float Offset, int NumBuckets);
113
114void DoFill(FILL_SPEC *FillSpec, CLASS_PRUNER_STRUCT *Pruner, uint32_t ClassMask,
115 uint32_t ClassCount, uint32_t WordIndex);
116
117bool FillerDone(TABLE_FILLER *Filler);
118
119void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
120 float Center, float Spread, bool debug);
121
122void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
123 float Center, float Spread, bool debug);
124
125void GetCPPadsForLevel(int Level, float *EndPad, float *SidePad, float *AnglePad);
126
127ScrollView::Color GetMatchColorFor(float Evidence);
128
129void GetNextFill(TABLE_FILLER *Filler, FILL_SPEC *Fill);
130
131void InitTableFiller(float EndPad, float SidePad, float AnglePad, PROTO_STRUCT *Proto,
132 TABLE_FILLER *Filler);
133
134#ifndef GRAPHICS_DISABLED
135void RenderIntFeature(ScrollView *window, const INT_FEATURE_STRUCT *Feature,
136 ScrollView::Color color);
137
138void 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*/
147static ScrollView *IntMatchWindow = nullptr;
148static ScrollView *FeatureDisplayWindow = nullptr;
149static ScrollView *ProtoDisplayWindow = nullptr;
150#endif
151
152/*-----------------------------------------------------------------------------
153 Variables
154-----------------------------------------------------------------------------*/
155
156/* control knobs */
157static INT_VAR(classify_num_cp_levels, 3, "Number of Class Pruner Levels");
158static double_VAR(classify_cp_angle_pad_loose, 45.0, "Class Pruner Angle Pad Loose");
159static double_VAR(classify_cp_angle_pad_medium, 20.0, "Class Pruner Angle Pad Medium");
160static double_VAR(classify_cp_angle_pad_tight, 10.0, "CLass Pruner Angle Pad Tight");
161static double_VAR(classify_cp_end_pad_loose, 0.5, "Class Pruner End Pad Loose");
162static double_VAR(classify_cp_end_pad_medium, 0.5, "Class Pruner End Pad Medium");
163static double_VAR(classify_cp_end_pad_tight, 0.5, "Class Pruner End Pad Tight");
164static double_VAR(classify_cp_side_pad_loose, 2.5, "Class Pruner Side Pad Loose");
165static double_VAR(classify_cp_side_pad_medium, 1.2, "Class Pruner Side Pad Medium");
166static double_VAR(classify_cp_side_pad_tight, 0.6, "Class Pruner Side Pad Tight");
167static double_VAR(classify_pp_angle_pad, 45.0, "Proto Pruner Angle Pad");
168static double_VAR(classify_pp_end_pad, 0.5, "Proto Prune End Pad");
169static double_VAR(classify_pp_side_pad, 2.5, "Proto Pruner Side Pad");
170
180static 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
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
344void 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
385uint8_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}
389uint16_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
399uint8_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
430void 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
452void 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
541void 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
559void 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
573INT_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);
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
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);
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);
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-----------------------------------------------------------------------------*/
989float BucketStart(int Bucket, float Offset, int NumBuckets) {
990 return static_cast<float>(Bucket) / NumBuckets - Offset;
991
992} /* BucketStart */
993
1005float BucketEnd(int Bucket, float Offset, int NumBuckets) {
1006 return static_cast<float>(Bucket + 1) / NumBuckets - Offset;
1007} /* BucketEnd */
1008
1019void 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
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
1083void 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
1128void 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
1163CLASS_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
1235void 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
1295void 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
1340void 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
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
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
1622ScrollView *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 NO_PROTO
Definition: matchdefs.h:41
#define MAX_NUM_CLASSES
Definition: matchdefs.h:31
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 ProtoIn(Class, Pid)
Definition: protos.h:70
#define GetPicoFeatureLength()
Definition: picofeat.h:56
#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 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 INT_VAR(name, val, comment)
Definition: params.h:356
#define double_VAR(name, val, comment)
Definition: params.h:365
#define ASSERT_HOST(x)
Definition: errcode.h:54
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:168
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:103
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:115
@ 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:151
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
const T & at(int id) const
Return the object from an id.
Definition: unicity_table.h:56
bool write(FILE *f, std::function< bool(FILE *, const T &)> cb) const
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:451
void ConvertProto(PROTO_STRUCT *Proto, int ProtoId, INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:452
UnicityTable< FontSet > fontset_table_
Definition: classify.h:442
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:434
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
unsigned NumShapes() const
Definition: shapetable.h:248
const Shape & GetShape(unsigned shape_id) const
Definition: shapetable.h:292
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