improve:实时笔锋
This commit is contained in:
@@ -1320,6 +1320,7 @@ namespace Ink_Canvas
|
|||||||
LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event);
|
LogHelper.WriteLogToFile("Ink Canvas Loaded", LogHelper.LogType.Event);
|
||||||
|
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
|
EnsureRealtimeStylusPipelineBinding();
|
||||||
BlackBoardLeftSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
|
BlackBoardLeftSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
|
||||||
BlackBoardRightSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
|
BlackBoardRightSidePageListView.ItemsSource = blackBoardSidePageListViewObservableCollection;
|
||||||
|
|
||||||
|
|||||||
@@ -2246,7 +2246,8 @@ namespace Ink_Canvas
|
|||||||
SetFloatingBarHighlightPosition("pen");
|
SetFloatingBarHighlightPosition("pen");
|
||||||
|
|
||||||
// 记录当前是否已经是批注模式且是否为高光显示模式
|
// 记录当前是否已经是批注模式且是否为高光显示模式
|
||||||
bool wasInInkMode = inkCanvas.EditingMode == InkCanvasEditingMode.Ink;
|
bool wasInInkMode = inkCanvas.EditingMode == InkCanvasEditingMode.Ink
|
||||||
|
|| (Pen_Icon.Background != null && StackPanelCanvasControls.Visibility == Visibility.Visible);
|
||||||
bool wasHighlighter = drawingAttributes.IsHighlighter;
|
bool wasHighlighter = drawingAttributes.IsHighlighter;
|
||||||
|
|
||||||
if (drawingShapeMode != 0 && !isLongPressSelected)
|
if (drawingShapeMode != 0 && !isLongPressSelected)
|
||||||
@@ -2451,6 +2452,8 @@ namespace Ink_Canvas
|
|||||||
forceEraser = false;
|
forceEraser = false;
|
||||||
forcePointEraser = false;
|
forcePointEraser = false;
|
||||||
drawingShapeMode = 0;
|
drawingShapeMode = 0;
|
||||||
|
|
||||||
|
EnsureRealtimeStylusPipelineBinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using H.NotifyIcon;
|
using H.NotifyIcon;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using Ink_Canvas.Windows.SettingsViews.Helpers;
|
using Ink_Canvas.Windows.SettingsViews.Helpers;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -517,6 +517,8 @@ namespace Ink_Canvas
|
|||||||
else
|
else
|
||||||
ComboBoxPenStyle.SelectedIndex = uiIndex;
|
ComboBoxPenStyle.SelectedIndex = uiIndex;
|
||||||
|
|
||||||
|
EnsureRealtimeStylusPipelineBinding();
|
||||||
|
|
||||||
SaveSettingsToFile();
|
SaveSettingsToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -721,6 +723,7 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
Settings.Gesture.IsEnableMultiTouchMode = ToggleSwitchEnableMultiTouchMode.IsOn;
|
Settings.Gesture.IsEnableMultiTouchMode = ToggleSwitchEnableMultiTouchMode.IsOn;
|
||||||
|
EnsureRealtimeStylusPipelineBinding();
|
||||||
|
|
||||||
// 如果启用多指书写模式,强制禁用所有双指手势
|
// 如果启用多指书写模式,强制禁用所有双指手势
|
||||||
if (ToggleSwitchEnableMultiTouchMode.IsOn)
|
if (ToggleSwitchEnableMultiTouchMode.IsOn)
|
||||||
|
|||||||
@@ -2489,6 +2489,7 @@ namespace Ink_Canvas
|
|||||||
/// 用于标识鼠标是否处于按下状态,在绘制过程中使用
|
/// 用于标识鼠标是否处于按下状态,在绘制过程中使用
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private bool isMouseDown;
|
private bool isMouseDown;
|
||||||
|
private bool _isMouseRealtimeInking;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触摸按下状态标志
|
/// 触摸按下状态标志
|
||||||
@@ -2512,6 +2513,17 @@ namespace Ink_Canvas
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void inkCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
private void inkCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (e.ChangedButton == MouseButton.Left && ShouldUseRealtimeVelocityBrushTip() && drawingShapeMode == 0)
|
||||||
|
{
|
||||||
|
_isMouseRealtimeInking = true;
|
||||||
|
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
|
var p = e.GetPosition(inkCanvas);
|
||||||
|
InitializeRealtimeBrushTipStateFromPoint(MouseRealtimeStrokeId, p);
|
||||||
|
var sv = GetStrokeVisual(MouseRealtimeStrokeId);
|
||||||
|
TryAppendRealtimeVelocityBrushTipPoint(sv, MouseRealtimeStrokeId, p);
|
||||||
|
sv.ForceRedraw();
|
||||||
|
}
|
||||||
|
|
||||||
inkCanvas.CaptureMouse();
|
inkCanvas.CaptureMouse();
|
||||||
ViewboxFloatingBar.IsHitTestVisible = false;
|
ViewboxFloatingBar.IsHitTestVisible = false;
|
||||||
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
|
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
|
||||||
@@ -2532,7 +2544,24 @@ namespace Ink_Canvas
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void inkCanvas_MouseMove(object sender, MouseEventArgs e)
|
private void inkCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (isMouseDown) MouseTouchMove(e.GetPosition(inkCanvas));
|
if (_isMouseRealtimeInking && isMouseDown)
|
||||||
|
{
|
||||||
|
var sv = GetStrokeVisual(MouseRealtimeStrokeId);
|
||||||
|
var handled = TryAppendRealtimeVelocityBrushTipPoint(sv, MouseRealtimeStrokeId, e.GetPosition(inkCanvas));
|
||||||
|
if (handled)
|
||||||
|
{
|
||||||
|
sv.ForceRedraw();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isMouseRealtimeInking = false;
|
||||||
|
MouseTouchMove(e.GetPosition(inkCanvas));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isMouseDown)
|
||||||
|
{
|
||||||
|
MouseTouchMove(e.GetPosition(inkCanvas));
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings.Canvas.IsShowCursor)
|
if (Settings.Canvas.IsShowCursor)
|
||||||
{
|
{
|
||||||
@@ -2560,6 +2589,39 @@ namespace Ink_Canvas
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void inkCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
private void inkCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_isMouseRealtimeInking)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sv = GetStrokeVisual(MouseRealtimeStrokeId);
|
||||||
|
sv?.ForceRedraw();
|
||||||
|
var stroke = sv?.Stroke;
|
||||||
|
if (stroke != null)
|
||||||
|
{
|
||||||
|
if (stroke.DrawingAttributes != null) stroke.DrawingAttributes.IgnorePressure = false;
|
||||||
|
if (!stroke.ContainsPropertyData(RealtimeVelocityBrushTipAppliedGuid))
|
||||||
|
stroke.AddPropertyData(RealtimeVelocityBrushTipAppliedGuid, true);
|
||||||
|
inkCanvas.Strokes.Add(stroke);
|
||||||
|
inkCanvas_StrokeCollected(inkCanvas, new InkCanvasStrokeCollectedEventArgs(stroke));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VisualCanvasList.TryGetValue(MouseRealtimeStrokeId, out var visualCanvas) && inkCanvas.Children.Contains(visualCanvas))
|
||||||
|
inkCanvas.Children.Remove(visualCanvas);
|
||||||
|
StrokeVisualList.Remove(MouseRealtimeStrokeId);
|
||||||
|
VisualCanvasList.Remove(MouseRealtimeStrokeId);
|
||||||
|
TouchDownPointsList.Remove(MouseRealtimeStrokeId);
|
||||||
|
CleanupRealtimeBrushTipState(MouseRealtimeStrokeId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isMouseRealtimeInking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HandleEraserOperationEnded();
|
HandleEraserOperationEnded();
|
||||||
inkCanvas.ReleaseMouseCapture();
|
inkCanvas.ReleaseMouseCapture();
|
||||||
ViewboxFloatingBar.IsHitTestVisible = true;
|
ViewboxFloatingBar.IsHitTestVisible = true;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Ink_Canvas
|
|||||||
private InkCanvasEditingMode palmEraserPreviousEditingMode = InkCanvasEditingMode.Ink;
|
private InkCanvasEditingMode palmEraserPreviousEditingMode = InkCanvasEditingMode.Ink;
|
||||||
private readonly Dictionary<int, RealtimeBrushTipState> _realtimeBrushTipStates = new Dictionary<int, RealtimeBrushTipState>();
|
private readonly Dictionary<int, RealtimeBrushTipState> _realtimeBrushTipStates = new Dictionary<int, RealtimeBrushTipState>();
|
||||||
private readonly Guid RealtimeVelocityBrushTipAppliedGuid = new Guid("74E57D95-945F-4A8C-B52A-7D3EF2D4FD5B");
|
private readonly Guid RealtimeVelocityBrushTipAppliedGuid = new Guid("74E57D95-945F-4A8C-B52A-7D3EF2D4FD5B");
|
||||||
|
internal const int MouseRealtimeStrokeId = -100001;
|
||||||
private sealed class OneEuroFilter
|
private sealed class OneEuroFilter
|
||||||
{
|
{
|
||||||
private readonly float _minCutoff;
|
private readonly float _minCutoff;
|
||||||
@@ -102,6 +102,7 @@ namespace Ink_Canvas
|
|||||||
public float LastRawY { get; set; }
|
public float LastRawY { get; set; }
|
||||||
public long LastTimestampMs { get; set; }
|
public long LastTimestampMs { get; set; }
|
||||||
public float SmoothedSampleRateHz { get; set; } = 120f;
|
public float SmoothedSampleRateHz { get; set; } = 120f;
|
||||||
|
public bool SawPressureVariation { get; set; }
|
||||||
public bool HasSeed { get; set; }
|
public bool HasSeed { get; set; }
|
||||||
public float LastSmoothX { get; set; }
|
public float LastSmoothX { get; set; }
|
||||||
public float LastSmoothY { get; set; }
|
public float LastSmoothY { get; set; }
|
||||||
@@ -120,12 +121,44 @@ namespace Ink_Canvas
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static float WidthToPressure(float width, float baseWidth)
|
||||||
|
{
|
||||||
|
if (baseWidth <= 1e-4f) return 0.5f;
|
||||||
|
var scale = width / baseWidth;
|
||||||
|
return RealtimeClamp((scale - 0.42f) / 1.16f, 0.08f, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
private bool ShouldUseRealtimeVelocityBrushTip()
|
private bool ShouldUseRealtimeVelocityBrushTip()
|
||||||
{
|
{
|
||||||
return Settings.Canvas.InkStyle == 3
|
return Settings.Canvas.InkStyle == 3
|
||||||
&& Settings.Canvas.VelocityBrushTipMix > 0
|
&& Settings.Canvas.VelocityBrushTipMix > 0
|
||||||
&& !Settings.Canvas.DisablePressure
|
&& !Settings.Canvas.DisablePressure;
|
||||||
&& penType == 0;
|
}
|
||||||
|
|
||||||
|
internal void EnsureRealtimeStylusPipelineBinding()
|
||||||
|
{
|
||||||
|
if (inkCanvas == null) return;
|
||||||
|
|
||||||
|
inkCanvas.StylusDown -= MainWindow_StylusDown;
|
||||||
|
inkCanvas.StylusMove -= MainWindow_StylusMove;
|
||||||
|
inkCanvas.StylusUp -= MainWindow_StylusUp;
|
||||||
|
|
||||||
|
inkCanvas.StylusDown += MainWindow_StylusDown;
|
||||||
|
inkCanvas.StylusMove += MainWindow_StylusMove;
|
||||||
|
inkCanvas.StylusUp += MainWindow_StylusUp;
|
||||||
|
|
||||||
|
if (ShouldUseRealtimeVelocityBrushTip()
|
||||||
|
&& inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint
|
||||||
|
&& inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke
|
||||||
|
&& inkCanvas.EditingMode != InkCanvasEditingMode.Select)
|
||||||
|
{
|
||||||
|
inkCanvas.EditingMode = InkCanvasEditingMode.None;
|
||||||
|
}
|
||||||
|
else if (!ShouldUseRealtimeVelocityBrushTip()
|
||||||
|
&& inkCanvas.EditingMode == InkCanvasEditingMode.None)
|
||||||
|
{
|
||||||
|
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeRealtimeBrushTipState(int stylusId, StylusDownEventArgs e)
|
private void InitializeRealtimeBrushTipState(int stylusId, StylusDownEventArgs e)
|
||||||
@@ -145,6 +178,22 @@ namespace Ink_Canvas
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeRealtimeBrushTipStateFromPoint(int strokeId, Point startPoint)
|
||||||
|
{
|
||||||
|
if (!ShouldUseRealtimeVelocityBrushTip())
|
||||||
|
{
|
||||||
|
_realtimeBrushTipStates.Remove(strokeId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_realtimeBrushTipStates[strokeId] = new RealtimeBrushTipState
|
||||||
|
{
|
||||||
|
LastRawX = (float)startPoint.X,
|
||||||
|
LastRawY = (float)startPoint.Y,
|
||||||
|
LastTimestampMs = RealtimeNowMs()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void CleanupRealtimeBrushTipState(int stylusId)
|
private void CleanupRealtimeBrushTipState(int stylusId)
|
||||||
{
|
{
|
||||||
_realtimeBrushTipStates.Remove(stylusId);
|
_realtimeBrushTipStates.Remove(stylusId);
|
||||||
@@ -164,6 +213,8 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
var mix = RealtimeClamp((float)Settings.Canvas.VelocityBrushTipMix, 0f, 1f);
|
var mix = RealtimeClamp((float)Settings.Canvas.VelocityBrushTipMix, 0f, 1f);
|
||||||
var appended = false;
|
var appended = false;
|
||||||
|
var baseWidth = (float)Math.Max(0.35,
|
||||||
|
strokeVisual.Stroke?.DrawingAttributes?.Width ?? inkCanvas.DefaultDrawingAttributes.Width);
|
||||||
|
|
||||||
foreach (StylusPoint rawPoint in stylusPointCollection)
|
foreach (StylusPoint rawPoint in stylusPointCollection)
|
||||||
{
|
{
|
||||||
@@ -183,15 +234,24 @@ namespace Ink_Canvas
|
|||||||
var filteredX = state.FilterX.Filter(rawX, dt, speed);
|
var filteredX = state.FilterX.Filter(rawX, dt, speed);
|
||||||
var filteredY = state.FilterY.Filter(rawY, dt, speed);
|
var filteredY = state.FilterY.Filter(rawY, dt, speed);
|
||||||
|
|
||||||
var speedPressure = RealtimeBrushTipMixRatePressureFromSpeed(GetPointSpeed(
|
var hwPressure = RealtimeClamp((float)rawPoint.PressureFactor, 0f, 1f);
|
||||||
new Point(state.LastRawX, state.LastRawY),
|
if (Math.Abs(hwPressure - 0.5f) > 0.02f)
|
||||||
new Point(rawX, rawY),
|
state.SawPressureVariation = true;
|
||||||
new Point(filteredX, filteredY)));
|
var usePressure = state.SawPressureVariation && hwPressure > 0f;
|
||||||
var pressure = (1f - mix) * (float)rawPoint.PressureFactor + mix * speedPressure;
|
|
||||||
|
var width = baseWidth;
|
||||||
|
if (usePressure)
|
||||||
|
width *= 0.25f + 0.75f * hwPressure;
|
||||||
|
var speedNormalization = 1800f + state.SmoothedSampleRateHz * 3.5f;
|
||||||
|
width *= RealtimeClamp(1.15f - (speed / speedNormalization), 0.45f, 1.25f);
|
||||||
|
var speedPressure = WidthToPressure(width, baseWidth);
|
||||||
|
|
||||||
|
var pressure = usePressure
|
||||||
|
? ((1f - mix) * hwPressure + mix * speedPressure)
|
||||||
|
: speedPressure;
|
||||||
pressure = RealtimeClamp(pressure, 0.08f, 1f);
|
pressure = RealtimeClamp(pressure, 0.08f, 1f);
|
||||||
pressure = state.FilterPressure.Filter(pressure, dt, speed);
|
pressure = state.FilterPressure.Filter(pressure, dt, speed);
|
||||||
|
|
||||||
// 高频采样时做最小距离门限,避免点爆炸导致实时重绘卡顿
|
|
||||||
var minDist = state.SmoothedSampleRateHz > 160f ? 0.55f
|
var minDist = state.SmoothedSampleRateHz > 160f ? 0.55f
|
||||||
: state.SmoothedSampleRateHz > 90f ? 0.4f
|
: state.SmoothedSampleRateHz > 90f ? 0.4f
|
||||||
: 0.25f;
|
: 0.25f;
|
||||||
@@ -213,7 +273,6 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 采用中点链减抖:保持实时笔锋同时降低折线锯齿
|
|
||||||
var midX = (state.LastSmoothX + filteredX) * 0.5f;
|
var midX = (state.LastSmoothX + filteredX) * 0.5f;
|
||||||
var midY = (state.LastSmoothY + filteredY) * 0.5f;
|
var midY = (state.LastSmoothY + filteredY) * 0.5f;
|
||||||
var midPressure = (state.LastSmoothPressure + pressure) * 0.5f;
|
var midPressure = (state.LastSmoothPressure + pressure) * 0.5f;
|
||||||
@@ -241,6 +300,86 @@ namespace Ink_Canvas
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryAppendRealtimeVelocityBrushTipPoint(StrokeVisual strokeVisual, int strokeId, Point point, float rawPressure = 0.5f)
|
||||||
|
{
|
||||||
|
if (!ShouldUseRealtimeVelocityBrushTip() || strokeVisual == null)
|
||||||
|
return false;
|
||||||
|
if (!_realtimeBrushTipStates.TryGetValue(strokeId, out var state))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var mix = RealtimeClamp((float)Settings.Canvas.VelocityBrushTipMix, 0f, 1f);
|
||||||
|
var nowMs = RealtimeNowMs();
|
||||||
|
var dtMs = Math.Max(1L, nowMs - state.LastTimestampMs);
|
||||||
|
var dt = dtMs / 1000f;
|
||||||
|
var sampleRate = 1f / Math.Max(1e-4f, dt);
|
||||||
|
state.SmoothedSampleRateHz = state.SmoothedSampleRateHz * 0.85f + sampleRate * 0.15f;
|
||||||
|
var baseWidth = (float)Math.Max(0.35,
|
||||||
|
strokeVisual.Stroke?.DrawingAttributes?.Width ?? inkCanvas.DefaultDrawingAttributes.Width);
|
||||||
|
|
||||||
|
var rawX = (float)point.X;
|
||||||
|
var rawY = (float)point.Y;
|
||||||
|
var dx = rawX - state.LastRawX;
|
||||||
|
var dy = rawY - state.LastRawY;
|
||||||
|
var dist = (float)Math.Sqrt(dx * dx + dy * dy);
|
||||||
|
var speed = dist / dt;
|
||||||
|
|
||||||
|
var filteredX = state.FilterX.Filter(rawX, dt, speed);
|
||||||
|
var filteredY = state.FilterY.Filter(rawY, dt, speed);
|
||||||
|
|
||||||
|
rawPressure = RealtimeClamp(rawPressure, 0f, 1f);
|
||||||
|
if (Math.Abs(rawPressure - 0.5f) > 0.02f)
|
||||||
|
state.SawPressureVariation = true;
|
||||||
|
var usePressure = state.SawPressureVariation && rawPressure > 0f;
|
||||||
|
|
||||||
|
var width = baseWidth;
|
||||||
|
if (usePressure)
|
||||||
|
width *= 0.25f + 0.75f * rawPressure;
|
||||||
|
var speedNormalization = 1800f + state.SmoothedSampleRateHz * 3.5f;
|
||||||
|
width *= RealtimeClamp(1.15f - (speed / speedNormalization), 0.45f, 1.25f);
|
||||||
|
var speedPressure = WidthToPressure(width, baseWidth);
|
||||||
|
|
||||||
|
var pressure = usePressure
|
||||||
|
? ((1f - mix) * rawPressure + mix * speedPressure)
|
||||||
|
: speedPressure;
|
||||||
|
pressure = RealtimeClamp(pressure, 0.08f, 1f);
|
||||||
|
pressure = state.FilterPressure.Filter(pressure, dt, speed);
|
||||||
|
|
||||||
|
var minDist = state.SmoothedSampleRateHz > 160f ? 0.55f
|
||||||
|
: state.SmoothedSampleRateHz > 90f ? 0.4f
|
||||||
|
: 0.25f;
|
||||||
|
if (dist < minDist && state.HasSeed)
|
||||||
|
{
|
||||||
|
state.LastRawX = rawX;
|
||||||
|
state.LastRawY = rawY;
|
||||||
|
state.LastTimestampMs = nowMs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.HasSeed)
|
||||||
|
{
|
||||||
|
state.HasSeed = true;
|
||||||
|
state.LastSmoothX = filteredX;
|
||||||
|
state.LastSmoothY = filteredY;
|
||||||
|
state.LastSmoothPressure = pressure;
|
||||||
|
strokeVisual.Add(new StylusPoint(filteredX, filteredY, pressure));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var midX = (state.LastSmoothX + filteredX) * 0.5f;
|
||||||
|
var midY = (state.LastSmoothY + filteredY) * 0.5f;
|
||||||
|
var midPressure = (state.LastSmoothPressure + pressure) * 0.5f;
|
||||||
|
strokeVisual.Add(new StylusPoint(midX, midY, midPressure));
|
||||||
|
state.LastSmoothX = filteredX;
|
||||||
|
state.LastSmoothY = filteredY;
|
||||||
|
state.LastSmoothPressure = pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.LastRawX = rawX;
|
||||||
|
state.LastRawY = rawY;
|
||||||
|
state.LastTimestampMs = nowMs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存画布上的非笔画元素(如图片、媒体元素等)
|
/// 保存画布上的非笔画元素(如图片、媒体元素等)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -566,7 +705,9 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke)
|
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke)
|
||||||
{
|
{
|
||||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
inkCanvas.EditingMode = ShouldUseRealtimeVelocityBrushTip()
|
||||||
|
? InkCanvasEditingMode.None
|
||||||
|
: InkCanvasEditingMode.Ink;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -754,7 +895,11 @@ namespace Ink_Canvas
|
|||||||
strokeVisual.Add(new StylusPoint(stylusPoint.X, stylusPoint.Y, stylusPoint.PressureFactor));
|
strokeVisual.Add(new StylusPoint(stylusPoint.X, stylusPoint.Y, stylusPoint.PressureFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
strokeVisual.Redraw();
|
if (isHandledByRealtime)
|
||||||
|
strokeVisual.ForceRedraw();
|
||||||
|
else
|
||||||
|
strokeVisual.Redraw();
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
|
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user