【问题标题】:Algorithm for determining solids/holes in a compound Bezier shape确定复合贝塞尔形状中的实体/孔洞的算法
【发布时间】:2017-09-19 21:44:14
【问题描述】:

我正在使用nanovg 库来渲染复合贝塞尔形状,但nanosvg 库并没有告诉我缠绕方向,也就是复合形状中每个子路径的坚固性/孔度。

假设所有路径都不相交,在给定子路径的 Bezier 点的情况下,有什么数学算法可以告诉我哪个子路径是实心的,哪个是洞?

我可以计算每个子路径的面积,按面积排序,并在实体和孔之间进行选择,但这仅在路径形成子集链时才有效,因此无法绘制这种复合形状。

【问题讨论】:

  • 技术说明:“贝塞尔多边形”不存在。多边形是由直线部分组成的路径,而贝塞尔曲线是曲线。这可能是吹毛求疵,但您要问的是技术主题,因此正确使用术语会带来很大的不同。至于“有算法吗?”答案取决于您的图书馆。一些库将顺时针/逆时针视为填充/剪切,一些库坚持“相反方向意味着相反的填充规则”。但是,没有算法可以告诉您必须完全基于路径填充/剪切什么,因为这不是路径的属性。
  • @Mike'Pomax'Kamermans 不错的收获,谢谢。还添加了所有路径不相交的假设,所以我相信现在应该明确定义。 nanovg 恰好将 CCW 视为填充,CW 视为切口。
  • 你能指定svg填充规则吗?如果是这样,请将其设置为偶数/奇数,这样就可以解决问题,而无需您做任何工作。如果没有,请在 nanosvg 生成文件之后使用辅助实用程序(甚至是字符串替换)进行设置。
  • 为什么不将 SVG 添加为代码,这样我们才能看到你真正得到了什么(遗憾的是 SO/SE 不支持 SVG 和 PCX 图像)。

标签: svg graphics bezier


【解决方案1】:

该算法是 SVG fill-rule 定义中描述的算法。从一个点开始,绘制一条任意射线到无穷远(嗯,一条在您需要考虑的区域之外结束的线),并使用 nonzeroevenodd 两种方法之一计算路径交叉点 描述。

确定交叉次数:不要尝试一次性对子路径执行此操作,而是单独考虑每个路径段。大多数人的计数为零,这很好。 This library 具有例如 function 用于计算三次贝塞尔曲线和直线之间的交点。查看源代码,它有据可查。 (虽然作者对版权持何种立场还不是很清楚。)

确定路径方向:您只需要确定线段的起点和终点是光线的左侧还是右侧。

  • 如果两者都在同一侧,则从左到右计数一个,从右到左计数一个。 (非零规则:0,偶数规则:+2)
  • 如果起点在左侧,终点在右侧,则从左到右计数一个 (+1),或者,对于具有三个交叉点的三次贝塞尔曲线,从左到右计数两个,从右计数一个 -向左。 (非零规则:+1,偶数规则:+3)
  • 如果起点在右,终点在左,则为一个交叉点(非零规则:-1,偶数规则:+1)或三个交叉点(非零规则:-1,偶数规则:+3)
  • 如果光线仅在段点处穿过子路径,则必须避免计算两次交叉。避免错误的最佳方法是将两个段视为一个,从添加的交叉点数中减去一个,并仅确定总体起点/终点的边。

最后,对于非零,如果最终计数不为零,则一个点在里面。对于 evenodd,如果最终计数总数为奇数,则它在里面。

【讨论】:

  • 谢谢!一旦三次求解器不碍事,这比我想象的要优雅。
猜你喜欢
  • 1970-01-01
  • 2015-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多