2026-06-23 03:20:59 +08:00
|
|
|
|
// Tests for the configurable pen-pressure response (F5).
|
|
|
|
|
|
|
2026-08-06 16:01:01 +08:00
|
|
|
|
import 'dart:math' as math;
|
|
|
|
|
|
|
2026-06-23 03:20:59 +08:00
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:badnote/editor/input/pressure_curve.dart';
|
|
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
|
test('linear is the identity over [0,1]', () {
|
|
|
|
|
|
const c = PressureCurve.linear;
|
|
|
|
|
|
expect(c.apply(0.0), closeTo(0.0, 1e-9));
|
|
|
|
|
|
expect(c.apply(0.5), closeTo(0.5, 1e-9));
|
|
|
|
|
|
expect(c.apply(1.0), closeTo(1.0, 1e-9));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('floor raises the minimum, endpoints stay anchored at floor and 1', () {
|
|
|
|
|
|
const c = PressureCurve(floor: 0.4);
|
|
|
|
|
|
expect(c.apply(0.0), closeTo(0.4, 1e-9)); // floor
|
|
|
|
|
|
expect(c.apply(1.0), closeTo(1.0, 1e-9)); // full
|
|
|
|
|
|
expect(c.apply(0.5), closeTo(0.4 + 0.6 * 0.5, 1e-9)); // 0.7
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('gamma < 1 boosts light pressure (more sensitive)', () {
|
|
|
|
|
|
const c = PressureCurve(gamma: 0.5);
|
|
|
|
|
|
// pow(0.25, 0.5) = 0.5 → output 0.5 > input 0.25
|
|
|
|
|
|
expect(c.apply(0.25), closeTo(0.5, 1e-9));
|
|
|
|
|
|
expect(c.apply(0.25), greaterThan(0.25));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('gamma > 1 dampens light pressure (firmer)', () {
|
|
|
|
|
|
const c = PressureCurve(gamma: 2.0);
|
|
|
|
|
|
expect(c.apply(0.5), closeTo(0.25, 1e-9)); // 0.5^2
|
|
|
|
|
|
expect(c.apply(0.5), lessThan(0.5));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('output is clamped: out-of-range and NaN inputs are safe', () {
|
|
|
|
|
|
const c = PressureCurve(floor: 0.2);
|
|
|
|
|
|
expect(c.apply(-1.0), closeTo(0.2, 1e-9)); // clamped to 0 → floor
|
|
|
|
|
|
expect(c.apply(2.0), closeTo(1.0, 1e-9)); // clamped to 1 → full
|
|
|
|
|
|
expect(c.apply(double.nan), closeTo(0.2, 1e-9)); // NaN → 0 → floor
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('marker-style high floor compresses the range toward full width', () {
|
|
|
|
|
|
const marker = PressureCurve(floor: 0.9);
|
|
|
|
|
|
expect(marker.apply(0.0), closeTo(0.9, 1e-9));
|
|
|
|
|
|
expect(marker.apply(1.0), closeTo(1.0, 1e-9));
|
|
|
|
|
|
// Even a light touch stays near full width.
|
|
|
|
|
|
expect(marker.apply(0.1), greaterThan(0.9));
|
|
|
|
|
|
});
|
2026-08-06 16:01:01 +08:00
|
|
|
|
|
|
|
|
|
|
group('PressureCurve.shaped', () {
|
|
|
|
|
|
const floor = 0.1;
|
|
|
|
|
|
|
|
|
|
|
|
test('every shape maps 0→floor and 1→1', () {
|
|
|
|
|
|
for (final shape in PressureCurveShape.values) {
|
|
|
|
|
|
final c = PressureCurve.shaped(shape, floor: floor);
|
|
|
|
|
|
expect(c.apply(0.0), closeTo(floor, 1e-9), reason: '$shape at 0');
|
|
|
|
|
|
expect(c.apply(1.0), closeTo(1.0, 1e-9), reason: '$shape at 1');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('midpoints differ across shapes', () {
|
|
|
|
|
|
final mids = {
|
|
|
|
|
|
for (final shape in PressureCurveShape.values)
|
|
|
|
|
|
shape: PressureCurve.shaped(shape).apply(0.5),
|
|
|
|
|
|
};
|
|
|
|
|
|
expect(mids[PressureCurveShape.linear], closeTo(0.5, 1e-9));
|
|
|
|
|
|
expect(mids[PressureCurveShape.soft], closeTo(math.pow(0.5, 0.6), 1e-9));
|
|
|
|
|
|
expect(mids[PressureCurveShape.quadratic], closeTo(0.25, 1e-9));
|
|
|
|
|
|
expect(mids[PressureCurveShape.cubic], closeTo(0.125, 1e-9));
|
|
|
|
|
|
expect(mids[PressureCurveShape.sqrt], closeTo(math.sqrt(0.5), 1e-9));
|
|
|
|
|
|
final logMid = math.log(1 + kLogarithmicPressureK * 0.5) /
|
|
|
|
|
|
math.log(1 + kLogarithmicPressureK);
|
|
|
|
|
|
expect(mids[PressureCurveShape.logarithmic], closeTo(logMid, 1e-9));
|
|
|
|
|
|
|
|
|
|
|
|
// Soft (γ<1) > linear > quadratic > cubic at p=0.5; log is above linear.
|
|
|
|
|
|
expect(mids[PressureCurveShape.soft]! > mids[PressureCurveShape.linear]!,
|
|
|
|
|
|
isTrue);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
mids[PressureCurveShape.linear]! >
|
|
|
|
|
|
mids[PressureCurveShape.quadratic]!,
|
|
|
|
|
|
isTrue);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
mids[PressureCurveShape.quadratic]! >
|
|
|
|
|
|
mids[PressureCurveShape.cubic]!,
|
|
|
|
|
|
isTrue);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
mids[PressureCurveShape.logarithmic]! >
|
|
|
|
|
|
mids[PressureCurveShape.linear]!,
|
|
|
|
|
|
isTrue);
|
|
|
|
|
|
// Distinct midpoints (no two shapes collide at p=0.5).
|
|
|
|
|
|
expect(mids.values.toSet().length, PressureCurveShape.values.length);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('shaped presets set expected gamma (except log)', () {
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.linear).gamma, 1.0);
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.soft).gamma, 0.6);
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.quadratic).gamma, 2.0);
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.cubic).gamma, 3.0);
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.sqrt).gamma, 0.5);
|
|
|
|
|
|
expect(PressureCurve.shaped(PressureCurveShape.logarithmic).shape,
|
|
|
|
|
|
PressureCurveShape.logarithmic);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-06-23 03:20:59 +08:00
|
|
|
|
}
|