如何获得中风的轮廓?

时间:2012-11-30 10:59:11

标签: svg raphael d3.js vector-graphics

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

这条线只是一条简单的曲线,一系列坐标。我可以将这条线渲染成一条路径,然后给它一个特定厚度的笔划......但我试图得到一个填充的形状而不是一条描边线,这样我就可以对它进行进一步的修改,比如翘曲它,所以产生的“笔划”可能会有所不同的厚度或者从它上面切出自定义位(据我所知,这些东西都不可能用真正的SVG笔划)。

所以我试图将一条线手动“加厚”成一个坚固的形状。我找不到任何这样做的功能 - 我查看了D3.jsRaphaël的文档,但没有运气。有没有人知道会这样做的库/函数?

或者,甚至更好:如果有人能够向我解释关于我将如何手动执行此任务的几何理论,通过获取我所拥有的线坐标列表并找出一条有效“抚摸”它的新路径,那就是太神奇了。换句话说,浏览器在你告诉它描述一条路径时会做什么 - 它如何解决笔画应该是什么形状?

3 个答案:

答案 0 :(得分:3)

最近出现了类似的问题: svg: generate 'outline path'

总而言之,这是一项非常重要的任务。正如我对链接问题的回答中所提到的,PostScript有一个生成路径的命令,这些路径产生与笔划基本相同的输出,称为strokepath。如果你看一下当你运行我在链接问题上发布的代码时Ghostscript吐出的内容,那就非常难看了。甚至Inkscape也没有真正做好。我刚试过Path => Inkscape中的大纲笔画(我认为这就是英文字幕应该说的),而且出来的内容与描边路径看起来并不相同。

“最简单”的情况是,如果您只有非自相交的折线,多边形或不包含曲线的路径,因为通常情况下,您无法在右侧绘制精确的“平行”Bézier曲线左边是一条非平凡的Bézier曲线,它可以划定描边区域 - 它在数学上是不存在的。所以你必须以某种方式近似它。对于直线段,可以比较容易地找到精确的解决方案。

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

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

很抱歉,如果我对此造成很多困惑,可能没什么帮助。

答案 1 :(得分:1)

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

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

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

我很遗憾地说,整合这段代码非常困难,但我已成功使用它,而且运行良好。

答案 2 :(得分:1)

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

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

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

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

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

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

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