返回

四叉树 + D3:碰撞检测和数据可视化中的强大组合

前端

四叉树实现 2D 碰撞检测与 D3 概览

四叉树回顾与 2D 碰撞检测

四叉树是一种空间分割数据结构,在二维空间中,它将区域划分为四个象限(西北、东北、西南、东南)。这对于处理大量的点集合很有用,例如实现碰撞检测。

实现 2D 碰撞检测的步骤如下:

  1. 创建一个根四叉树节点,它包含所有点。
  2. 对于每个点:
    • 如果点落在根节点中,则将其添加到该节点。
    • 否则,找到点落入的象限,并在该象限的子节点中插入该点。
  3. 当检查两个点是否发生碰撞时,从根节点开始:
    • 如果两个点都落在同一个子节点中,则检查它们是否重叠。
    • 否则,继续检查每个象限的子节点,直到找到它们重叠的子节点。

D3 简单分析

D3.js 是一款流行的 JavaScript 库,用于使用 HTML、SVG 和 CSS 创建交互式数据可视化。

D3 具有许多强大的功能,包括:

  • 数据绑定:将数据与 DOM 元素相关联。
  • 选择器:查找和操作 DOM 元素。
  • 过渡和动画:创建平滑的动画和过渡。
  • 缩放和拖动:启用图表和可视化的交互。

应用示例

下面是一个示例,展示了如何使用四叉树来检测 2D 碰撞:

class QuadTree {
  constructor(bounds) {
    this.bounds = bounds;
    this.points = [];
    this.children = [];
  }

  insert(point) {
    if (!this.bounds.contains(point)) return;

    if (this.children.length === 0) {
      this.points.push(point);

      if (this.points.length > MAX_POINTS) {
        this.subdivide();
      }
    } else {
      for (let child of this.children) {
        child.insert(point);
      }
    }
  }

  query(bounds) {
    const result = [];

    if (!this.bounds.intersects(bounds)) return result;

    if (this.children.length === 0) {
      result.push(...this.points);
    } else {
      for (let child of this.children) {
        result.push(...child.query(bounds));
      }
    }

    return result;
  }

  subdivide() {
    const { x, y, width, height } = this.bounds;

    this.children = [
      new QuadTree({ x, y, width: width / 2, height: height / 2 }),
      new QuadTree({ x: x + width / 2, y, width: width / 2, height: height / 2 }),
      new QuadTree({ x, y: y + height / 2, width: width / 2, height: height / 2 }),
      new QuadTree({ x: x + width / 2, y: y + height / 2, width: width / 2, height: height / 2 }),
    ];

    for (let point of this.points) {
      this.insert(point);
    }

    this.points = [];
  }
}

// 使用 D3 创建一个 SVG 画布
const svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

// 创建一个四叉树来存储点
const quadTree = new QuadTree({ x: 0, y: 0, width, height });

// 生成随机点并插入四叉树
for (let i = 0; i < numPoints; i++) {
  const x = Math.random() * width;
  const y = Math.random() * height;
  quadTree.insert({ x, y });
}

// 为每个点创建一个圆圈
svg
  .selectAll("circle")
  .data(quadTree.points)
  .enter()
  .append("circle")
  .attr("cx", d => d.x)
  .attr("cy", d => d.y)
  .attr("r", 5);

// 当鼠标移动时,检测碰撞
svg.on("mousemove", function() {
  const mouseX = d3.mouse(this)[0];
  const mouseY = d3.mouse(this)[1];

  const bounds = { x: mouseX - 5, y: mouseY - 5, width: 10, height: 10 };

  // 从四叉树中查询所有与鼠标边界相交的点
  const collidingPoints = quadTree.query(bounds);

  // 更改与鼠标相交点的颜色
  svg
    .selectAll("circle")
    .filter(d => collidingPoints.includes(d))
    .attr("fill", "red")
    .attr("stroke", "black")
    .attr("stroke-width", 2);
});

结论

四叉树在实现 2D 碰撞检测方面非常有用,而 D3.js 提供了强大的工具来可视化和交互数据。通过结合这两个库,可以创建高效且交互式的数据可视化。