3

Problem :

Given the vertices of two triangles, check whether both of them have any common interior point. No points on the edges or vertices are considered interior to a triangle.
I think this is a problem to find whether two triangles intersect or not.

My idea is :

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 .

My code :

#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;
}  

However for this input ..

1

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

My program gives output

no

but the correct answer is

yes

and there are many cases for which my program doesn't work.
I checked my Segment class for other program and it worked fine.
But in this , i can't find the mistake.
Please help.

Thank you.

Ashwin Nanjappa
  • 76,204
  • 83
  • 211
  • 292
palatok
  • 1,022
  • 5
  • 20
  • 30
  • 2
    Your approach doesn't consider the case where one triangle is entirely contained within the other. – Oliver Charlesworth Mar 29 '13 at 19:55
  • thanks for pointing out. in that case, what should be my approach ? – palatok Mar 29 '13 at 19:57
  • but the problem statement said : NO points on the edges or vertices are considered interior to a triangle. – palatok Mar 29 '13 at 19:59
  • @palatok Good point - I removed that comment. If you're at the *what should be my approach* stage, it's really more of a geometry problem than a programming problem. – Drew Dormann Mar 29 '13 at 20:01
  • Personally, I would write a triangle class that takes 3 vertices. Then have a function ContainsVertex that takes a vertex. For each vertex in the other triangle, call ContainsVertex. If at any point ContainsVertex returns true, you're done. If 2 triangles intersect, each one will contain a vertex from the other. EDIT: except for the case where 1 is entirely in the other. But it's trivial to handle this case. – Aeluned Mar 29 '13 at 20:03
  • @Aeluned , " If 2 triangles intersect, each one will contain a vertex from the other. " is it always right ? what for these points : {(0,0),(0,5),(5,0)} and {(-1,4),(4,4),(4,3)} ? – palatok Mar 29 '13 at 20:12
  • No, I don't know what I was thinking. That isn't true. You may very well have to test both triangles. If triangle 1 doesn't contain any points from tri 2, it's possible that it's true the other way around. – Aeluned Mar 29 '13 at 20:34
  • 1
    Why is this marked a duplicate? The other question was about triangles in 3d and while the answer may generalize (unlikely since step 1 of the process in 3d is eliminating coplanar triangles) it's likely to be relatively inefficient in the 2d case. AFAIK the answer is in Oliver's first comment -- if one of either triangle's vertices is contained in the other triangle, then they intersect and you're done OTHERWISE look for on edge interestion. – podperson Dec 12 '14 at 20:29

2 Answers2

1

I think there is a bug in the line

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

If I understand it correctly, the Direction function tells you whether a point is to the left or right of the vector representing your line segment. The statement above assumes that both your other segment's points are either to the left or right, but doesn't account for the case when one point of e.g. segment B lies on e.g. segment A but the other doesn't.

So I would change it so that, for example, instead of strictly greater than (>), you check for greater than or equal to (>=).

This may explain the problem with your example. In your example, it just happens that the point (4,0) lies on the segment (0,0),(5,0) and the point (2,4) lies on the segment (-4,16),(4,0).

maditya
  • 8,626
  • 2
  • 28
  • 28
0

If the number of rectangles is more than two, you should consider solving this by line sweep. If it is just two rectangles, you can do a couple of checks that give you the answer if they have common interior point.

The observation is that either the segments of the triangles intersect or if one rectangle is entirely contained in the other one. We break it down to a couple of checks if lines intersect or a rectangle contains a point.

The first condition can be checked by pair-wise comparison of the appropriate segments if they intersect. The second condition can be checked by testing if an endpoint of any segment is contained in the other rectangle. Not a beautiful solution but easily codeable.

DennisL
  • 466
  • 3
  • 6