Skip to content

Commit

Permalink
feat: Add averageDistanceThreshold Option for Stroke Matching Leniency (
Browse files Browse the repository at this point in the history
#307)

* replace AVG_DIST_THRESHOLD constant with configurable option

* fix trailing comma
  • Loading branch information
wststone authored Sep 15, 2023
1 parent 319ea83 commit 1682d83
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 9 deletions.
8 changes: 3 additions & 5 deletions src/Quiz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export default class Quiz {
{
isOutlineVisible: this._renderState.state.character.outline.opacity > 0,
leniency: this._options!.leniency,
averageDistanceThreshold: this._options!.averageDistanceThreshold,
},
);

Expand All @@ -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 &&
Expand Down
1 change: 1 addition & 0 deletions src/defaultOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const defaultOptions: HanziWriterOptions = {
markStrokeCorrectAfterMisses: false,
acceptBackwardsStrokes: false,
quizStartStrokeNum: 0,
averageDistanceThreshold: 350,

// undocumented obscure options

Expand Down
18 changes: 14 additions & 4 deletions src/strokeMatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,6 +35,7 @@ export default function strokeMatches(
options: {
leniency?: number;
isOutlineVisible?: boolean;
averageDistanceThreshold?: number;
} = {},
): StrokeMatchResult {
const strokes = character.strokes;
Expand Down Expand Up @@ -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 } };
Expand Down
2 changes: 2 additions & 0 deletions src/typings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 1682d83

Please sign in to comment.