为什么这个线段交叉算法不起作用?

时间:2014-07-02 08:56:05

标签: javascript algorithm

我试图计算两个段的交点。每个段都是垂直或水平(0°,90°,180°,270°)。如果两个段都是垂直或水平的,我还需要计算交点。

enter image description here

function intersection(line1, line2) {
    var origin1x = Math.min(line1.getStartPosition().x, line1.getEndPosition().x);
    var origin1y = Math.min(line1.getStartPosition().y, line1.getEndPosition().y);
    var origin2x = Math.min(line2.getStartPosition().x, line2.getEndPosition().x);
    var origin2y = Math.min(line2.getStartPosition().y, line2.getEndPosition().y);

    var dx = origin2x - origin1x;
    var dy = origin2y - origin1y;

    if((line1.isHorizontal() && (dx < 0 || dx > line2.getLength())) || (!line1.isHorizontal() && (dy < 0 || dy > line1.getLength()))) {
        return null;
    }

    return {
        x: line1.isHorizontal() ? origin1x + dx : origin1x,
        y: !line2.isHorizontal() ? origin2y - dy : origin2y
    }
}

代码在某些情况下运行良好,但有时会失败。

例如:

line1 = ((0, 50), (0, 30)) // ((startX, startY), (endX, endY))
line2 = ((0, 0), (0, 30))
shouldBe = (0, 30)

谢谢。

2 个答案:

答案 0 :(得分:2)

以下是解决此问题的一种方法:

使用y = m1x + c1y = m2x + c2编写两行的等式。请注意特殊情况:如果一条线是水平的,那么它具有等式y = c,如果是垂直的则它具有等式x = c(在最后一种情况下c实际上是截止点x轴,但代数仍能很好地运作。)

使用第一行提供的顶点求解系数m1c1,使用第二行的顶点对m2c2进行求解。

一旦得到这些方程,交点就是两个联立方程的解,它将根据计算出的系数给出xy的值。

请注意,这适用于线的任何非平行排列。 (对于并行情况,联立方程将是彼此的线性倍数,因此不会产生解决方案。)

一些代数,但你应该能够突然想到它。

答案 1 :(得分:1)

由于线条总是水平或垂直,因此它们与轴对齐的边界框完全相同。因此,我们可以简单地使用边界框交叉算法,而不是使用线交叉算法,就像这个伪代码一样:

# get the minimum and maximum x and y coordinates of each region
# (this part can be skipped if you know the coordinates are sorted already)
(xmin1, xmax1) = sort(region1.start.x, region1.end.x)
(ymin1, ymax1) = sort(region1.start.y, region1.end.y)
(xmin2, xmax2) = sort(region2.start.x, region2.end.x)
(ymin2, ymax2) = sort(region2.start.y, region2.end.y)

# get the maximum of the minimums and the minimum of the maximums
xmin = max(xmin1, xmin2), xmax = min(xmax1, xmax2) 
ymin = max(ymin1, ymin2), ymax = min(ymax1, ymax2) 

# check if there is any overlap
if xmin > xmax or ymin > ymax:
    raise error("the regions do not intersect")
else:
    return new region( start=(xmin, ymin), end=(xmax, ymax) )

请注意,此代码返回一个新的边界框,覆盖两个区域重叠的整个区域。即使对于水平/垂直线的区域,如果两条线具有相同的方向并且在一系列点上重叠,则该区域可能包含多个点。如果您只需要一个点,您可以随时选择重叠区域的中点。