2017-12-20 14 views
1

すべて、楕円のD3強制衝突検出

円と矩形のD3.js衝突検出の例はたくさんあります。

私は楕円ノードの強制的なシミュレーションをしようとしています。

私はもともと長方形のスニペットを試しましたが、完璧ではありません。

var width = 960, 
 
    height = 500, 
 
    minSize = 10, 
 
    maxSize = 30; 
 

 
var n = 20, 
 
    m = 10; 
 

 
var color = d3.scaleOrdinal(d3.schemeCategory10) 
 
    .domain(d3.range(m)); 
 

 
var nodes = d3.range(n).map(function() { 
 
    var c = Math.floor(Math.random() * m), 
 
     rx = Math.sqrt((c + 1)/m * -Math.log(Math.random())) * (maxSize - minSize) + minSize, 
 
     ry = Math.sqrt((c + 1)/m * -Math.log(Math.random())) * (maxSize - minSize) + minSize, 
 
     d = {color: c, rx: rx, ry: ry}; 
 
    return d; 
 
}); 
 

 
var collide = function(alpha) { 
 
    var quadtree = d3.quadtree() 
 
      .x((d) => d.x) 
 
      .y((d) => d.y) 
 
      .addAll(nodes); 
 

 
     nodes.forEach((d) => { 
 
     quadtree.visit((quad, x0, y0, x1, y1) => { 
 
      let updated = false; 
 

 
      if (quad.data && (quad.data !== d)) { 
 
      let x = d.x - quad.data.x, 
 
       y = d.y - quad.data.y, 
 
       xSpacing = (quad.data.rx + d.rx), 
 
       ySpacing = (quad.data.ry + d.ry), 
 
       absX = Math.abs(x), 
 
       absY = Math.abs(y), 
 
       l, lx, ly; 
 

 
      if (absX < xSpacing && absY < ySpacing) { 
 
       l = Math.sqrt(x * x + y * y); 
 

 
       lx = (absX - xSpacing)/l * alpha; 
 
       ly = (absY - ySpacing)/l * alpha; 
 

 
       if (Math.abs(lx) > Math.abs(ly)) { 
 
       lx = 0; 
 
       } else { 
 
       ly = 0; 
 
       } 
 

 
       d.x -= x *= lx; 
 
       d.y -= y *= ly; 
 
       quad.data.x += x; 
 
       quad.data.y += y; 
 

 
       updated = true; 
 
      } 
 
      } 
 
      return updated; 
 
     }); 
 
     }); 
 
}; 
 
var force = d3.forceSimulation() 
 
    .nodes(nodes) 
 
    .force("center", d3.forceCenter()) 
 
    .force("collide", (alpha) => collide(alpha)) 
 
    .force("x", d3.forceX().strength(.01)) 
 
    .force("y", d3.forceY().strength(.01)) 
 
    .on("tick", tick); 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", width) 
 
    .attr("height", height) 
 
    .append('g') 
 
    .attr('transform', 'translate(' + width/2 + ',' + height/2 + ')'); 
 

 
var ellipse = svg.selectAll("ellipse") 
 
    .data(nodes) 
 
    .enter().append("ellipse") 
 
    .attr("rx", function(d) { return d.rx; }) 
 
    .attr("ry", function(d) { return d.ry; }) 
 
    .style("fill", function(d) { return color(d.color); }) 
 
    .call(d3.drag() 
 
     .on("start", dragstarted) 
 
     .on("drag", dragged) 
 
     .on("end", dragended)); 
 

 
function tick() { 
 
    ellipse 
 
     .attr("cx", function(d) { return d.x; }) 
 
     .attr("cy", function(d) { return d.y; }); 
 
} 
 

 
function dragstarted(d) { 
 
    if (!d3.event.active) force.alphaTarget(0.3).restart(); 
 
    d.x = d.x; 
 
    d.y = d.y; 
 
} 
 

 
function dragged(d) { 
 
    d.x = d3.event.x; 
 
    d.y = d3.event.y; 
 
} 
 

 
function dragended(d) { 
 
    if (!d3.event.active) force.alphaTarget(0); 
 
    d.x = d3.event.x; 
 
    d.y = d3.event.y; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script>

は、ノード間の、あまりにも多くのギャップがあり、私は楕円の衝突検出で四角形として扱われるので、それは知っています。

これには良い解決策がありますか?

ありがとうございます。

答えて

0

私はこれを自分で考え出しました。

ここには、d3の衝突検出ライブラリがあります。

ellipse-collision-detection

私は上記のリポジトリに実施例を添付しました。

ありがとうございます!