{
  "lead": "把平面上的一堆点连成三角形有无数种方法，Delaunay 三角剖分是其中「最匀称」的一种：任何一个三角形的外接圆里都没有其他点。它会尽量避免细长的三角形，因此广泛用于地形建模、有限元网格和插值。它的对偶图是 Voronoi 图：把平面划分成若干区域，每个区域里的位置离某一个点最近。页面上鼠标悬停时显示的圆就是外接圆，你会发现圆里总是空的。",
  "formulas": [
    [
      "∀ 三角形 T，∀ 点 p ∉ T：|p − c<sub>T</sub>| ≥ r<sub>T</sub>",
      "空外接圆性质：c、r 是三角形的外接圆圆心和半径"
    ],
    [
      "Voronoi 边 = 相邻两个三角形外心的连线",
      "外心到三个顶点等距，所以正好在三块 Voronoi 区域的交界处"
    ]
  ],
  "terms": [
    [
      "Bowyer-Watson 增量算法",
      "每次加入一个点：找出所有外接圆包含这个点的三角形，把它们删掉，会留下一个多边形空洞（可以证明这些三角形连成一片），再把空洞的每条边与新点相连，形成新的三角形。每一步之后，空外接圆性质依然成立。"
    ],
    [
      "无穷远顶点",
      "算法需要一个「包住所有点」的起点。常见做法是先放一个巨大的超级三角形，但它的顶点只是「很远」而不是真正无穷远，凸包边附近偶尔会漏掉很扁的三角形（测试里正好遇到过）。这里改用一个无穷远顶点：每条凸包边外侧挂一个「幽灵三角形」，它的外接圆严格等于这条边外侧的半平面，于是凸包边也能精确处理。所有点共线时还构不成三角形，就先暂存，等出现第一个不共线的点再开始。"
    ],
    [
      "Voronoi 图",
      "共享一条边的两个三角形，把它们的外心连起来，就是一条 Voronoi 边；凸包边上只有一个三角形，就从外心向外画一条射线。"
    ],
    [
      "低多边形艺术",
      "先用 Sobel 算子求出图片每个像素的边缘强度，按「均匀 + 边缘强度」的权重随机撒点，边缘处的点更密，再加上图片四周的点。剖分完后，每个三角形用它覆盖的所有像素的平均色填充。「边缘权重」越大，点越集中在轮廓上，形状越清楚。"
    ]
  ],
  "flow": [
    [
      "js",
      "点击时调用 <code>dl_add(x, y)</code>，随机撒点调用 <code>dl_random(n)</code>；悬停时用 <code>dl_find</code> 找到所在的三角形，<code>dl_circumcircle</code> 取它的外接圆。"
    ],
    [
      "rust",
      "Rust 维护三角网，每加一个点做一次 Bowyer-Watson 更新；<code>dl_triangles()</code>、<code>dl_voronoi()</code> 返回三角形和 Voronoi 线段。低多边形模式由 <code>dl_lowpoly(像素, 宽, 高, 点数, 种子, 边缘权重)</code> 一次完成撒点、剖分和上色，返回新图片。"
    ],
    [
      "js",
      "JS 用 Canvas 画出三角形、Voronoi 线段和外接圆。"
    ]
  ],
  "perf": [
    "实测（Node 中运行同一个 WASM）：500 个点 3.7ms，2000 个点 26ms，5000 个点 144ms；Voronoi 图 1~2ms；把 800×560 的图片做成 1200 个点的低多边形约 50ms。",
    "这里寻找「外接圆包含新点的三角形」时直接检查所有三角形，所以总耗时是 O(n²)，点数加倍耗时约变成 4 倍。更快的实现会从上一个三角形出发沿着网格「走」到新点附近，只检查局部，整体接近 O(n log n)。",
    "测试检查了空外接圆性质、三角形方向、欧拉公式（三角形数 = 2n − 2 − 凸包点数，50 组随机点）、共圆的网格点和共线点。"
  ],
  "src": [
    [
      "crates/algorithms/delaunay/src/mesh.rs",
      ""
    ],
    [
      "www/delaunay/index.js",
      ""
    ]
  ]
}
