7

I'm looking for a definitive answer, maybe a function cos I'm slow, that will determine if a line segment and circle have collided, in javascript (working with canvas)

A function like the one below that simply returns true if collided or false if not would be awesome. I might even donate a baby to you.

function isCollided(lineP1x, lineP1y, lineP2x, lineP2y, circlex, circley, radius) {

    ...
}

I've found plenty of formulas, like this one, but they are over my head.

Community
  • 1
  • 1
Jarrod
  • 9,349
  • 5
  • 58
  • 73

4 Answers4

8

Here you will need some Math:

enter image description here This is the basic concept if you don't know how to solve equations in general. I will leave the rest of the thinking to you. ;) Figuring out CD's length isn't that hard.

If you are asking how, that's how: enter image description here Finding collisions in JavaScript is kind of complicated.

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • A really really appreciate the help you've given me so far. But "find angle ABE then subtract angle DBE" is really not easy for me. I'm not mathematically inclined which is why I thought I'd give stackoverflow ago. – Jarrod Jun 09 '12 at 02:10
  • 1
    Nice graphics man! @Jarrod: Subtracting the numbers shouldn't be the problem, so I guess your problem is with trigonometry/vectors? There's lot of info about that on the internet, I doubt that it would be sensible to summarize it specifically for this question. – Niklas B. Jun 09 '12 at 02:16
  • 1
    (Or simply `Math.atan((m1 - m2)/(1 + m1*m2))`, where `m` is the slope) – Derek 朕會功夫 Jun 09 '12 at 02:18
  • 1
    Don't be surprised if you found the angle does not look right, since in JavaScript all angle is in radian instead of degree. – Derek 朕會功夫 Jun 09 '12 at 02:26
  • Thanks again. Could you maybe go step by step as to how to get point C. I've still working on the problem but think I can work out the circle part. – Jarrod Jun 09 '12 at 02:37
  • @Jarrod - You don't need to find the coordinates of point C. `CD/BD = sin(CBD)` Therefore `CD = sin(CBD)*BD` – Derek 朕會功夫 Jun 09 '12 at 02:46
  • THANKS! But how do you calculate the restitution/resolve the collision? I mean, setting new position and velocities of the circle? –  Mar 22 '14 at 14:46
  • @Murplyx - I don't know much about physics, but you can [calculate the exact point of collision](https://www.desmos.com/calculator/lnobsoneki). Maybe this can help? – Derek 朕會功夫 Mar 24 '14 at 02:40
4

I Spent about a day and a half to make it perfect.. Hope this helps.

function collisionCircleLine(circle,line){ // Both are objects

    var side1 = Math.sqrt(Math.pow(circle.x - line.p1.x,2) + Math.pow(circle.y - line.p1.y,2)); // Thats the pythagoras theoram If I can spell it right

    var side2 = Math.sqrt(Math.pow(circle.x - line.p2.x,2) + Math.pow(circle.y - line.p2.y,2));

    var base = Math.sqrt(Math.pow(line.p2.x - line.p1.x,2) + Math.pow(line.p2.y - line.p1.y,2));

    if(circle.radius > side1 || circle.radius > side2)
        return true;

    var angle1 = Math.atan2( line.p2.x - line.p1.x, line.p2.y - line.p1.y ) - Math.atan2( circle.x - line.p1.x, circle.y - line.p1.y ); // Some complicated Math

    var angle2 = Math.atan2( line.p1.x - line.p2.x, line.p1.y - line.p2.y ) - Math.atan2( circle.x - line.p2.x, circle.y - line.p2.y ); // Some complicated Math again

    if(angle1 > Math.PI / 2 || angle2 > Math.PI / 2) // Making sure if any angle is an obtuse one and Math.PI / 2 = 90 deg
        return false;


        // Now if none are true then

        var semiperimeter = (side1 + side2 + base) / 2;

        var areaOfTriangle = Math.sqrt( semiperimeter * (semiperimeter - side1) * (semiperimeter - side2) * (semiperimeter - base) ); // Heron's formula for the area

        var height = 2*areaOfTriangle/base;

        if( height < circle.radius )
            return true;
        else
            return false;

}

And that is how you do it..

Coding Hub
  • 49
  • 1
  • 2
    *"And that is how you do it.."*? But this is how you do not answer. on a lighter note, add some context to support your code buddy. Plainly posting some code is not a good way of answering. – Harshith Rai Mar 06 '19 at 05:45
  • I don't know if this works or not but Math.atan2 requires y and then x input you got it reversed. – Pattycake Jr Mar 22 '19 at 15:04
1

Matt DesLauriers published a Javascript library for this problem at https://www.npmjs.com/package/line-circle-collision. The API is straightforward:

var circle = [5, 5],
    radius = 25,
    a = [5, 6],
    b = [10, 10]

var hit = collide(a, b, circle, radius)
Martin Omander
  • 3,223
  • 28
  • 23
0
function pointCircleCollide(point, circle, r) {
    if (r===0) return false
    var dx = circle[0] - point[0]
    var dy = circle[1] - point[1]
    return dx * dx + dy * dy <= r * r
}

var tmp = [0, 0]

function lineCircleCollide(a, b, circle, radius, nearest) {
    //check to see if start or end points lie within circle
    if (pointCircleCollide(a, circle, radius)) {
        if (nearest) {
            nearest[0] = a[0]
            nearest[1] = a[1]
        }
        return true
    } if (pointCircleCollide(b, circle, radius)) {
        if (nearest) {
            nearest[0] = b[0]
            nearest[1] = b[1]
        }
        return true
    }

    var x1 = a[0],
        y1 = a[1],
        x2 = b[0],
        y2 = b[1],
        cx = circle[0],
        cy = circle[1]

    //vector d
    var dx = x2 - x1
    var dy = y2 - y1

    //vector lc
    var lcx = cx - x1
    var lcy = cy - y1

    //project lc onto d, resulting in vector p
    var dLen2 = dx * dx + dy * dy //len2 of d
    var px = dx
    var py = dy
    if (dLen2 > 0) {
        var dp = (lcx * dx + lcy * dy) / dLen2
        px *= dp
        py *= dp
    }

    if (!nearest)
        nearest = tmp
    nearest[0] = x1 + px
    nearest[1] = y1 + py

    //len2 of p
    var pLen2 = px * px + py * py

    //check collision
    return pointCircleCollide(nearest, circle, radius)
            && pLen2 <= dLen2 && (px * dx + py * dy) >= 0
}

var circle = [5, 5],
    radius = 25,
    a = [5, 6],
    b = [10, 10]

var hit = lineCircleCollide(a, b, circle, radius)

yaya
  • 7,675
  • 1
  • 39
  • 38