improve:墨迹平滑方案

This commit is contained in:
2025-07-20 15:57:51 +08:00
parent 09f17caabe
commit 62d35127b1
7 changed files with 446 additions and 54 deletions
+349 -33
View File
@@ -40,6 +40,21 @@ namespace Ink_Canvas.Helpers
/// </summary>
public double MaxPointDistance { get; set; } = 30.0; // 减少最大间距,提高平滑度
/// <summary>
/// 手抖修正强度 (0.0 - 1.0)
/// </summary>
public double ShakeCorrectionStrength { get; set; } = 0.6;
/// <summary>
/// 速度加权平滑强度 (0.0 - 1.0)
/// </summary>
public double VelocityWeightedSmoothingStrength { get; set; } = 0.7;
/// <summary>
/// 时间加权平滑强度 (0.0 - 1.0)
/// </summary>
public double TimeWeightedSmoothingStrength { get; set; } = 0.5;
/// <summary>
/// 对笔画进行高级贝塞尔曲线平滑处理
/// </summary>
@@ -53,18 +68,35 @@ namespace Ink_Canvas.Helpers
var originalPoints = stroke.StylusPoints.ToList();
var smoothedPoints = new List<StylusPoint>();
// 第一步:点过滤和重采样
var filteredPoints = FilterAndResamplePoints(originalPoints);
// 检查采样率,如果点太少则使用不同的处理策略
bool isLowSamplingRate = originalPoints.Count < 10; // 少于10个点认为是低采样率
// 第二步:计算控制点
if (isLowSamplingRate)
{
// 低采样率情况下的特殊处理
return HandleLowSamplingRateStroke(stroke);
}
// 第一步:手抖修正
var shakeCorrectedPoints = ApplyShakeCorrection(originalPoints);
// 第二步:基于速度和时间的加权平滑
var velocityTimeWeightedPoints = ApplyVelocityTimeWeightedSmoothing(shakeCorrectedPoints);
// 第三步:点过滤和重采样
var filteredPoints = FilterAndResamplePoints(velocityTimeWeightedPoints);
// 第四步:计算控制点
var controlPoints = CalculateControlPoints(filteredPoints);
// 第步:生成平滑曲线点
// 第步:生成平滑曲线点
var curvePoints = GenerateCurvePoints(filteredPoints, controlPoints);
// 第步:创建新的笔画
var newStylusPoints = new StylusPointCollection(curvePoints);
var smoothedStroke = new Stroke(newStylusPoints)
// 第步:修正收尾相连问题
var fixedStylusPoints = FixEndToEndConnection(new StylusPointCollection(curvePoints));
// 第七步:创建新的笔画
var smoothedStroke = new Stroke(fixedStylusPoints)
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
@@ -72,6 +104,39 @@ namespace Ink_Canvas.Helpers
return smoothedStroke;
}
/// <summary>
/// 检测并修正收尾相连问题
/// </summary>
private StylusPointCollection FixEndToEndConnection(StylusPointCollection points)
{
if (points.Count < 3) return points;
var resultPoints = new StylusPointCollection();
// 复制所有点
foreach (var point in points)
{
resultPoints.Add(point);
}
// 检查首尾是否过于接近
var firstPoint = resultPoints[0];
var lastPoint = resultPoints[resultPoints.Count - 1];
double endToEndDistance = GetDistance(firstPoint.ToPoint(), lastPoint.ToPoint());
// 如果首尾距离太近,可能是收尾相连问题
if (endToEndDistance < 5.0)
{
// 移除最后一个点,避免收尾相连
if (resultPoints.Count > 1)
{
resultPoints.RemoveAt(resultPoints.Count - 1);
}
}
return resultPoints;
}
/// <summary>
/// 过滤和重采样点
/// </summary>
@@ -145,6 +210,11 @@ namespace Ink_Canvas.Helpers
if (points.Count < 2) return controlPoints;
// 检查点密度,如果点太稀疏则使用更保守的控制点计算
bool isSparsePoints = points.Count < 5;
double tensionMultiplier = isSparsePoints ? 0.1 : 0.3; // 稀疏点时使用更小的张力
double maxOffset = isSparsePoints ? 5.0 : 10.0; // 稀疏点时使用更小的最大偏移
for (int i = 0; i < points.Count; i++)
{
Point currentPoint = points[i].ToPoint();
@@ -154,19 +224,39 @@ namespace Ink_Canvas.Helpers
{
// 第一个点的控制点
Point nextPoint = points[i + 1].ToPoint();
controlPoint = new Point(
currentPoint.X + (nextPoint.X - currentPoint.X) * Tension * 0.3, // 减少张力,减少毛刺
currentPoint.Y + (nextPoint.Y - currentPoint.Y) * Tension * 0.3
);
double distance = GetDistance(currentPoint, nextPoint);
// 如果距离太远,使用更保守的控制点
if (distance > 50.0)
{
controlPoint = currentPoint; // 直接使用当前点作为控制点
}
else
{
controlPoint = new Point(
currentPoint.X + (nextPoint.X - currentPoint.X) * Tension * tensionMultiplier,
currentPoint.Y + (nextPoint.Y - currentPoint.Y) * Tension * tensionMultiplier
);
}
}
else if (i == points.Count - 1)
{
// 最后一个点的控制点
Point prevPoint = points[i - 1].ToPoint();
controlPoint = new Point(
currentPoint.X + (currentPoint.X - prevPoint.X) * Tension * 0.3,
currentPoint.Y + (currentPoint.Y - prevPoint.Y) * Tension * 0.3
);
double distance = GetDistance(currentPoint, prevPoint);
// 如果距离太远,使用更保守的控制点
if (distance > 50.0)
{
controlPoint = currentPoint; // 直接使用当前点作为控制点
}
else
{
controlPoint = new Point(
currentPoint.X + (currentPoint.X - prevPoint.X) * Tension * tensionMultiplier,
currentPoint.Y + (currentPoint.Y - prevPoint.Y) * Tension * tensionMultiplier
);
}
}
else
{
@@ -174,27 +264,41 @@ namespace Ink_Canvas.Helpers
Point prevPoint = points[i - 1].ToPoint();
Point nextPoint = points[i + 1].ToPoint();
// 计算切线方向,使用更保守的方法
double tangentX = (nextPoint.X - prevPoint.X) * 0.3; // 减少切线强度
double tangentY = (nextPoint.Y - prevPoint.Y) * 0.3;
// 应用张力参数,但限制最大偏移
double maxOffset = 10.0; // 限制控制点最大偏移距离
double offsetX = tangentX * Tension;
double offsetY = tangentY * Tension;
// 检查前后点的距离,如果太远则使用更保守的方法
double prevDistance = GetDistance(currentPoint, prevPoint);
double nextDistance = GetDistance(currentPoint, nextPoint);
// 限制偏移距离
double offsetDistance = Math.Sqrt(offsetX * offsetX + offsetY * offsetY);
if (offsetDistance > maxOffset)
if (prevDistance > 50.0 || nextDistance > 50.0)
{
offsetX = offsetX * maxOffset / offsetDistance;
offsetY = offsetY * maxOffset / offsetDistance;
// 距离太远,使用线性插值作为控制点
controlPoint = new Point(
(prevPoint.X + nextPoint.X) / 2.0,
(prevPoint.Y + nextPoint.Y) / 2.0
);
}
else
{
// 计算切线方向,使用更保守的方法
double tangentX = (nextPoint.X - prevPoint.X) * tensionMultiplier;
double tangentY = (nextPoint.Y - prevPoint.Y) * tensionMultiplier;
controlPoint = new Point(
currentPoint.X + offsetX,
currentPoint.Y + offsetY
);
// 应用张力参数,但限制最大偏移
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(
currentPoint.X + offsetX,
currentPoint.Y + offsetY
);
}
}
controlPoints.Add(controlPoint);
@@ -222,7 +326,17 @@ namespace Ink_Canvas.Helpers
// 计算自适应步长,减少步数以避免毛刺
double distance = GetDistance(startPoint.ToPoint(), endPoint.ToPoint());
int steps = Math.Max(2, Math.Min(15, (int)(distance / 8.0))); // 减少步数,增加步长
// 根据点密度调整步数
int steps;
if (points.Count < 5) // 低密度点
{
steps = Math.Max(1, Math.Min(3, (int)(distance / 15.0))); // 更少的步数
}
else
{
steps = Math.Max(2, Math.Min(15, (int)(distance / 8.0))); // 正常步数
}
// 生成贝塞尔曲线点
for (int j = 0; j <= steps; j++)
@@ -305,6 +419,208 @@ namespace Ink_Canvas.Helpers
return t * t * (3.0 - 2.0 * t);
}
/// <summary>
/// 应用手抖修正
/// </summary>
private List<StylusPoint> ApplyShakeCorrection(List<StylusPoint> points)
{
if (points.Count < 3) return points;
var correctedPoints = new List<StylusPoint>();
correctedPoints.Add(points[0]); // 添加第一个点
for (int i = 1; i < points.Count - 1; i++)
{
var prev = points[i - 1];
var curr = points[i];
var next = points[i + 1];
// 计算当前点的预期位置(基于前后点的线性插值)
double expectedX = (prev.X + next.X) / 2.0;
double expectedY = (prev.Y + next.Y) / 2.0;
// 计算当前点与预期位置的偏差
double deviationX = Math.Abs(curr.X - expectedX);
double deviationY = Math.Abs(curr.Y - expectedY);
double deviation = Math.Sqrt(deviationX * deviationX + deviationY * deviationY);
// 如果偏差超过阈值,认为是手抖
double shakeThreshold = 5.0; // 手抖检测阈值
if (deviation > shakeThreshold)
{
// 应用手抖修正
double correctionFactor = ShakeCorrectionStrength;
double correctedX = curr.X + (expectedX - curr.X) * correctionFactor;
double correctedY = curr.Y + (expectedY - curr.Y) * correctionFactor;
// 保持压感值不变
var correctedPoint = new StylusPoint(correctedX, correctedY, curr.PressureFactor);
correctedPoints.Add(correctedPoint);
}
else
{
correctedPoints.Add(curr);
}
}
correctedPoints.Add(points[points.Count - 1]); // 添加最后一个点
return correctedPoints;
}
/// <summary>
/// 应用基于速度和时间的加权平滑
/// </summary>
private List<StylusPoint> ApplyVelocityTimeWeightedSmoothing(List<StylusPoint> points)
{
if (points.Count < 3) return points;
var smoothedPoints = new List<StylusPoint>();
smoothedPoints.Add(points[0]); // 添加第一个点
// 计算每个点的速度和加速度
var velocities = new List<double>();
var accelerations = new List<double>();
var timeWeights = new List<double>();
for (int i = 1; i < points.Count; i++)
{
var prev = points[i - 1];
var curr = points[i];
// 计算速度(距离/时间,这里假设时间间隔为1)
double velocity = GetDistance(prev.ToPoint(), curr.ToPoint());
velocities.Add(velocity);
// 计算加速度
if (i > 1)
{
double prevVelocity = velocities[velocities.Count - 2];
double acceleration = velocity - prevVelocity;
accelerations.Add(acceleration);
}
// 计算时间权重(基于点的密度)
double timeWeight = 1.0;
if (i > 1)
{
// 如果点过于密集,增加时间权重
double avgDistance = velocity;
if (avgDistance < 2.0)
{
timeWeight = 1.5; // 增加权重
}
else if (avgDistance > 20.0)
{
timeWeight = 0.5; // 减少权重
}
}
timeWeights.Add(timeWeight);
}
// 应用加权平滑
for (int i = 1; i < points.Count - 1; i++)
{
var prev = points[i - 1];
var curr = points[i];
var next = points[i + 1];
// 计算速度权重
double velocityWeight = 1.0;
if (i < velocities.Count)
{
double velocity = velocities[i - 1];
// 速度越快,权重越大(更平滑)
velocityWeight = Math.Min(2.0, velocity / 10.0 + 0.5);
}
// 计算加速度权重
double accelerationWeight = 1.0;
if (i < accelerations.Count)
{
double acceleration = Math.Abs(accelerations[i - 1]);
// 加速度越大,权重越大(更平滑)
accelerationWeight = Math.Min(2.0, acceleration / 5.0 + 0.5);
}
// 获取时间权重
double timeWeight = timeWeights[i];
// 综合权重
double totalWeight = (velocityWeight * VelocityWeightedSmoothingStrength +
accelerationWeight * VelocityWeightedSmoothingStrength +
timeWeight * TimeWeightedSmoothingStrength) / 3.0;
// 应用加权平滑
double smoothedX = curr.X;
double smoothedY = curr.Y;
if (totalWeight > 1.0)
{
// 向相邻点加权平均
double weight = (totalWeight - 1.0) * 0.3; // 限制最大影响
smoothedX = curr.X * (1.0 - weight) + (prev.X + next.X) * 0.5 * weight;
smoothedY = curr.Y * (1.0 - weight) + (prev.Y + next.Y) * 0.5 * weight;
}
var smoothedPoint = new StylusPoint(smoothedX, smoothedY, curr.PressureFactor);
smoothedPoints.Add(smoothedPoint);
}
smoothedPoints.Add(points[points.Count - 1]); // 添加最后一个点
return smoothedPoints;
}
/// <summary>
/// 处理低采样率笔画
/// </summary>
private Stroke HandleLowSamplingRateStroke(Stroke stroke)
{
var points = stroke.StylusPoints.ToList();
var resultPoints = new List<StylusPoint>();
// 对于低采样率,使用简单的线性插值而不是贝塞尔曲线
for (int i = 0; i < points.Count - 1; i++)
{
var currentPoint = points[i];
var nextPoint = points[i + 1];
// 添加当前点
resultPoints.Add(currentPoint);
// 计算两点间距离
double distance = GetDistance(currentPoint.ToPoint(), nextPoint.ToPoint());
// 如果距离太远,插入中间点
if (distance > 20.0) // 低采样率下使用更大的阈值
{
int segments = Math.Max(2, Math.Min(5, (int)(distance / 10.0))); // 限制插值段数
for (int j = 1; j < segments; j++)
{
double ratio = (double)j / segments;
var interpolatedPoint = InterpolatePoint(currentPoint, nextPoint, ratio);
resultPoints.Add(interpolatedPoint);
}
}
}
// 添加最后一个点
resultPoints.Add(points[points.Count - 1]);
// 应用轻微的手抖修正
var shakeCorrectedPoints = ApplyShakeCorrection(resultPoints);
// 修正收尾相连问题
var fixedStylusPoints = FixEndToEndConnection(new StylusPointCollection(shakeCorrectedPoints));
// 创建新的笔画
var smoothedStroke = new Stroke(fixedStylusPoints)
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
return smoothedStroke;
}
/// <summary>
/// 应用自适应平滑
/// </summary>
+32 -2
View File
@@ -782,7 +782,7 @@
Foreground="#a1a1aa" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="使用WPF默认贝塞尔曲线平滑"
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
VerticalAlignment="Center" FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchFitToCurve"
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchFitToCurve_Toggled" />
@@ -822,7 +822,37 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchEnableAdaptiveSmoothing_Toggled" />
</ui:SimpleStackPanel>
<TextBlock Text="# 高级贝塞尔曲线平滑(推荐):使用自定义算法替代系统默认的FitToCurve,提供更平滑的笔迹效果并解决墨迹闪烁和毛刺问题。启用高级平滑时会自动禁用系统默认平滑。平滑强度控制平滑程度(较低值减少毛刺),张力参数控制曲线的紧绷程度(较低值减少毛刺),自适应平滑会根据笔迹速度自动调整平滑参数。" TextWrapping="Wrap" Foreground="#a1a1aa" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
Visibility="{Binding ElementName=ToggleSwitchAdvancedBezierSmoothing, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Foreground="#fafafa" Text="手抖修正强度" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider Name="ShakeCorrectionStrengthSlider" Width="150" Minimum="0.0" Maximum="1.0"
Value="0.6" TickFrequency="0.1" IsSnapToTickEnabled="True"
ValueChanged="ShakeCorrectionStrengthSlider_ValueChanged" />
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=ShakeCorrectionStrengthSlider, Path=Value, StringFormat={}{0:F1}}"
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
Visibility="{Binding ElementName=ToggleSwitchAdvancedBezierSmoothing, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Foreground="#fafafa" Text="速度加权强度" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider Name="VelocityWeightedSmoothingStrengthSlider" Width="150" Minimum="0.0" Maximum="1.0"
Value="0.7" TickFrequency="0.1" IsSnapToTickEnabled="True"
ValueChanged="VelocityWeightedSmoothingStrengthSlider_ValueChanged" />
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=VelocityWeightedSmoothingStrengthSlider, Path=Value, StringFormat={}{0:F1}}"
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
Visibility="{Binding ElementName=ToggleSwitchAdvancedBezierSmoothing, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Foreground="#fafafa" Text="时间加权强度" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<Slider Name="TimeWeightedSmoothingStrengthSlider" Width="150" Minimum="0.0" Maximum="1.0"
Value="0.5" TickFrequency="0.1" IsSnapToTickEnabled="True"
ValueChanged="TimeWeightedSmoothingStrengthSlider_ValueChanged" />
<TextBlock Foreground="#fafafa" Text="{Binding ElementName=TimeWeightedSmoothingStrengthSlider, Path=Value, StringFormat={}{0:F1}}"
VerticalAlignment="Center" FontSize="14" Margin="16,0,0,0" />
</ui:SimpleStackPanel>
<TextBlock Text="# 高级贝塞尔曲线平滑(推荐):使用自定义算法替代系统默认的FitToCurve,提供更平滑的笔迹效果并解决墨迹闪烁、毛刺和低采样率收尾相连问题。启用高级平滑时会自动禁用系统默认平滑。手抖修正可自动检测并修正手抖造成的偏差,速度加权平滑根据笔迹速度调整平滑强度,时间加权平滑根据点密度调整平滑参数,自适应平滑会根据笔迹速度自动调整平滑参数。低采样率时自动使用线性插值避免收尾相连。" TextWrapping="Wrap" Foreground="#a1a1aa" />
</ui:SimpleStackPanel>
</GroupBox>
<!-- 新增:崩溃后操作设置 -->
+21
View File
@@ -1329,6 +1329,24 @@ namespace Ink_Canvas {
SaveSettingsToFile();
}
private void ShakeCorrectionStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
if (!isLoaded) return;
Settings.Canvas.ShakeCorrectionStrength = ShakeCorrectionStrengthSlider.Value;
SaveSettingsToFile();
}
private void VelocityWeightedSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
if (!isLoaded) return;
Settings.Canvas.VelocityWeightedSmoothingStrength = VelocityWeightedSmoothingStrengthSlider.Value;
SaveSettingsToFile();
}
private void TimeWeightedSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
if (!isLoaded) return;
Settings.Canvas.TimeWeightedSmoothingStrength = TimeWeightedSmoothingStrengthSlider.Value;
SaveSettingsToFile();
}
private void ToggleSwitchAutoSaveStrokesInPowerPoint_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
Settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint = ToggleSwitchAutoSaveStrokesInPowerPoint.IsOn;
@@ -1634,6 +1652,9 @@ namespace Ink_Canvas {
Settings.Canvas.AdvancedSmoothingStrength = 0.4;
Settings.Canvas.AdvancedSmoothingTension = 0.3;
Settings.Canvas.EnableAdaptiveSmoothing = true;
Settings.Canvas.ShakeCorrectionStrength = 0.6;
Settings.Canvas.VelocityWeightedSmoothingStrength = 0.7;
Settings.Canvas.TimeWeightedSmoothingStrength = 0.5;
Settings.Canvas.EnablePressureTouchMode = false;
Settings.Canvas.DisablePressure = false;
Settings.Canvas.AutoStraightenLine = true;
@@ -540,6 +540,9 @@ namespace Ink_Canvas {
AdvancedSmoothingStrengthSlider.Value = Settings.Canvas.AdvancedSmoothingStrength;
AdvancedSmoothingTensionSlider.Value = Settings.Canvas.AdvancedSmoothingTension;
ToggleSwitchEnableAdaptiveSmoothing.IsOn = Settings.Canvas.EnableAdaptiveSmoothing;
ShakeCorrectionStrengthSlider.Value = Settings.Canvas.ShakeCorrectionStrength;
VelocityWeightedSmoothingStrengthSlider.Value = Settings.Canvas.VelocityWeightedSmoothingStrength;
TimeWeightedSmoothingStrengthSlider.Value = Settings.Canvas.TimeWeightedSmoothingStrength;
// 初始化直线自动拉直相关设置
ToggleSwitchAutoStraightenLine.IsOn = Settings.Canvas.AutoStraightenLine;
+4 -1
View File
@@ -1599,7 +1599,10 @@ namespace Ink_Canvas {
{
SmoothingStrength = Settings.Canvas.AdvancedSmoothingStrength,
Tension = Settings.Canvas.AdvancedSmoothingTension,
EnableAdaptiveSmoothing = Settings.Canvas.EnableAdaptiveSmoothing
EnableAdaptiveSmoothing = Settings.Canvas.EnableAdaptiveSmoothing,
ShakeCorrectionStrength = Settings.Canvas.ShakeCorrectionStrength,
VelocityWeightedSmoothingStrength = Settings.Canvas.VelocityWeightedSmoothingStrength,
TimeWeightedSmoothingStrength = Settings.Canvas.TimeWeightedSmoothingStrength
};
// 对临时笔画应用平滑
@@ -16,6 +16,9 @@ namespace Ink_Canvas {
private const double LINE_STRAIGHTEN_THRESHOLD = 0.20; // 默认灵敏度阈值,与UI默认值对应
private void inkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e) {
// 标记是否进行了直线拉直
bool wasStraightened = false;
// 禁用原有的FitToCurve,使用新的高级贝塞尔曲线平滑
if (Settings.Canvas.FitToCurve == true) drawingAttributes.FitToCurve = false;
@@ -118,8 +121,9 @@ namespace Ink_Canvas {
}
}
// Apply line straightening and endpoint snapping if ink-to-shape is enabled
if (Settings.InkToShape.IsInkToShapeEnabled) {
// Apply line straightening and endpoint snapping if ink-to-shape is enabled
if (Settings.InkToShape.IsInkToShapeEnabled) {
// 检查是否启用了直线自动拉直功能
if (Settings.Canvas.AutoStraightenLine && IsPotentialStraightLine(e.Stroke)) {
// Get start and end points of the stroke
@@ -169,6 +173,8 @@ namespace Ink_Canvas {
newStrokes.Remove(e.Stroke);
newStrokes.Add(straightStroke);
}
wasStraightened = true; // 标记已进行直线拉直
}
}
}
@@ -573,26 +579,33 @@ namespace Ink_Canvas {
}
catch { }
// 应用高级贝塞尔曲线平滑
if (Settings.Canvas.UseAdvancedBezierSmoothing)
// 应用高级贝塞尔曲线平滑(仅在未进行直线拉直时)
if (Settings.Canvas.UseAdvancedBezierSmoothing && !wasStraightened)
{
try
{
var advancedSmoothing = new Helpers.AdvancedBezierSmoothing
// 检查原始笔画是否仍然存在于画布中
if (inkCanvas.Strokes.Contains(e.Stroke))
{
SmoothingStrength = Settings.Canvas.AdvancedSmoothingStrength,
Tension = Settings.Canvas.AdvancedSmoothingTension,
EnableAdaptiveSmoothing = Settings.Canvas.EnableAdaptiveSmoothing
};
var advancedSmoothing = new Helpers.AdvancedBezierSmoothing
{
SmoothingStrength = Settings.Canvas.AdvancedSmoothingStrength,
Tension = Settings.Canvas.AdvancedSmoothingTension,
EnableAdaptiveSmoothing = Settings.Canvas.EnableAdaptiveSmoothing,
ShakeCorrectionStrength = Settings.Canvas.ShakeCorrectionStrength,
VelocityWeightedSmoothingStrength = Settings.Canvas.VelocityWeightedSmoothingStrength,
TimeWeightedSmoothingStrength = Settings.Canvas.TimeWeightedSmoothingStrength
};
var smoothedStroke = advancedSmoothing.SmoothStroke(e.Stroke);
// 替换原始笔画
SetNewBackupOfStroke();
_currentCommitType = CommitReason.ShapeRecognition;
inkCanvas.Strokes.Remove(e.Stroke);
inkCanvas.Strokes.Add(smoothedStroke);
_currentCommitType = CommitReason.UserInput;
var smoothedStroke = advancedSmoothing.SmoothStroke(e.Stroke);
// 替换原始笔画
SetNewBackupOfStroke();
_currentCommitType = CommitReason.ShapeRecognition;
inkCanvas.Strokes.Remove(e.Stroke);
inkCanvas.Strokes.Add(smoothedStroke);
_currentCommitType = CommitReason.UserInput;
}
}
catch (Exception ex)
{
@@ -600,7 +613,7 @@ namespace Ink_Canvas {
System.Diagnostics.Debug.WriteLine($"高级贝塞尔曲线平滑失败: {ex.Message}");
}
}
else if (Settings.Canvas.FitToCurve == true)
else if (Settings.Canvas.FitToCurve == true && !wasStraightened)
{
drawingAttributes.FitToCurve = true;
}
+6
View File
@@ -56,6 +56,12 @@ namespace Ink_Canvas
public double AdvancedSmoothingTension { get; set; } = 0.3; // 高级平滑张力 (0.0 - 1.0),降低以减少毛刺
[JsonProperty("enableAdaptiveSmoothing")]
public bool EnableAdaptiveSmoothing { get; set; } = true; // 是否启用自适应平滑
[JsonProperty("shakeCorrectionStrength")]
public double ShakeCorrectionStrength { get; set; } = 0.6; // 手抖修正强度 (0.0 - 1.0)
[JsonProperty("velocityWeightedSmoothingStrength")]
public double VelocityWeightedSmoothingStrength { get; set; } = 0.7; // 速度加权平滑强度 (0.0 - 1.0)
[JsonProperty("timeWeightedSmoothingStrength")]
public double TimeWeightedSmoothingStrength { get; set; } = 0.5; // 时间加权平滑强度 (0.0 - 1.0)
[JsonProperty("clearCanvasAndClearTimeMachine")]
public bool ClearCanvasAndClearTimeMachine { get; set; } = false;
[JsonProperty("enablePressureTouchMode")]