检查是否在 P5.js 中单击了圆弧

Check if an arc clicked in P5.js

在P5中检查圆是否被点击非常简单,但是我想不出用圆弧做同样的简单方法。

这就是我创建弧线的方式:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);
  stroke(0);
  strokeWeight(10); 
  noFill();
  arc(200, 200, 200, 200, HALF_PI, PI*1.75);
}

这就是检查圆圈是否被点击的方法:

function mousePressed() {
  var d = dist(mouseX, mouseY, 200,200);
  var within_diam = (d<200+width/2 && d>200-width/2);
  console.log('Circle clicked');
}

除了圆圈是否被点击之外,我还可以检查圆弧缺失的扇区是否被点击,但它看起来很麻烦,我很确定这应该是一种正确且简单的方法。

你可以做的是使用圆碰撞检测的公式,也许不是更好的方法,但可以完成工作。

假设您有一个圆 A(4, 5) 和一个圆 B(6, 8),因此您将应用公式:

sqrt(sqr(x) + sqr(y))

sqrt(sqr(4 − 3) + sqr(8 − 4)) = 8.062

因此在您的情况下,圆圈 A 将是您的鼠标,圆圈 B 将是固定圆圈,但您也可以将其反转。 检查下面的代码,这应该可以正常工作。

var mouseRadius = 10;
var _circle = {
  x: 200, 
  y: 200, 
  r: 100
};

function setup() {
  createCanvas(400, 400);
  print(_circle);
}

function draw() {
  background(255);
  stroke(0);
  strokeWeight(10); 
  noFill();
  arc(_circle.x, _circle.y, _circle.r * 2, _circle.r * 2, HALF_PI, PI*1.75);
}

function mousePressed() {
  if (isColliding(mouseX, mouseY, _circle.x, _circle.y, _circle.r + mouseRadius)) {
    console.log('Circle pressed');
  }

}

function isColliding(x1, y1, x2, y2, r) {
  let part1 =  (x1 - x2 ) * ( x1 - x2 );
  let part2 = ( y1 - y2 ) * ( y1 - y2 );
  if (Math.sqrt(part1 +  part2) < r )  {
    return true;
  }

  return false;
}

编辑

您可以将此功能替换为其他功能,将完成相同的工作,但此功能将使用较少的计算机进程,因为不再有 SQRT:


function isColliding(x1, y1, x2, y2, r) {
  let dx =  x2 - x1;
  let dy = y2 - y1;
  let radius = r * r;

  if ((dx * dx) + (dy* dy) < radius )  {
    return true;
  }

  return false;
}

您需要检查距离和角度。

下面的示例正确使用了距离,但角度计算不正确。

let withinAngle = angle > angleStart && angle < angleEnd;

角度值从起始角度开始增加,直到达到180度。然后角度值再次下降。我不确定为什么会这样。

var pos        = { x: 200, y: 200 },
    radius     = 100,
    size       = { width: radius * 2, height: radius * 2 },
    weight     = 10,
    angleStart = Math.PI / 2,
    angleEnd   = Math.PI * 1.75,
    angleDiff  = angleEnd - angleStart;

function setup() {
  createCanvas(400, 400);
  textFont('Arial', 16);
}

function draw() {
  background(255);
  stroke(0);
  strokeWeight(weight);
  //noFill();
  arc(pos.x, pos.y, size.width, size.height, angleStart, angleEnd);
  
  let origin = createVector(pos.x, pos.y);
  drawArrow(origin, createVector(size.width / 2, 0), 'red');
  drawArrow(origin, createVector(mouseX - pos.x, mouseY - pos.y), 'blue');
  
  let target = createVector(mouseX - pos.x, (mouseY - pos.y) * -1);
  let magnitude = dist(mouseX, mouseY, pos.x, pos.y);
  let angle = origin.angleBetween(target);
  
  strokeWeight(0);
  text([
    `Target: (${target.x}, ${target.y})`,
    `Magnitude: ${magnitude.toFixed(3)}`,
    `Radians: ${(angle / Math.PI).toFixed(3)}π`,
    `Degrees: ${degrees(angle).toFixed(3)}°`
  ].join('\n'), 250, 20);
}

function mousePressed(e) {
  let origin = createVector(pos.x, pos.y);
  let target = createVector(mouseX - pos.x, (mouseY - pos.y) * -1);
  if (checkBounds(origin, target)) {
    console.log('Circle stroke clicked');
  }
}

// Check to see if the click was within the stroke weight.
// There is no angle check in here...
function checkBounds(origin, target) {
  let magnitude = dist(mouseX, mouseY, size.width, size.height);
  let withinDist = magnitude > radius && magnitude < radius + weight;
  let angle = origin.angleBetween(target);
  let withinAngle = angle > angleStart && angle < angleEnd;
  return withinDist && withinAngle;
}

/** https://p5js.org/reference/#/p5.Vector/angleBetween */
function drawArrow(base, vec, myColor) {
  push();
  stroke(myColor);
  strokeWeight(3);
  fill(myColor);
  translate(base.x, base.y);
  line(0, 0, vec.x, vec.y);
  rotate(vec.heading());
  let arrowSize = 7;
  translate(vec.mag() - arrowSize, 0);
  triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
  pop();
}
.as-console-wrapper { height: 80px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>