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")]