可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have dynamically generated lines that animate and I want to detect when a lines hits another. I'm trying to implement some basic linear algebra to obtain the equation of the lines and then solving for x,y, but the results are erratic. At this point I'm testing only with two lines which means I should be getting one point of intersection, but I get two. I just want to make sure my math is ok and that I should be looking elsewhere for the problem.
function collision(boid1, boid2) {
var x1 = boid1.initialX, y1 = boid1.initialY, x2 = boid1.x, y2 = boid1.y, x3 = boid2.initialX, y3 = boid2.initialY, x4 = boid2.x, y4 = boid2.y;
slope1 = (y1 - y2)/(x1 - x2);
slope2 = (y3 - y4)/(x3- x4);
//console.log("slope1:"+slope1);
//console.log('x2:'+x2+' y2:'+y2);
if(slope1 != slope2){
var b1 = getB(slope1,x1,y1);
var b2 = getB(slope2,x3,y3);
if(slope2 >= 0){
u = slope1 - slope2;
}else{
u = slope1 + slope2;
}
if(b1 >= 0){
z = b2 - b1;
}else{
z = b2 + b1;
}
pointX = z / u;
pointY = (slope1*pointX)+b1;
pointYOther = (slope2*pointX)+b2;
console.log("pointx:"+pointX+" pointy:"+pointY+" othery:"+pointYOther);
//return true;
context.beginPath();
context.arc(pointX, pointY, 2, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();
}
return false;
}
function getB(slope,x,y){
var y = y, x = x, m = slope;
a = m*x;
if(a>=0){
b = y - a;
}else{
b = y + a;
}
return b;
}
EDIT:
The problem is that I'm getting two different values for the point of intersection. There should only be one, which leads me to believe my calculations are wrong. Yes, x2,y2,x4,y4 are all moving, but they have a set angle and the consistent slopes confirm that.
回答1:
You don't need to alternate between adding/subtracting y-intersects when plugging 'found-x' back into one of the equations:
(function () {
window.linear = {
slope: function (x1, y1, x2, y2) {
if (x1 == x2) return false;
return (y1 - y2) / (x1 - x2);
},
yInt: function (x1, y1, x2, y2) {
if (x1 === x2) return y1 === 0 ? 0 : false;
if (y1 === y2) return y1;
return y1 - this.slope(x1, y1, x2, y2) * x1 ;
},
getXInt: function (x1, y1, x2, y2) {
var slope;
if (y1 === y2) return x1 == 0 ? 0 : false;
if (x1 === x2) return x1;
return (-1 * ((slope = this.slope(x1, y1, x2, y2)) * x1 - y1)) / slope;
},
getIntersection: function (x11, y11, x12, y12, x21, y21, x22, y22) {
var slope1, slope2, yint1, yint2, intx, inty;
if (x11 == x21 && y11 == y21) return [x11, y11];
if (x12 == x22 && y12 == y22) return [x12, y22];
slope1 = this.slope(x11, y11, x12, y12);
slope2 = this.slope(x21, y21, x22, y22);
if (slope1 === slope2) return false;
yint1 = this.yInt(x11, y11, x12, y12);
yint2 = this.yInt(x21, y21, x22, y22);
if (yint1 === yint2) return yint1 === false ? false : [0, yint1];
if (slope1 === false) return [y21, slope2 * y21 + yint2];
if (slope2 === false) return [y11, slope1 * y11 + yint1];
intx = (slope1 * x11 + yint1 - yint2)/ slope2;
return [intx, slope1 * intx + yint1];
}
}
}());
回答2:
I found a great solution by Paul Bourke. Here it is, implemented in JavaScript:
function line_intersect(x1, y1, x2, y2, x3, y3, x4, y4)
{
var ua, ub, denom = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
if (denom == 0) {
return null;
}
ua = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3))/denom;
ub = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3))/denom;
return {
x: x1 + ua * (x2 - x1),
y: y1 + ub * (y2 - y1),
seg1: ua >= 0 && ua <= 1,
seg2: ub >= 0 && ub <= 1
};
}
回答3:
You may do as follows;
function lineIntersect(a,b){
a.m = (a[0].y-a[1].y)/(a[0].x-a[1].x); // slope of line 1
b.m = (b[0].y-b[1].y)/(b[0].x-b[1].x); // slope of line 2
return a.m - b.m < Number.EPSILON ? undefined
: { x: (a.m * a[0].x - b.m*b[0].x + b[0].y - a[0].y) / (a.m - b.m),
y: (a.m*b.m*(b[0].x-a[0].x) + b.m*a[0].y - a.m*b[0].y) / (b.m - a.m)};
}
var line1 = [{x:3, y:3},{x:17, y:8}],
line2 = [{x:7, y:10},{x:11, y:2}];
console.log(lineIntersect(line1, line2));
回答4:
There is an npm module that does just that: line-intersect.
Install it using
npm install --save line-intersect
ES6 usage:
import { checkIntersection } from "line-intersect";
const result = lineIntersect.checkIntersection(
line1.start.x, line1.start.y, line1.end.x, line1.end.y,
line2.start.x, line2.start.y, line2.end.x, line2.end.y
);
result.type // any of "none", "parallel", "colinear", "intersecting"
result.point // only exists when result.type == 'intersecting'
If you're using typescript, here are the typings:
declare module "line-intersect" {
export function checkIntersection(
x1: number, y1: number,
x2: number, y2: number,
x3: number, y3: number,
x4: number, y4: number): {
type: string,
point: {x:number, y:number}
};
}
Put it in a file and reference if in tsconfig.json
's "files"
section.