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

时间:2013-07-02 12:33:27

标签: c# adobe-illustrator polyline

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

enter image description here

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

对于有兴趣的人,上图所示笔画的坐标可以gist on GitHub获得。

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

enter image description here

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

enter image description here

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

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

2 个答案:

答案 0 :(得分:8)

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

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

enter image description here

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

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

适应

因此,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;
}

结果列表的格式为起点控制点1 控制点2 终点

答案 1 :(得分:0)

我一直在广泛使用贝塞尔曲线简化,以尝试复制Illustrator的路径>简化。最有效且最类似于Illustrator的是Philip J. Schneider的Graphic的Gems简化,但还有一个附加步骤。该步骤排除了路径上的尖锐/成角度的点。

使用贝塞尔曲线路径:

在每个尖锐的贝塞尔曲线段处分割路径。因此,贝塞尔曲线手柄不平滑/共线的任何线段,或者相对于该线段的两条相邻曲线创建“尖锐点”的线段。您可以设置自己的阈值,以定义何时将细分视为“清晰”。 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

相关问题