From 1682d83907d289b18d4525dce83e48ce17ab7606 Mon Sep 17 00:00:00 2001 From: Rozstone <42225395+wststone@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:28:44 +0800 Subject: [PATCH] feat: Add averageDistanceThreshold Option for Stroke Matching Leniency (#307) * replace AVG_DIST_THRESHOLD constant with configurable option * fix trailing comma --- src/Quiz.ts | 8 +++----- src/defaultOptions.ts | 1 + src/strokeMatches.ts | 18 ++++++++++++++---- src/typings/types.ts | 2 ++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Quiz.ts b/src/Quiz.ts index e6a1616a..2c1ba36f 100644 --- a/src/Quiz.ts +++ b/src/Quiz.ts @@ -110,6 +110,7 @@ export default class Quiz { { isOutlineVisible: this._renderState.state.character.outline.opacity > 0, leniency: this._options!.leniency, + averageDistanceThreshold: this._options!.averageDistanceThreshold, }, ); @@ -126,11 +127,8 @@ export default class Quiz { } else { this._handleFailure(meta); - const { - showHintAfterMisses, - highlightColor, - strokeHighlightSpeed, - } = this._options!; + const { showHintAfterMisses, highlightColor, strokeHighlightSpeed } = + this._options!; if ( showHintAfterMisses !== false && diff --git a/src/defaultOptions.ts b/src/defaultOptions.ts index 9994b5c6..3ec8f2bf 100644 --- a/src/defaultOptions.ts +++ b/src/defaultOptions.ts @@ -41,6 +41,7 @@ const defaultOptions: HanziWriterOptions = { markStrokeCorrectAfterMisses: false, acceptBackwardsStrokes: false, quizStartStrokeNum: 0, + averageDistanceThreshold: 350, // undocumented obscure options diff --git a/src/strokeMatches.ts b/src/strokeMatches.ts index ea2beb75..61bfbfdc 100644 --- a/src/strokeMatches.ts +++ b/src/strokeMatches.ts @@ -14,7 +14,6 @@ import UserStroke from './models/UserStroke'; import Stroke from './models/Stroke'; import Character from './models/Character'; -const AVG_DIST_THRESHOLD = 350; // bigger = more lenient const COSINE_SIMILARITY_THRESHOLD = 0; // -1 to 1, smaller = more lenient const START_AND_END_DIST_THRESHOLD = 250; // bigger = more lenient const FRECHET_THRESHOLD = 0.4; // bigger = more lenient @@ -36,6 +35,7 @@ export default function strokeMatches( options: { leniency?: number; isOutlineVisible?: boolean; + averageDistanceThreshold?: number; } = {}, ): StrokeMatchResult { const strokes = character.strokes; @@ -156,12 +156,22 @@ const shapeFit = (curve1: Point[], curve2: Point[], leniency: number) => { const getMatchData = ( points: Point[], stroke: Stroke, - options: { leniency?: number; isOutlineVisible?: boolean; checkBackwards?: boolean }, + options: { + leniency?: number; + isOutlineVisible?: boolean; + checkBackwards?: boolean; + averageDistanceThreshold?: number; + }, ): StrokeMatchResult & { avgDist: number } => { - const { leniency = 1, isOutlineVisible = false, checkBackwards = true } = options; + const { + leniency = 1, + isOutlineVisible = false, + checkBackwards = true, + averageDistanceThreshold = 350, + } = options; const avgDist = stroke.getAverageDistance(points); const distMod = isOutlineVisible || stroke.strokeNum > 0 ? 0.5 : 1; - const withinDistThresh = avgDist <= AVG_DIST_THRESHOLD * distMod * leniency; + const withinDistThresh = avgDist <= averageDistanceThreshold * distMod * leniency; // short circuit for faster matching if (!withinDistThresh) { return { isMatch: false, avgDist, meta: { isStrokeBackwards: false } }; diff --git a/src/typings/types.ts b/src/typings/types.ts index f3ac2967..f05d988d 100644 --- a/src/typings/types.ts +++ b/src/typings/types.ts @@ -72,6 +72,8 @@ export type QuizOptions = { quizStartStrokeNum: number; /** After a user makes this many mistakes, just mark the stroke correct and move on. Default: false */ markStrokeCorrectAfterMisses: number | false; + /** bigger = more lenient */ + averageDistanceThreshold: number; onMistake?: (strokeData: StrokeData) => void; onCorrectStroke?: (strokeData: StrokeData) => void; /** Callback when the quiz completes */