111.交点
题目链接
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-lcci
题目描述
给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
示例 1:
输入:
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
输出: {0.5, 0}
示例 2:
输入:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出: {1, 1}
示例 3:
输入:
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
输出: {},两条线段没有交点
提示:
坐标绝对值不会超过 2^7
输入的坐标均是有效的二维坐标
重难点
分析斜率判断两条直线相交情况
题目分析
作者:ari-5
链接:https://leetcode-cn.com/problems/intersection-lcci/solution/wo-mei-you-wen-hua-yi-ju-ykxbzou-tian-xia-by-ari-5/
分析斜率k1和k2,判断交点;
k1=0,k2=0;
k1=0,k2不存在;
k1不存在,k2=0;
k1不存在,k2不存在;
k1,k2都存在;
var intersection = function (start1, end1, start2, end2, k = 0) {
// 特殊k值前置,保证特殊都在前边,好处理
if (k === 0) {
if (start2[0] - end2[0] === 0 || start2[1] - end2[1] === 0)
return intersection(start2, end2, start1, end1, k = 1)
}
// 这个是可能的交点
let x = null, y = null
// 第一条平行于Y轴
if (start1[0] - end1[0] === 0) {
if (start2[0] - end2[0] === 0) {
// 两条线都平行Y轴
if (start1[0] === start2[0] && Math.max(start1[1], end1[1]) >= Math.min(start2[1], end2[1]) && Math.min(start1[1], end1[1]) <= Math.max(start2[1], end2[1]))
return [start1[0], Math.max(Math.min(start2[1], end2[1]), Math.min(start1[1], end1[1]))]
} else {
// 第二条线不平行Y(未判断线段可交)
let k = (end2[1] - start2[1]) / (end2[0] - start2[0])
x = start1[0]
y = (x - end2[0]) * k + end2[1]
}
} else if (start1[1] - end1[1] === 0) {
// 第一条平行于X轴
if (start2[1] - end2[1] === 0) {
// 两条线都平行X轴
if (start1[1] === start2[1] && Math.max(start1[0], end1[0]) >= Math.min(start2[0], end2[0]) && Math.min(start1[0], end1[0]) >= Math.max(start2[0], end2[0]))
return [Math.max(Math.min(start2[0], end2[0]), Math.min(start1[0], end1[0]), start1[1])]
} else if (start2[0] - end2[0] === 0) {
// 第二条线平行Y(未判断线段可交)
x = start2[0]
y = start1[1]
} else {
// 第二条线存在K
let k = (end2[1] - start2[1]) / (end2[0] - start2[0])
y = start1[1]
x = (y - (start2[1] - (k * start2[0]))) / k
}
} else if ((end2[1] - start2[1]) / (end2[0] - start2[0]) === (end1[1] - start1[1]) / (end1[0] - start1[0])) {
// 斜率不为0存在且相等
let k = (end2[1] - start2[1]) / (end2[0] - start2[0])
if ((end2[1] - k * end2[0]) === (end1[1] - k * end1[0])) {
// b相等
x = Math.max(Math.min(start1[0], end1[0]), Math.min(start2[0], end2[0]))
y = Math.max(Math.min(start1[1], end1[1]), Math.min(start2[1], end2[1]))
} else {
// b不相等 没有交点
return []
}
} else {
// 两个都是正常的K
let k2 = (end2[1] - start2[1]) / (end2[0] - start2[0])
let k1 = (end1[1] - start1[1]) / (end1[0] - start1[0])
let b2 = (start2[1] - k2 * start2[0])
let b1 = (start1[1] - k1 * start1[0])
x = (b2 - b1) / (k1 - k2)
y = (x * k1) + b1
}
// 上下左右边界,确定所求出来的x,y是不是在线段上面
let l = Math.max(Math.min(start1[0], end1[0]), Math.min(start2[0], end2[0]))
let r = Math.min(Math.max(start1[0], end1[0]), Math.max(start2[0], end2[0]))
let b = Math.max(Math.min(start1[1], end1[1]), Math.min(start2[1], end2[1]))
let t = Math.min(Math.max(start1[1], end1[1]), Math.max(start2[1], end2[1]))
if (x !== null && x >= l && x <= r && y <= t && y >= b) {
return [x, y]
} else {
return []
}
};