哪个JavaScript库可以对Bezier曲线进行布尔运算?

14

是否存在一种JavaScript库,可以对路径(贝塞尔曲线)执行布尔运算?

我知道Paper.js和Raphael.js,但现在都不能执行这些操作。


你的意思是要比较曲线并检查它们是否相等吗? - Aesthete
我指的是布尔运算,例如并集、交集和差集。也许曲线不是这个概念的正确表述,但这些操作在所有矢量图形应用程序中都是标准的,例如Adobe Illustrator或Inkscape。请看这里:http://www.angelfire.com/mi/kevincharles/inkscape/p7c4.html - philipp
那么 https://dev59.com/q3VD5IYBdhLWcg3wDG_m#3005394 呢? - wnrph
5个回答

9

1
我尝试了一下,将两个圆合并后已经显示出了一些显著的错误。 - Ian Terrell
2
@IanTerrell 自从那时起,我们已经大大改进了布尔运算。但是如果您遇到错误,报告它们会很好,这样我们就可以修复它们。 - Jürg Lehni
1
@NicholasKyriakides paper.js使用贝塞尔线段裁剪算法来检测路径交点,因此执行非常快。我们已经对我们的方法进行了大量测试,并发现它非常可靠。请注意,在多边形(仅由线段组成)和实际贝塞尔路径上执行此类操作之间存在很大差异。Paper.js保留贝塞尔路径,不需要您将路径转换为多边形以损失精度。 - Jürg Lehni
1
我们正在使用浮点数,并解决了鲁棒性问题。我们目前正在实施一种基于卷绕方向的新方法,正如Cary Clark在这个视频中所概述的:“Skia Path Ops: High Performance Set Operations for Geometry”,http://www.youtube.com/watch?v=OmfliNQsk88 - Jürg Lehni
1
@NicholasKyriakides 我们正在处理这个问题,很快就会准备好! - Jürg Lehni
显示剩余6条评论

6
如果您将路径转换为多边形(例如使用pathelement.getPointAtLength()),则可以使用Javascript Clipper,它是流行的Angus Johnson Clipper Library的JavaScript端口。
这是差异的一个例子,但也可能进行联合、相交和异或操作:Union, Intersect and Xor
Javascript Clipper的页面在这里
如果getPointAtLength()返回太多点,则Javascript Clipper具有ClipperLib.Lighten()函数,可显著减少点数。
该库还支持多边形偏移。请参见实时演示

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

编辑:我已经成功实现了SVG路径多边形化函数,它可以处理各种路径并平铺变换。在测试数千个随机生成的路径和变换时,它似乎是可靠的。而且处理了所有可能的退化情况(曲线共线或某些点相同)而没有问题。虽然它比本地getPointAtLength()快得多,精度也更高,同时生成的点数量显著减少,但该过程仍有提速的空间,例如使用出租车角度代替atan2()以及通过删除所有DOM方法使代码完全兼容Web Workers 。发布之前我想让它百分之百无错误,其理想用例是例如用生成的多边形进行布尔运算的可能性。


3

使用PaperJS交集函数的布尔运算示例

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

PaperJS有5种不同的布尔运算: exclude, subtract, unite, intersect, divide。你可以在这里看到所有这些示例。

这些运算也是同名的函数,并返回item对象,该对象具有函数exportSVG()。它返回一个true值的SVG Path元素,其形状为两个路径的交集。这非常有用 - 您可以获取路径属性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>

有用的链接:


1

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接