使用delaunator 用三角形拟合平面圆

♀尐吖头ヾ 提交于 2021-02-14 21:31:41

原文链接: 使用delaunator 拥三角形拟合平面圆

 

https://github.com/mapbox/delaunator

 

 

对于圆环, 有些三角形是穿过中间的

计算速度确实快, 卡顿是因为canvas的绘制太慢了, 因为三角形太多了

使用也非常简单, 直接一个nx2的数组就行, 还接收getx和gety用来做坐标转换

<!DOCTYPE html>
<html>
  <head>
    <title>
      Delaunator, the fastest JavaScript library for Delaunay triangulation of
      2D points
    </title>
    <style>
      body {
        margin: 0;
        text-align: center;
        font-family: sans-serif;
      }
      canvas {
        border: 1px solid #ccc;
        position: relative;
      }
      a,
      a:visited {
        color: #09f;
      }
    </style>
  </head>
  <body>
    <h2><a href="https://github.com/mapbox/delaunator">delaunator</a> demo</h2>
    <canvas id="canvas"></canvas>

    <script src="https://unpkg.com/delaunator@4.0.1/delaunator.js"></script>
    <script>
      const points = [];
      const width = 100;
      const height = 100;
      const step = 4;
      for (let r = 0; r <= height; r += step) {
        for (let x = 0; x <= r; x++) {
          const y = (r ** 2 - x ** 2) ** 0.5;
          points.push([x, y]);
          points.push([x, -y]);
          points.push([-x, y]);
          points.push([-x, -y]);
        }
      }
      console.log(points.length);
      console.time("delaunay");
      let delaunay = Delaunator.from(points);
      console.log("===",delaunay)
      console.timeEnd("delaunay");

      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");

      let minX = Infinity;
      let minY = Infinity;
      let maxX = -Infinity;
      let maxY = -Infinity;
      for (let i = 0; i < points.length; i++) {
        const x = points[i][0];
        const y = points[i][1];
        if (x < minX) minX = x;
        if (y < minY) minY = y;
        if (x > maxX) maxX = x;
        if (y > maxY) maxY = y;
      }

      const padding = 5;
      const w = 1024;
      const h =
        ((w - 2 * padding) * (maxY - minY)) / (maxX - minX) + 2 * padding;

      canvas.style.width = w + "px";
      canvas.style.height = h + "px";

      canvas.width = w;
      canvas.height = h;

      if (window.devicePixelRatio >= 2) {
        canvas.width = w * 2;
        canvas.height = h * 2;
        ctx.scale(2, 2);
      }

      const ratio = (w - 2 * padding) / Math.max(maxX - minX, maxY - minY);

      ctx.lineJoin = "round";
      ctx.lineCap = "round";

      let updated = true;

      canvas.onmousemove = function (e) {
        points.push([
          (e.layerX - padding) / ratio + minX,
          (e.layerY - padding) / ratio + minY,
        ]);
        console.time("delaunay111");
        delaunay = Delaunator.from(points);
        console.timeEnd("delaunay111");
        console.log("delaunay222", delaunay);
        updated = true;
      };

      function getX(i) {
        return padding + ratio * (points[i][0] - minX);
      }
      function getY(i) {
        return padding + ratio * (points[i][1] - minY);
      }

      function frame() {
        requestAnimationFrame(frame);
        draw();
      }
      frame();

      function draw() {
        if (!updated) return;
        updated = false;

        ctx.clearRect(0, 0, w, h);

        const triangles = delaunay.triangles;

        ctx.beginPath();
        for (let i = 0; i < triangles.length; i += 3) {
          const p0 = triangles[i];
          const p1 = triangles[i + 1];
          const p2 = triangles[i + 2];
          ctx.moveTo(getX(p0), getY(p0));
          ctx.lineTo(getX(p1), getY(p1));
          ctx.lineTo(getX(p2), getY(p2));
          ctx.closePath();
        }
        ctx.strokeStyle = "rgba(0,200,0,1)";
        ctx.lineWidth = 0.5;
        ctx.stroke();
        // ctx.fillStyle = 'rgba(255,255,0,0.1)';
        // ctx.fill();

        ctx.beginPath();
        for (const i of delaunay.hull) {
          ctx.lineTo(getX(i), getY(i));
        }
        ctx.closePath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "red";
        ctx.stroke();

        ctx.fillStyle = "black";
        ctx.beginPath();
        for (let i = 0; i < points.length; i++) {
          ctx.rect(getX(i) - 1.5, getY(i) - 1.5, 3, 3);
        }
        ctx.fill();
      }
    </script>
  </body>
</html>

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!