从线段生成晶格图

Generating a lattice graph from line segments

提问人:George Reith 提问时间:11/9/2023 最后编辑:George Reith 更新时间:11/10/2023 访问量:37

问:

我有两个矩形,我试图在它们之间找到一条视觉上令人愉悦的纯直线路线。

为此,我想生成以下格子/网格作为图形结构(连接到其他顶点的顶点列表),以便我可以在其上运行像 Djikstra 这样的寻路算法:

Example lattice graph

这是通过填充每个矩形以获得一个新矩形(上面的红色和蓝色)来获得的,并取这些新矩形的边界框(绿色)。然后从矩形每边的中心投射光线,并细分这些矩形接触的线条。

但是,我在研究如何以有效的方式将此晶格生成为图形结构时遇到了麻烦。

理想情况下,我正在寻找一种算法和数据结构,使我能够逐条线段构建图形线段,将现有线段(边)细分为新线段相交的地方。

网格 寻路线 数学格子

评论


答:

0赞 George Reith 11/10/2023 #1

我通过以不同的方式解决这个问题找到了解决方案。我没有用线思考,而是从线的起点和终点以及它们的交叉点收集了所有点。

然后,我将每个唯一点作为节点添加到图形中。

然后,我为我所有节点中所有唯一的 X 值中的每一个都做了一个集合,并为 Y 值做了另一个集合。

我按升序对这些集合进行了排序。

然后,我遍历了 X 和 Y 值的每个可能组合(搜索空间很小,因为创建交点的所有线都是正交的)。

当我找到一个节点时,我向后迭代 X 值,直到我命中另一个节点并链接它们,然后对 Y 值执行相同的操作。

这是我生成的代码:

function pointId(x: number, y: number) {
  return `${x},${y}`;
}

function pointsToGraph(points: Point[]) {
  const xValues: Set<number> = new Set();
  const yValues: Set<number> = new Set();
  const graph = createGraph<{ point: Point }>();

  points.forEach((point) => {
    const [x, y] = point;
    xValues.add(x);
    yValues.add(y);
    graph.addNode(pointId(x, y), { point });
  });

  const sortedXValues = Array.from(xValues).sort((a, b) => a - b);
  const sortedYValues = Array.from(yValues).sort((a, b) => a - b);
  for (let i = 0; i < sortedYValues.length; i++) {
    for (let j = 0; j < sortedXValues.length; j++) {
      const x = sortedXValues[j];
      const y = sortedYValues[i];
      const currentId = pointId(x, y);
      // eslint-disable-next-line no-continue
      if (!graph.hasNode(currentId)) continue;

      for (let k = j - 1; k >= 0; k--) {
        const previousXId = pointId(sortedXValues[k], y);
        if (graph.hasNode(previousXId)) {
          graph.addLink(previousXId, currentId);
          break;
        }
      }

      for (let k = i - 1; k >= 0; k--) {
        const previousYId = pointId(x, sortedYValues[k]);
        if (graph.hasNode(previousYId)) {
          graph.addLink(previousYId, currentId);
          break;
        }
      }
    }
  }

  return graph;
}