Circle Intersection Test

Yet another quick test for a geometry function:

Click, drag, and release to draw a line. A point will be drawn at the intersections if there are any. Hit ‘S’ to toggle between treating the drawn segment as a line segments or a line.

The demo uses some basic Phaser features for the interaction and drawing. The Javascript code is:

var game = new Phaser.Game(530, 300, Phaser.CANVAS, 'container',
                           { create: create, update: update, render: render });

var line;

var setting;

var result1;
var result2;

var circle;

var segment = true;

function create() {

  line = new Phaser.Line(game.world.width/4, game.world.height/4,
                         3*game.world.width/4, 3*game.world.height/4);

  circle = new Phaser.Circle(game.world.width/2, game.world.height/2,
                             Math.min(game.world.height, game.world.width)/2);

  game.input.onDown.add(click, this);
  setting = false;

  result1 = new Phaser.Point();
  result2 = new Phaser.Point();

    game.input.keyboard.addKey(Phaser.Keyboard.S)
        .onDown.add(function() {
            segment = !segment;
        }, this);
}


function update() {

    if (setting) {
        line.end.set(game.input.activePointer.x,
                      game.input.activePointer.y);

        if (!game.input.activePointer.isDown) {
            setting = false;
        }
    }
}


function click(pointer) {
    setting = true;
    line.start.set(pointer.x, pointer.y);
}


function render() {
  game.debug.geom(line);

  game.debug.geom(circle, '#00ff00', false, 2);

  var res = intersection(line, circle, result1, result2, segment);
  if (res) {
    result1.x--;
    result1.y--;
    result2.x--;
    result2.y--;

    game.debug.geom(result1, '#ff0000');

    if (res == INTERSECTION)
      game.debug.geom(result2, '#ff0000');
  }

}


var NO_INTERSECTION = 0;
var INTERSECTION = 1;
var SINGLE_INTERSECTION = 2;
var TANGENT = 3;

function intersection(line, circle, result1, result2, segment) {
  var lx = line.end.x - line.start.x;
  var ly = line.end.y - line.start.y;

  var len = Math.sqrt(lx*lx + ly*ly);

  var dx = lx / len;
  var dy = ly / len;

  var t = dx*(circle.x-line.start.x) + dy*(circle.y-line.start.y);

  var ex = t * dx + line.start.x;
  var ey = t * dy + line.start.y;

  var lec = Math.sqrt((ex-circle.x)*(ex-circle.x) +
                      (ey-circle.y)*(ey-circle.y));

  if (lec < circle.radius) {

    var dt = Math.sqrt(circle.radius*circle.radius - lec*lec);

    var te = dx*(line.end.x-line.start.x) + dy*(line.end.y-line.start.y);

    if (segment) {
      if ((t-dt < 0 || t-dt > te) &&
          (t+dt < 0 || t+dt > te)) {
            return NO_INTERSECTION;
      } else if (t-dt < 0 || t-dt > te) {
          result1.x = (t+dt)*dx + line.start.x;
          result1.y = (t+dt)*dy + line.start.y;
          return SINGLE_INTERSECTION;
      } else if (t+dt < 0 || t+dt > te) {
          result1.x = (t-dt)*dx + line.start.x;
          result1.y = (t-dt)*dy + line.start.y;
          return SINGLE_INTERSECTION;
      }
    }

    result1.x = (t-dt)*dx + line.start.x;
    result1.y = (t-dt)*dy + line.start.y;

    result2.x = (t+dt)*dx + line.start.x;
    result2.y = (t+dt)*dy + line.start.y;

    return INTERSECTION;
  } else if (lec == circle.radius) {

    result1.x = ex;
    result1.y = ey;

    result2.x = ex;
    result2.y = ey;

    return TANGENT;
  }

  return NO_INTERSECTION;
}