2条相交线

时间:2018-10-18 01:01:39

标签: c++ geometry linear-algebra

我有这段代码来查找2行的状态,共有3种情况:

1-直线相交于一个点

2-它们是平行的

3-平行的特例,它们是相同的[同一行]

这是我的代码,但我仍然看不懂代码的这两部分

if(!D && (Dx || Dy))
    puts("NONE"); // the lines are parallel
if(!D && !Dx && !Dy)
    puts("LINE"); // they are the same lime

为什么当决定因素为零且dx = 0dy = 0时它们是平行的,而当d = 0dx = 0dy = 0时它们是同一行 我知道确定子等于零时没有唯一的解决方案,但无法理解!DX!DYDX || DY

的部分

这是完整的代码

#include <iostream>

using namespace std;

struct point{
    int x , y;
};

struct segment{
    point s , e;
};

int main(){
    int n;
    scanf("%d" , &n);
    puts("INTERSECTING LINES OUTPUT");
    while(n--){
        segment a , b;
        scanf("%d%d%d%d" , &a.s.x , &a.s.y , &a.e.x , &a.e.y);
        scanf("%d%d%d%d" , &b.s.x , &b.s.y , &b.e.x , &b.e.y);
        double a1 , b1 , c1 , a2 , b2 , c2 , D , Dx , Dy;
        a1 = a.e.y - a.s.y;
        b1 = a.s.x - a.e.x;
        c1 = a1 * (a.s.x) + b1 * (a.s.y);

        a2 = b.e.y - b.s.y;
        b2 = b.s.x - b.e.x;
        c2 = a2 * (b.s.x) + b2 * (b.s.y);

        D = a1 * b2 - a2 * b1;
        Dx = c1 * b2 - c2 * b1;
        Dy = a1 * c2 - a2 * c1;

        if(!D && (Dx || Dy))
            puts("NONE"); // the lines are parallel
        if(!D && !Dx && !Dy)
            puts("LINE"); // they are the same line
        else printf("POINT %.2f %.2f\n" , (double)Dx / D , (double) Dy / D);
     }
     return 0;
 }

3 个答案:

答案 0 :(得分:0)

对此粗略地考虑的一种方法是,当D == 0且Dx == 0且Dy == 0时,则“交点坐标” Dx / D和Dy / D是不确定的形式0/0,可以是任何数字。这意味着这些线相交成一整点,只有在它们是同一条线的情况下才有可能。

另一方面,如果D == 0且Dx!= 0或Dy!= 0(或两者),则Dx / D或Dy / D(或两者)的值是无穷大。换句话说,这些线在无限远处相交(仅),这是另一种说法,即这些线是平行且不重合的。

测试double的if(D)是一个坏主意,这有两个原因。 1)不清楚。理解表达式需要坦率地说并不是每个程序员都拥有某种相当详细的语言类型转换知识。 2)舍入误差和其他数值不稳定性问题可能会干扰计算,因此,您有一些不等于0的小D而不是D == 0。然后,即使没有舍入误差也应该为假!相反,您应该比较abs(D)是否小于某个略大于0的公差。

最后,您的程序容易受到溢出问题的影响:如果两条线的斜率很近,但是如果完全合理,则交点可能会非常大。在纯粹的数学上下文中,这种情况是有意义的,但在计算机上却没有太大意义。取而代之,一个更好的问题是交点是否位于由点定义的线段内。 Wikipedia page上对此问题进行了讨论。

答案 1 :(得分:0)

担心浮点运算的反馈是在点(Ha!)上。但是,由于输入是整数,所以我建议使用整数类型进行数学运算。

您要问的问题归结为两个分数是否相等。我建议使用以下帮助程序类:

struct ratio {
    int dx;
    int dy;

    ratio(int dxIn, int dyIn) :
        dx(dxIn), dy(dyIn) {
    }

    bool isEquivalent(ratio rhs) const {
        if ((dx == 0 && dy == 0) || (rhs.dx == 0 && rhs.dy == 0))
            return (dx == 0 && dy == 0) && (rhs.dx == 0 && rhs.dy == 0);
        return dx * rhs.dy == dy * rhs.dx;
    }
};

答案 2 :(得分:0)

每个线段均转换为扩展线的(a,b,c)坐标,形成线方程a*x+b*y+c=0。您需要知道的是向量(a,b)与直线正交。

数量D = a1*b2 - a2*b1是两个正交向量之间的叉积。如您所知,两个并行向量的叉积为0。因此,如果这是真的,则这两行要么重合要么平行。

相交点定义为(Dx/D,Dy/D),其中Dx=b1*c2-b2*c1Dy=a2*c1-a1*c2,所以当全部等于零Dx=Dy=D=0时,相交点是不确定的,这意味着直线是重合的。否则,如果仅D=0的交点位于无穷大且直线平行。

其余只是典型的令人困惑的 C语法。