繁体   English   中英

2 条 SVG 路径的交集

[英]Intersection of 2 SVG Paths

我需要检查两个 SVG Path 元素是否相交。 检查边界框与.getBBox()交集太不准确了。 我目前正在做的是用.getTotalLength()迭代两条路径,然后检查两个点.getPointAtLength()是否相等。

下面是一个片段,但正如您所看到的,这非常慢并且会阻止浏览器选项卡。 必须有一种更有效的方法来检查两条路径之间的交叉点。

 var path1 = document.getElementById("p1"); var path2 = document.getElementById("p2"); var time = document.getElementById("time"); var btn = document.getElementById("start"); btn.addEventListener("click", getIntersection); function getIntersection() { var start = Date.now(); for (var i = 0; i < path1.getTotalLength(); i++) { for (var j = 0; j < path2.getTotalLength(); j++) { var point1 = path1.getPointAtLength(i); var point2 = path2.getPointAtLength(j); if (pointIntersect(point1, point2)) { var end = Date.now(); time.innerHTML = (end - start) / 1000 + "s"; return; } } } } function pointIntersect(p1, p2) { p1.x = Math.round(p1.x); p1.y = Math.round(p1.y); p2.x = Math.round(p2.x); p2.y = Math.round(p2.y); return p1.x === p2.x && p1.y === p2.y; }
 svg { fill: none; stroke: black; } #start { border: 1px solid; display: inline-block; position: absolute; }
 <div id="start">Start </div> <svg xmlns="http://www.w3.org/2000/svg"> <path d="M 50 10 c 120 120 120 120 120 20 z" id="p1"></path> <path d="M 150 10 c 120 120 120 120 120 20 z" id="p2"></path> </svg> <div id="time"></div>

您可以使用现有的库来执行此操作: https : //github.com/signavio/svg-intersections

它以数学方式而不是迭代方式计算交点,因此性能不应因路径很长而降低。

我不确定,但如果您可以从路径中提取向量和曲线,则有可能从数学上解决这个问题。 但是,您可以通过缓存一条路径中的点并减少对getTotalLengthgetPointAtLength的调用次数来优化您的函数。

function getIntersection() {
    var start = Date.now(),
    path1Length = path1.getTotalLength(),
    path2Length = path2.getTotalLength(),
    path2Points = [];

    for (var j = 0; j < path2Length; j++) {      
        path2Points.push(path2.getPointAtLength(j));
    }

    for (var i = 0; i < path1Length; i++) {  
        var point1 = path1.getPointAtLength(i);

        for (var j = 0; j < path2Points.length; j++) {
            if (pointIntersect(point1, path2Points[j])) {
                var end = Date.now();
                time.innerHTML = (end - start) / 1000 + "s";        
                return;
            }
       }
    }
}

这可以在大约 0.07 秒而不是 4-5 秒内计算示例路径。

提琴手

时间 0.027s

function getIntersection2() {
  function Intersect(p1, p2) {
    return p1.z!==p2.z && p1.x === p2.x && p1.y === p2.y;
  }
  var paths = [path1,path2];
    var start = Date.now(),
    pathLength = [path1.getTotalLength(),path2.getTotalLength()],
    pathPoints = [],
    inters = [];
 
  for (var i = 0; i < 2; i++) {  
    for (var j = 0; j < pathLength[i]; j++) {
      var p = paths[i].getPointAtLength(j);
      p.z=i;
      p.x=Math.round(p.x);
      p.y=Math.round(p.y);
      pathPoints.push(p);
    }
  }
  pathPoints.sort((a,b)=>a.x!=b.x?a.x-b.x:a.y!=b.y?a.y-b.y:0)
  // todos os pontos
  .forEach((a,i,m)=>i&&Intersect(m[i-1],a)?inters.push([a.x,a.y]):0)
  // somente o primeiro
  //.some((a,i,m)=>i&&Intersect(m[i-1],a)?inters.push([a.x,a.y]):0);
  result.innerHTML = inters;
        var end = Date.now();
        time.innerHTML = (end - start) / 1000 + "s";
        return;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM