add:实时笔锋及墨迹预测

This commit is contained in:
2026-03-28 17:04:50 +08:00
parent d325a58f17
commit de3f5d16a2
8 changed files with 161 additions and 55 deletions
+41 -9
View File
@@ -4,12 +4,11 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Ink_Canvas
{
/// <summary>
/// 墨迹预测书写中速度外推预览线)与笔锋相关输入状态,思路参考智绘教 Inkeys 的 RTS 速度与低延迟手感
/// 墨迹预测书写过程中根据速度与选项外推一小段预览线,减轻感知延迟
/// </summary>
public partial class MainWindow
{
@@ -21,12 +20,21 @@ namespace Ink_Canvas
private double _inkPredictionVx;
private double _inkPredictionVy;
private void ResetInkPredictionState()
private void SyncInkStrokePredictionLeadComboVisibility()
{
_inkPredictionStrokeActive = false;
_inkPredictionHasSample = false;
_inkPredictionHasVelocity = false;
ClearInkPredictionOverlay();
try
{
bool on = Settings?.Canvas != null && Settings.Canvas.EnableInkStrokePrediction;
var v = on ? Visibility.Visible : Visibility.Collapsed;
if (ComboBoxInkStrokePredictionLead != null)
ComboBoxInkStrokePredictionLead.Visibility = v;
if (BoardComboBoxInkStrokePredictionLead != null)
BoardComboBoxInkStrokePredictionLead.Visibility = v;
}
catch
{
// ignore
}
}
private void ClearInkPredictionOverlay()
@@ -75,6 +83,30 @@ namespace Ink_Canvas
ClearInkPredictionOverlay();
}
private double GetInkPredictionLeadMs()
{
int mode = Settings?.Canvas?.InkStrokePredictionLeadMode ?? 0;
if (mode == 1) return 25.0;
if (mode == 2) return 50.0;
double speed = Math.Sqrt(_inkPredictionVx * _inkPredictionVx + _inkPredictionVy * _inkPredictionVy);
double norm = Math.Min(1.0, speed / 2600.0);
double lead = 16.0 + norm * 34.0;
return Math.Max(14.0, Math.Min(52.0, lead));
}
private double GetInkPredictionMaxDistance(double leadMs)
{
double baseD = Math.Max(4.0, Settings?.Canvas?.InkStrokePredictionMaxDistance ?? 18.0);
int mode = Settings?.Canvas?.InkStrokePredictionLeadMode ?? 0;
if (mode != 0)
return Math.Max(6.0, Math.Min(42.0, baseD * (leadMs / 24.0)));
double speed = Math.Sqrt(_inkPredictionVx * _inkPredictionVx + _inkPredictionVy * _inkPredictionVy);
double norm = Math.Min(1.0, speed / 2200.0);
return Math.Max(6.0, Math.Min(48.0, baseD + norm * baseD * 0.9));
}
private void inkCanvas_PreviewStylusMove(object sender, StylusEventArgs e)
{
try
@@ -155,11 +187,11 @@ namespace Ink_Canvas
_inkPredictionVy = velocitySmooth * _inkPredictionVy + (1.0 - velocitySmooth) * vy;
}
const double leadMs = 24.0;
double leadMs = GetInkPredictionLeadMs();
double predX = pos.X + _inkPredictionVx * (leadMs / 1000.0);
double predY = pos.Y + _inkPredictionVy * (leadMs / 1000.0);
double maxDist = Math.Max(4.0, Settings.Canvas.InkStrokePredictionMaxDistance);
double maxDist = GetInkPredictionMaxDistance(leadMs);
double dx = predX - pos.X;
double dy = predY - pos.Y;
double len = Math.Sqrt(dx * dx + dy * dy);
+24 -5
View File
@@ -2700,21 +2700,40 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
private void ToggleSwitchEnableInkStrokePrediction_Toggled(object sender, RoutedEventArgs e)
private void ToggleSwitchInkStrokePredictionPanel_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
Settings.Canvas.EnableInkStrokePrediction = ToggleSwitchEnableInkStrokePrediction.IsOn;
if (!Settings.Canvas.EnableInkStrokePrediction)
bool on = ReferenceEquals(sender, BoardToggleSwitchInkStrokePredictionPanel)
? BoardToggleSwitchInkStrokePredictionPanel.IsOn
: ToggleSwitchInkStrokePredictionPanel.IsOn;
if (ReferenceEquals(sender, ToggleSwitchInkStrokePredictionPanel) && BoardToggleSwitchInkStrokePredictionPanel != null)
BoardToggleSwitchInkStrokePredictionPanel.IsOn = on;
else if (ReferenceEquals(sender, BoardToggleSwitchInkStrokePredictionPanel) && ToggleSwitchInkStrokePredictionPanel != null)
ToggleSwitchInkStrokePredictionPanel.IsOn = on;
Settings.Canvas.EnableInkStrokePrediction = on;
SyncInkStrokePredictionLeadComboVisibility();
if (!on)
EndInkPredictionStroke();
SaveSettingsToFile();
}
private void ToggleSwitchEnableVelocityBrushTip_Toggled(object sender, RoutedEventArgs e)
private void ComboBoxInkStrokePredictionLead_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!isLoaded) return;
var cb = sender as ComboBox;
if (cb?.SelectedIndex < 0) return;
int idx = cb.SelectedIndex;
Settings.Canvas.InkStrokePredictionLeadMode = idx;
if (ReferenceEquals(cb, ComboBoxInkStrokePredictionLead) && BoardComboBoxInkStrokePredictionLead != null)
BoardComboBoxInkStrokePredictionLead.SelectedIndex = idx;
else if (ReferenceEquals(cb, BoardComboBoxInkStrokePredictionLead) && ComboBoxInkStrokePredictionLead != null)
ComboBoxInkStrokePredictionLead.SelectedIndex = idx;
Settings.Canvas.EnableVelocityBrushTip = ToggleSwitchEnableVelocityBrushTip.IsOn;
SaveSettingsToFile();
}
+22 -4
View File
@@ -824,6 +824,15 @@ namespace Ink_Canvas
ToggleSwitchDisablePressure.IsOn = Settings.Canvas.DisablePressure;
inkCanvas.DefaultDrawingAttributes.IgnorePressure = Settings.Canvas.DisablePressure;
if (Settings.Canvas.EnableVelocityBrushTip)
{
Settings.Canvas.InkStyle = 3;
Settings.Canvas.EnableVelocityBrushTip = false;
}
if (Settings.Canvas.InkStyle < 0 || Settings.Canvas.InkStyle > 3)
Settings.Canvas.InkStyle = 0;
ComboBoxPenStyle.SelectedIndex = Settings.Canvas.InkStyle;
BoardComboBoxPenStyle.SelectedIndex = Settings.Canvas.InkStyle;
@@ -942,10 +951,19 @@ namespace Ink_Canvas
ToggleSwitchLineEndpointSnapping.IsOn = Settings.Canvas.LineEndpointSnapping;
ToggleSwitchCompressPicturesUploaded.IsOn = Settings.Canvas.IsCompressPicturesUploaded;
if (ToggleSwitchEnableInkStrokePrediction != null)
ToggleSwitchEnableInkStrokePrediction.IsOn = Settings.Canvas.EnableInkStrokePrediction;
if (ToggleSwitchEnableVelocityBrushTip != null)
ToggleSwitchEnableVelocityBrushTip.IsOn = Settings.Canvas.EnableVelocityBrushTip;
int leadMode = Settings.Canvas.InkStrokePredictionLeadMode;
if (leadMode < 0 || leadMode > 2) leadMode = 0;
Settings.Canvas.InkStrokePredictionLeadMode = leadMode;
if (ToggleSwitchInkStrokePredictionPanel != null)
ToggleSwitchInkStrokePredictionPanel.IsOn = Settings.Canvas.EnableInkStrokePrediction;
if (BoardToggleSwitchInkStrokePredictionPanel != null)
BoardToggleSwitchInkStrokePredictionPanel.IsOn = Settings.Canvas.EnableInkStrokePrediction;
if (ComboBoxInkStrokePredictionLead != null)
ComboBoxInkStrokePredictionLead.SelectedIndex = leadMode;
if (BoardComboBoxInkStrokePredictionLead != null)
BoardComboBoxInkStrokePredictionLead.SelectedIndex = leadMode;
SyncInkStrokePredictionLeadComboVisibility();
}
else
{
@@ -315,7 +315,7 @@ namespace Ink_Canvas
}
}
if (Settings.Canvas.EnableVelocityBrushTip
if (Settings.Canvas.InkStyle == 3
&& !touchPressureSimulationApplied
&& !Settings.Canvas.DisablePressure
&& penType != 1
@@ -825,6 +825,8 @@ namespace Ink_Canvas
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
break;
case 3:
break;
}
}