Reputation: 27748
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};
}
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)?
Upvotes: 1
Views: 291
Reputation: 27748
I think I am close to an answer.
This is my approach
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);
Upvotes: 0
Reputation:
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));
Upvotes: 2