/// <summary> /// /// </summary> /// <param name="timepoints"></param> /// <param name="protractor"></param> /// <returns></returns> public NBestList Recognize(List <TimePointF> timepoints, bool protractor) // candidate points { double I = GeotrigEx.PathLength(timepoints) / (NumPoints - 1); // interval distance between points List <PointF> points = TimePointF.ConvertList(SeriesEx.ResampleInSpace(timepoints, I)); double radians = GeotrigEx.Angle(GeotrigEx.Centroid(points), points[0], false); points = GeotrigEx.RotatePoints(points, -radians); points = GeotrigEx.ScaleTo(points, SquareSize); points = GeotrigEx.TranslateTo(points, Origin, true); List <double> vector = Unistroke.Vectorize(points); // candidate's vector representation NBestList nbest = new NBestList(); foreach (Unistroke u in _gestures.Values) { if (protractor) // Protractor extension by Yang Li (CHI 2010) { double[] best = OptimalCosineDistance(u.Vector, vector); double score = 1.0 / best[0]; nbest.AddResult(u.Name, score, best[0], best[1]); // name, score, distance, angle } else // original $1 angular invariance search -- Golden Section Search (GSS) { double[] best = GoldenSectionSearch( points, // to rotate u.Points, // to match GeotrigEx.Degrees2Radians(-45.0), // lbound GeotrigEx.Degrees2Radians(+45.0), // ubound GeotrigEx.Degrees2Radians(2.0) // threshold ); double score = 1.0 - best[0] / HalfDiagonal; nbest.AddResult(u.Name, score, best[0], best[1]); // name, score, distance, angle } } nbest.SortDescending(); // sort descending by score so that nbest[0] is best result return(nbest); }