2017-12-20 6 views
1

Alle,D3 Kraft Kollisionserkennung für Ellipsen

Ich weiß, es gibt viele Beispiele für D3.js Kollisionserkennung für Kreise und Rechtecke.

Ich versuche Kraft Simulation von Ellipsenknoten zu tun.

Ich versuchte folgenden Ausschnitt, der ursprünglich für Rechtecke ist, aber es ist nicht perfekt.

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>

Es gibt zu viele Lücken zwischen den Knoten, und ich weiß, es ist, weil Ellipsen als Rechtecke in der Kollisionserkennung behandelt werden.

Wer hat eine gute Lösung dafür?

Danke, im Voraus.

Antwort

0

Ich habe das selbst herausgefunden.

Hier ist die Kollisionserkennungsbibliothek für d3.

ellipse-collision-detection

Ich habe angebracht Beispiel in dem oben Repository arbeiten.

Danke!

Verwandte Themen