improve:插入图片及墨迹平滑

This commit is contained in:
2025-08-30 22:59:12 +08:00
parent b64cefad46
commit d7df39290f
2 changed files with 71 additions and 20 deletions
+53 -13
View File
@@ -97,13 +97,20 @@ namespace Ink_Canvas.Helpers
cancellationToken.ThrowIfCancellationRequested();
// 确保点数合理
if (smoothedPoints.Length > originalPoints.Length * 3)
// 严格控制点数,避免产生过多点
if (smoothedPoints.Length > originalPoints.Length * 2)
{
// 如果点数增加太多,进行重采样
smoothedPoints = ResampleEquidistantOptimized(smoothedPoints, ResampleInterval);
}
// 最终检查:确保点数不会过多
if (smoothedPoints.Length > originalPoints.Length * 1.5)
{
// 如果仍然太多点,使用原始笔画
return stroke;
}
// 创建平滑后的笔画
var smoothedStroke = new Stroke(new StylusPointCollection(smoothedPoints))
{
@@ -125,23 +132,23 @@ namespace Ink_Canvas.Helpers
// 添加第一个点
result.Add(points[0]);
// 使用滑动窗口进行贝塞尔曲线拟合
for (int i = 0; i <= points.Length - 4; i++)
// 使用非重叠的窗口进行贝塞尔曲线拟合
for (int i = 0; i < points.Length - 3; i += 3) // 每次移动3个点,避免重叠
{
var p0 = points[i];
var p1 = points[i + 1];
var p2 = points[i + 2];
var p3 = points[i + 3];
var p1 = points[Math.Min(i + 1, points.Length - 1)];
var p2 = points[Math.Min(i + 2, points.Length - 1)];
var p3 = points[Math.Min(i + 3, points.Length - 1)];
// 计算改进的控制点
var controlPoints = CalculateImprovedControlPoints(p0, p1, p2, p3);
// 自适应插值步数
int steps = UseAdaptiveInterpolation ?
CalculateAdaptiveSteps(p0, p1, p2, p3) : InterpolationSteps;
// 限制插值步数,避免点数爆炸
int steps = Math.Min(UseAdaptiveInterpolation ?
CalculateAdaptiveSteps(p0, p1, p2, p3) : InterpolationSteps, 16);
// 生成贝塞尔曲线点
for (int j = 1; j <= steps; j++) // 从1开始避免重复第一个点
// 生成贝塞尔曲线点,但跳过第一个点避免重复
for (int j = 1; j <= steps; j++)
{
double t = (double)j / steps;
var bezierPoint = CubicBezierWithControlPoints(controlPoints, t, p0, p3);
@@ -152,7 +159,8 @@ namespace Ink_Canvas.Helpers
// 添加最后一个点
result.Add(points[points.Length - 1]);
return result.ToArray();
// 去重和优化点数
return RemoveDuplicatePoints(result.ToArray());
}
/// <summary>
@@ -233,6 +241,38 @@ namespace Ink_Canvas.Helpers
return (angle1 + angle2) / Math.PI; // 归一化到0-1
}
/// <summary>
/// 去除重复和过近的点
/// </summary>
private StylusPoint[] RemoveDuplicatePoints(StylusPoint[] points)
{
if (points.Length < 2) return points;
var result = new List<StylusPoint>();
result.Add(points[0]);
double minDistance = ResampleInterval * 0.5; // 最小距离阈值
for (int i = 1; i < points.Length; i++)
{
var lastPoint = result[result.Count - 1];
var currentPoint = points[i];
// 计算距离
double distance = Math.Sqrt(
(currentPoint.X - lastPoint.X) * (currentPoint.X - lastPoint.X) +
(currentPoint.Y - lastPoint.Y) * (currentPoint.Y - lastPoint.Y));
// 如果距离足够大,添加这个点
if (distance >= minDistance)
{
result.Add(currentPoint);
}
}
return result.ToArray();
}
/// <summary>
/// 使用控制点的三次贝塞尔曲线计算
/// </summary>
@@ -40,11 +40,6 @@ namespace Ink_Canvas
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
image.Name = timestamp;
// 初始化TransformGroup
InitializeElementTransform(image);
CenterAndScaleElement(image);
// 设置图片属性,避免被InkCanvas选择系统处理
image.IsHitTestVisible = true;
image.Focusable = false;
@@ -52,8 +47,15 @@ namespace Ink_Canvas
// 初始化InkCanvas选择设置
InitializeInkCanvasSelectionSettings();
// 先添加到画布
inkCanvas.Children.Add(image);
// 初始化TransformGroup
InitializeElementTransform(image);
// 居中缩放
CenterAndScaleElement(image);
// 绑定事件处理器
BindElementEvents(image);
@@ -99,6 +101,8 @@ namespace Ink_Canvas
{
if (sender is FrameworkElement element)
{
LogHelper.WriteLogToFile($"图片鼠标按下: {element.Name}");
// 取消之前选中的元素
if (currentSelectedElement != null && currentSelectedElement != element)
{
@@ -151,6 +155,8 @@ namespace Ink_Canvas
{
if (sender is FrameworkElement element)
{
LogHelper.WriteLogToFile($"图片滚轮事件: {element.Name}, Delta={e.Delta}");
// 使用滚轮缩放的核心机制
ApplyWheelScaleTransform(element, e);
@@ -890,8 +896,13 @@ namespace Ink_Canvas
InkCanvas.SetLeft(element, centerX);
InkCanvas.SetTop(element, centerY);
// 清除任何现有的RenderTransform
element.RenderTransform = Transform.Identity;
// 保持TransformGroup,不清除RenderTransform
// 这样可以保持滚轮缩放和拖动功能
if (element.RenderTransform == null || element.RenderTransform == Transform.Identity)
{
// 只有在没有TransformGroup时才创建
InitializeElementTransform(element);
}
LogHelper.WriteLogToFile($"元素居中完成: 位置({centerX}, {centerY}), 尺寸({newWidth}x{newHeight})");
}