1

How do I calculate the bounced end point of intersecting two lines?

When given the following two lines, I was able to calculate intersection point of two lines with the following function.

export function intersection(line1, line2) {
  line1.y1 *= -1; line1.y2 *= -1; // for Webpage coordinates
  line2.y3 *= -1; line2.y4 *= -1; // for Webpage coordinates

  const [x1, y1, x2, y2] = line1;
  const [x3, y3, x4, y4] = line2;

  const  [a1, b1, c1] = [y2 - y1, x1 - x2, x2 * y1 - x1 * y2];
  if ( a1 === 0 && b1 === 0 ) return 'line1 does not have length';

  const [a2, b2, c2] = [y4 - y3, x3 - x4, x4 * y3 - x3 * y4];
  if ( a2 === 0 && b2 === 0 ) return 'line2 does not have length';
  
  const denom = a1 * b2 - a2 * b1;
  if (denom === 0) return 'lines are parallel';

  const x = (b1 * c2 - b2 * c1) / denom;   // (x,y) is the intersection
  const y = (a2 * c1 - a1 * c2) / denom;

  // check if two lines are actually crossing w/o extending it
  function getDist(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
  }
  const distLine1 = getDist(x1, y1, x2, y2);
  const distLine2 = getDist(x3, y3, x4, y4);
  const distToXY1  = Math.max(getDist(x1, y1, x, y), getDist(x2, y2, x, y)) ;
  const distToXY2  = Math.max(getDist(x3, y3, x, y), getDist(x4, y4, x, y)) ;
  if (distToXY1 > distLine1 || distToXY2 > distLine2) 
    return 'lines does not meet';

  return {x, y};
}

enter image description here DEMO: https://stackblitz.com/edit/intersection-of-two-lines?file=index.js

However, I am struggling to find a bounced-off position(or reflection point) of two lines using two lines.

What's the formula of getting x/y position from line1(x1, x2, y1, y2) and line2(x1, x2, y1, y2)?

allenhwkim
  • 27,270
  • 18
  • 89
  • 122
  • you have to get the perpendicular line to the one you hit and the angle to that line is the same on the other side –  Aug 23 '21 at 23:04
  • like reflecting over the normal in 3d graphics –  Aug 23 '21 at 23:05
  • something like... function reflectLines(x,y,x2,y2,xx,yy,xx2,yy2){var slope1=(y-y2)/(x-x2);var slope2=(yy-yy2)/(xx-xx2);var angleFromOrigin=Math.asin(slope1); var angleFromOrigin2=Math.asin(slope2);var reciprical=1.0/(slope1);var reciprical2=1.0/(slope2);var angleToReciprical=Math.acos(reciprical/slope1);var angleToReciprical2=Math.acos(reciprical2/slope2);var newSlope=sin(angleFromOrigin2+Math.rad(90)+angleToReciprical); var newSlope2=sin(angleFromOrigin+Math.rad(90)+angleToReciprical2);return [newSlope,newSlope2];} I probably mixed up some of my math but something like that. –  Aug 23 '21 at 23:40

2 Answers2

2

You have to split the part of the red vector that's "inside the wall" into two components, one parallel to the wall, the other perpendicular to it. Then you negate the perpendicular component and add them back together.

class Line {
  constructor(x1, y1, x2, y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.dx = x2 - x1;
    this.dy = y2 - y1;
  }
  intersect(o) {
    const d = this.dy * o.dx - this.dx * o.dy;
    if (d === 0) return null; // parallel
    const k = ((o.y1 - this.y1) * o.dx + (this.x1 - o.x1) * o.dy) / d;
    return {
      x: this.x1 + k * this.dx,
      y: this.y1 + k * this.dy
    };
  }
  bounce(o) {
    const i = this.intersect(o);
    if (!i) return null;
    // vector from intersection to end
    const v = {
      x: this.x2 - i.x,
      y: this.y2 - i.y
    };
    // split v into two perpendicular vectors, one parallel to o
    // the perpendicular one is o's direction rotated by 90°
    const p = { x: o.dy, y: -o.dx };
    // v.x = a * o.dx + b * p.x
    // v.y = a * o.dy + b * p.y
    // division by zero is impossible since o and p are perpendicular
    const a = (v.y * p.x - v.x * p.y) / (o.dy * p.x - o.dx * p.y);
    const b = (v.y * o.dx - v.x * o.dy) / (p.y * o.dx - p.x * o.dy);
    // negate b to mirror end of line on o
    return {
        x: i.x + a * o.dx - b * p.x,
      y: i.y + a * o.dy - b * p.y
    }
  }
}

const l1 = new Line(100, 300, 400, 100);
const l2 = new Line(100, 100, 400, 300);
console.log(l1.bounce(l2));
  • Thanks. I have applied your function and it works fine when the first line is vertical. https://stackblitz.com/edit/intersection-of-two-lines?file=index.js When the first line is horizontal, it behaves differently. – allenhwkim Aug 24 '21 at 15:39
0

I think I am close to an answer.

This is my approach

  1. get a perpendicular meeting point from the intersection and end of line2.
  2. Make a line(start: end of line2, end: perpendicular meeting point), then extend the line double amount to get the endpoint.

enter image description here https://stackblitz.com/edit/intersection-of-two-lines-nes7zy?view=preview

In the demo, this approach looks fine, If a math expert can confirm this approach, it would be appreciated.

// https://stackoverflow.com/a/1811636/454252
function getPerpendicularPoint(iPoint, line1, line2) {
  const [x1, y1] = [iPoint.x, iPoint.y]; // start point
  const [x2, y2] = [line1[2], line1[3]]; // baseline end point
  const [x3, y3] = [line2[2], line2[3]]; // extended line end point

  const k = ((y2-y1) * (x3-x1) - (x2-x1) * (y3-y1)) / ((y2-y1)**2 + (x2-x1)**2);
  const x4 = x3 - k * (y2-y1);
  const y4 = y3 + k * (x2-x1);
  return {x: x4, y: y4};
}

//http://www.java2s.com/Tutorials/Javascript/Canvas_How_to/Shape/Extend_a_line_before_and_after_original_endpoints.htm
function getExtendedPoint(startPt, endPt, extent) {
  var dx = endPt.x - startPt.x;
  var dy = endPt.y - startPt.y;
  var x = startPt.x + dx * extent;
  var y = startPt.y + dy * extent;
  return {x, y};
}

let line1 = [100, 100, 400, 300];
let line2 = [100, 300, 400, 100];

const iPoint = {x: 250, y: 200}; // intersection(line1, line2);
const pPoint = getPerpendicularPoint(iPoint, line1, line2);
const ePoint = getExtendedPoint({x:line2[2], y:line2[3]}, pPoint, 2);

console.log(pPoint, ePoint);
allenhwkim
  • 27,270
  • 18
  • 89
  • 122