【问题标题】:Which JavaScript library can do boolean operations with bezier curves?哪个 JavaScript 库可以对贝塞尔曲线进行布尔运算?
【发布时间】:2012-08-09 09:50:13
【问题描述】:

是否存在可以对路径(贝塞尔曲线)执行布尔运算的 Javascript 库?

我知道 Paper.js 和 Raphael.js,但现在两者都无法执行这些操作。

【问题讨论】:

标签: javascript svg html5-canvas bezier boolean-operations


【解决方案1】:

Paper.js 现在在其核心中具有布尔运算:

https://github.com/paperjs/paper.js/blob/master/src/path/PathItem.Boolean.js

在这里您可以看到正在执行的操作:

http://assets.paperjs.org/boolean/

【讨论】:

  • 我试过了,联合两个圆圈已经显示出一些重大错误。
  • @IanTerrell 从那以后我们对布尔运算进行了相当大的改进。但是,如果您遇到错误,最好能报告它们,以便我们修复它们。
  • @NicholasKyriakides paper.js 使用贝塞尔粗线裁剪算法来检测路径交叉点,因此执行速度非常快。我们已经对我们的方法进行了大量测试,发现它非常可靠。请注意,在多边形(仅由线组成)和实际贝塞尔路径上执行此类操作之间存在很大差异。 Paper.js 保留了 bezier 路径,并且不要求您将路径转换为多边形而损失精度。
  • 我们使用浮点数,并解决健壮性问题。我们目前正在实施一种基于缠绕方向的新方法,正如 Cary Clark 在这段视频中所概述的那样:“Skia Path Ops: High Performance Set Operations for Geometry”,youtube.com/watch?v=OmfliNQsk88
  • @NicholasKyriakides 我们正在努力,应该很快准备好!
【解决方案2】:

如果您将路径转换为多边形(例如,使用 pathelement.getPointAtLength()),那么您可以使用 Javascript Clipper,它是流行的 Angus Johnson 的 Clipper 库的 javascript 端口。

这是一个Difference的例子,但Union, Intersect and Xor也是可能的:

Javascript Clipper的页面是here

如果getPointAtLength()给出的点太多,Javascript Clipper有一个函数ClipperLib.Lighten(),可以显着减少点数。

该库还支持多边形偏移。请参阅live demo


编辑:经过测试,我可以确认 pathelement.getPointAtLength() 最适合例如。命中测试,但在这种情况下对多边形化不太好,因为它产生的点太少或太多,并且没有考虑曲率。事实上,紧曲线需要更多点,而松曲线需要更少。更好的是将所有路径段转换为三次曲线并使用一些自适应算法来多边形化曲线。我已经进行了一些测试,可能很快就会介绍一种更好的多边形化方法。

编辑:我已经设法实现了 SVG 路径多边形化功能,它可以处理所有类型的路径并且还可以展平变换。在测试了数千个随机生成的路径和转换之后,它似乎是可靠的。此外,所有可能的退化情况(曲线共线或某些点相同)都可以毫无问题地处理。尽管它已经比本机 getPointAtLength() 快很多倍且更精确,同时产生的点数要少得多,但该过程还有使用例如提高速度的空间。出租车角度而不是 atan2() 并通过删除所有 DOM 方法使代码与 Web Workers 完全兼容。我想在发布之前让它 100% 没有错误。它的理想用例是例如。可以对生成的多边形进行布尔运算。

【讨论】:

    【解决方案3】:

    具有相交函数的 PaperJS 布尔运算示例

    我们可以使用 PaperJS 布尔运算来做到这一点,它可以使用 SVG 路径(包括贝塞尔曲线路径)进行操作。

    PaperJS 有 5 种不同的布尔运算:excludesubtractuniteintersectdivide。你可以看到所有这些例子here

    该操作也是同名函数,返回item对象,该对象具有exportSVG()函数。它返回 true SVG Path element,它具有两条路径相交的新形状。它非常有用——您可以获取路径属性 d 的值,或者您可以将此路径元素附加到新的 SVG 元素。

    paper.install(window);
    window.onload = function()
    {
        paper.setup('canvas');
    
        var p1 = 'M 24.379464,51.504463 23.434524,23.156249 38.742559,12.572916 c 0,0 29.860118,-9.0714281 17.00893,0.755953 -12.851191,9.82738 13.229166,19.465774 13.229166,19.465774 z',
            p2 = 'm 32.883928,0.28869028 c 0,0 -15.686011,1.51190452 -8.504463,7.18154712 7.181546,5.6696426 50.270836,30.0491076 26.458332,42.3333336 -23.8125,12.284226 47.058036,14.174107 47.058036,14.174107 z',
            path1 = new Path(p1),
            path2 = new Path(p2);
    
        path1.fillColor = 'rgba(255,0,0,.5)';
        path1.position = new Point(25, 25);
    
        path2.fillColor = 'rgba(0,255,0,.5)';
        path2.position = new Point(40, 25);
        
        var result = path2.intersect(path1);
        result.selected = true;
        result.fillColor = '#77f';
    
        //exportSVG() docu: http://paperjs.org/reference/item/#exportsvg
        var svgPathElement = result.exportSVG(),
            dPath = svgPathElement.getAttribute('d');
        
        document.querySelector('path').setAttribute('d', dPath);
    
        var output = document.querySelector('#output');
        output.innerHTML = '<pre><b>D value from path:</b> ' + dPath + '</pre>';
        output.innerHTML += '<xmp>HTML string of path: ' + svgPathElement.outerHTML + '</xmp>';
    };
    table
    {
        margin-left:14px;
        padding-left:14px;
        border-left:1px solid gray;
        display:inline-block
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.0/paper-full.min.js"></script>
    
    <canvas id="canvas" width="75" height="75" resize></canvas>
    <table><tr><td><b>Our new shape of both paths intersection in separate SVG:</b></td></tr>
    <tr><td>
        <svg width="75" height="75" viewBox="0 0 75 75">
        <path fill="rgba(0,0,255,.5)" d=""/>
        </svg>
    </td></tr></table>
    
    <div id="output"></div>

    有用的链接:

    【讨论】:

      【解决方案4】:

      【讨论】:

        【解决方案5】:

        有一个用于 raphael.js 的插件提供此功能 - https://github.com/poilu/raphael-boolean

        【讨论】:

          猜你喜欢
          • 2014-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-10
          • 2011-08-03
          • 2013-01-21
          相关资源
          最近更新 更多