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

Posted

技术标签:

【中文标题】Adobe Illustrator 中的折线简化如何工作?【英文标题】:How does polyline simplification in Adobe Illustrator work? 【发布时间】:2013-06-29 19:56:39 【问题描述】:

我正在开发一个记录笔划的应用程序,您可以使用指点设备进行绘制。

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

对于那些感兴趣的人,上图中的笔划坐标可通过gist on GitHub 获得。

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

正如我们所见,笔画只有 14 个数据点。尽管还有其他控制点定义了贝塞尔样条曲线(或他们正在使用的任何样条曲线)的倾斜度。在这里我们可以看到其中一些控制点:

我看过Ramer–Douglas–Peucker algorithm 之类的算法,但这些算法似乎只从输入集中删除点。如果我没记错的话,我正在寻找的方法还必须在集合中引入新点以实现所需的曲线。

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

【问题讨论】:

您的数据点是存储为序列(保持绘制顺序)还是一组(只是点云,没有定义的顺序)? @mbeckish:前者。它实际上是一个List<Point>,它按照记录的顺序填充坐标。 这可能无法回答您的问题,因为它依赖于 MatLab 库,但它可能会提供一些见解:http://***.com/q/12674532/21727。 另见here。 所以听起来您知道 B 样条曲线是要走的路,您只是想知道如何计算结应该是什么?我会考虑使用切比雪夫多项式。 【参考方案1】:

我已经广泛使用贝塞尔简化来尝试复制 Illustrator 的路径 > 简化。最有效且最像 Illustrator 的是 Philip J. Schneider 的 Graphic's 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

【讨论】:

【参考方案2】:

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

将提供的示例代码快速适应我的绘图方法会产生以下曲线:

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

我不确定 Adob​​e 正在使用哪种方法,但到目前为止,这种方法对我来说非常有用。

适应

所以,the code provided by Kris 是为 WPF 编写的,并在这方面做了一些假设。为了解决我的问题(并且因为我不想调整他的代码),我编写了以下 sn-p:

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 em>。

【讨论】:

以上是关于Adobe Illustrator 中的折线简化如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

使用Adobe Illustrator + ArcGIS绘制地图 | Map Design Using ArcGIS + Adobe Illustrator

Adobe Illustrator CS试题库带答案

Illustrator的功能和用途?

Inkscape和Adobe Illustrator哪个好?

javascript Adobe Illustrator icns导出

Adobe-illustrator11.0打开文件问题(解决后给高分)