1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - PRC -
3   File:     prc_algo_standard.c
4 
5   Copyright 2003-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-18#$
14   $Rev: 8573 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro.h>
19 #include <nitro/prc/algo_standard.h>
20 
21 /*===========================================================================*
22   Prototype Declarations
23  *===========================================================================*/
CityBlockDistance(const PRCPoint * p1,const PRCPoint * p2)24 static inline int CityBlockDistance(const PRCPoint *p1, const PRCPoint *p2)
25 {
26     int     x = p1->x - p2->x;
27     int     y = p1->y - p2->y;
28     if (x < 0)
29         x = -x;
30     if (y < 0)
31         y = -y;
32     return (x + y);
33 }
34 
GetMiddlePoint(PRCPoint * p,const PRCPoint * p1,const PRCPoint * p2)35 static inline void GetMiddlePoint(PRCPoint *p, const PRCPoint *p1, const PRCPoint *p2)
36 {
37     p->x = (s16)((p1->x + p2->x) / 2);
38     p->y = (s16)((p1->y + p2->y) / 2);
39 }
40 
41 /*===========================================================================*
42   Variable Definitions
43  *===========================================================================*/
44 
45 /*===========================================================================*
46   Functions
47  *===========================================================================*/
48 
49 /*---------------------------------------------------------------------------*
50   Name:         PRC_GetRecognitionBufferSizeEx_Standard
51 
52   Description:  Calculates the work area size required for recognition algorithm.
53 
54 
55   Arguments:    maxPointCount: Upper limit of number of input points (includes pen up marker)
56                 maxStrokeCount: Upper limit of stroke count
57                 protoDB: Sample DB
58                 param: Parameters for recognition processing
59 
60   Returns:      The memory capacity required for the recognition algorithm.
61  *---------------------------------------------------------------------------*/
62 u32
PRC_GetRecognitionBufferSizeEx_Standard(int maxPointCount,int maxStrokeCount,const PRCPrototypeDB_Standard * protoDB,const PRCRecognizeParam_Standard * param)63 PRC_GetRecognitionBufferSizeEx_Standard(int maxPointCount,
64                                         int maxStrokeCount,
65                                         const PRCPrototypeDB_Standard *protoDB,
66                                         const PRCRecognizeParam_Standard *param)
67 {
68     (void)maxPointCount;
69     (void)maxStrokeCount;
70     (void)protoDB;
71     (void)param;
72 
73     return 1;                          // Because OS_Alloc(0) causes an error
74 }
75 
76 /*---------------------------------------------------------------------------*
77   Name:         PRC_GetRecognizedEntriesEx_Standard
78 
79   Description:  Compares and recognizes a specific kind entry and input pattern to return the top numRanking ranking of the result.
80 
81 
82   Arguments:    resultEntries: Pointer to array that holds pointers to recognition results.
83                                 If less than the requested number could be recognized, fill in remainder with NULL.
84 
85                 resultScores: Pointer to recognition result score array
86                 numRanking: Number of returns to result*
87                 buffer: Pointer to memory region used by recognition algorithm
88                                 (Region size >= return value of PRC_GetRecognitionBufferSize)
89                 input: Input pattern
90                 protoDB: Sample DB
91                 kindMask: Takes the logical AND of the 'kind' values for all the sample DB entries. Considered valid if it is non-zero.
92 
93                 param: Parameters for recognition processing
94 
95   Returns:      Number of patterns in the compared sample DBs.
96  *---------------------------------------------------------------------------*/
97 int
PRC_GetRecognizedEntriesEx_Standard(PRCPrototypeEntry ** resultEntries,fx32 * resultScores,int numRanking,void * buffer,const PRCInputPattern_Standard * input,const PRCPrototypeDB_Standard * protoDB,u32 kindMask,const PRCRecognizeParam_Standard * param)98 PRC_GetRecognizedEntriesEx_Standard(PRCPrototypeEntry **resultEntries,
99                                     fx32 *resultScores,
100                                     int numRanking,
101                                     void *buffer,
102                                     const PRCInputPattern_Standard *input,
103                                     const PRCPrototypeDB_Standard *protoDB,
104                                     u32 kindMask, const PRCRecognizeParam_Standard *param)
105 {
106     int     i;
107     const PRCiPatternData_Common *inputData;
108     int     numCompared;
109     int     normalizeSize;
110     int     doubleWidth;
111 
112     (void)buffer;
113     (void)param;
114 
115     SDK_ASSERT(resultEntries);
116     SDK_ASSERT(resultScores);
117     SDK_ASSERT(input);
118     SDK_ASSERT(protoDB);
119     SDK_ASSERT(numRanking > 0);
120 
121     for (i = 0; i < numRanking; i++)
122     {
123         resultEntries[i] = NULL;
124         resultScores[i] = 0;
125     }
126 
127     normalizeSize = protoDB->normalizeSize;
128     if (normalizeSize < input->normalizeSize)
129     {
130         normalizeSize = input->normalizeSize;
131     }
132     doubleWidth = normalizeSize * 2;
133 
134     inputData = &input->data;
135     numCompared = 0;
136 
137     {
138         const PRCiPrototypeEntry_Common *proto;
139         int     iPattern;
140 
141         proto = protoDB->patterns;
142 
143         for (iPattern = 0; iPattern < protoDB->patternCount; iPattern++, proto++)
144         {
145             const PRCiPatternData_Common *protoData;
146             int     iStroke;
147             fx32    wholeScore;
148             fx32    wholeWeight;
149 
150             if (!proto->entry->enabled || !(proto->entry->kind & kindMask))
151                 continue;
152 
153             protoData = &proto->data;
154 
155             if (inputData->strokeCount != protoData->strokeCount)
156                 continue;
157 
158             wholeScore = 0;
159             wholeWeight = 0;
160 
161             for (iStroke = 0; iStroke < inputData->strokeCount; iStroke++)
162             {
163                 int     iProto, iInput;
164                 int     protoStrokeIndex, inputStrokeIndex;
165                 int     protoSize, inputSize;
166                 const PRCPoint *protoPoints;
167                 const PRCPoint *inputPoints;
168                 const u16 *protoAngle;
169                 const u16 *inputAngle;
170                 const fx16 *protoRatio;
171                 const fx16 *inputRatio;
172 //                PRCPoint protoMidPoint, inputMidPoint;
173                 fx16    protoNextRatio, inputNextRatio;
174                 fx32    strokeScore;
175                 fx16    strokeRatio;
176 
177                 strokeScore = 0;
178 
179                 protoStrokeIndex = protoData->strokes[iStroke];
180                 inputStrokeIndex = inputData->strokes[iStroke];
181                 protoSize = protoData->strokeSizes[iStroke];
182                 inputSize = inputData->strokeSizes[iStroke];
183                 protoPoints = &protoData->pointArray[protoStrokeIndex];
184                 inputPoints = &inputData->pointArray[inputStrokeIndex];
185                 protoAngle = &protoData->lineSegmentAngleArray[protoStrokeIndex];
186                 inputAngle = &inputData->lineSegmentAngleArray[inputStrokeIndex];
187                 protoRatio = &protoData->lineSegmentRatioToStrokeArray[protoStrokeIndex];
188                 inputRatio = &inputData->lineSegmentRatioToStrokeArray[inputStrokeIndex];
189 
190                 SDK_ASSERT(protoSize >= 2);
191                 SDK_ASSERT(inputSize >= 2);
192 
193                 iProto = iInput = 1;
194                 protoNextRatio = protoRatio[iProto];
195                 inputNextRatio = inputRatio[iInput];
196 //                GetMiddlePoint(&protoMidPoint, &protoPoints[iProto-1], &protoPoints[iProto]);
197 //                GetMiddlePoint(&inputMidPoint, &inputPoints[iInput-1], &inputPoints[iInput]);
198                 for (i = 0; i < protoSize + inputSize - 3; i++)
199                 {
200                     int     diff, score;
201                     SDK_ASSERT(iProto < protoSize);
202                     SDK_ASSERT(iInput < inputSize);
203                     diff = (s16)(protoAngle[iProto] - inputAngle[iInput]);
204                     if (diff < 0)
205                     {
206                         diff = -diff;
207                     }
208                     score = ((32768 - diff) / 128);
209                     if (protoNextRatio <= inputNextRatio)
210                     {
211                         // Trace one step in the sample stroke
212                         // The distance from the closer of the points in the input stroke is reflected in the score
213                         inputNextRatio -= protoNextRatio;
214                         score *= (inputNextRatio < inputRatio[iInput] / 2)      // Remainder of less than half = Next point is closer
215                             ? (doubleWidth -
216                                CityBlockDistance(&inputPoints[iInput],
217                                                  &protoPoints[iProto])) : (doubleWidth -
218                                                                            CityBlockDistance
219                                                                            (&inputPoints
220                                                                             [iInput - 1],
221                                                                             &protoPoints[iProto]));
222                         strokeScore += protoNextRatio * score;
223                         iProto++;
224                         protoNextRatio = protoRatio[iProto];
225 //                        GetMiddlePoint(&protoMidPoint, &protoPoints[iProto-1], &protoPoints[iProto]);
226                     }
227                     else
228                     {
229                         // Trace one step in the input stroke
230                         // The distance from the closer of the points in the sample stroke is reflected in the score
231                         protoNextRatio -= inputNextRatio;
232                         score *= (protoNextRatio < protoRatio[iProto] / 2)      // Remainder of less than half = Next point is closer
233                             ? (doubleWidth -
234                                CityBlockDistance(&inputPoints[iInput],
235                                                  &protoPoints[iProto])) : (doubleWidth -
236                                                                            CityBlockDistance
237                                                                            (&inputPoints[iInput],
238                                                                             &protoPoints[iProto -
239                                                                                          1]));
240                         strokeScore += inputNextRatio * score;
241                         iInput++;
242                         inputNextRatio = inputRatio[iInput];
243 //                        GetMiddlePoint(&inputMidPoint, &inputPoints[iInput-1], &inputPoints[iInput]);
244                     }
245                 }
246 
247                 strokeRatio = protoData->strokeRatios[iStroke];
248                 if (strokeRatio < inputData->strokeRatios[iStroke])
249                 {
250                     strokeRatio = inputData->strokeRatios[iStroke];
251                 }
252 
253                 wholeScore += FX_Mul(strokeScore, strokeRatio);
254                 wholeWeight += strokeRatio;
255             }
256 
257             wholeScore = FX_Div(wholeScore, wholeWeight * doubleWidth);
258             wholeScore /= 256;
259 
260             if (proto->entry->correction != 0)
261             {
262                 wholeScore = FX_Mul(wholeScore, FX32_ONE - proto->entry->correction)
263                     + proto->entry->correction;
264             }
265 
266             if (wholeScore < 0)
267                 wholeScore = 0;
268             if (wholeScore >= FX32_ONE)
269                 wholeScore = FX32_ONE;
270 
271             numCompared++;
272             if (resultScores[numRanking - 1] < wholeScore)
273             {
274                 resultScores[numRanking - 1] = wholeScore;
275                 resultEntries[numRanking - 1] = (PRCPrototypeEntry *)proto->entry;
276                 for (i = numRanking - 2; i >= 0; i--)
277                 {
278                     if (resultScores[i] < resultScores[i + 1])
279                     {
280                         fx32    tmpScore;
281                         PRCPrototypeEntry *tmpEntry;
282                         tmpScore = resultScores[i];
283                         resultScores[i] = resultScores[i + 1];
284                         resultScores[i + 1] = tmpScore;
285                         tmpEntry = resultEntries[i];
286                         resultEntries[i] = resultEntries[i + 1];
287                         resultEntries[i + 1] = tmpEntry;
288                     }
289                 }
290             }
291         }
292     }
293     // Normalize the score
294 
295     return numCompared;
296 }
297 
298 /*===========================================================================*
299   Static Functions
300  *===========================================================================*/
301 
302 
303 /*---------------------------------------------------------------------------*
304   End of file
305  *---------------------------------------------------------------------------*/
306