一、概述
题目来源于leetcode。
二、思路
先通过快速排斥试验判断以线段为对角线的矩形是否相交,不相交则无交点;
再判断线段是否跨立;
再判断是否共线,并计算交点;
线段相交,根据三角形面积和定比分点公式计算交点坐标。
三、代码
/**
* @param {number[]} start1
* @param {number[]} end1
* @param {number[]} start2
* @param {number[]} end2
* @return {number[]}
*/
var intersection = function (start1, end1, start2, end2) {
let P1 = new Point(start1);
let P2 = new Point(end1);
let Q1 = new Point(start2);
let Q2 = new Point(end2);
let arr = []; //先通过快速排斥试验判断以线段为对角线的矩形是否相交,不相交则无交点;
if (Math.max(P1.x, P2.x) < Math.min(Q1.x, Q2.x) ||
Math.max(Q1.x, Q2.x) < Math.min(P1.x, P2.x) ||
Math.max(P1.y, P2.y) < Math.min(Q1.y, Q2.y) ||
Math.max(Q1.y, Q2.y) < Math.min(P1.y, P2.y)) {
return [];
}
let Q1P1=getLine(Q1,P1);
let Q1P2=getLine(Q1,P2);
let Q1Q2=getLine(Q1,Q2);
let P1P2=getLine(P1,P2);
let P1Q1=getLine(P1,Q1);
let P1Q2=getLine(P1,Q2);
let P2Q2=getLine(P2,Q2); //再判断线段是否跨立;
let crossV=vectorCross(Q1P1,Q1Q2)*vectorCross(Q1P2,Q1Q2);
let crossV2=vectorCross(P1Q1,P1P2)*vectorCross(P1Q2,P1P2);
if(crossV>0||crossV2>0){
return [];
} //再判断是否共线,并计算交点;
if(vectorCross(Q1P1,P1Q2)===0||vectorCross(Q1P2,P2Q2)===0||vectorCross(Q1P2,P2Q2)===0){//共线
let isQ1inP1P2=isPointInLine(P1,P2,Q1);
if(isQ1inP1P2){
arr=update(Q1.x,Q1.y,arr);
}
let isQ2inP1P2=isPointInLine(P1,P2,Q2);
if(isQ2inP1P2){
arr=update(Q2.x,Q2.y,arr);
}
let isP1inQ1Q2=isPointInLine(Q1,Q2,P1);
if(isP1inQ1Q2){
arr=update(P1.x,P1.y,arr);
}
let isP2inQ1Q2=isPointInLine(Q1,Q2,P2);
if(isP2inQ1Q2){
arr=update(P2.x,P2.y,arr);
}
}else{ //线段相交,根据三角形面积和定比分点公式计算交点坐标。
let s1=Math.abs(vectorCross(Q1Q2,Q1P2))*0.5;
let s2=Math.abs(vectorCross(Q1Q2,Q1P1))*0.5;
let lamda=s1/s2;
let x,y;
x=(P2.x+lamda*P1.x)/(1+lamda);
y=(P2.y+lamda*P1.y)/(1+lamda);
arr=[x,y];
}
return arr;
};
var Point = function (p) {
this.x = p[0];
this.y = p[1];
}
var vectorCross=function(v1,v2){
return v1[0]*v2[1]-v2[0]*v1[1];
}
//点p在线段point1——point2上,且是有交点的前提下
var isPointInLine=function(point1,point2,p){
let minX=min(point1.x,point2.x);
let minY=min(point1.y,point2.y);
let maxX=max(point1.x,point2.x);
let maxY=max(point1.y,point2.y);
if(p.x>=minX&&p.x<=maxX&&p.y>=minY&&p.y<=maxY&&vectorCross(getLine(point1,p),getLine(p,point2))===0){
return true;
}
return false;
}
var update=function(x,y,arr){//获取坐标最小的点
if(arr.length===0||x<arr[0]||(x===arr[0]&&y<arr[1])){
arr=[x,y];
}
return arr;
}
var min=function(a,b){
return Math.min(a,b);
}
var max=function(a,b){
return Math.max(a,b);
}
var getLine=function(Q1,P1){
let Q1P1=[P1.x-Q1.x,P1.y-Q1.y];
return Q1P1;
}