2015-11-21 17 views
5

Tôi có 2 ellipses và tôi cần phát hiện bất kỳ sự chồng chéo nào giữa chúng.Tính toán chồng chéo giữa hai hình elip

Dưới đây là một ví dụ về việc phát hiện chồng chéo giữa hai vòng tròn, và tôi đang tìm kiếm một cái gì đó tương tự cho elip:

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

Đối với elip, tôi có cùng một biến vì bán kính của tôi trên trục dọc là 2 lần nhỏ hơn bán kính trên trục ngang:

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>

Trả lời

7

Như elip của bạn là rất cụ thể, trong đó họ chỉ là vòng tròn thu nhỏ dọc theo trục Y, bạn chỉ có thể tưởng tượng điều gì sẽ xảy ra nếu bạn sẽ căng máy bay dọc theo trục Y với một yếu tố 2. Bạn sẽ đồng ý rằng những hình elip chồng lên nhau đó sẽ trở thành các vòng tròn chồng lên nhau và những hình elip trùng lặp cũng sẽ không trùng lặp khi bị kéo dài. Bạn có thể tưởng tượng nó như thể các hình elip được vẽ trên một vật liệu đàn hồi, và bạn chỉ cần kéo vật liệu theo hướng thẳng đứng: tất nhiên điều này sẽ không thay đổi bất kỳ điều kiện chồng chéo nào.

Vì vậy, bạn có thể viết này:

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

... và tiếp tục với điều kiện như nó đứng, bởi vì nó được dựa trên bán kính trong X-hướng, trong đó, sau khi kéo dài, cũng là bán kính theo hướng Y. Tất nhiên, tôi đặt tên biến khác nhau, vì vậy bạn nên thử nghiệm với biến đó. Vì vậy, để hoàn thành mã, chúng tôi nhận được:

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

Lưu ý rằng sự kéo căng được đưa vào tính toán bằng cách nhân dy với 2. Trong công thức khoảng cách nó tương đương và ngắn hơn để viết 4 * dy * dy.

Đây là giao diện đẹp fiddle bạn đã tạo, với bản cập nhật của tôi cho nó.

+0

Tôi nghĩ nó không thực sự hiệu quả, hoặc tôi không hiểu bạn. Bạn có thể thử công thức của bạn ở đây: https://jsfiddle.net/rodriguevb/c60aefwn/ – Rodrigue

+0

Rất thú vị! Tôi đã cập nhật câu trả lời của mình. Lần đầu tiên tôi nghĩ bán kính của bạn là bán kính theo hướng Y, nhưng bây giờ tôi thấy trong fiddle của bạn nó là theo hướng X, và Y-tọa độ đã được giảm đi một nửa. Vì vậy, bạn cần '4 * dy * dy' trong công thức. Tôi đã sử dụng câu đố của bạn và đặt phiên bản cập nhật vào câu trả lời của tôi. – trincot

+0

Cảm ơn bạn rất nhiều! Nó hoạt động hoàn hảo ngay bây giờ. Vấn đề đã được giải quyết! – Rodrigue

Các vấn đề liên quan