我编写了以下程序,用于查明两个线段是否相交。对于某些情况,该程序似乎工作不正常。有人可以帮我纠正我哪里出错了吗?
bool FindLineIntersection(double start1[2], double end1[2], double start2[2], double end2[2])
{
float denom = ((end1[0] - start1[0]) * (end2[1] - start2[1])) - ((end1[1] - start1[1]) * (end2[0] - start2[0]));
// AB & CD are parallel
if (denom == 0)
return false;
float numer = ((start1[1] - start2[1]) * (end2[0] - start2[0])) - ((start1[0] - start2[0]) * (end2[1] - start2[1]));
float r = numer / denom;
float numer2 = ((start1[1] - start2[1]) * (end1[0] - start1[0])) - ((start1[0] - start2[0]) * (end1[1] - start1[1]));
float s = numer2 / denom;
if ((r < 0 || r > 1) || (s < 0 || s > 1))
return false;
return true;
}
答案 0 :(得分:3)
您想要找到两行[P]
和a
的交叉点b
:
[P] = [A] + [a]*r = [B] + [b] * s
产生线性方程:
[a]*r - [b]*s = [S] - [R]
或
| ax -bx | | r | |Sx - Rx|
| | * | | = | |
| ay -by | | s | |Sy - Ry|
从你的决定因素来看,这不是你想要解决的等式。我认为你的功能应该是这样的:
bool intersection(double start1[2], double end1[2],
double start2[2], double end2[2])
{
float ax = end1[0] - start1[0]; // direction of line a
float ay = end1[1] - start1[1]; // ax and ay as above
float bx = start2[0] - end2[0]; // direction of line b, reversed
float by = start2[1] - end2[1]; // really -by and -by as above
float dx = start2[0] - start1[0]; // right-hand side
float dy = start2[1] - start1[1];
float det = ax * by - ay * bx;
if (det == 0) return false;
float r = (dx * by - dy * bx) / det;
float s = (ax * dy - ay * dx) / det;
return !(r < 0 || r > 1 || s < 0 || s > 1);
}
编辑II :上述算法非常粗糙。它正确地计算以非零角度彼此交叉的两个线段的交点。以下问题未得到解决:
共线性。当主要行列式为零时,方向矢量是平行的。要检查两个线段是否共线,请测试一个方向矢量的叉积和两个起点的差值是否为零:
ax * dy - ay * dx == 0
共线性并不一定意味着线段重叠。为此,第二条曲线的起始点和终点的系数r
必须与区间[0, 1]
重叠。
零长度细分。这里,零长度线段的系数是不确定的,主要决定因素是零。算法可以检查长度并确定简并分段的起点是否位于另一个上。
两个零长度的细分。测试点的相等性或确定点可以重合但不相交。
精密。这里的代码只测试零,这在使用浮点坐标时通常不是一个好主意。测试可能应该是明智地选择的epsilon:
if (fabs(det) < epsilon) ...
强健的线路交叉算法应该适应这些情况。正如他们所说,这是留给读者的练习。
编辑:我已将逻辑转换为Javascript,以便直观地检查功能。 (我在此过程中发现了两个错误,我已经修复了。)为了您的交互式交叉乐趣,将下面的网页复制到一个html文件,并在可以解释HTML5画布的浏览器中运行它。随机生成一对线,交叉时应为红色,否则为灰色。重新加载。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Intersect!</title>
<script type="text/javascript">
function point(cx, a)
{
cx.fillRect(a[0] - 3, a[1] - 3, 7, 7);
}
function line(cx, a, b)
{
cx.beginPath();
cx.moveTo(a[0], a[1]);
cx.lineTo(b[0], b[1]);
cx.stroke();
}
function uni(x) {
return (Math.random() * x) | 0;
}
window.onload = function() {
var cv = document.getElementById("c");
var cx = cv.getContext("2d");
var a1 = [uni(500), uni(500)];
var a2 = [uni(500), uni(500)];
var b1 = [uni(500), uni(500)];
var b2 = [uni(500), uni(500)];
if (intersect(a1, a2, b1, b2)) {
cx.strokeStyle = "crimson";
cx.fillStyle = "crimson";
} else {
cx.strokeStyle = "slategray";
cx.fillStyle = "slategray";
}
point(cx, a1);
point(cx, a2);
point(cx, b1);
point(cx, b2);
line(cx, a1, a2);
line(cx, b1, b2);
}
</script>
<style type="text/css">
</style>
</head>
<body>
<canvas id="c" width="500" height="500">Kann nix.</canvas>
</body>
</html>