From 4a776c1fe8f80b02301973ddfe0a1394c26da17b Mon Sep 17 00:00:00 2001
From: unknown <2564608840@qq.com>
Date: Sun, 20 Jul 2025 19:17:32 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E5=A2=A8=E8=BF=B9=E5=B9=B3=E6=BB=91?=
=?UTF-8?q?=E6=96=B9=E6=A1=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/AdvancedBezierSmoothing.cs | 748 ++----------------
Ink Canvas/MainWindow.xaml | 73 +-
Ink Canvas/MainWindow_cs/MW_Settings.cs | 50 +-
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 7 -
Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs | 8 -
.../MW_SimulatePressure&InkToShape.cs | 8 -
Ink Canvas/Resources/Settings.cs | 16 -
7 files changed, 85 insertions(+), 825 deletions(-)
diff --git a/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs b/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
index 8a476ec9..16ac88c8 100644
--- a/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
+++ b/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
@@ -10,722 +10,138 @@ using Point = System.Windows.Point;
namespace Ink_Canvas.Helpers
{
///
- /// 高级贝塞尔曲线平滑算法 - 优化版本
- /// 用于解决墨迹闪烁问题,提供更平滑的笔迹效果
- /// 优化特性:
- /// 1. 更平滑的墨迹:改进的贝塞尔曲线算法
- /// 2. 更平滑的拐点:优化的控制点计算
- /// 3. 1像素级别插点:精确到像素级别的曲线生成
+ /// 适合手写/触摸的墨迹平滑方案:指数平滑+等距重采样+Catmull-Rom样条插值,防止自交和异常填充
///
public class AdvancedBezierSmoothing
{
- ///
- /// 平滑强度 (0.0 - 1.0) - 优化为更平滑的默认值
- ///
- public double SmoothingStrength { get; set; } = 0.7;
+ public double SmoothingStrength { get; set; } = 0.8;
+ public double ResampleInterval { get; set; } = 0.8;
+ public int InterpolationSteps { get; set; } = 64;
- ///
- /// 张力参数 (0.0 - 1.0) - 优化为更平滑的默认值
- ///
- public double Tension { get; set; } = 0.4;
-
- ///
- /// 是否启用自适应平滑
- ///
- public bool EnableAdaptiveSmoothing { get; set; } = true;
-
- ///
- /// 最小点间距阈值 - 优化为1像素级别
- ///
- public double MinPointDistance { get; set; } = 1.0; // 降低到1像素级别
-
- ///
- /// 最大点间距阈值 - 优化为更精细的控制
- ///
- public double MaxPointDistance { get; set; } = 15.0; // 进一步减少最大间距,提高平滑度
-
- ///
- /// 手抖修正强度 (0.0 - 1.0) - 优化为更平滑的默认值
- ///
- public double ShakeCorrectionStrength { get; set; } = 0.8;
-
- ///
- /// 速度加权平滑强度 (0.0 - 1.0) - 优化为更平滑的默认值
- ///
- public double VelocityWeightedSmoothingStrength { get; set; } = 0.8;
-
- ///
- /// 时间加权平滑强度 (0.0 - 1.0) - 优化为更平滑的默认值
- ///
- public double TimeWeightedSmoothingStrength { get; set; } = 0.6;
-
- ///
- /// 拐点平滑强度 (0.0 - 1.0) - 新增参数,优化为更平滑的默认值
- ///
- public double CornerSmoothingStrength { get; set; } = 0.8;
-
- ///
- /// 1像素级别插点精度 - 新增参数
- ///
- public double PixelLevelPrecision { get; set; } = 1.0;
-
- ///
- /// 对笔画进行高级贝塞尔曲线平滑处理
- ///
- /// 原始笔画
- /// 平滑后的笔画
public Stroke SmoothStroke(Stroke stroke)
{
- if (stroke == null || stroke.StylusPoints.Count < 3)
+ if (stroke == null || stroke.StylusPoints.Count < 2)
return stroke;
-
var originalPoints = stroke.StylusPoints.ToList();
- var smoothedPoints = new List();
-
- // 检查采样率,如果点太少则使用不同的处理策略
- bool isLowSamplingRate = originalPoints.Count < 10; // 少于10个点认为是低采样率
-
- if (isLowSamplingRate)
- {
- // 低采样率情况下的特殊处理
- return HandleLowSamplingRateStroke(stroke);
- }
-
- // 第一步:手抖修正
- var shakeCorrectedPoints = ApplyShakeCorrection(originalPoints);
-
- // 第二步:基于速度和时间的加权平滑
- var velocityTimeWeightedPoints = ApplyVelocityTimeWeightedSmoothing(shakeCorrectedPoints);
-
- // 第三步:拐点检测和平滑
- var cornerSmoothedPoints = ApplyCornerSmoothing(velocityTimeWeightedPoints);
-
- // 第四步:点过滤和重采样(1像素级别)
- var filteredPoints = FilterAndResamplePoints(cornerSmoothedPoints);
-
- // 第五步:计算优化的控制点
- var controlPoints = CalculateOptimizedControlPoints(filteredPoints);
-
- // 第六步:生成1像素级别的平滑曲线点
- var curvePoints = GeneratePixelLevelCurvePoints(filteredPoints, controlPoints);
-
- // 第七步:修正收尾相连问题
- var fixedStylusPoints = FixEndToEndConnection(new StylusPointCollection(curvePoints));
-
- // 第八步:创建新的笔画
- var smoothedStroke = new Stroke(fixedStylusPoints)
+ var smoothedPoints = ApplyExponentialSmoothing(originalPoints, SmoothingStrength);
+ var resampledPoints = ResampleEquidistant(smoothedPoints, ResampleInterval);
+ var interpolatedPoints = SlidingBezierFit(resampledPoints, 4, 24);
+ var finalPoints = ApplyExponentialSmoothing(interpolatedPoints, 0.5); // 二次平滑
+ var ultraSmoothPoints = SlidingWindowSmooth(finalPoints, 7); // 滑动窗口平滑
+ var smoothedStroke = new Stroke(new StylusPointCollection(ultraSmoothPoints))
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
-
return smoothedStroke;
}
- ///
- /// 检测并修正收尾相连问题
- ///
- private StylusPointCollection FixEndToEndConnection(StylusPointCollection points)
+ private List ApplyExponentialSmoothing(List points, double alpha)
{
- if (points.Count < 3) return points;
-
- var resultPoints = new StylusPointCollection();
-
- // 复制所有点
- foreach (var point in points)
+ var result = new List();
+ if (points.Count == 0) return result;
+ result.Add(points[0]);
+ double lastX = points[0].X;
+ double lastY = points[0].Y;
+ float lastPressure = points[0].PressureFactor;
+ for (int i = 1; i < points.Count; i++)
{
- resultPoints.Add(point);
+ var p = points[i];
+ lastX = alpha * p.X + (1 - alpha) * lastX;
+ lastY = alpha * p.Y + (1 - alpha) * lastY;
+ lastPressure = (float)(alpha * p.PressureFactor + (1 - alpha) * lastPressure);
+ if (lastPressure < 0.1f) lastPressure = 0.1f;
+ result.Add(new StylusPoint(lastX, lastY, lastPressure));
}
-
- // 检查首尾是否过于接近
- var firstPoint = resultPoints[0];
- var lastPoint = resultPoints[resultPoints.Count - 1];
- double endToEndDistance = GetDistance(firstPoint.ToPoint(), lastPoint.ToPoint());
-
- // 如果首尾距离太近,可能是收尾相连问题
- if (endToEndDistance < 3.0) // 降低阈值到3像素
- {
- // 移除最后一个点,避免收尾相连
- if (resultPoints.Count > 1)
- {
- resultPoints.RemoveAt(resultPoints.Count - 1);
- }
- }
-
- return resultPoints;
+ return result;
}
- ///
- /// 过滤和重采样点(1像素级别优化)
- ///
- private List FilterAndResamplePoints(List points)
+ private List ResampleEquidistant(List points, double interval = 2.0)
{
- var filteredPoints = new List();
-
- if (points.Count == 0) return filteredPoints;
-
- // 添加第一个点
- filteredPoints.Add(points[0]);
-
- // 使用改进的移动平均来减少毛刺
- var smoothedPoints = new List();
- int windowSize = 5; // 增加窗口大小以获得更平滑的效果
-
- for (int i = 0; i < points.Count; i++)
+ var result = new List();
+ if (points.Count == 0) return result;
+ result.Add(points[0]);
+ double accumulated = 0;
+ for (int i = 1; i < points.Count; i++)
{
- var currentPoint = points[i];
- var lastPoint = filteredPoints[filteredPoints.Count - 1];
-
- double distance = GetDistance(lastPoint.ToPoint(), currentPoint.ToPoint());
-
- // 如果距离太近,跳过(1像素级别)
- if (distance < MinPointDistance)
- continue;
-
- // 应用改进的移动平均平滑
- if (i >= windowSize - 1)
+ var prev = result.Last();
+ var curr = points[i];
+ double dx = curr.X - prev.X;
+ double dy = curr.Y - prev.Y;
+ double dist = Math.Sqrt(dx * dx + dy * dy);
+ if (dist + accumulated >= interval)
{
- double avgX = 0, avgY = 0, avgPressure = 0;
- double totalWeight = 0;
-
- // 使用加权移动平均,中心点权重更高
- for (int j = 0; j < windowSize; j++)
- {
- var point = points[i - j];
- double weight = 1.0 - Math.Abs(j - (windowSize - 1) / 2.0) / (windowSize / 2.0);
- weight = Math.Max(0.1, weight); // 确保最小权重
-
- avgX += point.X * weight;
- avgY += point.Y * weight;
- avgPressure += point.PressureFactor * weight;
- totalWeight += weight;
- }
-
- avgX /= totalWeight;
- avgY /= totalWeight;
- avgPressure /= totalWeight;
-
- var smoothedPoint = new StylusPoint(avgX, avgY, (float)avgPressure);
- currentPoint = smoothedPoint;
- }
-
- // 如果距离太远,插入中间点(1像素级别精度)
- if (distance > MaxPointDistance)
- {
- int segments = Math.Max(2, (int)(distance / PixelLevelPrecision));
- for (int j = 1; j < segments; j++)
- {
- double ratio = (double)j / segments;
- var interpolatedPoint = InterpolatePoint(lastPoint, currentPoint, ratio);
- filteredPoints.Add(interpolatedPoint);
- }
- }
-
- filteredPoints.Add(currentPoint);
- }
-
- return filteredPoints;
- }
-
- ///
- /// 计算优化的控制点(改进拐点平滑)
- ///
- private List CalculateOptimizedControlPoints(List points)
- {
- var controlPoints = new List();
-
- if (points.Count < 2) return controlPoints;
-
- // 检查点密度,如果点太稀疏则使用更保守的控制点计算
- bool isSparsePoints = points.Count < 5;
- double tensionMultiplier = isSparsePoints ? 0.05 : 0.2; // 进一步减少张力
- double maxOffset = isSparsePoints ? 3.0 : 8.0; // 减少最大偏移
-
- for (int i = 0; i < points.Count; i++)
- {
- Point currentPoint = points[i].ToPoint();
- Point controlPoint;
-
- if (i == 0)
- {
- // 第一个点的控制点
- Point nextPoint = points[i + 1].ToPoint();
- double distance = GetDistance(currentPoint, nextPoint);
-
- // 如果距离太远,使用更保守的控制点
- if (distance > 30.0) // 降低阈值
- {
- controlPoint = currentPoint; // 直接使用当前点作为控制点
- }
- else
- {
- // 使用更平滑的控制点计算
- double tension = Tension * tensionMultiplier * CornerSmoothingStrength;
- controlPoint = new Point(
- currentPoint.X + (nextPoint.X - currentPoint.X) * tension,
- currentPoint.Y + (nextPoint.Y - currentPoint.Y) * tension
- );
- }
- }
- else if (i == points.Count - 1)
- {
- // 最后一个点的控制点
- Point prevPoint = points[i - 1].ToPoint();
- double distance = GetDistance(currentPoint, prevPoint);
-
- // 如果距离太远,使用更保守的控制点
- if (distance > 30.0) // 降低阈值
- {
- controlPoint = currentPoint; // 直接使用当前点作为控制点
- }
- else
- {
- // 使用更平滑的控制点计算
- double tension = Tension * tensionMultiplier * CornerSmoothingStrength;
- controlPoint = new Point(
- currentPoint.X + (currentPoint.X - prevPoint.X) * tension,
- currentPoint.Y + (currentPoint.Y - prevPoint.Y) * tension
- );
- }
+ double t = (interval - accumulated) / dist;
+ double x = prev.X + t * dx;
+ double y = prev.Y + t * dy;
+ float pressure = (float)(prev.PressureFactor * (1 - t) + curr.PressureFactor * t);
+ if (pressure < 0.1f) pressure = 0.1f;
+ var newPoint = new StylusPoint(x, y, pressure);
+ result.Add(newPoint);
+ accumulated = 0;
+ i--; // 重新处理当前点
}
else
{
- // 中间点的控制点(改进拐点平滑)
- Point prevPoint = points[i - 1].ToPoint();
- Point nextPoint = points[i + 1].ToPoint();
-
- // 检查前后点的距离,如果太远则使用更保守的方法
- double prevDistance = GetDistance(currentPoint, prevPoint);
- double nextDistance = GetDistance(currentPoint, nextPoint);
-
- if (prevDistance > 30.0 || nextDistance > 30.0) // 降低阈值
- {
- // 距离太远,使用线性插值作为控制点
- 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;
-
- // 应用张力参数和拐点平滑,但限制最大偏移
- double offsetX = tangentX * Tension * CornerSmoothingStrength;
- double offsetY = tangentY * Tension * CornerSmoothingStrength;
-
- // 限制偏移距离
- 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
- );
- }
+ accumulated += dist;
}
-
- controlPoints.Add(controlPoint);
}
-
- return controlPoints;
+ return result;
}
- ///
- /// 生成1像素级别的平滑曲线点
- ///
- private List GeneratePixelLevelCurvePoints(List points, List controlPoints)
+ private List SlidingBezierFit(List points, int window = 4, int steps = 24)
{
- var curvePoints = new List();
-
- if (points.Count < 2) return curvePoints;
-
- // 为每个线段生成贝塞尔曲线点
- for (int i = 0; i < points.Count - 1; i++)
+ var result = new List();
+ if (points.Count < window) return points;
+ for (int i = 0; i <= points.Count - window; i++)
{
- var startPoint = points[i];
- var endPoint = points[i + 1];
- var startControl = controlPoints[i];
- var endControl = controlPoints[i + 1];
-
- // 计算1像素级别的步长
- double distance = GetDistance(startPoint.ToPoint(), endPoint.ToPoint());
-
- // 根据距离计算精确的步数,确保1像素级别精度
- int steps = Math.Max(1, (int)(distance / PixelLevelPrecision));
-
- // 限制最大步数以避免过度细分
- steps = Math.Min(steps, 50);
-
- // 生成贝塞尔曲线点
- for (int j = 0; j <= steps; j++)
+ var p0 = points[i];
+ var p1 = points[i + 1];
+ var p2 = points[i + 2];
+ var p3 = points[i + 3];
+ for (int j = 0; j < steps; j++)
{
double t = (double)j / steps;
- var curvePoint = CalculateBezierPoint(startPoint.ToPoint(), startControl, endControl, endPoint.ToPoint(), 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);
- curvePoints.Add(stylusPoint);
+ var pt = CubicBezier(p0, p1, p2, p3, t);
+ result.Add(pt);
}
}
-
- return curvePoints;
+ // 保证最后一个点被包含
+ result.Add(points.Last());
+ return result;
}
- ///
- /// 应用拐点平滑
- ///
- private List ApplyCornerSmoothing(List points)
- {
- if (points.Count < 3) return points;
-
- var smoothedPoints = new List();
- smoothedPoints.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 angle1 = Math.Atan2(curr.Y - prev.Y, curr.X - prev.X);
- double angle2 = Math.Atan2(next.Y - curr.Y, next.X - curr.X);
- double angleDiff = Math.Abs(angle2 - angle1);
-
- // 标准化角度差
- if (angleDiff > Math.PI) angleDiff = 2 * Math.PI - angleDiff;
-
- // 如果角度变化太大,认为是拐点
- if (angleDiff > Math.PI / 4) // 45度阈值
- {
- // 应用拐点平滑
- double smoothingFactor = CornerSmoothingStrength;
- double smoothedX = curr.X * (1.0 - smoothingFactor) +
- (prev.X + next.X) * 0.5 * smoothingFactor;
- double smoothedY = curr.Y * (1.0 - smoothingFactor) +
- (prev.Y + next.Y) * 0.5 * smoothingFactor;
-
- var smoothedPoint = new StylusPoint(smoothedX, smoothedY, curr.PressureFactor);
- smoothedPoints.Add(smoothedPoint);
- }
- else
- {
- smoothedPoints.Add(curr);
- }
- }
-
- smoothedPoints.Add(points[points.Count - 1]); // 添加最后一个点
- return smoothedPoints;
- }
-
- ///
- /// 计算贝塞尔曲线上的点
- ///
- private Point CalculateBezierPoint(Point p0, Point p1, Point p2, Point p3, double t)
+ private StylusPoint CubicBezier(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3, double t)
{
double u = 1 - t;
double tt = t * t;
double uu = u * u;
double uuu = uu * u;
double ttt = tt * t;
-
- Point point = new Point();
- point.X = uuu * p0.X + 3 * uu * t * p1.X + 3 * u * tt * p2.X + ttt * p3.X;
- point.Y = uuu * p0.Y + 3 * uu * t * p1.Y + 3 * u * tt * p2.Y + ttt * p3.Y;
-
- return point;
+ double x = uuu * p0.X + 3 * uu * t * p1.X + 3 * u * tt * p2.X + ttt * p3.X;
+ double y = uuu * p0.Y + 3 * uu * t * p1.Y + 3 * u * tt * p2.Y + ttt * p3.Y;
+ float pressure = (float)(p1.PressureFactor * (1 - t) + p2.PressureFactor * t);
+ if (pressure < 0.1f) pressure = 0.1f;
+ return new StylusPoint(x, y, pressure);
}
- ///
- /// 计算两点间距离
- ///
- private double GetDistance(Point p1, Point p2)
+ private List SlidingWindowSmooth(List points, int window = 5)
{
- return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
- }
-
- ///
- /// 插值两点间的点
- ///
- private StylusPoint InterpolatePoint(StylusPoint p1, StylusPoint p2, double ratio)
- {
- return new StylusPoint(
- p1.X + (p2.X - p1.X) * ratio,
- p1.Y + (p2.Y - p1.Y) * ratio,
- InterpolatePressure(p1.PressureFactor, p2.PressureFactor, ratio)
- );
- }
-
- ///
- /// 插值压感值
- ///
- private float InterpolatePressure(float p1, float p2, double ratio)
- {
- // 使用平滑的插值函数来减少毛刺
- double smoothRatio = SmoothStep(ratio);
- return (float)(p1 + (p2 - p1) * smoothRatio);
- }
-
- ///
- /// 平滑步进函数,用于减少插值时的毛刺
- ///
- private double SmoothStep(double t)
- {
- // 使用三次平滑函数
- return t * t * (3.0 - 2.0 * t);
- }
-
- ///
- /// 应用手抖修正
- ///
- private List ApplyShakeCorrection(List points)
- {
- if (points.Count < 3) return points;
-
- var correctedPoints = new List();
- correctedPoints.Add(points[0]); // 添加第一个点
-
- for (int i = 1; i < points.Count - 1; i++)
+ var result = new List();
+ int half = window / 2;
+ for (int i = 0; i < points.Count; 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 = 3.0; // 降低手抖检测阈值
- if (deviation > shakeThreshold)
+ double sumX = 0, sumY = 0, sumP = 0;
+ int count = 0;
+ for (int j = Math.Max(0, i - half); j <= Math.Min(points.Count - 1, i + half); j++)
{
- // 应用手抖修正
- 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);
+ sumX += points[j].X;
+ sumY += points[j].Y;
+ sumP += points[j].PressureFactor;
+ count++;
}
+ result.Add(new StylusPoint(sumX / count, sumY / count, (float)(sumP / count)));
}
-
- correctedPoints.Add(points[points.Count - 1]); // 添加最后一个点
- return correctedPoints;
- }
-
- ///
- /// 应用基于速度和时间的加权平滑
- ///
- private List ApplyVelocityTimeWeightedSmoothing(List points)
- {
- if (points.Count < 3) return points;
-
- var smoothedPoints = new List();
- smoothedPoints.Add(points[0]); // 添加第一个点
-
- // 计算每个点的速度和加速度
- var velocities = new List();
- var accelerations = new List();
- var timeWeights = new List();
-
- 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 < 1.0) // 降低阈值
- {
- timeWeight = 1.5; // 增加权重
- }
- else if (avgDistance > 15.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 / 8.0 + 0.5); // 调整参数
- }
-
- // 计算加速度权重
- double accelerationWeight = 1.0;
- if (i < accelerations.Count)
- {
- double acceleration = Math.Abs(accelerations[i - 1]);
- // 加速度越大,权重越大(更平滑)
- accelerationWeight = Math.Min(2.0, acceleration / 3.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.2; // 减少最大影响
- 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;
- }
-
- ///
- /// 处理低采样率笔画
- ///
- private Stroke HandleLowSamplingRateStroke(Stroke stroke)
- {
- var points = stroke.StylusPoints.ToList();
- var resultPoints = new List();
-
- // 对于低采样率,使用简单的线性插值而不是贝塞尔曲线
- 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());
-
- // 如果距离太远,插入中间点(1像素级别)
- if (distance > 15.0) // 降低阈值
- {
- int segments = Math.Max(2, Math.Min(8, (int)(distance / PixelLevelPrecision))); // 使用像素级别精度
- 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;
- }
-
- ///
- /// 应用自适应平滑
- ///
- private void ApplyAdaptiveSmoothing(List points)
- {
- if (!EnableAdaptiveSmoothing || points.Count < 3)
- return;
-
- // 计算笔迹的速度变化
- var speeds = new List();
- for (int i = 1; i < points.Count - 1; i++)
- {
- var prev = points[i - 1].ToPoint();
- var curr = points[i].ToPoint();
- var next = points[i + 1].ToPoint();
-
- double speed1 = GetDistance(prev, curr);
- double speed2 = GetDistance(curr, next);
- double avgSpeed = (speed1 + speed2) / 2.0;
-
- speeds.Add(avgSpeed);
- }
-
- // 根据速度调整平滑强度
- if (speeds.Count > 0)
- {
- double avgSpeed = speeds.Average();
- double maxSpeed = speeds.Max();
- double minSpeed = speeds.Min();
-
- // 速度变化越大,平滑强度越小
- double speedVariation = (maxSpeed - minSpeed) / avgSpeed;
- SmoothingStrength = Math.Max(0.1, Math.Min(0.9, SmoothingStrength * (1.0 - speedVariation * 0.3)));
- }
+ return result;
}
}
}
\ No newline at end of file
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 96c460bc..57795b2c 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -788,81 +788,12 @@
Toggled="ToggleSwitchFitToCurve_Toggled" />
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index 241c34be..494e1029 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -1310,49 +1310,7 @@ namespace Ink_Canvas {
SaveSettingsToFile();
}
-
- private void AdvancedSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.AdvancedSmoothingStrength = AdvancedSmoothingStrengthSlider.Value;
- SaveSettingsToFile();
- }
-
- private void AdvancedSmoothingTensionSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.AdvancedSmoothingTension = AdvancedSmoothingTensionSlider.Value;
- SaveSettingsToFile();
- }
-
- private void ToggleSwitchEnableAdaptiveSmoothing_Toggled(object sender, RoutedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.EnableAdaptiveSmoothing = ToggleSwitchEnableAdaptiveSmoothing.IsOn;
- SaveSettingsToFile();
- }
-
- private void ShakeCorrectionStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.ShakeCorrectionStrength = ShakeCorrectionStrengthSlider.Value;
- SaveSettingsToFile();
- }
-
- private void VelocityWeightedSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.VelocityWeightedSmoothingStrength = VelocityWeightedSmoothingStrengthSlider.Value;
- SaveSettingsToFile();
- }
-
- private void TimeWeightedSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.TimeWeightedSmoothingStrength = TimeWeightedSmoothingStrengthSlider.Value;
- SaveSettingsToFile();
- }
-
- private void CornerSmoothingStrengthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
- if (!isLoaded) return;
- Settings.Canvas.CornerSmoothingStrength = CornerSmoothingStrengthSlider.Value;
- SaveSettingsToFile();
- }
-
+
private void ToggleSwitchAutoSaveStrokesInPowerPoint_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
Settings.PowerPointSettings.IsAutoSaveStrokesInPowerPoint = ToggleSwitchAutoSaveStrokesInPowerPoint.IsOn;
@@ -1655,12 +1613,6 @@ namespace Ink_Canvas {
Settings.Canvas.ClearCanvasAndClearTimeMachine = false;
Settings.Canvas.FitToCurve = false;
Settings.Canvas.UseAdvancedBezierSmoothing = true;
- 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;
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index c23a553e..5eb58242 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -537,13 +537,6 @@ namespace Ink_Canvas {
ToggleSwitchAdvancedBezierSmoothing.IsOn = false;
drawingAttributes.FitToCurve = false;
}
- 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;
- CornerSmoothingStrengthSlider.Value = Settings.Canvas.CornerSmoothingStrength;
// 初始化直线自动拉直相关设置
ToggleSwitchAutoStraightenLine.IsOn = Settings.Canvas.AutoStraightenLine;
diff --git a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
index 46e93c0a..24bfc805 100644
--- a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
+++ b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
@@ -1597,14 +1597,6 @@ namespace Ink_Canvas {
{
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,
- CornerSmoothingStrength = Settings.Canvas.CornerSmoothingStrength,
- PixelLevelPrecision = Settings.Canvas.PixelLevelPrecision
};
// 对临时笔画应用平滑
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index e8a8d710..648317a0 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -589,14 +589,6 @@ namespace Ink_Canvas {
{
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,
- CornerSmoothingStrength = Settings.Canvas.CornerSmoothingStrength,
- PixelLevelPrecision = Settings.Canvas.PixelLevelPrecision
};
var smoothedStroke = advancedSmoothing.SmoothStroke(e.Stroke);
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index bf648ba5..5a96a5c2 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -50,22 +50,6 @@ namespace Ink_Canvas
public bool FitToCurve { get; set; } = false; // 默认关闭原来的贝塞尔平滑
[JsonProperty("useAdvancedBezierSmoothing")]
public bool UseAdvancedBezierSmoothing { get; set; } = true; // 默认启用高级贝塞尔曲线平滑
- [JsonProperty("advancedSmoothingStrength")]
- public double AdvancedSmoothingStrength { get; set; } = 0.7; // 高级平滑强度 (0.0 - 1.0),提高以获得更平滑的效果
- [JsonProperty("advancedSmoothingTension")]
- public double AdvancedSmoothingTension { get; set; } = 0.4; // 高级平滑张力 (0.0 - 1.0),适度提高以获得更平滑的曲线
- [JsonProperty("enableAdaptiveSmoothing")]
- public bool EnableAdaptiveSmoothing { get; set; } = true; // 是否启用自适应平滑
- [JsonProperty("shakeCorrectionStrength")]
- public double ShakeCorrectionStrength { get; set; } = 0.8; // 手抖修正强度 (0.0 - 1.0),提高以减少手抖
- [JsonProperty("velocityWeightedSmoothingStrength")]
- public double VelocityWeightedSmoothingStrength { get; set; } = 0.8; // 速度加权平滑强度 (0.0 - 1.0),提高以获得更平滑的效果
- [JsonProperty("timeWeightedSmoothingStrength")]
- public double TimeWeightedSmoothingStrength { get; set; } = 0.6; // 时间加权平滑强度 (0.0 - 1.0),提高以获得更平滑的效果
- [JsonProperty("cornerSmoothingStrength")]
- public double CornerSmoothingStrength { get; set; } = 0.8; // 拐点平滑强度 (0.0 - 1.0),新增参数用于更平滑的拐点
- [JsonProperty("pixelLevelPrecision")]
- public double PixelLevelPrecision { get; set; } = 1.0; // 1像素级别插点精度,新增参数用于精确控制
[JsonProperty("clearCanvasAndClearTimeMachine")]
public bool ClearCanvasAndClearTimeMachine { get; set; } = false;
[JsonProperty("enablePressureTouchMode")]