确定复合贝塞尔曲线中 solids/holes 的算法

Algorithm for determining solids/holes in a compound Bezier shape

我正在使用 nanovg library to render a compound Bezier shape, but the nanosvg 库没有告诉我缠绕方向,也就是复合形状中每个子路径的 solidity/hole-ness。

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

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

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

确定交叉点的数量:不要尝试一次对子路径执行此操作,而是单独考虑每个路径段。大多数人的计数为零,这很好。 This library has for example a function 用于计算三次贝塞尔曲线和直线之间的交点。看源码,文档很齐全。 (虽然不太清楚作者对版权持何种立场。)

确定路径方向:你只需要确定线段的起点和终点是在你的射线的左边还是右边。

  • 如果两者都在同一侧,则从左到右数一个,从右到左数一个。 (非零规则:0,偶数规则:+2)
  • 如果起点在左而终点在右,则从左到右数一个 (+1),或者,对于具有三个交叉点的立方贝塞尔曲线,从左到右数两个和一个右到左。 (非零规则:+1,偶数规则:+3)
  • 如果起点在右,终点在左,一次交叉(非零规则:-1,evenodd规则:+1)或三交叉(非零规则:-1,evenodd规则:+3) )
  • 如果光线只在一个段点穿过子路径,你必须避免计算两次交叉。避免错误的最佳方法是将这两个部分当作一个部分来处理,从增加的交叉点数中减去一个,并仅针对总 start/end 点确定一侧。

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