计算两个椭圆之间的重叠

时间:2015-11-21 22:47:16

标签: javascript math

我有2 ellipses,我需要检测它们之间的任何重叠。

以下是检测两个圆圈之间重叠的示例,我正在寻找类似椭圆的东西:

var circle1 = {radius: 20, x: 5, y: 5};
var circle2 = {radius: 12, x: 10, y: 5};

var dx = circle1.x - circle2.x;
var dy = circle1.y - circle2.y;
var distance = Math.sqrt(dx * dx + dy * dy);

if (distance < circle1.radius + circle2.radius) {
    // collision !
}

对于省略号,我有相同的变量,因为垂直轴上的半径是水平轴上半径的2倍:

var oval1 = {radius: 20, x: 5, y: 5};
var oval2 = {radius: 12, x: 10, y: 5};

// what comes here?

if ( /* condition ? */ ) {
    // collision !
}

Image: collision between two oval

&#13;
&#13;
var result = document.getElementById("result");
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");


// First eclipse
var eclipse1 = { radius: 20,
                 x: 100,
                 y: 40 };


// Second eclipse
var eclipse2 = { radius: 20,
                 x: 120,
                 y: 65 };



function have_collision( element1, element2 )
{
  var dx = element1.x - element2.x;
  var dy = element1.y - element2.y;
  var distance = Math.sqrt(dx * dx + dy * dy);

  if (distance <= element1.radius + element2.radius) {
    return true;
  }
  else {
    return false;
   }
}

function draw( element ) {
// http://scienceprimer.com/draw-oval-html5-canvas
context.beginPath();
for (var i = 0 * Math.PI; i < 2 * Math.PI; i += 0.01 ) {
  xPos = element.x - (element.radius/2 * Math.sin(i)) * Math.sin(0 * Math.PI) + (element.radius * Math.cos(i)) * Math.cos(0 * Math.PI);
  yPos = element.y + (element.radius * Math.cos(i)) * Math.sin(0 * Math.PI) + (element.radius/2 * Math.sin(i)) * Math.cos(0 * Math.PI);

  if (i == 0) {
    context.moveTo(xPos, yPos);
  } else {
    context.lineTo(xPos, yPos);
  }
}
context.fillStyle = "#C4C4C4";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "#FF0000";
context.stroke();
context.closePath();
}

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

canvas.addEventListener('mousemove', function(e) {
  var mousePos = getMousePos(canvas, e);
  eclipse2.x = mousePos.x;
  eclipse2.y = mousePos.y;
  result.innerHTML = 'Collision ? ' + have_collision( eclipse1, eclipse2 );
  context.clearRect(0, 0, canvas.width, canvas.height);
  draw( eclipse1 );
  draw( eclipse2 );
}, false);


draw( eclipse1 );
draw( eclipse2 );
result.innerHTML = 'Collision ? ' + have_collision( eclipse1, eclipse2 );
&#13;
#canvas {
  border: solid 1px rgba(0,0,0,0.5);
}
&#13;
<canvas id="canvas"></canvas>
<p id="result"></p>
<code>distance = Math.sqrt(dx * dx + dy * dy);</code>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:7)

由于你的椭圆是非常具体的,因为它们只是沿着Y轴收缩的圆圈,你可以想象如果你沿着Y轴以2因子拉伸平面会发生什么。你会同意那些重叠的椭圆将成为重叠的圆,而那些不重叠的椭圆也会在拉伸后不重叠。您可以想象它就像椭圆是在弹性材料上绘制的,而您只是在垂直方向上拉伸材料:这当然不会改变任何重叠条件。

所以,你可以这样写:

var stretchedDistance = Math.sqrt(dx * dx + 2 * dy * 2 * dy);

...并继续处理现状,因为它基于X方向的半径,在拉伸之后,也是Y方向的半径。当然,我以不同的方式命名变量,因此您应该使用该变量进行测试。因此,为了完成代码,我们得到:

var stretchedDistance = Math.sqrt(dx * dx + 4 * dy * dy);
if (stretchedDistance < circle1.radius + circle2.radius) {
    // collision !
}

请注意,通过将dy乘以2来考虑拉伸。在距离公式中,它与写4 * dy * dy相同且更短。

以下是您创建的精彩互动fiddle,并对其进行了更新。