feat(f5): configurable pen pressure curve (floor + gamma) pure core
Some checks failed
CI / Windows build (push) Has been cancelled
Some checks failed
CI / Windows build (push) Has been cancelled
The user's repeated "可配置笔" ask, as a pure value type: raw normalized pressure is pre-shaped into [floor, 1] via a min-width floor (the plan's marker fixed-pressure floor) and a gamma response (γ<1 = more sensitive at light touch, γ>1 = firmer). Clamps out-of-range + NaN inputs; endpoints anchored at floor and 1. Widget-free/storage-free; PenConfig + the canvas wire it later (live-path, on-device validated). flutter analyze lib/editor clean; 145/145 tests (+6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
40
lib/editor/input/pressure_curve.dart
Normal file
40
lib/editor/input/pressure_curve.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
// lib/editor/input/pressure_curve.dart
|
||||
//
|
||||
// Configurable pen-pressure response (F5 — the user's repeated "可配置笔" ask).
|
||||
// Raw normalized stylus pressure [0,1] is pre-shaped here before it reaches
|
||||
// perfect_freehand, giving two user-facing knobs:
|
||||
// - [floor]: a minimum output (the plan's marker "min-width floor" — a fixed-
|
||||
// pressure marker uses floor≈1.0; a pen uses 0.0).
|
||||
// - [gamma]: the response exponent — γ<1 makes light touches register more
|
||||
// width (more sensitive), γ>1 requires firmer pressure (less sensitive).
|
||||
//
|
||||
// Pure value type (widget-free, storage-free) so the full mapping is unit
|
||||
// tested; PenConfig / the canvas wire it later (the wiring touches the live
|
||||
// draw path and is validated on-device).
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
/// Maps raw normalized pressure to a shaped response in `[floor, 1]`.
|
||||
class PressureCurve {
|
||||
const PressureCurve({this.floor = 0.0, this.gamma = 1.0})
|
||||
: assert(floor >= 0.0 && floor < 1.0),
|
||||
assert(gamma > 0.0);
|
||||
|
||||
/// Minimum output (>=0, <1). 0 = full dynamic range; raise toward 1 for a
|
||||
/// fixed-pressure feel (marker).
|
||||
final double floor;
|
||||
|
||||
/// Response exponent (>0). 1 = linear; <1 = more sensitive at light pressure;
|
||||
/// >1 = firmer.
|
||||
final double gamma;
|
||||
|
||||
/// Linear, full-range pen response (identity).
|
||||
static const PressureCurve linear = PressureCurve();
|
||||
|
||||
/// Shape [pressure] (clamped to [0,1]) into `[floor, 1]`.
|
||||
double apply(double pressure) {
|
||||
final p = pressure.isNaN ? 0.0 : pressure.clamp(0.0, 1.0);
|
||||
final shaped = gamma == 1.0 ? p : math.pow(p, gamma).toDouble();
|
||||
return floor + (1.0 - floor) * shaped;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user