2015-11-21 26 views
5

Ho 2 ellipses e ho bisogno di rilevare qualsiasi sovrapposizione tra di loro.Calcolo della sovrapposizione tra due ellissi

Ecco un esempio di rilevare sovrapposizione tra due cerchi, e cerco qualcosa di simile per ellissi:

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 ! 
} 

Per ellissi, ho la stessa variabile perché il mio raggio sull'asse verticale è 2 volte più piccolo del raggio sull'asse orizzontale:

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>

risposta

7

Man mano che le ellissi sono molto specifici, in quanto sono appena cerchi compattati lungo l'asse Y, si può solo immaginare che cosa accadrebbe se si desidera allungare il piano lungo l'asse Y con un fattore 2. Sarai d'accordo sul fatto che quelle ellissi sovrapposte diventerebbero cerchi sovrapposti, e quelli che non si sovrappongono non si sovrapporranno nemmeno una volta allungati. Potresti immaginarlo come se le ellissi fossero disegnate su un materiale elastico, e tu stessi semplicemente allungando il materiale in direzione verticale: questo ovviamente non cambierebbe alcuna condizione di sovrapposizione.

Quindi, si potrebbe scrivere questo:

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

... e continuare con la condizione così com'è, perché si basa sul raggio in direzione X, che, dopo lo stretching, è anche il raggio nella direzione Y. Naturalmente, ho chiamato la variabile in modo diverso, quindi dovresti testare con quella variabile. Quindi, per completare il codice, otteniamo:

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

Si noti che l'allungamento si tiene conto moltiplicando dy con 2. Nella formula della distanza è equivalente e più corto di scrivere 4 * dy * dy.

Ecco il bello interattivo fiddle che hai creato, con il mio aggiornamento ad esso.

+0

Penso che non funzioni davvero, o non ti capisco. Puoi provare la tua formula qui: https://jsfiddle.net/rodriguevb/c60aefwn/ – Rodrigue

+0

Very nice fiddle! Ho aggiornato la mia risposta. Avevo pensato che il tuo raggio fosse il raggio nella direzione Y, ma ora vedo che il tuo violino è nella direzione X, e la coordinata Y è stata dimezzata. Quindi hai bisogno di '4 * dy * dy' nella formula. Ho usato il tuo violino e ho inserito la versione aggiornata nella mia risposta. – trincot

+0

Grazie mille! Funziona perfettamente ora. Il problema è risolto! – Rodrigue

Problemi correlati