#include "UniStrokeRecognizer.h" FUniStrokeRecognizer::FUniStrokeRecognizer() { this->Templates = TArray(); } FUniStrokeRecognizer::~FUniStrokeRecognizer() { // DO NOTHING } // TODO: Review this function FUniStrokeResult FUniStrokeRecognizer::Recognize(const TArray& VectorPoints, const bool& UseProtractor) { TArray Points = FUniStrokePoint::From(VectorPoints); // Edge case: Not enough points if (Points.Num() < 2 || FUniStrokePoint::PathLength(Points) < 100.0f) { return FUniStrokeResult("Too few points made", 0.0); } const FUniStrokeTemplate Candidate = FUniStrokeTemplate("", Points); int TemplateIndex = -1; // b <- +infty float b = TNumericLimits::Max(); // foreach template T in templates do for (int i = 0; i < Templates.Num(); i++) { // d <- DistanceAtBestAngle(points, T, -theta, theta, threshold) const float d = UseProtractor ? FUniStrokePoint::OptimalCosineDistance( Templates[i].Vector, Candidate.Vector ) : FUniStrokePoint::DistanceAtBestAngle( Candidate.Points, Templates[i].Points, -AngleRange, AngleRange, AnglePrecision ); // if d < b then if (d < b) { // b <- d b = d; // T' <- T TemplateIndex = i; } } // score <- 1 – b / 0.5 sqrt(size^2 + size^2) const float Score = UseProtractor ? 1.0 - b : 1.0 - b / HalfDiagonal; // return return TemplateIndex == -1 ? FUniStrokeResult("No match", 0.0) : FUniStrokeResult(Templates[TemplateIndex].Name, Score); } void FUniStrokeRecognizer::AddTemplate(const FString& Name, const TArray& VectorPoints) { const TArray Points = FUniStrokePoint::From(VectorPoints); this->Templates.Add(FUniStrokeTemplate(Name, Points)); } void FUniStrokeRecognizer::Reset() { Templates.SetNum(NumTemplates); }