Home > Software design >  How can I clamp a position to a circle?
How can I clamp a position to a circle?

Time:11-06

I'm trying to clamp a small point into a sphere, but every time I do it, I get a rectangle -- how can I clamp this correctly?

const canvas = document.getElementById("canvas");

const center = { x: canvas.width / 2, y: canvas.height / 2 }
const point = { ...center }

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

const GROUND_RADIUS = 50;

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // ground

  ctx.beginPath();
  ctx.arc(center.x, center.y, GROUND_RADIUS, 0, 2 * Math.PI);
  ctx.stroke(); 

  // point

  ctx.beginPath();
  ctx.arc(point.x, point.y, 10, 0, 2 * Math.PI);
  ctx.fill();
  
  requestAnimationFrame(render)
}

requestAnimationFrame(render)

canvas.addEventListener("mousemove", event => {
  point.x = Math.max(Math.min(event.clientX, center.x   GROUND_RADIUS), center.x - GROUND_RADIUS);
  point.y = Math.max(Math.min(event.clientY, center.y   GROUND_RADIUS), center.y - GROUND_RADIUS);
})
canvas {
  border: 1px solid black;
}
<canvas id="canvas" width="150" height="150">

CodePudding user response:

The angle of the position from the center equals Math.tan(y/x). By using some trigonometry we can confine x to radius * cos(alpha) and same for y.

const canvas = document.getElementById("canvas");
const status = document.getElementById("status");

const center = {
  x: canvas.width / 2,
  y: canvas.height / 2
}

const point = { ...center }

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

const GROUND_RADIUS = 50;

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // ground
  ctx.beginPath();
  ctx.arc(center.x, center.y, GROUND_RADIUS, 0, 2 * Math.PI);
  ctx.stroke();

  // point
  ctx.beginPath();
  ctx.arc(point.x, point.y, 10, 0, 2 * Math.PI);
  ctx.fill();

  requestAnimationFrame(render)
}

function getAngle(dy, dx) {
  return (Math.atan2(dy, -dx) * 180 / Math.PI   360) % 360;
}

requestAnimationFrame(render)

canvas.addEventListener("mousemove", event => {
  point.x = event.offsetX
  point.y = event.offsetY

  var dx = (center.x - point.x)
  var dy = (center.y - point.y)
  var alpha = getAngle(dy, dx);
  status.innerText = dx   ", "   dy   " and alpha = "   alpha.toFixed(2);

  var maxX = Math.abs(GROUND_RADIUS * Math.cos(alpha / 180 * Math.PI));
  var maxY = Math.abs(GROUND_RADIUS * Math.sin(alpha / 180 * Math.PI));

  dx = Math.min(Math.max(-maxX, dx), maxX)
  dy = Math.min(Math.max(-maxY, dy), maxY)

  point.x = -dx   center.x
  point.y = -dy   center.y
})
canvas {
  border: 1px solid black;
}
<div id="status"></div>
<canvas id="canvas" width="320" height="200">

  • Related