c ++:检查两个三角形是否相交

时间:2013-03-29 19:54:03

标签: c++ computational-geometry intersection

问题:

给定两个三角形的顶点,检查它们是否都有任何共同的内点。边缘或顶点上没有点被认为是三角形的内部 我认为这是一个问题,以确定两个三角形是否相交。

我的想法是:

1. Make three line segments for each of the two triangles
2. For each pair of line segment (A,B) (where A is in triangle #1 and B is in Triangle #2) check whether they intersect or not.
3. If any pair of segments intersect, then the two triangles have a interior point. Otherwise not .

我的代码:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#define READ freopen("in.txt","r",stdin)
#define ui64 unsigned long long int
#define i64 long long int

using namespace std;

class Point{
public:
    i64 x, y;
    Point() : x(0), y(0) {}
    Point(int a, i64 b) : x(a), y(b) {}
};

class Segment{
public:
    Point a, b;
    Segment() : a(0,0), b(0,0) {}
    Segment(Point e, Point r) : a(e), b(r) {}
    Segment(const Segment &s){
        a = s.a;
        b = s.b;
    }
    i64 Direction(const Point &p){
        return (p.x - a.x) * (b.y - a.y) - (b.x - a.x) * (p.y - a.y);
    }
    inline bool inside(int a,int b,int c){
        return a<=c && c<=b;
    }
    bool onSegment(const Point &p){
        return inside(min(a.x,b.x), max(a.x,b.x), p.x) && inside(min(a.y,b.y), max(a.y,b.y), p.y);
    }
    bool Intersect(Segment &s){
        int d1 = this->Direction(s.a);
        int d2 = this->Direction(s.b);

        int d3 = s.Direction(a);
        int d4 = s.Direction(b);

        if(((d1>0 && d2<0) || (d1<0 && d2>0)) && ((d3>0 && d4<0) || (d3<0 && d4>0))) return true;

        //check if the two segments just touch each other but don't cross  
        //i ignored this because as the problem said ...  
        //No points on the edges or vertices are considered interior to a triangle.
        /*if(!d1 && this->onSegment(s.a)) return true;
        if(!d2 && this->onSegment(s.b)) return true;
        if(!d3 && s.onSegment(a)) return true;
        if(!d4 && s.onSegment(b)) return true;*/
        return false;
    }
};

Point p1[3], p2[3];
Segment s1[3], s2[3];

bool check()
{
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if(s1[i].Intersect(s2[j]))
                return true;
    return false;
}

int main()
{
    //READ;

    int t, ts=0;

    scanf("%d",&t);//number of test cases
    while(t--){
        //points for first triangle
        for(int i=0;i<3;i++){
            scanf("%lld %lld",&p1[i].x, &p1[i].y);
        }
        //points for second triangle
        for(int i=0;i<3;i++){
            scanf("%lld %lld",&p2[i].x, &p2[i].y);
        }
        for(int i=0;i<3;i++){
            s1[i] = Segment(p1[i], p1[(i+1)%3]);
            s2[i] = Segment(p2[i], p2[(i+1)%3]);
        }
        printf("pair %d: %s\n",++ts, check() ? "yes" : "no");
    }

    return 0;
}  

但是对于这个输入..

1

0 0 5 0 2 4
4 0 5 0 -4 16

我的程序提供输出

no

但正确答案是

yes

并且有很多情况我的程序不起作用 我查看了我的Segment课程以了解其他课程,并且工作正常 但在这方面,我找不到错误 请帮忙。

谢谢。

2 个答案:

答案 0 :(得分:1)

我认为行中存在错误

if(((d1>0 && d2<0) || (d1<0 && d2>0)) && ((d3>0 && d4<0) || (d3<0 && d4>0))) return true;

如果我理解正确,方向功能会告诉您一个点是否代表您的线段的向量的左侧或右侧。上面的陈述假设你的其他部分的点都是向左或向右,但不考虑例如一个点的情况。段B位于例如段A但另一段则没有。

所以我会改变它,例如,而不是严格地大于(>),你检查大于或等于(>=)。

这可以解释您的示例的问题。在你的例子中,恰好点(4,0)位于段(0,0),(5,0)上,点(2,4)位于段(-4,16)上,( 4,0)。

答案 1 :(得分:0)

如果矩形的数量超过两个,您应该考虑通过线扫描来解决这个问题。如果它只是两个矩形,你可以做几个检查,如果它们有共同的内部点,给你答案。

观察结果是三角形的片段相交或者如果一个矩形完全包含在另一个矩形中。如果线相交或矩形包含一个点,我们将其分解为几个检查。

如果相应的段相交,则可以通过成对比较来检查第一个条件。可以通过测试任何段的端点是否包含在另一个矩形中来检查第二个条件。不是一个漂亮的解决方案,但很容易编码。