qlabfgerkaSmurf
qlabfgerkaSmurf

Reputation: 396

Programmatically draw a circle using lines

How can i draw a circle using lines, by having a constant pixel difference between points?

I have been trying to edit this algorithm

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>

This algorithm draws a circle which has 22 points. How can i change this algorithm so that a pixel difference between two points will always be a value, for example 50 pixels between each point?

Upvotes: 1

Views: 928

Answers (1)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48600

If you want the distance between the points to be consistent, you can calculate the radius given the number of points (aka sides) and the distance you want the points to be apart from one another.

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

sample image

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

Demo

In the example below, eight (odd-sided) polygons are drawn with each adjacent point 50 pixels from one another.

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>

Upvotes: 2

Related Questions