Search code examples
javascriptalgorithmcollision-detection

How do I get the percentage along a line that a collision is occurring?


I'm using this collision detection function to determine A) whether or not a line segment is intersecting with a circle, and B) how far down the line segment that collision is occurring.

I'm not very good at math so this isn't a function that I wrote myself, and it seems to work fine to detect collision, but when it gets to the intercept points, I'm getting values that I didn't expect. I'm trying to get the distance down the line where the collision occurs as a percentage, so for example if the line segment is 100px long, and the circle is colliding with it 50px down the line, I want the function to return 50px, from which I can easily calculate the percentage.

function interceptOnCircle(p1, p2, c, r) {
  console.log(arguments);
  //p1 is the first line point
  //p2 is the second line point
  //c is the circle's center
  //r is the circle's radius
  var p3 = {
    x: p1.x - c.x,
    y: p1.y - c.y
  }; //shifted line points
  var p4 = {
    x: p2.x - c.x,
    y: p2.y - c.y
  };
  var m = (p4.y - p3.y) / (p4.x - p3.x); //slope of the line
  var b = p3.y - m * p3.x; //y-intercept of line
  var underRadical = Math.pow(r, 2) * Math.pow(m, 2) + Math.pow(r, 2) - Math.pow(b, 2); //the value under the square root sign
  if (underRadical < 0) {
    //line completely missed
    return false;
  } else {
    var t1 = (-m * b + Math.sqrt(underRadical)) / (Math.pow(m, 2) + 1); //one of the intercept x's
    var t2 = (-m * b - Math.sqrt(underRadical)) / (Math.pow(m, 2) + 1); //other intercept's x
    var i1 = {
      x: t1 + c.x,
      y: m * t1 + b + c.y
    }; //intercept point 1
    var i2 = {
      x: t2 + c.x,
      y: m * t2 + b + c.y
    }; //intercept point 2
    console.log('Collision points: [' + i1.x + ', ' + i1.y + '], [' + i2.x + ', ' + i2.y + ']')
    var distance = Math.hypot(p1.x - i2.x, p1.y - i2.y);
    return distance;
  }
}

For a collision between a line that's 50px long, I'm getting this log:

Collision points: [111.91311159515845, 90.88529912057992], [92.30169719247377, 112.87385466298396]

with var distance = Math.hypot(p1.x - i2.x, p1.y - i2.y); resulting in a value longer than the line itself. I would expect the distance value to be between 0 and 50. How do I get the percentage along a line (from p1) that a collision is occurring?

Edit: just to verify the lines I'm testing are the correct length, I tested it with console.log(Math.hypot(p1.x - p2.x, p1.y - p2.y)); //returns 49


Solution

  • I think the problem may be that you're not limiting your solutions to those between the two original points.

    You're calculating the intersect with the line given by y = mx + c where m is the gradient calculated from the two points and c is point one, but this is a line of infinite length, so you can get intersections outside the two original points.

    The simplest thing would be to calculate the percentage as required, and conclude that anything less than 0 or more than 100% is not actually a valid intersection with the line segment between the two points.

    var length = Math.hypot(p1.x - p2.x, p1.y - p2.y);
      var distance1 = Math.hypot(p1.x - i2.x, p1.y - i2.y);
      var distance2 = Math.hypot(p1.x - i1.x, p1.y - i1.y);
      var lowerBounds = Math.min(distance1, distance2);
      if (lowerBounds < length) {
        return lowerBounds;
      } else {
        return false;
      }