首页 > 解决方案 > 使用线条以编程方式绘制圆

问题描述

通过在点之间具有恒定的像素差,我如何使用线条画一个圆?

我一直在尝试编辑这个算法

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

var step = 2 * Math.PI / 22; //(22 points)
var h = 250;
var k = 250;
var r = 105;

ctx.beginPath(); //tell canvas to start a set of lines

for (var theta = 0; theta < 2 * Math.PI; theta += step) {
  var x = h + r * Math.cos(theta);
  var y = k - r * Math.sin(theta);

  ctx.lineTo(x, y);
  ctx.stroke();
}

ctx.closePath();
#myCanvas {
  border: thin solid grey;
}
<canvas id="myCanvas" width="500px" height="500px"></canvas>

该算法绘制一个有 22 个点的圆。我如何更改此算法以使两点之间的像素差始终是一个值,例如每个点之间的 50 个像素?

标签: javascriptalgorithmgeometry

解决方案


如果您希望点之间的距离保持一致,您可以在给定点数(又名边)和您希望点彼此分开的距离的情况下计算半径。

x = (distance / 2) / sine(step / 2)

示例图像

const sides = 3;
const distance = 100;
const step = Math.PI * 2 / sides;
const radius = (distance / 2) / Math.sin(step / 2); // 57.735

演示

在下面的示例中,绘制了八个(奇边)多边形,每个相邻点彼此相距 50 像素。

const DEBUG = true;

const main = () => {
  const
    ctx = document.getElementById('myCanvas').getContext('2d'),
    origin = { x: ctx.canvas.width / 2, y: ctx.canvas.height / 2 },
    distance = 50, maxPoints = 18, start = 3, step = 2;

  for (let points = start; points < maxPoints; points += step) {
    drawCircle(ctx, origin.x, origin.y, distance, points);
  }
};

const drawCircle = (ctx, x, y, distance, sides) => {
  if (sides < 2) throw new Error('Circle must have 3 or more sides');
  const
    vector = (x, y, radius, theta) => ({
      x: x + radius * Math.cos(theta),
      y: y + radius * Math.sin(theta)
    }),
    d = 2 * Math.PI,
    step = d / sides,
    radius = (distance / 2) / Math.sin(step / 2),
    limit = d + step;

  // Display 
  if (DEBUG) {
    const
      d2 = distance / 2, h = ctx.canvas.height / 2,
      y1 = h - d2, y2 = h + d2, x1 = 0, x2 = ctx.canvas.width;
    
    ctx.beginPath();
    ctx.setLineDash([2, 5]);
    ctx.strokeStyle = 'red';
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y1);
    ctx.moveTo(x1, y2);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    ctx.closePath();
  }
  
  ctx.beginPath();
  ctx.setLineDash([]);
  ctx.strokeStyle = 'blue';
  for (let theta = 0; theta < limit; theta += step) {
    const { x: xOffset, y: yOffset } = vector(x, y, radius, theta);
    ctx.lineTo(xOffset, yOffset);
  }
  ctx.stroke();
  ctx.closePath();
};

main();
#myCanvas {
  border: thin solid grey;
}
<canvas id="myCanvas" width="300px" height="300px"></canvas>


推荐阅读