椭圆的D3力碰撞检测

问题描述 投票:1回答:1

所有,

我知道圆形和矩形的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>

节点之间的间隙太多,我知道这是因为在碰撞检测中椭圆被视为矩形。

谁有一个很好的解决方案呢?

提前致谢。

d3.js collision-detection force-layout ellipse
1个回答
0
投票

我自己想出来了。

这是d3的碰撞检测库。

ellipse-collision-detection

我在上面的存储库中附加了工作示例。

谢谢!

© www.soinside.com 2019 - 2024. All rights reserved.