Skip to content

Commit

Permalink
Add a parameter that may be used to disable wobble smoothing.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 662224794
  • Loading branch information
Jon T Moran authored and copybara-github committed Aug 13, 2024
1 parent 0bbaec0 commit 204fab8
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 5 deletions.
4 changes: 2 additions & 2 deletions ink_stroke_modeler/internal/wobble_smoother.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

#include "ink_stroke_modeler/internal/wobble_smoother.h"

#include <algorithm>

#include "ink_stroke_modeler/internal/utils.h"
#include "ink_stroke_modeler/params.h"
#include "ink_stroke_modeler/types.h"
Expand All @@ -37,6 +35,8 @@ void WobbleSmoother::Reset(const WobbleSmootherParams& params, Vec2 position,
}

Vec2 WobbleSmoother::Update(Vec2 position, Time time) {
if (!params_.is_enabled) return position;

// The moving average acts as a low-pass signal filter, removing
// high-frequency fluctuations in the position caused by the discrete nature
// of the touch digitizer. To compensate for the distance between the average
Expand Down
13 changes: 13 additions & 0 deletions ink_stroke_modeler/internal/wobble_smoother_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ TEST(WobbleSmootherTest, FastZigZag) {
Vec2Eq({7.048, 3.048}));
}

TEST(WobbleSmootherTest, NoOpIfNotEnabled) {
WobbleSmoother smoother;
smoother.Reset({.is_enabled = false,
.timeout = Duration(10),
.speed_floor = 1,
.speed_ceiling = 5},
{0, 0}, Time(0));
EXPECT_THAT(smoother.Update({.1, 0}, Time(1)), Vec2Eq({.1, 0}));
EXPECT_THAT(smoother.Update({.2, 0}, Time(2)), Vec2Eq({.2, 0}));
EXPECT_THAT(smoother.Update({.3, 0}, Time(3)), Vec2Eq({.3, 0}));
EXPECT_THAT(smoother.Update({.4, 0}, Time(4)), Vec2Eq({.4, 0}));
}

TEST(WobbleSmootherTest, SaveAndRestore) {
WobbleSmoother filter;
filter.Reset(kDefaultParams, {1, 2}, Time{5});
Expand Down
2 changes: 2 additions & 0 deletions ink_stroke_modeler/params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ absl::Status ValidateStylusStateModelerParams(
}

absl::Status ValidateWobbleSmootherParams(const WobbleSmootherParams& params) {
if (!params.is_enabled) return absl::OkStatus();

RETURN_IF_ERROR(ValidateGreaterThanOrEqualToZero(
params.timeout.Value(), "WobbleSmootherParams::timeout"));
RETURN_IF_ERROR(ValidateGreaterThanOrEqualToZero(
Expand Down
5 changes: 5 additions & 0 deletions ink_stroke_modeler/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ struct StylusStateModelerParams {
// These parameters are used for applying smoothing to the input to reduce
// wobble in the prediction.
struct WobbleSmootherParams {
// If true, the wobble smoothing will be applied to the stroke. If false, the
// wobble smoothing step will be skipped, and the remainder of the parameters
// in the struct will be ignored.
bool is_enabled = true;

// The length of the window over which the moving average of speed and
// position are calculated.
//
Expand Down
8 changes: 8 additions & 0 deletions ink_stroke_modeler/params_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ TEST(ParamsTest, ValidateWobbleSmootherParams) {
{.timeout = Duration(0), .speed_floor = 0, .speed_ceiling = 0})
.ok());

// This is valid because `is_enabled` is false; otherwise, this would not be a
// valid configuration.
EXPECT_TRUE(ValidateWobbleSmootherParams({.is_enabled = false,
.timeout = Duration(-5),
.speed_floor = -3,
.speed_ceiling = -4})
.ok());

EXPECT_EQ(ValidateWobbleSmootherParams(
{.timeout = Duration(-1), .speed_floor = 2, .speed_ceiling = 5})
.code(),
Expand Down
6 changes: 3 additions & 3 deletions ink_stroke_modeler/stroke_modeler_fuzz_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ fuzztest::Domain<Time> ArbitraryTime() {

fuzztest::Domain<StrokeModelParams> ArbitraryStrokeModelParams() {
return fuzztest::StructOf<StrokeModelParams>(
fuzztest::StructOf<WobbleSmootherParams>(ArbitraryDuration(),
fuzztest::Arbitrary<float>(),
fuzztest::Arbitrary<float>()),
fuzztest::StructOf<WobbleSmootherParams>(
fuzztest::Arbitrary<bool>(), ArbitraryDuration(),
fuzztest::Arbitrary<float>(), fuzztest::Arbitrary<float>()),
fuzztest::Arbitrary<PositionModelerParams>(),
fuzztest::StructOf<SamplingParams>(
fuzztest::Arbitrary<double>(), fuzztest::Arbitrary<float>(),
Expand Down
140 changes: 140 additions & 0 deletions ink_stroke_modeler/stroke_modeler_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,146 @@ TEST(StrokeModelerTest, WobbleSmoothed) {
kTol)));
}

TEST(StrokeModelerTest, WobbleNotSmoothedIfNotEnabled) {
const Duration kDeltaTime{.0167};

StrokeModelParams params = kDefaultParams;
params.wobble_smoother_params.is_enabled = false;
StrokeModeler modeler;
ASSERT_TRUE(modeler.Reset(params).ok());

Time time{4};
std::vector<Result> results;

ASSERT_TRUE(modeler
.Update({.event_type = Input::EventType::kDown,
.position = {-6, -2},
.time = time},
results)
.ok());
EXPECT_THAT(results, ElementsAre(ResultNear(
{.position = {-6, -2}, .time = Time(4)}, kTol)));

time += kDeltaTime;
results.clear();
ASSERT_TRUE(modeler
.Update({.event_type = Input::EventType::kMove,
.position = {-6.02, -2},
.time = time},
results)
.ok());
EXPECT_THAT(results, ElementsAre(ResultNear({.position = {-6.0003, -2},
.velocity = {-0.0615, 0},
.acceleration = {-14.7276, 0},
.time = Time(4.0042)},
kTol),
ResultNear({.position = {-6.0009, -2},
.velocity = {-0.1628, 0},
.acceleration = {-24.2725, 0},
.time = Time(4.0084)},
kTol),
ResultNear({.position = {-6.0021, -2},
.velocity = {-0.2868, 0},
.acceleration = {-29.6996, 0},
.time = Time(4.0125)},
kTol),
ResultNear({.position = {-6.0039, -2},
.velocity = {-0.4203, 0},
.acceleration = {-31.9728, 0},
.time = Time(4.0167)},
kTol)));

time += kDeltaTime;
results.clear();
ASSERT_TRUE(modeler
.Update({.event_type = Input::EventType::kMove,
.position = {-6.02, -2.02},
.time = time},
results)
.ok());
EXPECT_THAT(results,
ElementsAre(ResultNear({.position = {-6.0059, -2.0003},
.velocity = {-0.4921, -0.0615},
.acceleration = {-17.1932, -14.7276},
.time = Time(4.0209)},
kTol),
ResultNear({.position = {-6.0081, -2.0009},
.velocity = {-0.5170, -0.1628},
.acceleration = {-5.9729, -24.2711},
.time = Time(4.0251)},
kTol),
ResultNear({.position = {-6.0102, -2.0021},
.velocity = {-0.5079, -0.2868},
.acceleration = {2.1807, -29.7000},
.time = Time(4.0292)},
kTol),
ResultNear({.position = {-6.0122, -2.0039},
.velocity = {-0.4755, -0.4203},
.acceleration = {7.7710, -31.9724},
.time = Time(4.0334)},
kTol)));

time += kDeltaTime;
results.clear();
ASSERT_TRUE(modeler
.Update({.event_type = Input::EventType::kMove,
.position = {-6.04, -2.02},
.time = time},
results)
.ok());
EXPECT_THAT(results,
ElementsAre(ResultNear({.position = {-6.0143, -2.0059},
.velocity = {-0.4899, -0.4921},
.acceleration = {-3.4456, -17.1929},
.time = Time(4.0376)},
kTol),
ResultNear({.position = {-6.0165, -2.0081},
.velocity = {-0.5363, -0.5170},
.acceleration = {-11.1122, -5.9734},
.time = Time(4.0418)},
kTol),
ResultNear({.position = {-6.0190, -2.0102},
.velocity = {-0.6027, -0.5079},
.acceleration = {-15.9053, 2.1804},
.time = Time(4.0459)},
kTol),
ResultNear({.position = {-6.0218, -2.0122},
.velocity = {-0.6796, -0.4755},
.acceleration = {-18.4402, 7.7708},
.time = Time(4.0501)},
kTol)));

time += kDeltaTime;
results.clear();
ASSERT_TRUE(modeler
.Update({.event_type = Input::EventType::kMove,
.position = {-6.04, -2.04},
.time = time},
results)
.ok());
EXPECT_THAT(results,
ElementsAre(ResultNear({.position = {-6.0248, -2.0143},
.velocity = {-0.6986, -0.4899},
.acceleration = {-4.5389, -3.4458},
.time = Time(4.0543)},
kTol),
ResultNear({.position = {-6.0276, -2.0165},
.velocity = {-0.6760, -0.5363},
.acceleration = {5.4168, -11.1130},
.time = Time(4.0585)},
kTol),
ResultNear({.position = {-6.0302, -2.0190},
.velocity = {-0.6255, -0.6027},
.acceleration = {12.1018, -15.9045},
.time = Time(4.0626)},
kTol),
ResultNear({.position = {-6.0325, -2.0218},
.velocity = {-0.5580, -0.6796},
.acceleration = {16.1550, -18.4404},
.time = Time(4.0668)},
kTol)));
}

TEST(StrokeModelerTest, UpdateAppendsToResults) {
const Duration kDeltaTime{1. / 300};

Expand Down

0 comments on commit 204fab8

Please sign in to comment.