Adobe Illustrator中的折线简化如何工作?

问题描述 投票:20回答:2

我正在研究一个记录笔画的应用程序,你用指点设备绘制它。

在上图中,我画了一个笔画,其中包含453个数据点。我的目标是在保持原始笔划形状的同时大幅减少数据点的数量。

对于那些感兴趣的人,上面描绘的笔画坐标可以作为gist on GitHub

事实上,Adobe Illustrator可以很好地实现我想要实现的目标。如果我在Illustrator中绘制类似的笔触(使用书法笔刷),则生成的形状将简化为我们在下面看到的内容。绘制笔划时,它看起来与我的应用程序非常相似。释放鼠标按钮后,曲线将简化为我们在此处看到的内容:

我们可以看到,笔划只有14个数据点。虽然还有其他控制点可以定义贝塞尔样条曲线的倾角(或者它们正在使用的任何样条曲线)。在这里,我们可以看到一些控制点:

我看过像Ramer–Douglas–Peucker algorithm这样的算法,但那些似乎只从输入集中删除了点。如果我没有弄错的话,我正在寻找的方法也必须在集合中引入新的点来实现所需的曲线。

我遇到过像iPhone smooth sketch drawing algorithm这样的问题。但那些似乎专注于从一小组输入点创建平滑曲线。我觉得我有相反的情况。

c# adobe-illustrator polyline
2个回答
8
投票

我遇到了问题Smoothing a hand-drawn curve(这个问题可能实际上是一个骗局),其答案建议使用Ramer-Douglas-Peucker然后根据Philip J. Schneiders approach应用曲线拟合。

快速调整所提供的示例代码到我的绘图方法会产生以下曲线:

来自问题的输入数据已减少到28个点(使用Bezier样条线绘制)。

我不确定Adobe正在使用哪种方法,但到目前为止这个方法对我非常好。

Adaptation

因此,the code provided by Kris是为WPF编写的,并在这方面做出了一些假设。为了我的情况(因为我不想调整他的代码),我编写了以下代码片段:

private List<Point> OptimizeCurve( List<Point> curve ) {
  const float tolerance = 1.5f;
  const double error    = 100.0;

  // Remember the first point in the series.
  Point startPoint = curve.First();
  // Simplify the input curve.
  List<Point> simplified = Douglas.DouglasPeuckerReduction( curve, tolerance ).ToList();
  // Create a new curve from the simplified one.
  List<System.Windows.Point> fitted = FitCurves.FitCurve( simplified.Select( p => new System.Windows.Point( p.X, p.Y ) ).ToArray(), error );
  // Convert the points back to our desired type.
  List<Point> fittedPoints = fitted.Select( p => new Point( (int)p.X, (int)p.Y ) ).ToList();
  // Add back our first point.
  fittedPoints.Insert( 0, startPoint );
  return fittedPoints;
}

结果列表将采用Start Point,Control Point 1,Control Point 2,End Point格式。


0
投票

为了复制Illustrator的路径>简化,我已经广泛使用bezier简化。什么效果最好,最像Illustrator的是Philip J. Schneider的Graphic's Gems简化,但还有一步。该步骤排除了路径上的尖锐/倾斜点。

有一个bezier路径:

在每个尖锐的贝塞尔曲线段拆分路径。因此,其贝塞尔曲柄处理的任何线段都不是平滑/共线的,或者它在相对于线段的两个相邻曲线创建“尖点”的位置。当段被视为“锐利”时,您可以设置自己定义的阈值。 180度是平滑的,179.99或170度或更小的任何东西都是被认为是尖锐部分的门槛。

将这些路径中的每一条路径从原始路径中分离出来,将曲线拟合算法应用于每个路径,然后重新加入它们。

这样可以保留锋利的边缘,但可以使多余的部分平滑,沿着路径的其余部分拟合曲线。

我的实现是在paper.js中,但可以使用fitcurve算法利用相同的技术:

C:https://github.com/erich666/GraphicsGems/blob/2bab77250b8d45b4dfcb9cf58cf68f19f8268e56/gems/FitCurves.c

JS:https://github.com/soswow/fit-curve

© www.soinside.com 2019 - 2024. All rights reserved.