import 'dart:math'; /// Predefined pressure curve types. enum PressureCurveType { linear, soft, hard, custom } /// Maps raw pen pressure [0,1] to effective pressure [0,1] using a power curve. /// /// - **Linear**: identity (p) /// - **Soft**: `pow(p, 1.5)` — light touch produces small lines, needs more pressure /// - **Hard**: `pow(p, 0.5)` — light touch already produces thick lines /// - **Custom**: `pow(p, exponent)` where exponent is derived from [softness] class PressureCurve { final PressureCurveType type; final double softness; const PressureCurve({ this.type = PressureCurveType.linear, this.softness = 0.5, }); /// Predefined linear curve (identity). static const linear = PressureCurve(type: PressureCurveType.linear); /// Predefined soft curve — needs more pressure to ramp up. static const soft = PressureCurve( type: PressureCurveType.soft, softness: 0.3, ); /// Predefined hard curve — light touch already produces thick lines. static const hard = PressureCurve( type: PressureCurveType.hard, softness: 0.7, ); /// Maps raw pressure [0,1] to effective pressure [0,1]. double apply(double rawPressure) { final p = rawPressure.clamp(0.0, 1.0); switch (type) { case PressureCurveType.linear: return p; case PressureCurveType.soft: return pow(p, 1.5).toDouble(); case PressureCurveType.hard: return pow(p, 0.5).toDouble(); case PressureCurveType.custom: final exponent = softness * 2 + 0.2; return pow(p, exponent).toDouble(); } } @override bool operator ==(Object other) => identical(this, other) || other is PressureCurve && runtimeType == other.runtimeType && type == other.type && softness == other.softness; @override int get hashCode => type.hashCode ^ softness.hashCode; }