【问题标题】:Intersection of 2 SVG Paths2 个 SVG 路径的交集
【发布时间】:2017-02-06 15:00:44
【问题描述】:

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

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

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>

【问题讨论】:

  • 不像您当前的算法那样采样数百或数千个点并检查它们是否“足够接近”,这看起来是一种更快、更可靠的方法:stackoverflow.com/a/4041286/1869660

标签: javascript svg intersection


【解决方案1】:

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

它以数学方式而非迭代方式计算交叉点,因此性能不会因路径太长而降低。

【讨论】:

    【解决方案2】:

    我不确定,但如果您可以从路径中提取向量和曲线,则可以通过数学方式解决此问题。但是,可以通过缓存一条路径中的点并减少对 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 秒内计算示例路径。

    jsfiddle

    【讨论】:

    • 我试过你的方法,也在这里做了测试:codepen.io/netsi1964/pen/yKagwx
    • 错误的结果在你的代码中试试这个&lt;div id="start"&gt;Start &lt;/div&gt; &lt;svg id="svg-element" xmlns="http://www.w3.org/2000/svg"&gt; &lt;path d="M 50 10 c 120 120 135 120 150 20 z" id="p1"&gt;&lt;/path&gt; &lt;path d="M 150 10 c 120 120 120 120 120 20 z" id="p2"&gt;&lt;/path&gt; &lt;/svg&gt; &lt;div id="time"&gt;&lt;/div&gt; &lt;div id="result"&gt;&lt;/div&gt;
    【解决方案3】:

    时间 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      • 2017-08-10
      • 1970-01-01
      • 2018-12-19
      • 1970-01-01
      • 2020-01-23
      相关资源
      最近更新 更多