简体   繁体   English

2 条 SVG 路径的交集

[英]Intersection of 2 SVG Paths

I need to check if two SVG Path elements intersect.我需要检查两个 SVG Path 元素是否相交。 Checking for intersection of the bounding boxes with .getBBox() is too inaccurate.检查边界框与.getBBox()交集太不准确了。 What I'm currently doing is iterating both paths with .getTotalLength() and then checking if two points .getPointAtLength() are equal.我目前正在做的是用.getTotalLength()迭代两条路径,然后检查两个点.getPointAtLength()是否相等。

Below is a snippet, but as you can see this is very slow and blocks the browser tab.下面是一个片段,但正如您所看到的,这非常慢并且会阻止浏览器选项卡。 There must be a more efficient method to check for intersections between two paths.必须有一种更有效的方法来检查两条路径之间的交叉点。

 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>

You can use an existing library to do this: https://github.com/signavio/svg-intersections您可以使用现有的库来执行此操作: https : //github.com/signavio/svg-intersections

It calculates the intersections mathematically rather than iteratively so the performance shouldn't degrade with very long paths.它以数学方式而不是迭代方式计算交点,因此性能不应因路径很长而降低。

I'm not sure but it may be possible to solve this mathematically if you could extract the vectors and curves from the paths.我不确定,但如果您可以从路径中提取向量和曲线,则有可能从数学上解决这个问题。 However, your function can be optimized by caching the points from one path, and reducing the number of calls to getTotalLength and getPointAtLength .但是,您可以通过缓存一条路径中的点并减少对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;
            }
       }
    }
}

This can calculate the example paths in around 0.07 seconds instead of 4-5 seconds.这可以在大约 0.07 秒而不是 4-5 秒内计算示例路径。

jsfiddle提琴手

time 0.027s时间 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