11

我想将描边路径转换为填充对象。(以编程方式,在 JavaScript 中。)

这条线只是一条简单的曲线,一个坐标序列。我可以将这条线渲染为一条路径,并给它一个一定厚度的笔触......但我试图获得一个填充的形状而不是一条笔触线,这样我就可以对其进行进一步的修改,例如翘曲它,因此生成的“笔画”可能会在粗细上有所不同,或者会从其中切出自定义位(据我所知,这些东西都不适用于真正的 SVG 笔画)。

所以我试图手动将一条线“加厚”成一个实心形状。我找不到执行此操作的任何函数——我查看了D3.jsRaphaël的文档,但没有运气。有谁知道可以做到这一点的库/函数?

或者,甚至更好:如果有人可以向我解释我将如何手动完成这项任务的几何理论,通过获取我拥有的线坐标列表并制定一条有效“抚摸”它的新路径,那将是惊人的。换句话说,当您告诉浏览器描边路径时,浏览器会做什么——它是如何计算出描边应该是什么形状的?

4

3 回答 3

4

最近有一个类似的问题: svg: generate 'outline path'

总而言之,这是一项不平凡的任务。正如我在对链接问题的回答中所提到的,PostScript 有一个用于生成路径的命令,该命令生成的输出与笔画基本相同,称为strokepath. 如果您在运行我在链接问题中发布的代码时查看 Ghostscript 吐出的内容,那会非常难看。甚至 Inkscape 也做得不好。我刚刚在 Inkscape 中尝试了 Path => Outline stroke (我认为这就是英文字幕应该说的),结果看起来与描边路径并不相同。

“最简单”的情况是,如果您只有非自相交的折线、多边形或不包含曲线的路径,因为一般情况下,您无法在 a 的右侧和左侧绘制精确的“平行”贝塞尔曲线将划定描边区域的非平凡贝塞尔曲线 - 它在数学上不存在。因此,您必须以一种或另一种方式对其进行近似。对于直线段,可以比较容易地找到精确解。

渲染带有曲线/圆弧的矢量路径的经典方法是使用足够平滑的折线来近似所有内容。De Casteljau 算法通常用于将贝塞尔曲线转换为线段。(这也是strokepath在 Ghostscript 中使用命令时出现的基本情况。)然后您可以找到分隔平行线段,但必须使用适当的 linejoin 和 miterlimit 规则正确连接它们。当然,不要忘记线帽。

我认为自相交路径可能会很棘手,因为您可能会在路径内部得到空心区域,即黑色路径的“交叉区域”可能会变成白色。使用非零缠绕规则时,这可能不是开放路径的问题,但我会对此保持谨慎。对于封闭路径,您可能需要两条“分隔”路径以相反的方向运行。但我现在不确定这是否真的涵盖了所有潜在的陷阱。

抱歉,如果我对此造成了很多困惑,也许并没有太大帮助。

于 2012-11-30T12:50:23.373 回答
2

这个页面有一个相当不错的关于贝塞尔曲线的教程,一般来说有一个关于偏移曲线的很好的部分。

http://pomax.github.io/bezierinfo/

可以在这里找到一种不太精确但可能更快的方法。

http://seant23.wordpress.com/2010/11/12/offset-bezier-curves/

没有数学答案,因为平行于贝塞尔曲线的曲线通常不是贝塞尔曲线。大多数方法都有退化的情况,尤其是在处理一系列曲线时。

把一条简单的曲线想象成一条没有问题点的曲线。没有尖点,没有环,没有拐点,理想情况下是严格增加的曲率。将所有起始曲线切成这些简单的曲线。找出这些简单曲线的所有偏移曲线。将所有偏移曲线重新放在一起处理间隙和交叉点。如果您可以选择使用二次曲线,则它们会更容易处理。

我认为大多数浏览器都会做一些类似于 processingjs 的事情,因为即使使用二次曲线,它们也会出现退化的情况。例如,看曲线 200,300 719,301 500,300 的厚度为 100 或更多。

于 2012-12-28T11:21:26.073 回答
1

标准方法是 Tiller-Hanson 算法(二维轮廓的偏移量,1984 年,令人恼火的是它不是免费在线的),它创建了一个很好的近似值。这个想法是,因为每条贝塞尔曲线的控制点都位于与曲线的起点和终点相切的线上,所以平行曲线将具有相同的属性。所以我们偏移曲线的起点和终点,然后使用这些交点找到新的控制点。但是,这对于尖锐的曲线会产生非常糟糕的结果,因此第一步是将原始曲线一分为二,这对贝塞尔曲线很容易做到,直到它转过一个足够小的角度。

需要其他改进来处理(i)平行线之间的交叉点,在每个顶点的内部;(ii) 插入圆弧以填充每个顶点外侧的间隙;(iii) 添加端盖 - 方形、对接或圆形。

Tiller-Hanson 很难实现,但是 FreeType 库中有一个很好的开源实现,在 ftstroke.c (http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/基础/ftstroke.c)。

很抱歉,集成此代码可能相当困难,但我已经成功使用它,并且效果很好。

于 2012-12-22T18:17:10.570 回答