improve:墨迹平滑方案
This commit is contained in:
@@ -33,12 +33,12 @@ namespace Ink_Canvas.Helpers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最小点间距阈值
|
/// 最小点间距阈值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double MinPointDistance { get; set; } = 2.0;
|
public double MinPointDistance { get; set; } = 3.0; // 增加最小间距,减少毛刺
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大点间距阈值
|
/// 最大点间距阈值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double MaxPointDistance { get; set; } = 50.0;
|
public double MaxPointDistance { get; set; } = 30.0; // 减少最大间距,提高平滑度
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对笔画进行高级贝塞尔曲线平滑处理
|
/// 对笔画进行高级贝塞尔曲线平滑处理
|
||||||
@@ -84,7 +84,11 @@ namespace Ink_Canvas.Helpers
|
|||||||
// 添加第一个点
|
// 添加第一个点
|
||||||
filteredPoints.Add(points[0]);
|
filteredPoints.Add(points[0]);
|
||||||
|
|
||||||
for (int i = 1; i < points.Count; i++)
|
// 使用移动平均来减少毛刺
|
||||||
|
var smoothedPoints = new List<StylusPoint>();
|
||||||
|
int windowSize = 3; // 移动平均窗口大小
|
||||||
|
|
||||||
|
for (int i = 0; i < points.Count; i++)
|
||||||
{
|
{
|
||||||
var currentPoint = points[i];
|
var currentPoint = points[i];
|
||||||
var lastPoint = filteredPoints[filteredPoints.Count - 1];
|
var lastPoint = filteredPoints[filteredPoints.Count - 1];
|
||||||
@@ -95,6 +99,25 @@ namespace Ink_Canvas.Helpers
|
|||||||
if (distance < MinPointDistance)
|
if (distance < MinPointDistance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// 应用移动平均平滑
|
||||||
|
if (i >= windowSize - 1)
|
||||||
|
{
|
||||||
|
double avgX = 0, avgY = 0, avgPressure = 0;
|
||||||
|
for (int j = 0; j < windowSize; j++)
|
||||||
|
{
|
||||||
|
var point = points[i - j];
|
||||||
|
avgX += point.X;
|
||||||
|
avgY += point.Y;
|
||||||
|
avgPressure += point.PressureFactor;
|
||||||
|
}
|
||||||
|
avgX /= windowSize;
|
||||||
|
avgY /= windowSize;
|
||||||
|
avgPressure /= windowSize;
|
||||||
|
|
||||||
|
var smoothedPoint = new StylusPoint(avgX, avgY, (float)avgPressure);
|
||||||
|
currentPoint = smoothedPoint;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果距离太远,插入中间点
|
// 如果距离太远,插入中间点
|
||||||
if (distance > MaxPointDistance)
|
if (distance > MaxPointDistance)
|
||||||
{
|
{
|
||||||
@@ -132,8 +155,8 @@ namespace Ink_Canvas.Helpers
|
|||||||
// 第一个点的控制点
|
// 第一个点的控制点
|
||||||
Point nextPoint = points[i + 1].ToPoint();
|
Point nextPoint = points[i + 1].ToPoint();
|
||||||
controlPoint = new Point(
|
controlPoint = new Point(
|
||||||
currentPoint.X + (nextPoint.X - currentPoint.X) * Tension * 0.5,
|
currentPoint.X + (nextPoint.X - currentPoint.X) * Tension * 0.3, // 减少张力,减少毛刺
|
||||||
currentPoint.Y + (nextPoint.Y - currentPoint.Y) * Tension * 0.5
|
currentPoint.Y + (nextPoint.Y - currentPoint.Y) * Tension * 0.3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (i == points.Count - 1)
|
else if (i == points.Count - 1)
|
||||||
@@ -141,8 +164,8 @@ namespace Ink_Canvas.Helpers
|
|||||||
// 最后一个点的控制点
|
// 最后一个点的控制点
|
||||||
Point prevPoint = points[i - 1].ToPoint();
|
Point prevPoint = points[i - 1].ToPoint();
|
||||||
controlPoint = new Point(
|
controlPoint = new Point(
|
||||||
currentPoint.X + (currentPoint.X - prevPoint.X) * Tension * 0.5,
|
currentPoint.X + (currentPoint.X - prevPoint.X) * Tension * 0.3,
|
||||||
currentPoint.Y + (currentPoint.Y - prevPoint.Y) * Tension * 0.5
|
currentPoint.Y + (currentPoint.Y - prevPoint.Y) * Tension * 0.3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -151,14 +174,26 @@ namespace Ink_Canvas.Helpers
|
|||||||
Point prevPoint = points[i - 1].ToPoint();
|
Point prevPoint = points[i - 1].ToPoint();
|
||||||
Point nextPoint = points[i + 1].ToPoint();
|
Point nextPoint = points[i + 1].ToPoint();
|
||||||
|
|
||||||
// 计算切线方向
|
// 计算切线方向,使用更保守的方法
|
||||||
double tangentX = (nextPoint.X - prevPoint.X) * 0.5;
|
double tangentX = (nextPoint.X - prevPoint.X) * 0.3; // 减少切线强度
|
||||||
double tangentY = (nextPoint.Y - prevPoint.Y) * 0.5;
|
double tangentY = (nextPoint.Y - prevPoint.Y) * 0.3;
|
||||||
|
|
||||||
|
// 应用张力参数,但限制最大偏移
|
||||||
|
double maxOffset = 10.0; // 限制控制点最大偏移距离
|
||||||
|
double offsetX = tangentX * Tension;
|
||||||
|
double offsetY = tangentY * Tension;
|
||||||
|
|
||||||
|
// 限制偏移距离
|
||||||
|
double offsetDistance = Math.Sqrt(offsetX * offsetX + offsetY * offsetY);
|
||||||
|
if (offsetDistance > maxOffset)
|
||||||
|
{
|
||||||
|
offsetX = offsetX * maxOffset / offsetDistance;
|
||||||
|
offsetY = offsetY * maxOffset / offsetDistance;
|
||||||
|
}
|
||||||
|
|
||||||
// 应用张力参数
|
|
||||||
controlPoint = new Point(
|
controlPoint = new Point(
|
||||||
currentPoint.X + tangentX * Tension,
|
currentPoint.X + offsetX,
|
||||||
currentPoint.Y + tangentY * Tension
|
currentPoint.Y + offsetY
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,9 +220,9 @@ namespace Ink_Canvas.Helpers
|
|||||||
var startControl = controlPoints[i];
|
var startControl = controlPoints[i];
|
||||||
var endControl = controlPoints[i + 1];
|
var endControl = controlPoints[i + 1];
|
||||||
|
|
||||||
// 计算自适应步长
|
// 计算自适应步长,减少步数以避免毛刺
|
||||||
double distance = GetDistance(startPoint.ToPoint(), endPoint.ToPoint());
|
double distance = GetDistance(startPoint.ToPoint(), endPoint.ToPoint());
|
||||||
int steps = Math.Max(3, Math.Min(20, (int)(distance / 5.0)));
|
int steps = Math.Max(2, Math.Min(15, (int)(distance / 8.0))); // 减少步数,增加步长
|
||||||
|
|
||||||
// 生成贝塞尔曲线点
|
// 生成贝塞尔曲线点
|
||||||
for (int j = 0; j <= steps; j++)
|
for (int j = 0; j <= steps; j++)
|
||||||
@@ -195,9 +230,16 @@ namespace Ink_Canvas.Helpers
|
|||||||
double t = (double)j / steps;
|
double t = (double)j / steps;
|
||||||
var curvePoint = CalculateBezierPoint(startPoint.ToPoint(), startControl, endControl, endPoint.ToPoint(), t);
|
var curvePoint = CalculateBezierPoint(startPoint.ToPoint(), startControl, endControl, endPoint.ToPoint(), t);
|
||||||
|
|
||||||
// 插值压感值
|
// 插值压感值,使用更平滑的插值
|
||||||
float pressure = InterpolatePressure(startPoint.PressureFactor, endPoint.PressureFactor, t);
|
float pressure = InterpolatePressure(startPoint.PressureFactor, endPoint.PressureFactor, t);
|
||||||
|
|
||||||
|
// 对压感值进行额外的平滑处理
|
||||||
|
if (j > 0 && j < steps)
|
||||||
|
{
|
||||||
|
float prevPressure = curvePoints[curvePoints.Count - 1].PressureFactor;
|
||||||
|
pressure = (prevPressure + pressure) * 0.5f; // 简单的移动平均
|
||||||
|
}
|
||||||
|
|
||||||
var stylusPoint = new StylusPoint(curvePoint.X, curvePoint.Y, pressure);
|
var stylusPoint = new StylusPoint(curvePoint.X, curvePoint.Y, pressure);
|
||||||
curvePoints.Add(stylusPoint);
|
curvePoints.Add(stylusPoint);
|
||||||
}
|
}
|
||||||
@@ -249,7 +291,18 @@ namespace Ink_Canvas.Helpers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private float InterpolatePressure(float p1, float p2, double ratio)
|
private float InterpolatePressure(float p1, float p2, double ratio)
|
||||||
{
|
{
|
||||||
return (float)(p1 + (p2 - p1) * ratio);
|
// 使用平滑的插值函数来减少毛刺
|
||||||
|
double smoothRatio = SmoothStep(ratio);
|
||||||
|
return (float)(p1 + (p2 - p1) * smoothRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 平滑步进函数,用于减少插值时的毛刺
|
||||||
|
/// </summary>
|
||||||
|
private double SmoothStep(double t)
|
||||||
|
{
|
||||||
|
// 使用三次平滑函数
|
||||||
|
return t * t * (3.0 - 2.0 * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -799,7 +799,7 @@
|
|||||||
<TextBlock Foreground="#fafafa" Text="平滑强度" VerticalAlignment="Center"
|
<TextBlock Foreground="#fafafa" Text="平滑强度" VerticalAlignment="Center"
|
||||||
FontSize="14" Margin="0,0,16,0" />
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
<Slider Name="AdvancedSmoothingStrengthSlider" Width="150" Minimum="0.1" Maximum="1.0"
|
<Slider Name="AdvancedSmoothingStrengthSlider" Width="150" Minimum="0.1" Maximum="1.0"
|
||||||
Value="0.6" TickFrequency="0.1" IsSnapToTickEnabled="True"
|
Value="0.4" TickFrequency="0.1" IsSnapToTickEnabled="True"
|
||||||
ValueChanged="AdvancedSmoothingStrengthSlider_ValueChanged" />
|
ValueChanged="AdvancedSmoothingStrengthSlider_ValueChanged" />
|
||||||
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=AdvancedSmoothingStrengthSlider, Path=Value, StringFormat={}{0:F1}}"
|
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=AdvancedSmoothingStrengthSlider, Path=Value, StringFormat={}{0:F1}}"
|
||||||
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
||||||
@@ -809,7 +809,7 @@
|
|||||||
<TextBlock Foreground="#fafafa" Text="张力参数" VerticalAlignment="Center"
|
<TextBlock Foreground="#fafafa" Text="张力参数" VerticalAlignment="Center"
|
||||||
FontSize="14" Margin="0,0,16,0" />
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
<Slider Name="AdvancedSmoothingTensionSlider" Width="150" Minimum="0.1" Maximum="1.0"
|
<Slider Name="AdvancedSmoothingTensionSlider" Width="150" Minimum="0.1" Maximum="1.0"
|
||||||
Value="0.5" TickFrequency="0.1" IsSnapToTickEnabled="True"
|
Value="0.3" TickFrequency="0.1" IsSnapToTickEnabled="True"
|
||||||
ValueChanged="AdvancedSmoothingTensionSlider_ValueChanged" />
|
ValueChanged="AdvancedSmoothingTensionSlider_ValueChanged" />
|
||||||
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=AdvancedSmoothingTensionSlider, Path=Value, StringFormat={}{0:F1}}"
|
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=AdvancedSmoothingTensionSlider, Path=Value, StringFormat={}{0:F1}}"
|
||||||
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
|
||||||
@@ -822,7 +822,7 @@
|
|||||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||||
Toggled="ToggleSwitchEnableAdaptiveSmoothing_Toggled" />
|
Toggled="ToggleSwitchEnableAdaptiveSmoothing_Toggled" />
|
||||||
</ui:SimpleStackPanel>
|
</ui:SimpleStackPanel>
|
||||||
<TextBlock Text="# 高级贝塞尔曲线平滑(推荐):使用自定义算法替代系统默认的FitToCurve,提供更平滑的笔迹效果并解决墨迹闪烁问题。启用高级平滑时会自动禁用系统默认平滑。平滑强度控制平滑程度,张力参数控制曲线的紧绷程度,自适应平滑会根据笔迹速度自动调整平滑参数。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
<TextBlock Text="# 高级贝塞尔曲线平滑(推荐):使用自定义算法替代系统默认的FitToCurve,提供更平滑的笔迹效果并解决墨迹闪烁和毛刺问题。启用高级平滑时会自动禁用系统默认平滑。平滑强度控制平滑程度(较低值减少毛刺),张力参数控制曲线的紧绷程度(较低值减少毛刺),自适应平滑会根据笔迹速度自动调整平滑参数。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||||
</ui:SimpleStackPanel>
|
</ui:SimpleStackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
<!-- 新增:崩溃后操作设置 -->
|
<!-- 新增:崩溃后操作设置 -->
|
||||||
|
|||||||
@@ -1631,8 +1631,8 @@ namespace Ink_Canvas {
|
|||||||
Settings.Canvas.ClearCanvasAndClearTimeMachine = false;
|
Settings.Canvas.ClearCanvasAndClearTimeMachine = false;
|
||||||
Settings.Canvas.FitToCurve = false;
|
Settings.Canvas.FitToCurve = false;
|
||||||
Settings.Canvas.UseAdvancedBezierSmoothing = true;
|
Settings.Canvas.UseAdvancedBezierSmoothing = true;
|
||||||
Settings.Canvas.AdvancedSmoothingStrength = 0.6;
|
Settings.Canvas.AdvancedSmoothingStrength = 0.4;
|
||||||
Settings.Canvas.AdvancedSmoothingTension = 0.5;
|
Settings.Canvas.AdvancedSmoothingTension = 0.3;
|
||||||
Settings.Canvas.EnableAdaptiveSmoothing = true;
|
Settings.Canvas.EnableAdaptiveSmoothing = true;
|
||||||
Settings.Canvas.EnablePressureTouchMode = false;
|
Settings.Canvas.EnablePressureTouchMode = false;
|
||||||
Settings.Canvas.DisablePressure = false;
|
Settings.Canvas.DisablePressure = false;
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ namespace Ink_Canvas
|
|||||||
[JsonProperty("useAdvancedBezierSmoothing")]
|
[JsonProperty("useAdvancedBezierSmoothing")]
|
||||||
public bool UseAdvancedBezierSmoothing { get; set; } = true; // 默认启用高级贝塞尔曲线平滑
|
public bool UseAdvancedBezierSmoothing { get; set; } = true; // 默认启用高级贝塞尔曲线平滑
|
||||||
[JsonProperty("advancedSmoothingStrength")]
|
[JsonProperty("advancedSmoothingStrength")]
|
||||||
public double AdvancedSmoothingStrength { get; set; } = 0.6; // 高级平滑强度 (0.0 - 1.0)
|
public double AdvancedSmoothingStrength { get; set; } = 0.4; // 高级平滑强度 (0.0 - 1.0),降低以减少毛刺
|
||||||
[JsonProperty("advancedSmoothingTension")]
|
[JsonProperty("advancedSmoothingTension")]
|
||||||
public double AdvancedSmoothingTension { get; set; } = 0.5; // 高级平滑张力 (0.0 - 1.0)
|
public double AdvancedSmoothingTension { get; set; } = 0.3; // 高级平滑张力 (0.0 - 1.0),降低以减少毛刺
|
||||||
[JsonProperty("enableAdaptiveSmoothing")]
|
[JsonProperty("enableAdaptiveSmoothing")]
|
||||||
public bool EnableAdaptiveSmoothing { get; set; } = true; // 是否启用自适应平滑
|
public bool EnableAdaptiveSmoothing { get; set; } = true; // 是否启用自适应平滑
|
||||||
[JsonProperty("clearCanvasAndClearTimeMachine")]
|
[JsonProperty("clearCanvasAndClearTimeMachine")]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ TRACE;DEBUG;NETFRAMEWORK;NET472;;NET30_OR_GREATER;NET35_OR_GREATER;NET40_OR_GREA
|
|||||||
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
|
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
|
||||||
21348134359
|
21348134359
|
||||||
|
|
||||||
731095817143
|
74373288771
|
||||||
471037513499
|
471037513499
|
||||||
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;
|
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user