Calculate overlap between two ellipses

I have 2 ellipses and I need to detect any overlap between them.

Here is an example of detecting overlap between two circles, and I'm looking for something similar for 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 ! } 

For ellipses, I have the same variable, because my radius on the vertical axis is 2 times smaller than the radius on the horizontal axis:

 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

 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 ); 
 #canvas { border: solid 1px rgba(0,0,0,0.5); } 
 <canvas id="canvas"></canvas> <p id="result"></p> <code>distance = Math.sqrt(dx * dx + dy * dy);</code> 
+5
source share
1 answer

Since your ellipses are very specific, in that they are just circles, squeezed along the Y axis, you can imagine what happens if you stretch a plane along the Y axis with a coefficient of 2. You will agree that these overlapping ellipses become overlapping circles, and those that do not overlap will also not overlap after stretching. You could imagine it as if the ellipses were drawn on an elastic material, and you simply stretch the material in the vertical direction: this, of course, will not change any overlapping state.

So you can write this:

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

... and continue with the condition, because it is based on the radius in the X direction, which after stretching is also the radius in the Y direction. Of course, I named the variable differently, so you should check this variable. So, to complete the code, we get:

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

Note that stretching is taken into account by multiplying dy by 2. In the distance formula, this is equivalent and shorter to write 4 * dy * dy .

Here is a nice interactive fiddle you created with my update.

+7
source

Source: https://habr.com/ru/post/1236522/


All Articles