tesseract v5.3.3.20231005
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 unsigned fs_size = FClass->font_set.size();
509 FontSet fs;
510 fs.reserve(fs_size);
511 for (unsigned i = 0; i < fs_size; ++i) {
512 fs.push_back(FClass->font_set[i]);
513 }
514 IClass->font_set_id = this->fontset_table_.push_back(fs);
515 AddIntClass(IntTemplates, ClassId, IClass);
516
517 for (ProtoId = 0; ProtoId < FClass->NumProtos; ProtoId++) {
518 AddIntProto(IClass);
519 ConvertProto(ProtoIn(FClass, ProtoId), ProtoId, IClass);
520 AddProtoToProtoPruner(ProtoIn(FClass, ProtoId), ProtoId, IClass,
521 classify_learning_debug_level >= 2);
522 AddProtoToClassPruner(ProtoIn(FClass, ProtoId), ClassId, IntTemplates);
523 }
524
525 for (ConfigId = 0; ConfigId < FClass->NumConfigs; ConfigId++) {
526 AddIntConfig(IClass);
527 ConvertConfig(FClass->Configurations[ConfigId], ConfigId, IClass);
528 }
529 }
530 return (IntTemplates);
531} /* CreateIntTemplates */
532
533#ifndef GRAPHICS_DISABLED
543void DisplayIntFeature(const INT_FEATURE_STRUCT *Feature, float Evidence) {
544 ScrollView::Color color = GetMatchColorFor(Evidence);
545 RenderIntFeature(IntMatchWindow, Feature, color);
546 if (FeatureDisplayWindow) {
547 RenderIntFeature(FeatureDisplayWindow, Feature, color);
548 }
549} /* DisplayIntFeature */
550
561void DisplayIntProto(INT_CLASS_STRUCT *Class, PROTO_ID ProtoId, float Evidence) {
562 ScrollView::Color color = GetMatchColorFor(Evidence);
563 RenderIntProto(IntMatchWindow, Class, ProtoId, color);
564 if (ProtoDisplayWindow) {
565 RenderIntProto(ProtoDisplayWindow, Class, ProtoId, color);
566 }
567} /* DisplayIntProto */
568#endif
569
575INT_CLASS_STRUCT::INT_CLASS_STRUCT(int MaxNumProtos, int MaxNumConfigs) :
576 NumProtos(0),
577 NumProtoSets((MaxNumProtos + PROTOS_PER_PROTO_SET - 1) / PROTOS_PER_PROTO_SET),
578 NumConfigs(0),
579 ProtoLengths(MaxNumIntProtosIn(this))
580{
581 assert(MaxNumConfigs <= MAX_NUM_CONFIGS);
583
584 for (int i = 0; i < NumProtoSets; i++) {
585 /* allocate space for a proto set, install in class, and initialize */
586 auto ProtoSet = new PROTO_SET_STRUCT;
587 memset(ProtoSet, 0, sizeof(*ProtoSet));
588 ProtoSets[i] = ProtoSet;
589
590 /* allocate space for the proto lengths and install in class */
591 }
592 memset(ConfigLengths, 0, sizeof(ConfigLengths));
593}
594
596 for (int i = 0; i < NumProtoSets; i++) {
597 delete ProtoSets[i];
598 }
599}
600
604 NumClasses = 0;
605 NumClassPruners = 0;
606
607 for (int i = 0; i < MAX_NUM_CLASSES; i++) {
608 ClassForClassId(this, i) = nullptr;
609 }
610}
611
613 for (unsigned i = 0; i < NumClasses; i++) {
614 delete Class[i];
615 }
616 for (unsigned i = 0; i < NumClassPruners; i++) {
617 delete ClassPruners[i];
618 }
619}
620
630 int j, w, x, y, z;
631 INT_TEMPLATES_STRUCT *Templates;
632 CLASS_PRUNER_STRUCT *Pruner;
633 INT_CLASS_STRUCT *Class;
634
635 /* variables for conversion from older inttemp formats */
636 int b, bit_number, last_cp_bit_number, new_b, new_i, new_w;
637 CLASS_ID class_id, max_class_id;
638 std::vector<CLASS_ID> ClassIdFor(MAX_NUM_CLASSES);
639 std::vector<CLASS_PRUNER_STRUCT *> TempClassPruner(MAX_NUM_CLASS_PRUNERS);
640 uint32_t SetBitsForMask = // word with NUM_BITS_PER_CLASS
641 (1 << NUM_BITS_PER_CLASS) - 1; // set starting at bit 0
642 uint32_t Mask, NewMask, ClassBits;
643 unsigned MaxNumConfigs = MAX_NUM_CONFIGS;
644 unsigned WerdsPerConfigVec = WERDS_PER_CONFIG_VEC;
645
646 /* first read the high level template struct */
647 Templates = new INT_TEMPLATES_STRUCT;
648 // Read Templates in parts for 64 bit compatibility.
649 uint32_t unicharset_size;
650 if (fp->FReadEndian(&unicharset_size, sizeof(unicharset_size), 1) != 1) {
651 tprintf("Bad read of inttemp!\n");
652 }
653 int32_t version_id = 0;
654 if (fp->FReadEndian(&version_id, sizeof(version_id), 1) != 1 ||
655 fp->FReadEndian(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners), 1) != 1) {
656 tprintf("Bad read of inttemp!\n");
657 }
658 if (version_id < 0) {
659 // This file has a version id!
660 version_id = -version_id;
661 if (fp->FReadEndian(&Templates->NumClasses, sizeof(Templates->NumClasses), 1) != 1) {
662 tprintf("Bad read of inttemp!\n");
663 }
664 } else {
665 Templates->NumClasses = version_id;
666 }
667
668 if (version_id < 3) {
669 MaxNumConfigs = OLD_MAX_NUM_CONFIGS;
670 WerdsPerConfigVec = OLD_WERDS_PER_CONFIG_VEC;
671 }
672
673 if (version_id < 2) {
674 std::vector<int16_t> IndexFor(MAX_NUM_CLASSES);
675 if (fp->FReadEndian(&IndexFor[0], sizeof(IndexFor[0]), unicharset_size) != unicharset_size) {
676 tprintf("Bad read of inttemp!\n");
677 }
678 if (fp->FReadEndian(&ClassIdFor[0], sizeof(ClassIdFor[0]), Templates->NumClasses) !=
679 Templates->NumClasses) {
680 tprintf("Bad read of inttemp!\n");
681 }
682 }
683
684 /* then read in the class pruners */
685 const unsigned kNumBuckets = NUM_CP_BUCKETS * NUM_CP_BUCKETS * NUM_CP_BUCKETS * WERDS_PER_CP_VECTOR;
686 for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
687 Pruner = new CLASS_PRUNER_STRUCT;
688 if (fp->FReadEndian(Pruner, sizeof(Pruner->p[0][0][0][0]), kNumBuckets) != kNumBuckets) {
689 tprintf("Bad read of inttemp!\n");
690 }
691 if (version_id < 2) {
692 TempClassPruner[i] = Pruner;
693 } else {
694 Templates->ClassPruners[i] = Pruner;
695 }
696 }
697
698 /* fix class pruners if they came from an old version of inttemp */
699 if (version_id < 2) {
700 // Allocate enough class pruners to cover all the class ids.
701 max_class_id = 0;
702 for (unsigned i = 0; i < Templates->NumClasses; i++) {
703 if (ClassIdFor[i] > max_class_id) {
704 max_class_id = ClassIdFor[i];
705 }
706 }
707 for (int i = 0; i <= CPrunerIdFor(max_class_id); i++) {
708 Templates->ClassPruners[i] = new CLASS_PRUNER_STRUCT;
709 memset(Templates->ClassPruners[i], 0, sizeof(CLASS_PRUNER_STRUCT));
710 }
711 // Convert class pruners from the old format (indexed by class index)
712 // to the new format (indexed by class id).
713 last_cp_bit_number = NUM_BITS_PER_CLASS * Templates->NumClasses - 1;
714 for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
715 for (x = 0; x < NUM_CP_BUCKETS; x++) {
716 for (y = 0; y < NUM_CP_BUCKETS; y++) {
717 for (z = 0; z < NUM_CP_BUCKETS; z++) {
718 for (w = 0; w < WERDS_PER_CP_VECTOR; w++) {
719 if (TempClassPruner[i]->p[x][y][z][w] == 0) {
720 continue;
721 }
722 for (b = 0; b < BITS_PER_WERD; b += NUM_BITS_PER_CLASS) {
723 bit_number = i * BITS_PER_CP_VECTOR + w * BITS_PER_WERD + b;
724 if (bit_number > last_cp_bit_number) {
725 break; // the rest of the bits in this word are not used
726 }
727 class_id = ClassIdFor[bit_number / NUM_BITS_PER_CLASS];
728 // Single out NUM_BITS_PER_CLASS bits relating to class_id.
729 Mask = SetBitsForMask << b;
730 ClassBits = TempClassPruner[i]->p[x][y][z][w] & Mask;
731 // Move these bits to the new position in which they should
732 // appear (indexed corresponding to the class_id).
733 new_i = CPrunerIdFor(class_id);
734 new_w = CPrunerWordIndexFor(class_id);
735 new_b = CPrunerBitIndexFor(class_id) * NUM_BITS_PER_CLASS;
736 if (new_b > b) {
737 ClassBits <<= (new_b - b);
738 } else {
739 ClassBits >>= (b - new_b);
740 }
741 // Copy bits relating to class_id to the correct position
742 // in Templates->ClassPruner.
743 NewMask = SetBitsForMask << new_b;
744 Templates->ClassPruners[new_i]->p[x][y][z][new_w] &= ~NewMask;
745 Templates->ClassPruners[new_i]->p[x][y][z][new_w] |= ClassBits;
746 }
747 }
748 }
749 }
750 }
751 }
752 for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
753 delete TempClassPruner[i];
754 }
755 }
756
757 /* then read in each class */
758 for (unsigned i = 0; i < Templates->NumClasses; i++) {
759 /* first read in the high level struct for the class */
760 Class = new INT_CLASS_STRUCT;
761 if (fp->FReadEndian(&Class->NumProtos, sizeof(Class->NumProtos), 1) != 1 ||
762 fp->FRead(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1) != 1 ||
763 fp->FRead(&Class->NumConfigs, sizeof(Class->NumConfigs), 1) != 1) {
764 tprintf("Bad read of inttemp!\n");
765 }
766 if (version_id == 0) {
767 // Only version 0 writes 5 pointless pointers to the file.
768 for (j = 0; j < 5; ++j) {
769 int32_t junk;
770 if (fp->FRead(&junk, sizeof(junk), 1) != 1) {
771 tprintf("Bad read of inttemp!\n");
772 }
773 }
774 }
775 unsigned num_configs = version_id < 4 ? MaxNumConfigs : Class->NumConfigs;
776 ASSERT_HOST(num_configs <= MaxNumConfigs);
777 if (fp->FReadEndian(Class->ConfigLengths, sizeof(uint16_t), num_configs) != num_configs) {
778 tprintf("Bad read of inttemp!\n");
779 }
780 if (version_id < 2) {
781 ClassForClassId(Templates, ClassIdFor[i]) = Class;
782 } else {
783 ClassForClassId(Templates, i) = Class;
784 }
785
786 /* then read in the proto lengths */
787 Class->ProtoLengths.clear();
788 if (MaxNumIntProtosIn(Class) > 0) {
789 Class->ProtoLengths.resize(MaxNumIntProtosIn(Class));
790 if (fp->FRead(&Class->ProtoLengths[0], sizeof(uint8_t), MaxNumIntProtosIn(Class)) !=
791 MaxNumIntProtosIn(Class)) {
792 tprintf("Bad read of inttemp!\n");
793 }
794 }
795
796 /* then read in the proto sets */
797 for (j = 0; j < Class->NumProtoSets; j++) {
798 auto ProtoSet = new PROTO_SET_STRUCT;
799 unsigned num_buckets = NUM_PP_PARAMS * NUM_PP_BUCKETS * WERDS_PER_PP_VECTOR;
800 if (fp->FReadEndian(&ProtoSet->ProtoPruner, sizeof(ProtoSet->ProtoPruner[0][0][0]),
801 num_buckets) != num_buckets) {
802 tprintf("Bad read of inttemp!\n");
803 }
804 for (x = 0; x < PROTOS_PER_PROTO_SET; x++) {
805 if (fp->FRead(&ProtoSet->Protos[x].A, sizeof(ProtoSet->Protos[x].A), 1) != 1 ||
806 fp->FRead(&ProtoSet->Protos[x].B, sizeof(ProtoSet->Protos[x].B), 1) != 1 ||
807 fp->FRead(&ProtoSet->Protos[x].C, sizeof(ProtoSet->Protos[x].C), 1) != 1 ||
808 fp->FRead(&ProtoSet->Protos[x].Angle, sizeof(ProtoSet->Protos[x].Angle), 1) != 1) {
809 tprintf("Bad read of inttemp!\n");
810 }
811 if (fp->FReadEndian(&ProtoSet->Protos[x].Configs, sizeof(ProtoSet->Protos[x].Configs[0]),
812 WerdsPerConfigVec) != WerdsPerConfigVec) {
813 tprintf("Bad read of inttemp!\n");
814 }
815 }
816 Class->ProtoSets[j] = ProtoSet;
817 }
818 if (version_id < 4) {
819 Class->font_set_id = -1;
820 } else {
821 fp->FReadEndian(&Class->font_set_id, sizeof(Class->font_set_id), 1);
822 }
823 }
824
825 if (version_id < 2) {
826 /* add an empty nullptr class with class id 0 */
827 assert(UnusedClassIdIn(Templates, 0));
828 ClassForClassId(Templates, 0) = new INT_CLASS_STRUCT(1, 1);
829 ClassForClassId(Templates, 0)->font_set_id = -1;
830 Templates->NumClasses++;
831 /* make sure the classes are contiguous */
832 for (unsigned i = 0; i < MAX_NUM_CLASSES; i++) {
833 if (i < Templates->NumClasses) {
834 if (ClassForClassId(Templates, i) == nullptr) {
835 fprintf(stderr, "Non-contiguous class ids in inttemp\n");
836 exit(1);
837 }
838 } else {
839 if (ClassForClassId(Templates, i) != nullptr) {
840 fprintf(stderr, "Class id %u exceeds NumClassesIn (Templates) %u\n", i,
841 Templates->NumClasses);
842 exit(1);
843 }
844 }
845 }
846 }
847 if (version_id >= 4) {
848 using namespace std::placeholders; // for _1, _2
849 this->fontinfo_table_.read(fp, std::bind(read_info, _1, _2));
850 if (version_id >= 5) {
851 this->fontinfo_table_.read(fp, std::bind(read_spacing_info, _1, _2));
852 }
853 this->fontset_table_.read(fp, [](auto *f, auto *fs) { return f->DeSerialize(*fs); } );
854 }
855
856 return (Templates);
857} /* ReadIntTemplates */
858
859#ifndef GRAPHICS_DISABLED
870 if (ProtoDisplayWindow) {
871 ProtoDisplayWindow->Clear();
872 }
873 if (FeatureDisplayWindow) {
874 FeatureDisplayWindow->Clear();
875 }
876 ClearFeatureSpaceWindow(static_cast<NORM_METHOD>(static_cast<int>(classify_norm_method)),
877 IntMatchWindow);
879 if (ProtoDisplayWindow) {
880 ProtoDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y, INT_MAX_X, INT_MAX_Y);
881 }
882 if (FeatureDisplayWindow) {
883 FeatureDisplayWindow->ZoomToRectangle(INT_MIN_X, INT_MIN_Y, INT_MAX_X, INT_MAX_Y);
884 }
885} /* ShowMatchDisplay */
886
890 window->Clear();
891
892 window->Pen(ScrollView::GREY);
893 // Draw the feature space limit rectangle.
894 window->Rectangle(0, 0, INT_MAX_X, INT_MAX_Y);
895 if (norm_method == baseline) {
896 window->SetCursor(0, INT_DESCENDER);
898 window->SetCursor(0, INT_BASELINE);
899 window->DrawTo(INT_MAX_X, INT_BASELINE);
900 window->SetCursor(0, INT_XHEIGHT);
901 window->DrawTo(INT_MAX_X, INT_XHEIGHT);
902 window->SetCursor(0, INT_CAPHEIGHT);
904 } else {
907 }
908}
909#endif
910
920 const UNICHARSET &target_unicharset) {
921 INT_CLASS_STRUCT *Class;
922 uint32_t unicharset_size = target_unicharset.size();
923 int version_id = -5; // When negated by the reader -1 becomes +1 etc.
924
925 if (Templates->NumClasses != unicharset_size) {
926 tprintf(
927 "Warning: executing WriteIntTemplates() with %d classes in"
928 " Templates, while target_unicharset size is %" PRIu32 "\n",
929 Templates->NumClasses, unicharset_size);
930 }
931
932 /* first write the high level template struct */
933 fwrite(&unicharset_size, sizeof(unicharset_size), 1, File);
934 fwrite(&version_id, sizeof(version_id), 1, File);
935 fwrite(&Templates->NumClassPruners, sizeof(Templates->NumClassPruners), 1, File);
936 fwrite(&Templates->NumClasses, sizeof(Templates->NumClasses), 1, File);
937
938 /* then write out the class pruners */
939 for (unsigned i = 0; i < Templates->NumClassPruners; i++) {
940 fwrite(Templates->ClassPruners[i], sizeof(CLASS_PRUNER_STRUCT), 1, File);
941 }
942
943 /* then write out each class */
944 for (unsigned i = 0; i < Templates->NumClasses; i++) {
945 Class = Templates->Class[i];
946
947 /* first write out the high level struct for the class */
948 fwrite(&Class->NumProtos, sizeof(Class->NumProtos), 1, File);
949 fwrite(&Class->NumProtoSets, sizeof(Class->NumProtoSets), 1, File);
950 ASSERT_HOST(Class->NumConfigs == this->fontset_table_.at(Class->font_set_id).size());
951 fwrite(&Class->NumConfigs, sizeof(Class->NumConfigs), 1, File);
952 for (int j = 0; j < Class->NumConfigs; ++j) {
953 fwrite(&Class->ConfigLengths[j], sizeof(uint16_t), 1, File);
954 }
955
956 /* then write out the proto lengths */
957 if (MaxNumIntProtosIn(Class) > 0) {
958 fwrite(&Class->ProtoLengths[0], sizeof(uint8_t), MaxNumIntProtosIn(Class), File);
959 }
960
961 /* then write out the proto sets */
962 for (int j = 0; j < Class->NumProtoSets; j++) {
963 fwrite(Class->ProtoSets[j], sizeof(PROTO_SET_STRUCT), 1, File);
964 }
965
966 /* then write the fonts info */
967 fwrite(&Class->font_set_id, sizeof(int), 1, File);
968 }
969
970 /* Write the fonts info tables */
971 using namespace std::placeholders; // for _1, _2
972 this->fontinfo_table_.write(File, std::bind(write_info, _1, _2));
973 this->fontinfo_table_.write(File, std::bind(write_spacing_info, _1, _2));
974 this->fontset_table_.write(File, std::bind(write_set, _1, _2));
975} /* WriteIntTemplates */
976
977/*-----------------------------------------------------------------------------
978 Private Code
979-----------------------------------------------------------------------------*/
991float BucketStart(int Bucket, float Offset, int NumBuckets) {
992 return static_cast<float>(Bucket) / NumBuckets - Offset;
993
994} /* BucketStart */
995
1007float BucketEnd(int Bucket, float Offset, int NumBuckets) {
1008 return static_cast<float>(Bucket + 1) / NumBuckets - Offset;
1009} /* BucketEnd */
1010
1021void DoFill(FILL_SPEC *FillSpec, CLASS_PRUNER_STRUCT *Pruner, uint32_t ClassMask,
1022 uint32_t ClassCount, uint32_t WordIndex) {
1023 int X, Y, Angle;
1024 uint32_t OldWord;
1025
1026 X = FillSpec->X;
1027 if (X < 0) {
1028 X = 0;
1029 }
1030 if (X >= NUM_CP_BUCKETS) {
1031 X = NUM_CP_BUCKETS - 1;
1032 }
1033
1034 if (FillSpec->YStart < 0) {
1035 FillSpec->YStart = 0;
1036 }
1037 if (FillSpec->YEnd >= NUM_CP_BUCKETS) {
1038 FillSpec->YEnd = NUM_CP_BUCKETS - 1;
1039 }
1040
1041 for (Y = FillSpec->YStart; Y <= FillSpec->YEnd; Y++) {
1042 for (Angle = FillSpec->AngleStart;; CircularIncrement(Angle, NUM_CP_BUCKETS)) {
1043 OldWord = Pruner->p[X][Y][Angle][WordIndex];
1044 if (ClassCount > (OldWord & ClassMask)) {
1045 OldWord &= ~ClassMask;
1046 OldWord |= ClassCount;
1047 Pruner->p[X][Y][Angle][WordIndex] = OldWord;
1048 }
1049 if (Angle == FillSpec->AngleEnd) {
1050 break;
1051 }
1052 }
1053 }
1054} /* DoFill */
1055
1064 FILL_SWITCH *Next;
1065
1066 Next = &(Filler->Switch[Filler->NextSwitch]);
1067
1068 return Filler->X > Next->X && Next->Type == LastSwitch;
1069
1070} /* FillerDone */
1071
1085void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
1086 float Center, float Spread, bool debug) {
1087 int i, FirstBucket, LastBucket;
1088
1089 if (Spread > 0.5) {
1090 Spread = 0.5;
1091 }
1092
1093 FirstBucket = static_cast<int>(std::floor((Center - Spread) * NUM_PP_BUCKETS));
1094 if (FirstBucket < 0) {
1095 FirstBucket += NUM_PP_BUCKETS;
1096 }
1097
1098 LastBucket = static_cast<int>(std::floor((Center + Spread) * NUM_PP_BUCKETS));
1099 if (LastBucket >= NUM_PP_BUCKETS) {
1100 LastBucket -= NUM_PP_BUCKETS;
1101 }
1102 if (debug) {
1103 tprintf("Circular fill from %d to %d", FirstBucket, LastBucket);
1104 }
1105 for (i = FirstBucket; true; CircularIncrement(i, NUM_PP_BUCKETS)) {
1106 SET_BIT(ParamTable[i], Bit);
1107
1108 /* exit loop after we have set the bit for the last bucket */
1109 if (i == LastBucket) {
1110 break;
1111 }
1112 }
1113
1114} /* FillPPCircularBits */
1115
1130void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit,
1131 float Center, float Spread, bool debug) {
1132 int i, FirstBucket, LastBucket;
1133
1134 FirstBucket = static_cast<int>(std::floor((Center - Spread) * NUM_PP_BUCKETS));
1135 if (FirstBucket < 0) {
1136 FirstBucket = 0;
1137 }
1138
1139 LastBucket = static_cast<int>(std::floor((Center + Spread) * NUM_PP_BUCKETS));
1140 if (LastBucket >= NUM_PP_BUCKETS) {
1141 LastBucket = NUM_PP_BUCKETS - 1;
1142 }
1143
1144 if (debug) {
1145 tprintf("Linear fill from %d to %d", FirstBucket, LastBucket);
1146 }
1147 for (i = FirstBucket; i <= LastBucket; i++) {
1148 SET_BIT(ParamTable[i], Bit);
1149 }
1150
1151} /* FillPPLinearBits */
1152
1153/*---------------------------------------------------------------------------*/
1154#ifndef GRAPHICS_DISABLED
1165CLASS_ID Classify::GetClassToDebug(const char *Prompt, bool *adaptive_on, bool *pretrained_on,
1166 int *shape_id) {
1167 tprintf("%s\n", Prompt);
1168 SVEventType ev_type;
1169 int unichar_id = INVALID_UNICHAR_ID;
1170 // Wait until a click or popup event.
1171 do {
1172 auto ev = IntMatchWindow->AwaitEvent(SVET_ANY);
1173 ev_type = ev->type;
1174 if (ev_type == SVET_POPUP) {
1175 if (ev->command_id == IDA_SHAPE_INDEX) {
1176 if (shape_table_ != nullptr) {
1177 *shape_id = atoi(ev->parameter);
1178 *adaptive_on = false;
1179 *pretrained_on = true;
1180 if (*shape_id >= 0 && static_cast<unsigned>(*shape_id) < shape_table_->NumShapes()) {
1181 int font_id;
1182 shape_table_->GetFirstUnicharAndFont(*shape_id, &unichar_id, &font_id);
1183 tprintf("Shape %d, first unichar=%d, font=%d\n", *shape_id, unichar_id, font_id);
1184 return unichar_id;
1185 }
1186 tprintf("Shape index '%s' not found in shape table\n", ev->parameter);
1187 } else {
1188 tprintf("No shape table loaded!\n");
1189 }
1190 } else {
1191 if (unicharset.contains_unichar(ev->parameter)) {
1192 unichar_id = unicharset.unichar_to_id(ev->parameter);
1193 if (ev->command_id == IDA_ADAPTIVE) {
1194 *adaptive_on = true;
1195 *pretrained_on = false;
1196 *shape_id = -1;
1197 } else if (ev->command_id == IDA_STATIC) {
1198 *adaptive_on = false;
1199 *pretrained_on = true;
1200 } else {
1201 *adaptive_on = true;
1202 *pretrained_on = true;
1203 }
1204 if (ev->command_id == IDA_ADAPTIVE || shape_table_ == nullptr) {
1205 *shape_id = -1;
1206 return unichar_id;
1207 }
1208 for (unsigned s = 0; s < shape_table_->NumShapes(); ++s) {
1209 if (shape_table_->GetShape(s).ContainsUnichar(unichar_id)) {
1210 tprintf("%s\n", shape_table_->DebugStr(s).c_str());
1211 }
1212 }
1213 } else {
1214 tprintf("Char class '%s' not found in unicharset", ev->parameter);
1215 }
1216 }
1217 }
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 INT_VAR(name, val, comment)
Definition: params.h:357
#define double_VAR(name, val, comment)
Definition: params.h:366
#define ASSERT_HOST(x)
Definition: errcode.h:54
#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 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 ProtoIn(Class, Pid)
Definition: protos.h:70
#define GetPicoFeatureLength()
Definition: picofeat.h:56
Uncopyable z
const double y
const char * p
bool FillerDone(TABLE_FILLER *Filler)
Definition: intproto.cpp:1063
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:1021
void FillPPCircularBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit, float Center, float Spread, bool debug)
Definition: intproto.cpp:1085
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:543
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
int IntCastRounded(double x)
Definition: helpers.h:170
bool write_spacing_info(FILE *f, const FontInfo &fi)
Definition: fontinfo.cpp:194
@ SVET_POPUP
Definition: scrollview.h:62
@ SVET_CLICK
Definition: scrollview.h:56
float BucketEnd(int Bucket, float Offset, int NumBuckets)
Definition: intproto.cpp:1007
@ 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:991
void FillPPLinearBits(uint32_t ParamTable[NUM_PP_BUCKETS][WERDS_PER_PP_VECTOR], int Bit, float Center, float Spread, bool debug)
Definition: intproto.cpp:1130
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:105
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:561
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
Definition: helpers.h:117
@ 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:889
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:153
int AddIntProto(INT_CLASS_STRUCT *Class)
Definition: intproto.cpp:270
bool write(FILE *f, const std::function< bool(FILE *, const T &)> &cb) const
int size() const
Return the size used.
Definition: unicity_table.h:51
bool read(tesseract::TFile *f, const std::function< bool(tesseract::TFile *, T *)> &cb)
int push_back(T object)
Add an element in the table.
Definition: unicity_table.h:80
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:919
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:1165
INT_TEMPLATES_STRUCT * ReadIntTemplates(TFile *fp)
Definition: intproto.cpp:629
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
std::unique_ptr< SVEvent > AwaitEvent(SVEventType type)
Definition: scrollview.cpp:432
void void ZoomToRectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:742
void Pen(Color color)
Definition: scrollview.cpp:710
static void Update()
Definition: scrollview.cpp:700
void Rectangle(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:576
void SetCursor(int x, int y)
Definition: scrollview.cpp:485
void DrawTo(int x, int y)
Definition: scrollview.cpp:491