begin % determine if two triangles overlap %
    record Point    ( real x, y );
    record Triangle ( reference(Point) p1, p2, p3 );
    procedure WritePoint ( reference(Point) value p ) ;
        writeon( r_w := 3, r_d := 1, r_format := "A", s_w := 0, "(", x(p), ", ", y(p), ")" );
    procedure WriteTriangle ( reference(Triangle) value t ) ;
    begin
        WritePoint( p1(t) );
        writeon( ", " );
        WritePoint( p2(t) );
        writeon( ", " );
        WritePoint( p3(t) )
    end WriteTriangle ;
    real procedure Det2D ( reference(Triangle) value t ) ;
        ( ( x(p1(t)) * ( y(p2(t)) - y(p3(t)) ) )
        + ( x(p2(t)) * ( y(p3(t)) - y(p1(t)) ) )
        + ( x(p3(t)) * ( y(p1(t)) - y(p2(t)) ) )
        );
    procedure CheckTriWinding ( reference(Triangle) value t ; logical value allowReversed ) ;
    begin
        real detTri;
        detTri := Det2D(t);
        if detTri < 0.0 then begin
            if allowReversed then begin
                reference(Point) a;
                a     := p3(t);
                p3(t) := p2(t);
                p2(t) := a
                end
            else begin
                write( "triangle has wrong winding direction" );
                assert( false )
            end
        end if_detTri_lt_0
    end CheckTriWinding ;
    logical procedure BoundaryCollideChk(       reference(Triangle) value t ; real value eps ) ; Det2D( t ) <  eps ;
    logical procedure BoundaryDoesntCollideChk( reference(Triangle) value t ; real value eps ) ; Det2D( t ) <= eps ;
    logical procedure TriTri2D( reference(Triangle) value t1, t2 ; real value eps ; logical value allowReversed, onBoundary ) ;
    begin
        logical procedure ChkEdge( reference(Triangle) value t ) ;
                if onBoundary then % Points on the boundary are considered as colliding %
                                   BoundaryCollideChk(       t, eps )
                              else % Points on the boundary are not considered as colliding %
                                   BoundaryDoesntCollideChk( t, eps )
                              ;
        reference(Point) array lp1, lp2 ( 0 :: 2 );
        logical                overlap;
        overlap := true;
        % Triangles must be expressed anti-clockwise %
        CheckTriWinding( t1, allowReversed );
        CheckTriWinding( t2, allowReversed );
        lp1( 0 ) := p1(t1); lp1( 1 ) := p2(t1); lp1( 2 ) := p3(t1);
        lp2( 0 ) := p1(t2); lp2( 1 ) := p2(t2); lp2( 2 ) := p3(t2);
        % for each edge E of t1 %
        for i := 0 until 2 do begin
            integer j;
            j := ( i + 1 ) rem 3;
            % Check all points of t2 lay on the external side of edge E. %
            % if they do, the triangles do not overlap.                  %
            if  ChkEdge( Triangle( lp1( i ), lp1( j ), lp2( 0 ) ) )
            and ChkEdge( Triangle( lp1( i ), lp1( j ), lp2( 1 ) ) )
            and ChkEdge( Triangle( lp1( i ), lp1( j ), lp2( 2 ) ) )
            then begin
                overlap := false;
                goto return
            end
        end for_i ;
        % for each edge E of t2 %
        for i := 0 until 2 do begin
            integer j;
            j := ( i + 1 ) rem 3;
            % Check all points of t1 lay on the external side of edge E. %
            % if they do, the triangles do not overlap.                  %
            if  ChkEdge( Triangle( lp2( i ), lp2( j ), lp1( 0 ) ) )
            and ChkEdge( Triangle( lp2( i ), lp2( j ), lp1( 1 ) ) )
            and ChkEdge( Triangle( lp2( i ), lp2( j ), lp1( 2 ) ) )
            then begin
                overlap := false;
                goto return
            end
        end for_i;
        % if we get here, The triangles overlap %
return: overlap
    end TriTri2D ;
    procedure CheckOverlap( reference(Triangle) value t1, t2
                          ; real                value eps
                          ; logical             value allowReversed, onBoundary
                          ) ;
    begin
        write( "Triangles " );
        WriteTriangle( t1 );
        writeon( " and " );
        WriteTriangle( t2 );
        writeon( if TriTri2D( t1, t2, eps, allowReversed, onBoundary ) then " overlap" else " do not overlap" );
    end CheckOverlap ;
    begin % main %
        reference(Triangle) t1, t2;
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 5.0, 0.0 ), Point( 0.0, 5.0 ) );
        t2 := Triangle( Point( 0.0, 0.0 ), Point( 5.0, 0.0 ), Point( 0.0, 6.0 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 0.0, 5.0 ), Point( 5.0, 0.0 ) );
        t2 := Triangle( Point( 0.0, 0.0 ), Point( 0.0, 5.0 ), Point( 5.0, 0.0 ) );
        CheckOverlap(t1, t2, 0.0, true, true );
        t1 := Triangle( Point(   0.0, 0.0 ), Point(  5.0, 0.0 ), Point(  0.0, 5.0 ) );
        t2 := Triangle( Point( -10.0, 0.0 ), Point( -5.0, 0.0 ), Point( -1.0, 6.0 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 5.0,  0.0 ), Point( 2.5, 5.0 ) );
        t2 := Triangle( Point( 0.0, 4.0 ), Point( 2.5, -1.0 ), Point( 5.0, 4.0 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 1.0, 1.0 ), Point( 0.0, 2.0 ) );
        t2 := Triangle( Point( 2.0, 1.0 ), Point( 3.0, 0.0 ), Point( 3.0, 2.0 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 1.0,  1.0 ), Point( 0.0, 2.0 ) );
        t2 := Triangle( Point( 2.0, 1.0 ), Point( 3.0, -2.0 ), Point( 3.0, 4.0 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 1.0, 0.0 ), Point( 0.0, 1.0 ) );
        t2 := Triangle( Point( 1.0, 0.0 ), Point( 2.0, 0.0 ), Point( 1.0, 1.1 ) );
        CheckOverlap( t1, t2, 0.0, false, true );
        t1 := Triangle( Point( 0.0, 0.0 ), Point( 1.0, 0.0 ), Point( 0.0, 1.0 ) );
        t2 := Triangle( Point( 1.0, 0.0 ), Point( 2.0, 0.0 ), Point( 1.0, 1.1 ) );
        CheckOverlap( t1, t2, 0.0, false, false );
    end
end.


TrianglesIntersect(T1, T2){		; T1 := [[x1,y1],[x2,y2],[x3,y3]]	, T2 :=[[x4,y4],[x5,y5],[x6,y6]]
	counter := 0
	for i, Pt in T1
		counter += PointInTriangle(Pt, T2)	; check if any coordinate of triangle 1 is inside triangle 2
	for i, Pt in T2
		counter += PointInTriangle(Pt, T1)	; check if any coordinate of triangle 2 is inside triangle 1
	; check if sides of triangle 1 intersect with sides of triangle 2
	counter += LinesIntersect([t1.1,t1.2],[t2.1,t2.2]) ? 1 : 0
	counter += LinesIntersect([t1.1,t1.3],[t2.1,t2.2]) ? 1 : 0
	counter += LinesIntersect([t1.2,t1.3],[t2.1,t2.2]) ? 1 : 0

	counter += LinesIntersect([t1.1,t1.2],[t2.1,t2.3]) ? 1 : 0
	counter += LinesIntersect([t1.1,t1.3],[t2.1,t2.3]) ? 1 : 0
	counter += LinesIntersect([t1.2,t1.3],[t2.1,t2.3]) ? 1 : 0

	counter += LinesIntersect([t1.1,t1.2],[t2.2,t2.3]) ? 1 : 0
	counter += LinesIntersect([t1.1,t1.3],[t2.2,t2.3]) ? 1 : 0
	counter += LinesIntersect([t1.2,t1.3],[t2.2,t2.3]) ? 1 : 0
	return (counter>3) ; 3 points inside or 1 point inside and 2 lines intersect or 3 lines intersect
}
PointInTriangle(pt, Tr){	; pt:=[x,y]	, Tr := [[x1,y1],[x2,y2],[x3,y3]]
	v1 := Tr.1, v2 := Tr.2, v3 := Tr.3
    d1 := sign(pt, v1, v2)
    d2 := sign(pt, v2, v3)
    d3 := sign(pt, v3, v1)
    has_neg := (d1 < 0) || (d2 < 0) || (d3 < 0)
    has_pos := (d1 > 0) || (d2 > 0) || (d3 > 0)
    return !(has_neg && has_pos)
}
sign(p1, p2, p3){
    return (p1.1 - p3.1) * (p2.2 - p3.2) - (p2.1 - p3.1) * (p1.2 - p3.2)
}
LinesIntersect(L1, L2){		; L1 := [[x1,y1],[x2,y2]]	, L2 := [[x3,y3],[x4,y4]]
	x1 := L1[1,1], y1 := L1[1,2]
	x2 := L1[2,1], y2 := L1[2,2]
	x3 := L2[1,1], y3 := L2[1,2]
	x4 := L2[2,1], y4 := L2[2,2]
	x := ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4))
	y := ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4))
	if (x<>"" && y<>"") && isBetween(x, x1, x2) && isBetween(x, x3, x4) && isBetween(y, y1, y2) && isBetween(y, y3, y4)
		return 1
}
isBetween(x, p1, p2){
	return !((x>p1 && x>p2) || (x<p1 && x<p2))
}


#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    double x, y;
} Point;

double det2D(const Point * const p1, const Point * const p2, const Point * const p3) {
    return p1->x * (p2->y - p3->y)
        + p2->x * (p3->y - p1->y)
        + p3->x * (p1->y - p2->y);
}

void checkTriWinding(Point * p1, Point * p2, Point * p3, bool allowReversed) {
    double detTri = det2D(p1, p2, p3);
    if (detTri < 0.0) {
        if (allowReversed) {
            double t = p3->x;
            p3->x = p2->x;
            p2->x = t;

            t = p3->y;
            p3->y = p2->y;
            p2->y = t;
        } else {
            errno = 1;
        }
    }
}

bool boundaryCollideChk(const Point *p1, const Point *p2, const Point *p3, double eps) {
    return det2D(p1, p2, p3) < eps;
}

bool boundaryDoesntCollideChk(const Point *p1, const Point *p2, const Point *p3, double eps) {
    return det2D(p1, p2, p3) <= eps;
}

bool triTri2D(Point t1[], Point t2[], double eps, bool allowReversed, bool onBoundary) {
    bool(*chkEdge)(Point*, Point*, Point*, double);
    int i;

    // Triangles must be expressed anti-clockwise
    checkTriWinding(&t1[0], &t1[1], &t1[2], allowReversed);
    if (errno != 0) {
        return false;
    }
    checkTriWinding(&t2[0], &t2[1], &t2[2], allowReversed);
    if (errno != 0) {
        return false;
    }

    if (onBoundary) {
        // Points on the boundary are considered as colliding
        chkEdge = boundaryCollideChk;
    } else {
        // Points on the boundary are not considered as colliding
        chkEdge = boundaryDoesntCollideChk;
    }

    //For edge E of trangle 1,
    for (i = 0; i < 3; ++i) {
        int j = (i + 1) % 3;

        //Check all points of trangle 2 lay on the external side of the edge E. If
        //they do, the triangles do not collide.
        if (chkEdge(&t1[i], &t1[j], &t2[0], eps) &&
            chkEdge(&t1[i], &t1[j], &t2[1], eps) &&
            chkEdge(&t1[i], &t1[j], &t2[2], eps)) {
            return false;
        }
    }

    //For edge E of trangle 2,
    for (i = 0; i < 3; i++) {
        int j = (i + 1) % 3;

        //Check all points of trangle 1 lay on the external side of the edge E. If
        //they do, the triangles do not collide.
        if (chkEdge(&t2[i], &t2[j], &t1[0], eps) &&
            chkEdge(&t2[i], &t2[j], &t1[1], eps) &&
            chkEdge(&t2[i], &t2[j], &t1[2], eps))
            return false;
    }

    //The triangles collide
    return true;
}

int main() {
    {
        Point t1[] = { {0, 0}, {5, 0}, {0, 5} };
        Point t2[] = { {0, 0}, {5, 0}, {0, 6} };
        printf("%d,true\n", triTri2D(t1, t2, 0.0, false, true));
    }

    {
        Point t1[] = { {0, 0}, {0, 5}, {5, 0} };
        Point t2[] = { {0, 0}, {0, 5}, {5, 0} };
        printf("%d,true\n", triTri2D(t1, t2, 0.0, true, true));
    }

    {
        Point t1[] = { {0, 0}, {5, 0}, {0, 5} };
        Point t2[] = { {-10, 0}, {-5, 0}, {-1, 6} };
        printf("%d,false\n", triTri2D(t1, t2, 0.0, false, true));
    }

    {
        Point t1[] = { {0, 0}, {5, 0}, {2.5, 5} };
        Point t2[] = { {0, 4}, {2.5, -1}, {5, 4} };
        printf("%d,true\n", triTri2D(t1, t2, 0.0, false, true));
    }

    {
        Point t1[] = { {0, 0}, {1, 1}, {0, 2} };
        Point t2[] = { {2, 1}, {3, 0}, {3, 2} };
        printf("%d,false\n", triTri2D(t1, t2, 0.0, false, true));
    }

    {
        Point t1[] = { {0, 0}, {1, 1}, {0, 2} };
        Point t2[] = { {2, 1}, {3, -2}, {3, 4} };
        printf("%d,false\n", triTri2D(t1, t2, 0.0, false, true));
    }

    //Barely touching
    {
        Point t1[] = { {0, 0}, {1, 0}, {0, 1} };
        Point t2[] = { {1, 0}, {2, 0}, {1, 1} };
        printf("%d,true\n", triTri2D(t1, t2, 0.0, false, true));
    }

    //Barely touching
    {
        Point t1[] = { {0, 0}, {1, 0}, {0, 1} };
        Point t2[] = { {1, 0}, {2, 0}, {1, 1} };
        printf("%d,false\n", triTri2D(t1, t2, 0.0, false, false));
    }

    return EXIT_SUCCESS;
}


using System;
using System.Collections.Generic;

namespace TriangleOverlap {
    class Triangle {
        public Tuple<double, double> P1 { get; set; }
        public Tuple<double, double> P2 { get; set; }
        public Tuple<double, double> P3 { get; set; }

        public Triangle(Tuple<double, double> p1, Tuple<double, double> p2, Tuple<double, double> p3) {
            P1 = p1;
            P2 = p2;
            P3 = p3;
        }

        public double Det2D() {
            return P1.Item1 * (P2.Item2 - P3.Item2)
                 + P2.Item1 * (P3.Item2 - P1.Item2)
                 + P3.Item1 * (P3.Item1 - P2.Item2);
        }

        public void CheckTriWinding(bool allowReversed) {
            var detTri = Det2D();
            if (detTri < 0.0) {
                if (allowReversed) {
                    var a = P3;
                    P3 = P2;
                    P2 = a;
                } else {
                    throw new Exception("Triangle has wrong winding direction");
                }
            }
        }

        public bool BoundaryCollideChk(double eps) {
            return Det2D() < eps;
        }

        public bool BoundaryDoesntCollideChk(double eps) {
            return Det2D() <= eps;
        }

        public override string ToString() {
            return string.Format("Triangle: {0}, {1}, {2}", P1, P2, P3);
        }
    }

    class Program {
        static bool BoundaryCollideChk(Triangle t, double eps) {
            return t.BoundaryCollideChk(eps);
        }

        static bool BoundaryDoesntCollideChk(Triangle t, double eps) {
            return t.BoundaryDoesntCollideChk(eps);
        }

        static bool TriTri2D(Triangle t1, Triangle t2, double eps = 0.0, bool allowReversed = false, bool onBoundary = true) {
            // Triangles must be expressed anti-clockwise
            t1.CheckTriWinding(allowReversed);
            t2.CheckTriWinding(allowReversed);
            // 'onBoundary' determines whether points on boundary are considered as colliding or not
            var chkEdge = onBoundary
                ? (Func<Triangle, double, bool>)BoundaryCollideChk
                : BoundaryDoesntCollideChk;
            List<Tuple<double, double>> lp1 = new List<Tuple<double, double>>() { t1.P1, t1.P2, t1.P3 };
            List<Tuple<double, double>> lp2 = new List<Tuple<double, double>>() { t2.P1, t2.P2, t2.P3 };

            // for each edge E of t1
            for (int i = 0; i < 3; i++) {
                var j = (i + 1) % 3;
                // Check all points of t2 lay on the external side of edge E.
                // If they do, the triangles do not overlap.
                if (chkEdge(new Triangle(lp1[i], lp1[j], lp2[0]), eps) &&
                    chkEdge(new Triangle(lp1[i], lp1[j], lp2[1]), eps) &&
                    chkEdge(new Triangle(lp1[i], lp1[j], lp2[2]), eps)) {
                    return false;
                }
            }

            // for each edge E of t2
            for (int i = 0; i < 3; i++) {
                var j = (i + 1) % 3;
                // Check all points of t1 lay on the external side of edge E.
                // If they do, the triangles do not overlap.
                if (chkEdge(new Triangle(lp2[i], lp2[j], lp1[0]), eps) &&
                    chkEdge(new Triangle(lp2[i], lp2[j], lp1[1]), eps) &&
                    chkEdge(new Triangle(lp2[i], lp2[j], lp1[2]), eps)) {
                    return false;
                }
            }

            // The triangles overlap
            return true;
        }

        static void Overlap(Triangle t1, Triangle t2, double eps = 0.0, bool allowReversed = false, bool onBoundary = true) {
            if (TriTri2D(t1, t2, eps, allowReversed, onBoundary)) {
                Console.WriteLine("overlap");
            } else {
                Console.WriteLine("do not overlap");
            }
        }

        static void Main(string[] args) {
            var t1 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(5.0, 0.0), new Tuple<double, double>(0.0, 5.0));
            var t2 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(5.0, 0.0), new Tuple<double, double>(0.0, 6.0));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2);
            Console.WriteLine();

            // need to allow reversed for this pair to avoid exception
            t1 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(0.0, 5.0), new Tuple<double, double>(5.0, 0.0));
            t2 = t1;
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2, 0.0, true);
            Console.WriteLine();

            t1 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(5.0, 0.0), new Tuple<double, double>(0.0, 5.0));
            t2 = new Triangle(new Tuple<double, double>(-10.0, 0.0), new Tuple<double, double>(-5.0, 0.0), new Tuple<double, double>(-1.0, 6.0));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2);
            Console.WriteLine();

            t1.P3 = new Tuple<double, double>(2.5, 5.0);
            t2 = new Triangle(new Tuple<double, double>(0.0, 4.0), new Tuple<double, double>(2.5, -1.0), new Tuple<double, double>(5.0, 4.0));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2);
            Console.WriteLine();

            t1 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(1.0, 1.0), new Tuple<double, double>(0.0, 2.0));
            t2 = new Triangle(new Tuple<double, double>(2.0, 1.0), new Tuple<double, double>(3.0, 0.0), new Tuple<double, double>(3.0, 2.0));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2);
            Console.WriteLine();

            t2 = new Triangle(new Tuple<double, double>(2.0, 1.0), new Tuple<double, double>(3.0, -2.0), new Tuple<double, double>(3.0, 4.0));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Overlap(t1, t2);
            Console.WriteLine();

            t1 = new Triangle(new Tuple<double, double>(0.0, 0.0), new Tuple<double, double>(1.0, 0.0), new Tuple<double, double>(0.0, 1.0));
            t2 = new Triangle(new Tuple<double, double>(1.0, 0.0), new Tuple<double, double>(2.0, 0.0), new Tuple<double, double>(1.0, 1.1));
            Console.WriteLine("{0} and\n{1}", t1, t2);
            Console.WriteLine("which have only a single corner in contact, if boundary points collide");
            Overlap(t1, t2);
            Console.WriteLine();

            Console.WriteLine("{0} and\n{1}", t1, t2);
            Console.WriteLine("which have only a single corner in contact, if boundary points do not collide");
            Overlap(t1, t2, 0.0, false, false);
        }
    }
}


#include <vector>
#include <iostream>
#include <stdexcept>
using namespace std;

typedef std::pair<double, double> TriPoint;

inline double Det2D(TriPoint &p1, TriPoint &p2, TriPoint &p3)
{
	return +p1.first*(p2.second-p3.second)
		+p2.first*(p3.second-p1.second)
		+p3.first*(p1.second-p2.second);
}

void CheckTriWinding(TriPoint &p1, TriPoint &p2, TriPoint &p3, bool allowReversed)
{
	double detTri = Det2D(p1, p2, p3);
	if(detTri < 0.0)
	{
		if (allowReversed)
		{
			TriPoint a = p3;
			p3 = p2;
			p2 = a;
		}
		else throw std::runtime_error("triangle has wrong winding direction");
	}
}

bool BoundaryCollideChk(TriPoint &p1, TriPoint &p2, TriPoint &p3, double eps)
{
	return Det2D(p1, p2, p3) < eps;
}

bool BoundaryDoesntCollideChk(TriPoint &p1, TriPoint &p2, TriPoint &p3, double eps)
{
	return Det2D(p1, p2, p3) <= eps;
}

bool TriTri2D(TriPoint *t1,
	TriPoint *t2,
	double eps = 0.0, bool allowReversed = false, bool onBoundary = true)
{
	//Trangles must be expressed anti-clockwise
	CheckTriWinding(t1[0], t1[1], t1[2], allowReversed);
	CheckTriWinding(t2[0], t2[1], t2[2], allowReversed);

	bool (*chkEdge)(TriPoint &, TriPoint &, TriPoint &, double) = NULL;
	if(onBoundary) //Points on the boundary are considered as colliding
		chkEdge = BoundaryCollideChk;
	else //Points on the boundary are not considered as colliding
		chkEdge = BoundaryDoesntCollideChk;

	//For edge E of trangle 1,
	for(int i=0; i<3; i++)
	{
		int j=(i+1)%3;

		//Check all points of trangle 2 lay on the external side of the edge E. If
		//they do, the triangles do not collide.
		if (chkEdge(t1[i], t1[j], t2[0], eps) &&
			chkEdge(t1[i], t1[j], t2[1], eps) &&
			chkEdge(t1[i], t1[j], t2[2], eps))
			return false;
	}

	//For edge E of trangle 2,
	for(int i=0; i<3; i++)
	{
		int j=(i+1)%3;

		//Check all points of trangle 1 lay on the external side of the edge E. If
		//they do, the triangles do not collide.
		if (chkEdge(t2[i], t2[j], t1[0], eps) &&
			chkEdge(t2[i], t2[j], t1[1], eps) &&
			chkEdge(t2[i], t2[j], t1[2], eps))
			return false;
	}

	//The triangles collide
	return true;
}

int main()
{
	{TriPoint t1[] = {TriPoint(0,0),TriPoint(5,0),TriPoint(0,5)};
	TriPoint t2[] = {TriPoint(0,0),TriPoint(5,0),TriPoint(0,6)};
	cout << TriTri2D(t1, t2) << "," << true << endl;}

	{TriPoint t1[] = {TriPoint(0,0),TriPoint(0,5),TriPoint(5,0)};
	TriPoint t2[] = {TriPoint(0,0),TriPoint(0,5),TriPoint(5,0)};
	cout << TriTri2D(t1, t2, 0.0, true) << "," << true << endl;}

	{TriPoint t1[] = {TriPoint(0,0),TriPoint(5,0),TriPoint(0,5)};
	TriPoint t2[] = {TriPoint(-10,0),TriPoint(-5,0),TriPoint(-1,6)};
	cout << TriTri2D(t1, t2) << "," << false << endl;}

	{TriPoint t1[] = {TriPoint(0,0),TriPoint(5,0),TriPoint(2.5,5)};
	TriPoint t2[] = {TriPoint(0,4),TriPoint(2.5,-1),TriPoint(5,4)};
	cout << TriTri2D(t1, t2) << "," << true << endl;}

	{TriPoint t1[] = {TriPoint(0,0),TriPoint(1,1),TriPoint(0,2)};
	TriPoint t2[] = {TriPoint(2,1),TriPoint(3,0),TriPoint(3,2)};
	cout << TriTri2D(t1, t2) << "," << false << endl;}

	{TriPoint t1[] = {TriPoint(0,0),TriPoint(1,1),TriPoint(0,2)};
	TriPoint t2[] = {TriPoint(2,1),TriPoint(3,-2),TriPoint(3,4)};
	cout << TriTri2D(t1, t2) << "," << false << endl;}

	//Barely touching
	{TriPoint t1[] = {TriPoint(0,0),TriPoint(1,0),TriPoint(0,1)};
	TriPoint t2[] = {TriPoint(1,0),TriPoint(2,0),TriPoint(1,1)};
	cout << TriTri2D(t1, t2, 0.0, false, true) << "," << true << endl;}

	//Barely touching
	{TriPoint t1[] = {TriPoint(0,0),TriPoint(1,0),TriPoint(0,1)};
	TriPoint t2[] = {TriPoint(1,0),TriPoint(2,0),TriPoint(1,1)};
	cout << TriTri2D(t1, t2, 0.0, false, false) << "," << false << endl;}

}


import std.stdio;
import std.typecons;

alias Pair = Tuple!(real, real);

struct Triangle {
    Pair p1;
    Pair p2;
    Pair p3;

    void toString(scope void delegate(const(char)[]) sink) const {
        import std.format;
        sink("Triangle: ");
        formattedWrite!"%s"(sink, p1);
        sink(", ");
        formattedWrite!"%s"(sink, p2);
        sink(", ");
        formattedWrite!"%s"(sink, p3);
    }
}

auto det2D(Triangle t) {
    return t.p1[0] *(t.p2[1] - t.p3[1])
         + t.p2[0] *(t.p3[1] - t.p1[1])
         + t.p3[0] *(t.p1[1] - t.p2[1]);
}

void checkTriWinding(Triangle t, bool allowReversed) {
    auto detTri = t.det2D();
    if (detTri < 0.0) {
        if (allowReversed) {
            auto a = t.p3;
            t.p3 = t.p2;
            t.p2 = a;
        } else {
            throw new Exception("Triangle has wrong winding direction");
        }
    }
}

auto boundaryCollideChk(Triangle t, real eps) {
    return t.det2D() < eps;
}

auto boundaryDoesntCollideChk(Triangle t, real eps) {
    return t.det2D() <= eps;
}

bool triTri2D(Triangle t1, Triangle t2, real eps = 0.0, bool allowReversed = false, bool onBoundary = true) {
    // Triangles must be expressed anti-clockwise
    checkTriWinding(t1, allowReversed);
    checkTriWinding(t2, allowReversed);
    // 'onBoundary' determines whether points on boundary are considered as colliding or not
    auto chkEdge = onBoundary ? &boundaryCollideChk : &boundaryDoesntCollideChk;
    auto lp1 = [t1.p1, t1.p2, t1.p3];
    auto lp2 = [t2.p1, t2.p2, t2.p3];

    // for each edge E of t1
    foreach (i; 0..3) {
        auto j = (i + 1) % 3;
        // Check all points of t2 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
        if (chkEdge(Triangle(lp1[i], lp1[j], lp2[0]), eps) &&
            chkEdge(Triangle(lp1[i], lp1[j], lp2[1]), eps) &&
            chkEdge(Triangle(lp1[i], lp1[j], lp2[2]), eps)) {
            return false;
        }
    }

    // for each edge E of t2
    foreach (i; 0..3) {
        auto j = (i + 1) % 3;
        // Check all points of t1 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
        if (chkEdge(Triangle(lp2[i], lp2[j], lp1[0]), eps) &&
            chkEdge(Triangle(lp2[i], lp2[j], lp1[1]), eps) &&
            chkEdge(Triangle(lp2[i], lp2[j], lp1[2]), eps)) {
            return false;
        }
    }

    // The triangles overlap
    return true;
}

void overlap(Triangle t1, Triangle t2, real eps = 0.0, bool allowReversed = false, bool onBoundary = true) {
    if (triTri2D(t1, t2, eps, allowReversed, onBoundary)) {
        writeln("overlap");
    } else {
        writeln("do not overlap");
    }
}

void main() {
    auto t1 = Triangle(Pair(0.0, 0.0), Pair(5.0, 0.0), Pair(0.0, 5.0));
    auto t2 = Triangle(Pair(0.0, 0.0), Pair(5.0, 0.0), Pair(0.0, 6.0));
    writeln(t1, " and\n", t2);
    overlap(t1, t2);
    writeln;

    // need to allow reversed for this pair to avoid exception
    t1 = Triangle(Pair(0.0, 0.0), Pair(0.0, 5.0), Pair(5.0, 0.0));
    t2 = t1;
    writeln(t1, " and\n", t2);
    overlap(t1, t2, 0.0, true);
    writeln;

    t1 = Triangle(Pair(0.0, 0.0), Pair(5.0, 0.0), Pair(0.0, 5.0));
    t2 = Triangle(Pair(-10.0, 0.0), Pair(-5.0, 0.0), Pair(-1.0, 6.0));
    writeln(t1, " and\n", t2);
    overlap(t1, t2);
    writeln;

    t1.p3 = Pair(2.5, 5.0);
    t2 = Triangle(Pair(0.0, 4.0), Pair(2.5, -1.0), Pair(5.0, 4.0));
    writeln(t1, " and\n", t2);
    overlap(t1, t2);
    writeln;

    t1 = Triangle(Pair(0.0, 0.0), Pair(1.0, 1.0), Pair(0.0, 2.0));
    t2 = Triangle(Pair(2.0, 1.0), Pair(3.0, 0.0), Pair(3.0, 2.0));
    writeln(t1, " and\n", t2);
    overlap(t1, t2);
    writeln;

    t2 = Triangle(Pair(2.0, 1.0), Pair(3.0, -2.0), Pair(3.0, 4.0));
    writeln(t1, " and\n", t2);
    overlap(t1, t2);
    writeln;

    t1 = Triangle(Pair(0.0, 0.0), Pair(1.0, 0.0), Pair(0.0, 1.0));
    t2 = Triangle(Pair(1.0, 0.0), Pair(2.0, 0.0), Pair(1.0, 1.1));
    writeln(t1, " and\n", t2);
    writeln("which have only a single corner in contact, if boundary points collide");
    overlap(t1, t2);
    writeln;

    writeln(t1, " and\n", t2);
    writeln("which have only a single corner in contact, if boundary points do not collide");
    overlap(t1, t2, 0.0, false, false);
}


open System

type Point = double * double
type Triangle = Point * Point * Point

let Det2D (t:Triangle) =
    let (p1, p2, p3) = t
    let (p1x, p1y) = p1
    let (p2x, p2y) = p2
    let (p3x, p3y) = p3

    p1x * (p2y - p3y) +
    p2x * (p3y - p1y) +
    p3x * (p1y - p2y)

let CheckTriWinding allowReversed t =
    let detTri = Det2D t
    if detTri < 0.0 then
        if allowReversed then
            let (p1, p2, p3) = t
            (p1, p3, p2)
        else
            raise (Exception "Triangle has wrong winding direction")
    else
        t

let boundaryCollideChk eps t =
    (Det2D t) < eps

let boundaryDoesntCollideChk eps t =
    (Det2D t) <= eps

let TriTri2D eps allowReversed onBoundary t1 t2 =
    // Triangles must be expressed anti-clockwise
    let t3 = CheckTriWinding allowReversed t1
    let t4 = CheckTriWinding allowReversed t2

    // 'onBoundary' determines whether points on boundary are considered as colliding or not
    let chkEdge = if onBoundary then boundaryCollideChk else boundaryDoesntCollideChk
    let (t1p1, t1p2, t1p3) = t3
    let (t2p1, t2p2, t2p3) = t4

    // Check all points of t2 lay on the external side of edge E.
    // If they do, the triangles do not overlap.
    if (chkEdge eps (t1p1, t1p2, t2p1)) && (chkEdge eps (t1p1, t1p2, t2p2)) && (chkEdge eps (t1p1, t1p2, t2p3)) then
        false
    else if (chkEdge eps (t1p2, t1p3, t2p1)) && (chkEdge eps (t1p2, t1p3, t2p2)) && (chkEdge eps (t1p2, t1p3, t2p3)) then
        false
    else if (chkEdge eps (t1p3, t1p1, t2p1)) && (chkEdge eps (t1p3, t1p1, t2p2)) && (chkEdge eps (t1p3, t1p1, t2p3)) then
        false

    // Check all points of t1 lay on the external side of edge E.
    // If they do, the triangles do not overlap.
    else if (chkEdge eps (t2p1, t2p2, t1p1)) && (chkEdge eps (t2p1, t2p2, t1p2)) && (chkEdge eps (t2p1, t2p2, t1p3)) then
        false
    else if (chkEdge eps (t2p2, t2p3, t1p1)) && (chkEdge eps (t2p2, t2p3, t1p2)) && (chkEdge eps (t2p2, t2p3, t1p3)) then
        false
    else if (chkEdge eps (t2p3, t2p1, t1p1)) && (chkEdge eps (t2p3, t2p1, t1p2)) && (chkEdge eps (t2p3, t2p1, t1p3)) then
        false

    else
        // The triangles overlap
        true

let Print t1 t2 =
    Console.WriteLine("{0} and\n{1}\n{2}\n", t1, t2, if TriTri2D 0.0 false true t1 t2 then "overlap" else "do not overlap")

[<EntryPoint>]
let main _ =
    let t1 = ((0.0, 0.0), (5.0, 0.0), (0.0, 5.0))
    let t2 = ((0.0, 0.0), (5.0, 0.0), (0.0, 6.0))
    Print t1 t2

    let t3 = ((0.0, 0.0), (0.0, 5.0), (5.0, 0.0))
    Console.WriteLine("{0} and\n{1}\n{2}\n", t3, t3, if TriTri2D 0.0 true true t3 t3 then "overlap (reversed)" else "do not overlap")

    let t4 = ((0.0, 0.0), (5.0, 0.0), (0.0, 5.0))
    let t5 = ((-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0))
    Print t4 t5

    let t6 = ((0.0, 0.0), (5.0, 0.0), (2.5, 5.0))
    let t7 = ((0.0, 4.0), (2.5, -1.0), (5.0, 4.0))
    Print t6 t7

    let t8 = ((0.0, 0.0), (1.0, 1.0), (0.0, 2.0))
    let t9 = ((2.0, 1.0), (3.0, 0.0), (3.0, 2.0))
    Print t8 t9

    let t10 = ((2.0, 1.0), (3.0, -2.0), (3.0, 4.0))
    Print t8 t10

    let t11 = ((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))
    let t12 = ((1.0, 0.0), (2.0, 0.0), (1.0, 1.1))
    printfn "The following triangles which have only a single corner in contact, if boundary points collide"
    Print t11 t12

    Console.WriteLine("{0} and\n{1}\nwhich have only a single corner in contact, if boundary points do not collide\n{2}", t11, t12, if TriTri2D 0.0 false false t11 t12 then "overlap" else "do not overlap")

    0 // return an integer exit code


#macro min(x,y)
   Iif(x>y,y,x)
#endmacro
#macro max(x,y)
   Iif(x>y,x,y)
#endmacro

type pnt  'typedef for a point
    x as double
    y as double
end type

type edg  'typedef for an edge
    p1 as pnt
    p2 as pnt
end type

function point_in_tri( r as pnt, a as pnt, b as pnt, c as pnt ) as boolean
    'uses barycentric coordinates to determine whether point r is in the triangle defined by a, b, c
    dim as double k = ((b.y - c.y)*(a.x - c.x) + (c.x - b.x)*(a.y - c.y))
    dim as double v = ((b.y - c.y)*(r.x - c.x) + (c.x - b.x)*(r.y - c.y)) / k
    dim as double w = ((c.y - a.y)*(r.x - c.x) + (a.x - c.x)*(r.y - c.y)) / k
    dim as double z = 1 - v- w
    if v<0 or v>1 then return false
    if w<0 or w>1 then return false
    if z<0 or z>1 then return false
    return true
end function

function bbox_overlap( a1 as pnt, a2 as pnt, b1 as pnt, b2 as pnt) as boolean
    dim as double a1x = min(a1.x, a2.x), a1y = min(a1.y, a2.y)
    dim as double a2x = max(a1.x, a2.x), a2y = max(a1.y, a2.y)
    dim as double b1x = min(b1.x, b2.x), b1y = min(b1.y, b2.y)
    dim as double b2x = max(b1.x, b2.x), b2y = max(b1.y, b2.y)
    if a1x > b2x or b1x > a2x then return false
    if a1y > b2y or b2y > a2y then return false
    return true
end function

function ccw( a as pnt, b as pnt, c as pnt) as double
   return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y)
end function

function line_intersect( a as edg, b as edg ) as boolean
   if ccw(a.p1, a.p2, b.p1)*ccw(a.p1, a.p2, b.p2) > 0 then return false
   if ccw(b.p1, b.p2, a.p1)*ccw(b.p1, b.p2, a.p2) > 0 then return false
   if not bbox_overlap( a.p1, a.p2, b.p1, b.p2 ) then return false
   return true
end function

function triangle_overlap( a() as pnt, b() as pnt ) as boolean
    'if two triangles overlap then either a corner of one triangle is inside
    'the other OR an edge of one triangle intersects an edge of the other.
    dim as uinteger i, j
    dim as edg c, d
    for i = 0 to 2
        if point_in_tri( a(i), b(0), b(1), b(2) ) then return true
        if point_in_tri( b(i), a(0), a(1), a(2) ) then return true
        c.p1.x = a(i).x
        c.p1.y = a(i).y
        c.p2.x = a((i+1) mod 3).x
        c.p2.y = a((i+1) mod 3).y
        for j = 0 to 2
            d.p1.x = b(i).x
            d.p1.y = b(i).y
            d.p2.x = b((i+1) mod 3).x
            d.p2.y = b((i+1) mod 3).y
            if line_intersect( c, d ) then return true
        next j
    next i
    return 00
end function

data 0,0 , 5,0 , 0,5     ,    0,0 , 5,0 , 0,6
data 0,0 , 0,5 , 5,0     ,    0,0 , 0,5 , 5,0
data 0,0 , 5,0 , 0,5     ,    -10,0 , -5,0 , -1,6
data 0,0 , 5,0 , 2.5,5   ,    0,4 , 2.5,-1 , 5,4
data 0,0 , 1,1 , 0,2     ,    2,1 , 3,0 , 3,2
data 0,0 , 1,1 , 0,2     ,    2,1 , 3,-2 , 3,4
data 0,0 , 1,0 , 0,1     ,    1,0 , 2,0 , 1,1

dim as uinteger t, i
dim as pnt a(0 to 2), b(0 to 2)

for t = 1 to 7
    for i = 0 to 2
        read a(i).x, a(i).y
    next i
    for i = 0 to 2
        read b(i).x, b(i).y
    next i
    print triangle_overlap( a(), b() )
next t


package main

import "fmt"

type point struct {
    x, y float64
}

func (p point) String() string {
    return fmt.Sprintf("(%.1f, %.1f)", p.x, p.y)
}

type triangle struct {
    p1, p2, p3 point
}

func (t *triangle) String() string {
    return fmt.Sprintf("Triangle %s, %s, %s", t.p1, t.p2, t.p3)
}

func (t *triangle) det2D() float64 {
    return t.p1.x * (t.p2.y - t.p3.y) +
           t.p2.x * (t.p3.y - t.p1.y) +
           t.p3.x * (t.p1.y - t.p2.y)
}

func (t *triangle) checkTriWinding(allowReversed bool) {
    detTri := t.det2D()
    if detTri < 0.0 {
        if allowReversed {
            a := t.p3
            t.p3 = t.p2
            t.p2 = a
        } else {
            panic("Triangle has wrong winding direction.")
        }
    }
}

func boundaryCollideChk(t *triangle, eps float64) bool {
    return t.det2D() < eps
}

func boundaryDoesntCollideChk(t *triangle, eps float64) bool {
    return t.det2D() <= eps
}

func triTri2D(t1, t2 *triangle, eps float64, allowReversed, onBoundary bool) bool {
    // Triangles must be expressed anti-clockwise.
    t1.checkTriWinding(allowReversed)
    t2.checkTriWinding(allowReversed)

    // 'onBoundary' determines whether points on boundary are considered as colliding or not.
    var chkEdge func (*triangle, float64) bool
    if onBoundary {
        chkEdge = boundaryCollideChk
    } else {
        chkEdge = boundaryDoesntCollideChk
    }
    lp1 := [3]point{t1.p1, t1.p2, t1.p3}
    lp2 := [3]point{t2.p1, t2.p2, t2.p3}

    // for each edge E of t1
    for i := 0; i < 3; i++ {
        j := (i + 1) % 3
        // Check all points of t2 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
        tri1 := &triangle{lp1[i], lp1[j], lp2[0]}
        tri2 := &triangle{lp1[i], lp1[j], lp2[1]}
        tri3 := &triangle{lp1[i], lp1[j], lp2[2]}
        if chkEdge(tri1, eps) && chkEdge(tri2, eps) && chkEdge(tri3, eps) {
            return false
        }
    }

    // for each edge E of t2
    for i := 0; i < 3; i++ {
        j := (i + 1) % 3
        // Check all points of t1 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
        tri1 := &triangle{lp2[i], lp2[j], lp1[0]}
        tri2 := &triangle{lp2[i], lp2[j], lp1[1]}
        tri3 := &triangle{lp2[i], lp2[j], lp1[2]}
        if chkEdge(tri1, eps) && chkEdge(tri2, eps) && chkEdge(tri3, eps) {
            return false
        }
    }

    // The triangles overlap.
    return true
}

func iff(cond bool, s1, s2 string) string {
    if cond {
        return s1
    }
    return s2
}

func main() {
    t1 := &triangle{point{0.0, 0.0}, point{5.0, 0.0}, point{0.0, 5.0}}
    t2 := &triangle{point{0.0, 0.0}, point{5.0, 0.0}, point{0.0, 6.0}}
    fmt.Printf("%s and\n%s\n", t1, t2)
    overlapping := triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    // Need to allow reversed for this pair to avoid panic.
    t1 = &triangle{point{0.0, 0.0}, point{0.0, 5.0}, point{5.0, 0.0}}
    t2 = t1
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    overlapping = triTri2D(t1, t2, 0.0, true, true)
    fmt.Println(iff(overlapping, "overlap (reversed)", "do not overlap"))

    t1 = &triangle{point{0.0, 0.0}, point{5.0, 0.0}, point{0.0, 5.0}}
    t2 = &triangle{point{-10.0, 0.0}, point{-5.0, 0.0}, point{-1.0, 6.0}}
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    overlapping = triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    t1.p3 = point{2.5, 5.0}
    t2 = &triangle{point{0.0, 4.0}, point{2.5, -1.0}, point{5.0, 4.0}}
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    overlapping = triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    t1 = &triangle{point{0.0, 0.0}, point{1.0, 1.0}, point{0.0, 2.0}}
    t2 = &triangle{point{2.0, 1.0}, point{3.0, 0.0}, point{3.0, 2.0}}
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    overlapping = triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    t2 = &triangle{point{2.0, 1.0}, point{3.0, -2.0}, point{3.0, 4.0}}
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    overlapping = triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    t1 = &triangle{point{0.0, 0.0}, point{1.0, 0.0}, point{0.0, 1.0}}
    t2 = &triangle{point{1.0, 0.0}, point{2.0, 0.0}, point{1.0, 1.1}}
    fmt.Printf("\n%s and\n%s\n", t1, t2)
    println("which have only a single corner in contact, if boundary points collide")
    overlapping = triTri2D(t1, t2, 0.0, false, true)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))

    fmt.Printf("\n%s and\n%s\n", t1, t2)
    fmt.Println("which have only a single corner in contact, if boundary points do not collide")
    overlapping = triTri2D(t1, t2, 0.0, false, false)
    fmt.Println(iff(overlapping, "overlap", "do not overlap"))
}


import java.util.function.BiFunction

class TriangleOverlap {
    private static class Pair {
        double first
        double second

        Pair(double first, double second) {
            this.first = first
            this.second = second
        }

        @Override
        String toString() {
            return String.format("(%s, %s)", first, second)
        }
    }

    private static class Triangle {
        Pair p1, p2, p3

        Triangle(Pair p1, Pair p2, Pair p3) {
            this.p1 = p1
            this.p2 = p2
            this.p3 = p3
        }

        @Override
        String toString() {
            return String.format("Triangle: %s, %s, %s", p1, p2, p3)
        }
    }

    private static double det2D(Triangle t) {
        Pair p1 = t.p1
        Pair p2 = t.p2
        Pair p3 = t.p3
        return p1.first * (p2.second - p3.second) + p2.first * (p3.second - p1.second) + p3.first * (p1.second - p2.second)
    }

    private static void checkTriWinding(Triangle t, boolean allowReversed) {
        double detTri = det2D(t)
        if (detTri < 0.0) {
            if (allowReversed) {
                Pair a = t.p3
                t.p3 = t.p2
                t.p2 = a
            } else throw new RuntimeException("Triangle has wrong winding direction")
        }
    }

    private static boolean boundaryCollideChk(Triangle t, double eps) {
        return det2D(t) < eps
    }

    private static boolean boundaryDoesntCollideChk(Triangle t, double eps) {
        return det2D(t) <= eps
    }

    private static boolean triTri2D(Triangle t1, Triangle t2) {
        return triTri2D(t1, t2, 0.0, false, true)
    }

    private static boolean triTri2D(Triangle t1, Triangle t2, double eps, boolean allowedReversed) {
        return triTri2D(t1, t2, eps, allowedReversed, true)
    }

    private static boolean triTri2D(Triangle t1, Triangle t2, double eps, boolean allowedReversed, boolean onBoundary) {
        // Triangles must be expressed anti-clockwise
        checkTriWinding(t1, allowedReversed)
        checkTriWinding(t2, allowedReversed)
        // 'onBoundary' determines whether points on boundary are considered as colliding or not
        BiFunction<Triangle, Double, Boolean> chkEdge = onBoundary ? TriangleOverlap.&boundaryCollideChk : TriangleOverlap.&boundaryDoesntCollideChk
        Pair[] lp1 = [t1.p1, t1.p2, t1.p3]
        Pair[] lp2 = [t2.p1, t2.p2, t2.p3]

        // for each edge E of t1
        for (int i = 0; i < 3; ++i) {
            int j = (i + 1) % 3
            // Check all points of t2 lay on the external side of edge E.
            // If they do, the triangles do not overlap.
            if (chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[0]), eps) &&
                    chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[1]), eps) &&
                    chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[2]), eps)) return false
        }

        // for each edge E of t2
        for (int i = 0; i < 3; ++i) {
            int j = (i + 1) % 3
            // Check all points of t1 lay on the external side of edge E.
            // If they do, the triangles do not overlap.
            if (chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[0]), eps) &&
                    chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[1]), eps) &&
                    chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[2]), eps)) return false
        }

        // The triangles overlap
        return true
    }

    static void main(String[] args) {
        Triangle t1 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 5.0))
        Triangle t2 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 6.0))
        printf("%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        // need to allow reversed for this pair to avoid exception
        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(0.0, 5.0), new Pair(5.0, 0.0))
        t2 = t1
        printf("\n%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2, 0.0, true)) {
            println("overlap (reversed)")
        } else {
            println("do not overlap")
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 5.0))
        t2 = new Triangle(new Pair(-10.0, 0.0), new Pair(-5.0, 0.0), new Pair(-1.0, 6.0))
        printf("\n%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        t1.p3 = new Pair(2.5, 5.0)
        t2 = new Triangle(new Pair(0.0, 4.0), new Pair(2.5, -1.0), new Pair(5.0, 4.0))
        printf("\n%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(1.0, 1.0), new Pair(0.0, 2.0))
        t2 = new Triangle(new Pair(2.0, 1.0), new Pair(3.0, 0.0), new Pair(3.0, 2.0))
        printf("\n%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        t2 = new Triangle(new Pair(2.0, 1.0), new Pair(3.0, -2.0), new Pair(3.0, 4.0))
        printf("\n%s and\n%s\n", t1, t2)
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(1.0, 0.0), new Pair(0.0, 1.0))
        t2 = new Triangle(new Pair(1.0, 0.0), new Pair(2.0, 0.0), new Pair(1.0, 1.1))
        printf("\n%s and\n%s\n", t1, t2)
        println("which have only a single corner in contact, if boundary points collide")
        if (triTri2D(t1, t2)) {
            println("overlap")
        } else {
            println("do not overlap")
        }

        printf("\n%s and\n%s\n", t1, t2)
        println("which have only a single corner in contact, if boundary points do not collide")
        if (triTri2D(t1, t2, 0.0, false, false)) {
            println("overlap")
        } else {
            println("do not overlap")
        }
    }
}


isOverlapping :: Triangle Double -> Triangle Double -> Bool
isOverlapping t1 t2 = vertexInside || midLineInside
  where
    vertexInside =
      any (isInside t1) (vertices t2) ||
      any (isInside t2) (vertices t1)

    isInside t = (Outside /=) . overlapping t

    midLineInside =
      any (\p -> isInside t1 p && isInside t2 p) midPoints

    midPoints =
      [ intersections l1 l2 | l1 <- midLines t1
                            , l2 <- midLines t2 ]

    intersections (a1,b1,c1) (a2,b2,c2) =
      ( -(-b2*c1+b1*c2)/(a2*b1-a1*b2)
      , -(a2*c1-a1*c2)/(a2*b1-a1*b2) )

    midLines (Triangle a b c) =
      [line a b c, line b c a, line c a b]

    line (x,y) (ax, ay) (bx, by) =
      (ay+by-2*y, -ax-bx+2*x, -ay*x-by*x+ax*y+bx*y)

test = map (uncurry isOverlapping)
  [ (Triangle (0,0) (5,0) (0,5), Triangle (0,0) (5,0) (0,6))
  , (Triangle (0,0) (0,5) (5,0), Triangle (0,0) (0,5) (5,0))
  , (Triangle (0,0) (5,0) (0,5), Triangle (-10,0) (-5,0) (-1,6))
  , (Triangle (0,0) (5,0) (2.5,5), Triangle (0,4) (2.5,-1) (5,4))
  , (Triangle (0,0) (1,1) (0,2), Triangle (2,1) (3,0) (3,2))
  , (Triangle (0,0) (1,1) (0,2), Triangle (2,1) (3,-2) (3,4))
  , (Triangle (0,0) (1,0) (0,1), Triangle (1,0) (2,0) (1,1))]


import java.util.function.BiFunction;

public class TriangleOverlap {
    private static class Pair {
        double first;
        double second;

        Pair(double first, double second) {
            this.first = first;
            this.second = second;
        }

        @Override
        public String toString() {
            return String.format("(%s, %s)", first, second);
        }
    }

    private static class Triangle {
        Pair p1, p2, p3;

        Triangle(Pair p1, Pair p2, Pair p3) {
            this.p1 = p1;
            this.p2 = p2;
            this.p3 = p3;
        }

        @Override
        public String toString() {
            return String.format("Triangle: %s, %s, %s", p1, p2, p3);
        }
    }

    private static double det2D(Triangle t) {
        Pair p1 = t.p1;
        Pair p2 = t.p2;
        Pair p3 = t.p3;
        return p1.first * (p2.second - p3.second)
            + p2.first * (p3.second - p1.second)
            + p3.first * (p1.second - p2.second);
    }

    private static void checkTriWinding(Triangle t, boolean allowReversed) {
        double detTri = det2D(t);
        if (detTri < 0.0) {
            if (allowReversed) {
                Pair a = t.p3;
                t.p3 = t.p2;
                t.p2 = a;
            } else throw new RuntimeException("Triangle has wrong winding direction");
        }
    }

    private static boolean boundaryCollideChk(Triangle t, double eps) {
        return det2D(t) < eps;
    }

    private static boolean boundaryDoesntCollideChk(Triangle t, double eps) {
        return det2D(t) <= eps;
    }

    private static boolean triTri2D(Triangle t1, Triangle t2) {
        return triTri2D(t1, t2, 0.0, false, true);
    }

    private static boolean triTri2D(Triangle t1, Triangle t2, double eps, boolean allowedReversed) {
        return triTri2D(t1, t2, eps, allowedReversed, true);
    }

    private static boolean triTri2D(Triangle t1, Triangle t2, double eps, boolean allowedReversed, boolean onBoundary) {
        // Triangles must be expressed anti-clockwise
        checkTriWinding(t1, allowedReversed);
        checkTriWinding(t2, allowedReversed);
        // 'onBoundary' determines whether points on boundary are considered as colliding or not
        BiFunction<Triangle, Double, Boolean> chkEdge = onBoundary ? TriangleOverlap::boundaryCollideChk : TriangleOverlap::boundaryDoesntCollideChk;
        Pair[] lp1 = new Pair[]{t1.p1, t1.p2, t1.p3};
        Pair[] lp2 = new Pair[]{t2.p1, t2.p2, t2.p3};

        // for each edge E of t1
        for (int i = 0; i < 3; ++i) {
            int j = (i + 1) % 3;
            // Check all points of t2 lay on the external side of edge E.
            // If they do, the triangles do not overlap.
            if (chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[0]), eps) &&
                chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[1]), eps) &&
                chkEdge.apply(new Triangle(lp1[i], lp1[j], lp2[2]), eps)) return false;
        }

        // for each edge E of t2
        for (int i = 0; i < 3; ++i) {
            int j = (i + 1) % 3;
            // Check all points of t1 lay on the external side of edge E.
            // If they do, the triangles do not overlap.
            if (chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[0]), eps) &&
                chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[1]), eps) &&
                chkEdge.apply(new Triangle(lp2[i], lp2[j], lp1[2]), eps)) return false;
        }

        // The triangles overlap
        return true;
    }

    public static void main(String[] args) {
        Triangle t1 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 5.0));
        Triangle t2 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 6.0));
        System.out.printf("%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        // need to allow reversed for this pair to avoid exception
        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(0.0, 5.0), new Pair(5.0, 0.0));
        t2 = t1;
        System.out.printf("\n%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2, 0.0, true)) {
            System.out.println("overlap (reversed)");
        } else {
            System.out.println("do not overlap");
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(5.0, 0.0), new Pair(0.0, 5.0));
        t2 = new Triangle(new Pair(-10.0, 0.0), new Pair(-5.0, 0.0), new Pair(-1.0, 6.0));
        System.out.printf("\n%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        t1.p3 = new Pair(2.5, 5.0);
        t2 = new Triangle(new Pair(0.0, 4.0), new Pair(2.5, -1.0), new Pair(5.0, 4.0));
        System.out.printf("\n%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(1.0, 1.0), new Pair(0.0, 2.0));
        t2 = new Triangle(new Pair(2.0, 1.0), new Pair(3.0, 0.0), new Pair(3.0, 2.0));
        System.out.printf("\n%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        t2 = new Triangle(new Pair(2.0, 1.0), new Pair(3.0, -2.0), new Pair(3.0, 4.0));
        System.out.printf("\n%s and\n%s\n", t1, t2);
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        t1 = new Triangle(new Pair(0.0, 0.0), new Pair(1.0, 0.0), new Pair(0.0, 1.0));
        t2 = new Triangle(new Pair(1.0, 0.0), new Pair(2.0, 0.0), new Pair(1.0, 1.1));
        System.out.printf("\n%s and\n%s\n", t1, t2);
        System.out.println("which have only a single corner in contact, if boundary points collide");
        if (triTri2D(t1, t2)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }

        System.out.printf("\n%s and\n%s\n", t1, t2);
        System.out.println("which have only a single corner in contact, if boundary points do not collide");
        if (triTri2D(t1, t2, 0.0, false, false)) {
            System.out.println("overlap");
        } else {
            System.out.println("do not overlap");
        }
    }
}


# Points are realized as arrays of two numbers [x, y]

# Triangles are realized as triples of Points [p1, p2, p3]

# Input: a Triangle
def det2D:
  . as [ [$p1x, $p1y],  [$p2x, $p2y],  [$p3x, $p3y]]
  | $p1x * ($p2y - $p3y) +
    $p2x * ($p3y - $p1y) +
    $p3x * ($p1y - $p2y) ;

# Input: a Triangle
def checkTriWinding(allowReversed):
  if det2D < 0
  then if allowReversed
       then . as [$p1, $p2, $p3]
       | [$p1, $p3, $p2 ]
       else "Triangle has wrong winding direction" | error
       end
  else .
  end;

def boundaryCollideChk(eps): det2D < eps;

def boundaryDoesntCollideChk(eps): det2D <= eps;

def triTri2D($t1; $t2; $eps; $allowReversed; $onBoundary):
  def chkEdge:
    if $onBoundary then boundaryCollideChk($eps)
    else boundaryDoesntCollideChk($eps)
    end;

  # Triangles must be expressed anti-clockwise
  ($t1|checkTriWinding($allowReversed))
  |  ($t2|checkTriWinding($allowReversed))
  # 'onBoundary' determines whether points on boundary are considered as colliding or not
  # for each edge E of t1
  | first( range(0;3) as $i
        | (($i + 1) % 3) as $j
        # Check all points of t2 lie on the external side of edge E.
        # If they do, the triangles do not overlap.
        | if ([$t1[$i], $t1[$j], $t2[0]]| chkEdge) and
             ([$t1[$i], $t1[$j], $t2[1]]| chkEdge) and
             ([$t1[$i], $t1[$j], $t2[2]]| chkEdge)
          then 0
          else empty
  	  end) // true
  | if . == 0 then false
    else
    # for each edge E of t2
    first( range(0;3) as $i
        |  (($i + 1) % 3) as $j
        # Check all points of t1 lie on the external side of edge E.
        # If they do, the triangles do not overlap.
        | if ([$t2[$i], $t2[$j], $t1[0]] | chkEdge) and
             ([$t2[$i], $t2[$j], $t1[1]] | chkEdge) and
             ([$t2[$i], $t2[$j], $t1[2]] | chkEdge)
	  then 0
	  else empty
	  end) // true
    | if . == 0 then false
      else true # The triangles overlap
      end
    end ;


module Triangles

using LinearAlgebra

export AntiClockwise, Both, StrictCheck, MildCheck

abstract type Widing end
struct AntiClockwise <: Widing end
struct Both          <: Widing end

function _check_triangle_winding(t, widing::AntiClockwise)
    trisq = fill!(Matrix{eltype(t)}(undef, 3, 3), 1)
    trisq[:, 1:2] .= t
    det(trisq) < 0 && throw(ArgumentError("triangle has wrong winding direction"))
    return trisq
end

function _check_triangle_winding(t, widing::Both)
    trisq = fill!(Matrix{eltype(t)}(undef, 3, 3), 1)
    trisq[:, 1:2] .= t
    if det(trisq) < 0
        tmp = trisq[2, :]
        trisq[2, :] .= trisq[1, :]
        trisq[1, :] .= tmp
    end
    return trisq
end

abstract type OnBoundaryCheck end
struct StrictCheck <: OnBoundaryCheck end
struct MildCheck   <: OnBoundaryCheck end

_checkedge(::StrictCheck, x, ϵ) = det(x) < ϵ
_checkedge(::MildCheck, x, ϵ)   = det(x) ≤ ϵ

function overlap(T₁, T₂, onboundary::OnBoundaryCheck=MildCheck(),; ϵ=0.0, widing::Widing=AntiClockwise())
    # Trangles must be expressed anti-clockwise
    T₁ = _check_triangle_winding(T₁, widing)
    T₂ = _check_triangle_winding(T₂, widing)

    edge = similar(T₁)
    for (A, B) in ((T₁, T₂), (T₂, T₁)), i in 1:3
        circshift!(edge, A, (i, 0))
        @views if all(_checkedge(onboundary, vcat(edge[1:2, :], B[r, :]'), ϵ) for r in 1:3)
            return false
        end
    end

    return true
end

end  # module Triangles


// version 1.1.0

typealias Point = Pair<Double, Double>

data class Triangle(var p1: Point, var p2: Point, var p3: Point) {
    override fun toString() = "Triangle: $p1, $p2, $p3"
}

fun det2D(t: Triangle): Double {
    val (p1, p2, p3) = t
    return  p1.first * (p2.second - p3.second) +
            p2.first * (p3.second - p1.second) +
            p3.first * (p1.second - p2.second)
}

fun checkTriWinding(t: Triangle, allowReversed: Boolean) {
    val detTri = det2D(t)
    if (detTri < 0.0) {
        if (allowReversed) {
           val a = t.p3
	   t.p3  = t.p2
	   t.p2 =  a
        }
        else throw RuntimeException("Triangle has wrong winding direction")
    }
}

fun boundaryCollideChk(t: Triangle, eps: Double) = det2D(t) < eps

fun boundaryDoesntCollideChk(t: Triangle, eps: Double) = det2D(t) <= eps

fun triTri2D(t1: Triangle, t2: Triangle, eps: Double = 0.0,
             allowReversed: Boolean = false, onBoundary: Boolean = true): Boolean {
    // Triangles must be expressed anti-clockwise
    checkTriWinding(t1, allowReversed)
    checkTriWinding(t2, allowReversed)
    // 'onBoundary' determines whether points on boundary are considered as colliding or not
    val chkEdge = if (onBoundary) ::boundaryCollideChk else ::boundaryDoesntCollideChk
    val lp1 = listOf(t1.p1, t1.p2, t1.p3)
    val lp2 = listOf(t2.p1, t2.p2, t2.p3)

    // for each edge E of t1
    for (i in 0 until 3) {
        val j = (i + 1) % 3
        // Check all points of t2 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
	if (chkEdge(Triangle(lp1[i], lp1[j], lp2[0]), eps) &&
            chkEdge(Triangle(lp1[i], lp1[j], lp2[1]), eps) &&
            chkEdge(Triangle(lp1[i], lp1[j], lp2[2]), eps)) return false
    }

    // for each edge E of t2
    for (i in 0 until 3) {
        val j = (i + 1) % 3
        // Check all points of t1 lay on the external side of edge E.
        // If they do, the triangles do not overlap.
        if (chkEdge(Triangle(lp2[i], lp2[j], lp1[0]), eps) &&
            chkEdge(Triangle(lp2[i], lp2[j], lp1[1]), eps) &&
            chkEdge(Triangle(lp2[i], lp2[j], lp1[2]), eps)) return false
    }

    // The triangles overlap
    return true
}

fun main(args: Array<String>) {
    var t1 = Triangle(0.0 to 0.0, 5.0 to 0.0, 0.0 to 5.0)
    var t2 = Triangle(0.0 to 0.0, 5.0 to 0.0, 0.0 to 6.0)
    println("$t1 and\n$t2")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    // need to allow reversed for this pair to avoid exception
    t1 = Triangle(0.0 to 0.0, 0.0 to 5.0, 5.0 to 0.0)
    t2 = t1
    println("\n$t1 and\n$t2")
    println(if (triTri2D(t1, t2, 0.0, true)) "overlap (reversed)" else "do not overlap")

    t1 = Triangle(0.0 to 0.0, 5.0 to 0.0, 0.0 to 5.0)
    t2 = Triangle(-10.0 to 0.0, -5.0 to 0.0, -1.0 to 6.0)
    println("\n$t1 and\n$t2")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    t1.p3 = 2.5 to 5.0
    t2 = Triangle(0.0 to 4.0, 2.5 to -1.0, 5.0 to 4.0)
    println("\n$t1 and\n$t2")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    t1 = Triangle(0.0 to 0.0, 1.0 to 1.0, 0.0 to 2.0)
    t2 = Triangle(2.0 to 1.0, 3.0 to 0.0, 3.0 to 2.0)
    println("\n$t1 and\n$t2")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    t2 = Triangle(2.0 to 1.0, 3.0 to -2.0, 3.0 to 4.0)
    println("\n$t1 and\n$t2")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    t1 = Triangle(0.0 to 0.0, 1.0 to 0.0, 0.0 to 1.0)
    t2 = Triangle(1.0 to 0.0, 2.0 to 0.0, 1.0 to 1.1)
    println("\n$t1 and\n$t2")
    println("which have only a single corner in contact, if boundary points collide")
    println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")

    println("\n$t1 and\n$t2")
    println("which have only a single corner in contact, if boundary points do not collide")
    println(if (triTri2D(t1, t2, 0.0, false, false)) "overlap" else "do not overlap")
}


Here we present a rasterized version based on a single function "isInside".

1) isInside

Given A, B, C, P is in the triangle ABC if the three cross-products
PA^PB, PB^PC and PC^PA are of equal sign.

{def isInside
 {lambda {:a :b :c :p}
  {let { {:ax {car :a}} {:ay {cdr :a}}
         {:bx {car :b}} {:by {cdr :b}}
         {:cx {car :c}} {:cy {cdr :c}}
         {:px {car :p}} {:py {cdr :p}}
       } {let { {:w1 {- {* {- :px :ax} {- :cy :ay}}
                        {* {- :cx :ax} {- :py :ay}} }}
                {:w2 {- {* {- :px :bx} {- :ay :by}}
                        {* {- :ax :bx} {- :py :by}} }}
                {:w3 {- {* {- :px :cx} {- :by :cy}}
                        {* {- :bx :cx} {- :py :cy}} }}
              } {or {and {>= :w1 0} {>= :w2 0} {>= :w3 0}}
                    {and {<  :w1 0} {<  :w2 0} {<  :w3 0}}} }}}}
-> isInside

2) overlapping

For every points in the rectangle surrounding two given triangles
we compute the number of points inside both. If it is null they don't overlap.

{def overlap

 {def overlap.row
  {lambda {:p0 :p1 :p2 :q0 :q1 :q2 :w :h :y}
     {S.map {{lambda {:p0 :p1 :p2 :q0 :q1 :q2 :qp}
                     {if {and {isInside :p0 :p1 :p2 :qp}
                              {isInside :q0 :q1 :q2 :qp}}
                      then x else}} :p0 :p1 :p2 :q0 :q1 :q2}
     {S.map {{lambda {:y :x} {cons :x :y}} :y}
            {S.serie :w :h} }}}}

 {lambda {:p0 :p1 :p2 :q0 :q1 :q2 :w :h}
  {S.length {S.map {overlap.row :p0 :p1 :p2 :q0 :q1 :q2 :w :h}
            {S.serie :w :h}} }}}
-> overlap

Given coordonnees will just be scaled to become integers, here miltiplied by 10

{overlap {cons 0 0} {cons 50 0} {cons 0 50}
         {cons 0 0} {cons 50 0} {cons 0 60} 0 60}          -> 1326

{overlap {cons 0 0} {cons 0 50} {cons 50 0}
         {cons 0 0} {cons 0 50} {cons 50 0} 0 50}          -> 1176

{overlap {cons 0 0} {cons 50 0} {cons 0 50}
         {cons -100 0} {cons -50 0} {cons -10 60} 100 60}  -> 0

{overlap {cons 0 0} {cons 50 0} {cons 25 50}
         {cons 0 40} {cons 25 -10} {cons 50 40} -10 50}    -> 831

{overlap {cons 0 0} {cons 10 10} {cons 0 20}
         {cons 20 10} {cons 30 0} {cons 30 20} 0 20}       -> 0

{overlap {cons 0 0} {cons 10 10} {cons 0 20}
         {cons 20 10} {cons 30 -20} {cons 40 40} -20 40}   -> 0

{overlap {cons 0 0} {cons 10 0} {cons 0 10}
         {cons 10 0} {cons 20 0} {cons 10 10} 0 20}        -> 1

3) plot

The first triangle is plotted with 1s, the second with 2s,
 the intersection with 3s, else with dots.

{def plot
 {def plot.row
  {lambda {:p0 :p1 :p2 :q0 :q1 :q2 :w :h :y}
   {br}{S.replace \s by in
    {S.map {{lambda {:p0 :p1 :p2 :q0 :q1 :q2 :qp}
                    {let { {:isinp {isInside :p0 :p1 :p2 :qp}}
                           {:isinq {isInside :q0 :q1 :q2 :qp}}
                         } {if {and :isinp :isinq} then 3
                            else {if :isnp then 1
                            else {if :isnq then 2
                            else .}}} }} :p0 :p1 :p2 :q0 :q1 :q2}
     {S.map {{lambda {:y :x} {cons :x :y}} :y}
            {S.serie :w :h} }}} }}
 {lambda {:p0 :p1 :p2 :q0 :q1 :q2 :w :h}
  {S.map {plot.row :p0 :p1 :p2 :q0 :q1 :q2 :w :h}
         {S.serie :w :h}} }}
-> plot

{plot {cons 0 0} {cons 30 0} {cons 30 30}
      {cons 5 10} {cons 25 10} {cons 5 25} 0 30}
->

1111111111111111111111111111111
.111111111111111111111111111111
..11111111111111111111111111111
...1111111111111111111111111111
....111111111111111111111111111
.....11111111111111111111111111
......1111111111111111111111111
.......111111111111111111111111
........11111111111111111111111
.........1111111111111111111111
.....22222333333333333333311111
.....22222233333333333331111111
.....22222223333333333311111111
.....22222222333333333111111111
.....22222222233333311111111111
.....22222222223333111111111111
.....22222222222331111111111111
.....22222222222.11111111111111
.....2222222222...1111111111111
.....222222222.....111111111111
.....2222222........11111111111
.....222222..........1111111111
.....22222............111111111
.....222...............11111111
.....22.................1111111
.....2...................111111
..........................11111
...........................1111
............................111
.............................11
..............................1


function det2D(p1,p2,p3)
    return p1.x * (p2.y - p3.y)
         + p2.x * (p3.y - p1.y)
         + p3.x * (p1.y - p2.y)
end

function checkTriWinding(p1,p2,p3,allowReversed)
    local detTri = det2D(p1,p2,p3)
    if detTri < 0.0 then
        if allowReversed then
            local t = p3
            p3 = p2
            p2 = t
        else
            error("triangle has wrong winding direction")
        end
    end
    return nil
end

function boundaryCollideChk(p1,p2,p3,eps)
    return det2D(p1,p2,p3) < eps
end

function boundaryDoesntCollideChk(p1,p2,p3,eps)
    return det2D(p1,p2,p3) <= eps
end

function triTri2D(t1,t2,eps,allowReversed,onBoundary)
    eps = eps or 0.0
    allowReversed = allowReversed or false
    onBoundary = onBoundary or true

    -- triangles must be expressed anti-clockwise
    checkTriWinding(t1[1], t1[2], t1[3], allowReversed)
    checkTriWinding(t2[1], t2[2], t2[3], allowReversed)

    local chkEdge
    if onBoundary then
        -- points on the boundary are considered as colliding
        chkEdge = boundaryCollideChk
    else
        -- points on the boundary are not considered as colliding
        chkEdge = boundaryDoesntCollideChk
    end

    -- for edge E of triangle 1
    for i=0,2 do
        local j = (i+1)%3

        -- check all points of triangle 2 lay on the external side of the edge E.
        -- If they do, the triangles do not collide
        if chkEdge(t1[i+1], t1[j+1], t2[1], eps) and
           chkEdge(t1[i+1], t1[j+1], t2[2], eps) and
           chkEdge(t1[i+1], t1[j+1], t2[3], eps) then
            return false
        end
    end

    -- for edge E of triangle 2
    for i=0,2 do
        local j = (i+1)%3

        -- check all points of triangle 1 lay on the external side of the edge E.
        -- If they do, the triangles do not collide
        if chkEdge(t2[i+1], t2[j+1], t1[1], eps) and
           chkEdge(t2[i+1], t2[j+1], t1[2], eps) and
           chkEdge(t2[i+1], t2[j+1], t1[3], eps) then
            return false
        end
    end

    -- the triangles collide
    return true
end

function formatTri(t)
    return "Triangle: ("..t[1].x..", "..t[1].y
                .."), ("..t[2].x..", "..t[2].y
                .."), ("..t[3].x..", "..t[3].y..")"
end

function overlap(t1,t2,eps,allowReversed,onBoundary)
    if triTri2D(t1,t2,eps,allowReversed,onBoundary) then
        return "overlap\n"
    else
        return "do not overlap\n"
    end
end

-- Main
local t1 = {{x=0,y=0},{x=5,y=0},{x=0,y=5}}
local t2 = {{x=0,y=0},{x=5,y=0},{x=0,y=6}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2))

t1 = {{x=0,y=0},{x=0,y=5},{x=5,y=0}}
t2 = {{x=0,y=0},{x=0,y=5},{x=5,y=0}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2,0.0,true))

t1 = {{x=0,y=0},{x=5,y=0},{x=0,y=5}}
t2 = {{x=-10,y=0},{x=-5,y=0},{x=-1,y=6}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2))

t1 = {{x=0,y=0},{x=5,y=0},{x=2.5,y=5}}
t2 = {{x=0,y=4},{x=2.5,y=-1},{x=5,y=4}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2))

t1 = {{x=0,y=0},{x=1,y=1},{x=0,y=2}}
t2 = {{x=2,y=1},{x=3,y=0},{x=3,y=2}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2))

t1 = {{x=0,y=0},{x=1,y=1},{x=0,y=2}}
t2 = {{x=2,y=1},{x=3,y=-2},{x=3,y=4}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2))

-- Barely touching
t1 = {{x=0,y=0},{x=1,y=0},{x=0,y=1}}
t2 = {{x=1,y=0},{x=2,y=0},{x=1,y=1}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2,0.0,false,true))

-- Barely touching
local t1 = {{x=0,y=0},{x=1,y=0},{x=0,y=1}}
local t2 = {{x=1,y=0},{x=2,y=0},{x=1,y=1}}
print(formatTri(t1).." and")
print(formatTri(t2))
print(overlap(t1,t2,0.0,false,false))


MODULE Overlap;
FROM EXCEPTIONS IMPORT AllocateSource,ExceptionSource,GetMessage,RAISE;
FROM LongStr IMPORT RealToFixed;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

TYPE
    Point = RECORD
        x,y : LONGREAL;
    END;
    Triangle = RECORD
        p1,p2,p3 : Point;
    END;

VAR
    TextWinExSrc : ExceptionSource;

PROCEDURE WritePoint(p : Point);
VAR buf : ARRAY[0..31] OF CHAR;
BEGIN
    WriteString("(");
    RealToFixed(p.x, 2, buf);
    WriteString(buf);
    WriteString(", ");
    RealToFixed(p.y, 2, buf);
    WriteString(buf);
    WriteString(")")
END WritePoint;

PROCEDURE WriteTriangle(t : Triangle);
BEGIN
    WriteString("Triangle: ");
    WritePoint(t.p1);
    WriteString(", ");
    WritePoint(t.p2);
    WriteString(", ");
    WritePoint(t.p3)
END WriteTriangle;

PROCEDURE Det2D(p1,p2,p3 : Point) : LONGREAL;
BEGIN
    RETURN p1.x * (p2.y - p3.y)
         + p2.x * (p3.y - p1.y)
         + p3.x * (p1.y - p2.y)
END Det2D;

PROCEDURE CheckTriWinding(VAR p1,p2,p3 : Point; allowReversed : BOOLEAN);
VAR
    detTri : LONGREAL;
    t : Point;
BEGIN
    detTri := Det2D(p1, p2, p3);
    IF detTri < 0.0 THEN
        IF allowReversed THEN
            t := p3;
            p3 := p2;
            p2 := t
        ELSE
            RAISE(TextWinExSrc, 0, "triangle has wrong winding direction")
        END
    END
END CheckTriWinding;

PROCEDURE BoundaryCollideChk(p1,p2,p3 : Point; eps : LONGREAL) : BOOLEAN;
BEGIN
    RETURN Det2D(p1, p2, p3) < eps
END BoundaryCollideChk;

PROCEDURE BoundaryDoesntCollideChk(p1,p2,p3 : Point; eps : LONGREAL) : BOOLEAN;
BEGIN
    RETURN Det2D(p1, p2, p3) <= eps
END BoundaryDoesntCollideChk;

PROCEDURE TriTri2D(t1,t2 : Triangle; eps : LONGREAL; allowReversed,onBoundary : BOOLEAN) : BOOLEAN;
TYPE
    Points = ARRAY[0..2] OF Point;
VAR
    chkEdge : PROCEDURE(Point, Point, Point, LONGREAL) : BOOLEAN;
    lp1,lp2 : Points;
    i,j : CARDINAL;
BEGIN
    (* Triangles must be expressed anti-clockwise *)
    CheckTriWinding(t1.p1, t1.p2, t1.p3, allowReversed);
    CheckTriWinding(t2.p1, t2.p2, t2.p3, allowReversed);

    (* 'onBoundary' determines whether points on boundary are considered as colliding or not *)
    IF onBoundary THEN
        chkEdge := BoundaryCollideChk
    ELSE
        chkEdge := BoundaryDoesntCollideChk
    END;

    lp1 := Points{t1.p1, t1.p2, t1.p3};
    lp2 := Points{t2.p1, t2.p2, t2.p3};

    (* for each edge E of t1 *)
    FOR i:=0 TO 2 DO
        j := (i + 1) MOD 3;
        (* Check all points of t2 lay on the external side of edge E.
           If they do, the triangles do not overlap. *)
        IF     chkEdge(lp1[i], lp1[j], lp2[0], eps)
           AND chkEdge(lp1[i], lp1[j], lp2[1], eps)
           AND chkEdge(lp1[i], lp1[j], lp2[2], eps)
        THEN
            RETURN FALSE
        END
    END;

    (* for each edge E of t2 *)
    FOR i:=0 TO 2 DO
        j := (i + 1) MOD 3;
        (* Check all points of t1 lay on the external side of edge E.
           If they do, the triangles do not overlap. *)
        IF     chkEdge(lp2[i], lp2[j], lp1[0], eps)
           AND chkEdge(lp2[i], lp2[j], lp1[1], eps)
           AND chkEdge(lp2[i], lp2[j], lp1[2], eps)
        THEN
            RETURN FALSE
        END
    END;

    (* The triangles overlap *)
    RETURN TRUE
END TriTri2D;

PROCEDURE CheckOverlap(t1,t2 : Triangle; eps : LONGREAL; allowReversed,onBoundary : BOOLEAN);
BEGIN
    WriteTriangle(t1);
    WriteString(" and");
    WriteLn;
    WriteTriangle(t2);
    WriteLn;

    IF TriTri2D(t1, t2, eps, allowReversed, onBoundary) THEN
        WriteString("overlap")
    ELSE
        WriteString("do not overlap")
    END;
    WriteLn
END CheckOverlap;

(* main *)
VAR
    t1,t2 : Triangle;
BEGIN
    t1 := Triangle{{0.0,0.0},{5.0,0.0},{0.0,5.0}};
    t2 := Triangle{{0.0,0.0},{5.0,0.0},{0.0,6.0}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{0.0,5.0},{5.0,0.0}};
    t2 := Triangle{{0.0,0.0},{0.0,5.0},{5.0,0.0}};
    CheckOverlap(t1, t2, 0.0, TRUE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{5.0,0.0},{0.0,5.0}};
    t2 := Triangle{{-10.0,0.0},{-5.0,0.0},{-1.0,6.0}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{5.0,0.0},{2.5,5.0}};
    t2 := Triangle{{0.0,4.0},{2.5,-1.0},{5.0,4.0}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{1.0,1.0},{0.0,2.0}};
    t2 := Triangle{{2.0,1.0},{3.0,0.0},{3.0,2.0}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{1.0,1.0},{0.0,2.0}};
    t2 := Triangle{{2.0,1.0},{3.0,-2.0},{3.0,4.0}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{1.0,0.0},{0.0,1.0}};
    t2 := Triangle{{1.0,0.0},{2.0,0.0},{1.0,1.1}};
    CheckOverlap(t1, t2, 0.0, FALSE, TRUE);
    WriteLn;

    t1 := Triangle{{0.0,0.0},{1.0,0.0},{0.0,1.0}};
    t2 := Triangle{{1.0,0.0},{2.0,0.0},{1.0,1.1}};
    CheckOverlap(t1, t2, 0.0, FALSE, FALSE);
    WriteLn;

    ReadChar
END Overlap.


import strformat

type Point = tuple[x, y: float]

type Triangle = array[3, Point]

func `$`(p: Point): string =
  fmt"({p.x:.1f}, {p.y:.1f})"

func `$`(t: Triangle): string =
  fmt"Triangle {t[0]}, {t[1]}, {t[2]}"

func det2D(t: Triangle): float =
  t[0].x * (t[1].y - t[2].y) +
  t[1].x * (t[2].y - t[0].y) +
  t[2].x * (t[0].y - t[1].y)

func checkTriWinding(t: var Triangle; allowReversed: bool) =
  let det = t.det2D()
  if det < 0:
    if allowReversed:
      swap t[1], t[2]
    else:
      raise newException(ValueError, "Triangle has wrong winding direction.")

func boundaryCollideChk(t: Triangle; eps: float): bool =
  t.det2D() < eps

func boundaryDoesntCollideChk(t: Triangle; eps: float): bool =
  t.det2D() <= eps

func triTri2D(t1, t2: var Triangle; eps = 0.0;
              allowReversed = false; onBoundary = true): bool =

  # Triangles must be expressed anti-clockwise.
  t1.checkTriWinding(allowReversed)
  t2.checkTriWinding(allowReversed)

  # "onBoundary" determines whether points on boundary are considered as colliding or not.
  let chkEdge = if onBoundary: boundaryCollideChk else: boundaryDoesntCollideChk

  # For each edge E of t1.
  for i in 0..2:
    let j = (i + 1) mod 3
    # Check that all points of t2 lay on the external side of edge E.
    # If they do, the triangles do not overlap.
    if chkEdge([t1[i], t1[j], t2[0]], eps) and
       chkEdge([t1[i], t1[j], t2[1]], eps) and
       chkEdge([t1[i], t1[j], t2[2]], eps):
         return false

  # For each edge E of t2.
  for i in 0..2:
    let j = (i + 1) mod 3
    # Check that all points of t1 lay on the external side of edge E.
    # If they do, the triangles do not overlap.
    if chkEdge([t2[i], t2[j], t1[0]], eps) and
       chkEdge([t2[i], t2[j], t1[1]], eps) and
       chkEdge([t2[i], t2[j], t1[2]], eps):
         return false

  # The triangles overlap.
  result = true

when isMainModule:

  var t1: Triangle = [(0.0, 0.0), (5.0, 0.0), (0.0, 5.0)]
  var t2: Triangle = [(0.0, 0.0), (5.0, 0.0), (0.0, 6.0)]
  echo t1, " and\n", t2
  var overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  # Need to allow reversed for this pair to avoid exception.
  t1 = [(0.0, 0.0), (5.0, 0.0), (5.0, 0.0)]
  t2 = t1
  echo t1, " and\n", t2
  overlapping = triTri2D(t1, t2, 0, true, true)
  echo if overlapping: "overlap (reversed)\n" else: "do not overlap\n"

  t1 = [(0.0, 0.0), (5.0, 0.0), (0.0, 5.0)]
  t2 = [(-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0)]
  echo t1, " and\n", t2
  overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  t1[2] = (2.5, 5.0)
  t2 = [(0.0, 4.0), (2.5, -1.0), (5.0, 4.0)]
  echo t1, " and\n", t2
  overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  t1 = [(0.0, 0.0), (1.0, 1.0), (0.0, 2.0)]
  t2 = [(2.0, 1.0), (3.0, 0.0), (3.0, 2.0)]
  echo t1, " and\n", t2
  overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  t2 = [(2.0, 1.0), (3.0, -2.0), (3.0, 4.0)]
  echo t1, " and\n", t2
  overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  t1 = [(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)]
  t2 = [(1.0, 0.0), (2.0, 0.0), (1.0, 1.1)]
  echo t1, " and\n", t2
  echo "which have only a single corner in contact, if boundary points collide"
  overlapping = triTri2D(t1, t2, 0, false, true)
  echo if overlapping: "overlap\n" else: "do not overlap\n"

  echo t1, " and\n", t2
  echo "which have only a single corner in contact, if boundary points do not collide"
  overlapping = triTri2D(t1, t2, 0, false, false)
  echo if overlapping: "overlap\n" else: "do not overlap\n"


program TrianglesOverlap;
{
The program looks for a separating line between the triangles. It's known that
only the triangle sides (produced) need to be considered as possible separators
(except in the degenerate case when both triangles are reduced to a point).
If there's a strong separator, i.e. one that is disjoint from at least one
of the triangles, then the triangles are disjoint. If there's only a weak
separator, i.e. one that intersects both triangles, then the triangles intersect
in a point or a line segment (this program doesn't work out which).
If there's no separator, then the triangles have an overlap of positive area.
}
{$IFDEF FPC}
  {$mode objfpc}{$H+}
{$ENDIF}}

uses Math, SysUtils;

{$DEFINE USE_FP}
{$IFDEF USE_FP}
type TCoordinate = double;
const TOLERANCE = 1.0E-6;
{$ELSE}
type TCoordinate = integer;
const TOLERANCE = 0;
{$ENDIF}

type TVertex = record
  x, y : TCoordinate;
end;

function Vertex( x_in, y_in : TCoordinate) : TVertex;
begin
  result.x := x_in;
  result.y := y_in;
end;

// Result of testing sides of a triangle for separator.
// Values are arbitrary but must be in this numerical order
const
  SEP_NO_TEST = -1; // triangle is a single point, no sides to be tested
  SEP_NONE    = 0;  // didn't find a separator
  SEP_WEAK    = 1;  // found a weak separator only
  SEP_STRONG  = 2;  // found a strong separator

function EqualVertices( V, W : TVertex) : boolean;
begin
  result := (Abs(V.x - W.x) <= TOLERANCE)
        and (Abs(V.y - W.y) <= TOLERANCE);
end;

// Determinant: twice the signed area of triangle PQR.
function Det( P, Q, R : TVertex) : TCoordinate;
begin
  result := Q.x*R.y - R.x*Q.y + R.x*P.y - P.x*R.y + P.x*Q.y - Q.x*P.y;
end;

// Get result of trying sides of LMN as separators.
function TrySides( L, M, N, P, Q, R : TVertex) : integer;
var
  s, sMin, sMax: TCoordinate;
  H, K : TVertex;

      function TestSide( V, W : TVertex) : integer;
      var
        detP, detQ, detR, tMin, tMax : TCoordinate;
      begin
        result := SEP_NONE;
        detP := Det( V, W, P);
        detQ := Det( V, W, Q);
        detR := Det( V, W, R);
        tMin := Math.Min( Math.Min( detP, detQ), detR);
        tMax := Math.Max( Math.Max( detP, detQ), detR);
        if (tMin - sMax > TOLERANCE) or (sMin - tMax > TOLERANCE) then
          result := SEP_STRONG
        else if (tMin - sMax >= -TOLERANCE) or (sMin - tMax >= -TOLERANCE) then
          result := SEP_WEAK;
      end;

begin
  sMin := 0;
  sMax := 0;
  s := Det( L, M, N);
  if (s <> 0) then begin // L, M, N are not collinear
    if (s < 0) then sMin := s else sMax := s;
    // Once we've found a strong separator, there's no need for further testing
    result := TestSide( M, N);
    if (result < SEP_STRONG) then result := Math.Max( result, TestSide( N, L));
    if (result < SEP_STRONG) then result := Math.Max( result, TestSide( L, M));
  end
  else begin // s = 0 so L, M, N are collinear
    // Look for distinct vertices from among L, M, N
    H := L;
    K := M;
    if EqualVertices( H, K) then K := N;
    if EqualVertices( H, K) then result := SEP_NO_TEST // L = M = N
    else result := TestSide( H, K);
  end;
end;

function Algo_5( A, B, C, D, E, F : TVertex) : integer;
begin
  result := TrySides( A, B, C, D, E, F);
  if (result < SEP_STRONG) then begin
    result := Math.Max( result, TrySides( D, E, F, A, B, C));
    if (result = SEP_NO_TEST) then begin // A = B = C and D = E = F
      if EqualVertices( A, D) then result := SEP_WEAK
                              else result := SEP_STRONG;
    end;
  end;
end;

procedure TestTrianglePair (Ax, Ay, Bx, By, Cx, Cy,
                            Dx, Dy, Ex, Ey, Fx, Fy : TCoordinate);
var
  ovStr : string;
begin
  case Algo_5( Vertex(Ax, Ay), Vertex(Bx, By), Vertex(Cx, Cy),
               Vertex(Dx, Dy), Vertex(Ex, Ey), Vertex(Fx, Fy)) of
    SEP_STRONG : ovStr := 'Disjoint';
    SEP_NONE   : ovStr := 'Overlap';
    else         ovStr := 'Borderline';
  end;
  WriteLn( SysUtils.Format(
      '(%g,%g),(%g,%g),(%g,%g) and (%g,%g),(%g,%g),(%g,%g): %s',
       [Ax, Ay, Bx, By, Cx, Cy, Dx, Dy, Ex, Ey, Fx, Fy, ovStr]));
end;

// Main routine
begin
  TestTrianglePair( 0,0,5,0,0,5, 0,0,5,0,0,6);
  TestTrianglePair( 0,0,0,5,5,0, 0,0,0,5,5,0);
  TestTrianglePair( 0,0,5,0,0,5, -10,0,-5,0,-1,6);
  TestTrianglePair( 0,0,5,0,2.5,5, 0,4,2.5,-1,5,4);
  TestTrianglePair( 0,0,1,1,0,2, 2,1,3,0,3,2);
  TestTrianglePair( 0,0,1,1,0,2, 2,1,3,-2,3,4);
  TestTrianglePair( 0,0,1,0,0,1, 1,0,2,0,1,1);
end.


use strict;
use warnings;

sub det2D {
    my $p1 = shift or die "4 Missing first point\n";
    my $p2 = shift or die "Missing second point\n";
    my $p3 = shift or die "Missing third point\n";

    return $p1->{x} * ($p2->{y} - $p3->{y})
         + $p2->{x} * ($p3->{y} - $p1->{y})
         + $p3->{x} * ($p1->{y} - $p2->{y});
}

sub checkTriWinding {
    my $p1 = shift or die "14 Missing first point\n";
    my $p2 = shift or die "Missing second point\n";
    my $p3 = shift or die "Missing third point\n";
    my $allowReversed = shift;

    my $detTri = det2D($p1, $$p2, $$p3);
    if ($detTri < 0.0) {
        if ($allowReversed) {
            my $t = $$p3;
            $$p3 = $$p2;
            $$p2 = $t;
        } else {
            die "triangle has wrong winding direction";
        }
    }
    return undef;
}

sub boundaryCollideChk {
    my $p1 = shift or die "33 Missing first point\n";
    my $p2 = shift or die "Missing second point\n";
    my $p3 = shift or die "Missing third point\n";
    my $eps = shift;

    return det2D($p1, $p2, $p3) < $eps;
}

sub boundaryDoesntCollideChk {
    my $p1 = shift or die "42 Missing first point\n";
    my $p2 = shift or die "Missing second point\n";
    my $p3 = shift or die "Missing third point\n";
    my $eps = shift;

    return det2D($p1, $p2, $p3) <= $eps;
}

sub triTri2D {
    my $t1 = shift or die "Missing first triangle to calculate with\n";
    my $t2 = shift or die "Missing second triangle to calculate with\n";
    my $eps = shift;
    my $allowReversed = shift;
    my $onBoundary = shift;

    # triangles must be expressed anti-clockwise
    checkTriWinding($t1->[0], \$t1->[1], \$t1->[2], $allowReversed);
    checkTriWinding($t2->[0], \$t2->[1], \$t2->[2], $allowReversed);

    my $chkEdge;
    if ($onBoundary) {
        # points on the boundary are considered as colliding
        $chkEdge = \&boundaryCollideChk;
    } else {
        # points on the boundary are NOT considered as colliding
        $chkEdge = \&boundaryDoesntCollideChk;
    }

    # for edge E of triangle 1
    foreach my $i (0, 1, 2) {
        my $j = ($i + 1) % 3;

        # check all points of triangle 2 lay on the external side of edge E
        # if they do, the triangles do not collide
        if ($chkEdge->($t1->[$i], $t1->[$j], $t2->[0], $eps)
        and $chkEdge->($t1->[$i], $t1->[$j], $t2->[1], $eps)
        and $chkEdge->($t1->[$i], $t1->[$j], $t2->[2], $eps)) {
            return 0; # false
        }
    }

    # for edge E of triangle 2
    foreach my $i (0, 1, 2) {
        my $j = ($i + 1) % 3;

        # check all points of triangle 1 lay on the external side of edge E
        # if they do, the triangles do not collide
        if ($chkEdge->($t2->[$i], $t2->[$j], $t1->[0], $eps)
        and $chkEdge->($t2->[$i], $t2->[$j], $t1->[1], $eps)
        and $chkEdge->($t2->[$i], $t2->[$j], $t1->[2], $eps)) {
            return 0; # false
        }
    }

    return 1; # true
}

sub formatTri {
    my $t = shift or die "Missing triangle to format\n";
    my $p1 = $t->[0];
    my $p2 = $t->[1];
    my $p3 = $t->[2];
    return "Triangle: ($p1->{x}, $p1->{y}), ($p2->{x}, $p2->{y}), ($p3->{x}, $p3->{y})";
}

sub overlap {
    my $t1 = shift or die "Missing first triangle to calculate with\n";
    my $t2 = shift or die "Missing second triangle to calculate with\n";
    my $eps = shift;
    my $allowReversed = shift or 0; # false
    my $onBoundary = shift or 1; # true

    unless ($eps) {
        $eps = 0.0;
    }

    if (triTri2D($t1, $t2, $eps, $allowReversed, $onBoundary)) {
        return "overlap\n";
    } else {
        return "do not overlap\n";
    }
}

###################################################
# Main
###################################################

my @t1 = ({x=>0, y=>0}, {x=>5, y=>0}, {x=>0, y=>5});
my @t2 = ({x=>0, y=>0}, {x=>5, y=>0}, {x=>0, y=>6});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2), "\n";

@t1 = ({x=>0, y=>0}, {x=>0, y=>5}, {x=>5, y=>0});
@t2 = ({x=>0, y=>0}, {x=>0, y=>5}, {x=>5, y=>0});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2, 0.0, 1), "\n";

@t1 = ({x=>0, y=>0}, {x=>5, y=>0}, {x=>0, y=>5});
@t2 = ({x=>-10, y=>0}, {x=>-5, y=>0}, {x=>-1, y=>6});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2), "\n";

@t1 = ({x=>0, y=>0}, {x=>5, y=>0}, {x=>2.5, y=>5});
@t2 = ({x=>0, y=>4}, {x=>2.5, y=>-1}, {x=>5, y=>4});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2), "\n";

@t1 = ({x=>0, y=>0}, {x=>1, y=>1}, {x=>0, y=>2});
@t2 = ({x=>2, y=>1}, {x=>3, y=>0}, {x=>3, y=>2});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2), "\n";

@t1 = ({x=>0, y=>0}, {x=>1, y=>1}, {x=>0, y=>2});
@t2 = ({x=>2, y=>1}, {x=>3, y=>-2}, {x=>3, y=>4});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2), "\n";

# Barely touching
@t1 = ({x=>0, y=>0}, {x=>1, y=>0}, {x=>0, y=>1});
@t2 = ({x=>1, y=>0}, {x=>2, y=>0}, {x=>1, y=>1});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2, 0.0, 0, 1), "\n";

# Barely touching
@t1 = ({x=>0, y=>0}, {x=>1, y=>0}, {x=>0, y=>1});
@t2 = ({x=>1, y=>0}, {x=>2, y=>0}, {x=>1, y=>1});
print formatTri(\@t1), " and\n", formatTri(\@t2), "\n", overlap(\@t1, \@t2, 0.0, 0, 0), "\n";


--
-- demo\rosetta\Determine_if_two_triangles_overlap.exw
--
with javascript_semantics
include pGUI.e

Ihandle dlg, canvas
cdCanvas cddbuffer, cdcanvas

constant triangles = {{{{0,0},{5,0},{0,5}},{{0,0},{5,0},{0,6}}},
                      {{{0,0},{0,5},{5,0}},{{0,0},{0,5},{5,0}}},
                      {{{0,0},{5,0},{0,5}},{{-10,0},{-5,0},{-1,6}}},
                      {{{0,0},{5,0},{2.5,5}},{{0,4},{2.5,-1},{5,4}}},
                      {{{0,0},{1,1},{0,2}},{{2,1},{3,0},{3,2}}},
                      {{{0,0},{1,1},{0,2}},{{2,1},{3,-2},{3,4}}},
                      {{{0,0},{1,0},{0,1}},{{1,0},{2,0},{1,1}}},
                      {{{0,0},{1,0},{0,1}},{{1,0},{2,0},{1,1}}}}

procedure draw_triangle(sequence t, integer cx,cy, c)
    cdCanvasSetForeground(cddbuffer, c)
    cdCanvasBegin(cddbuffer,CD_CLOSED_LINES)
    for c=1 to 3 do
        atom {x,y} = t[c]
        cdCanvasVertex(cddbuffer, cx+x*10, cy+y*10)
    end for
    cdCanvasEnd(cddbuffer)
end procedure

function det2D(sequence triangle)
   atom {{p1x,p1y},{p2x,p2y},{p3x,p3y}} := triangle
   return p1x*(p2y-p3y) + p2x*(p3y-p1y) + p3x*(p1y-p2y)
end function

bool bReversed
function checkWinding(sequence triangle, bool allowReversed)
    atom detTri := det2D(triangle);
    if detTri<0.0 then
        if allowReversed then
            bReversed = true
            triangle = extract(triangle,{1,3,2})
        else
            throw("triangle has wrong winding direction")
        end if
    end if
    return triangle
end function

function overlap(sequence t1, t2, atom epsilon=0.0, bool allowReversed=false, onBoundary=true)
    -- Trangles must be expressed anti-clockwise
    bReversed = false
    t1 = checkWinding(t1, allowReversed)
    t2 = checkWinding(t2, allowReversed)

    for t=1 to 2 do                     -- check t1 then t2
        for edge=1 to 3 do              -- check each edge
            sequence p1 = t1[edge],
                     p2 = t1[mod(edge,3)+1]
            -- Check all points of trangle 2 lay on the external side
            -- of the edge E. If they do, the triangles do not collide.
            integer onside = 0
            for k=1 to 3 do
                integer c = compare(det2D({p1,p2,t2[k]}),epsilon)
                if onBoundary then
                    if not (c<0) then exit end if
                else
                    if not (c<=0) then exit end if
                end if
--              -- (the following incomprehensible one-liner is equivalent:)
--              if compare(det2D({p1,p2,t2[k]}),epsilon)>-onBoundary then exit end if
                onside += 1
            end for
            if onside=3 then
                return iff(onBoundary?"no overlap":"no overlap (no boundary)")
            end if
        end for
        {t2,t1} = {t1,t2}           -- flip and re-test
    end for
    return iff(bReversed?"overlap (reversed)":"overlap")
end function

function redraw_cb(Ihandle /*ih*/)
    cdCanvasActivate(cddbuffer)
    integer cy = 200, cx = 100
    for i=1 to length(triangles) do
        sequence {t1,t2} = triangles[i]
        draw_triangle(t1,cx,cy,CD_RED)
        integer s = (i<=2)  -- (smudge tests[1..2] by one
                            --  pixel to show them better)
        draw_triangle(t2,cx+s,cy+s,CD_BLUE)
        cdCanvasSetForeground(cddbuffer, CD_BLACK)
        cdCanvasText(cddbuffer,cx+10,cy-40,overlap(t1,t2,0,i=2,i!=8))
        if i=4 then
            cy = 100
            cx = 100
        else
            cx += 300
        end if
    end for
    cdCanvasFlush(cddbuffer)
    return IUP_DEFAULT
end function

function map_cb(Ihandle ih)
    cdcanvas = cdCreateCanvas(CD_IUP, ih)
    cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
    cdCanvasSetBackground(cddbuffer, CD_WHITE)
    return IUP_DEFAULT
end function

procedure main()
    IupOpen()
    canvas = IupCanvas("RASTERSIZE=1250x300")
    IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"),
                             "ACTION", Icallback("redraw_cb")})
    dlg = IupDialog(canvas,`RESIZE=NO, TITLE="Triangle overlap"`)
    IupShow(dlg)
    IupSetAttribute(canvas, "RASTERSIZE", NULL)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()


from __future__ import print_function
import numpy as np

def CheckTriWinding(tri, allowReversed):
	trisq = np.ones((3,3))
	trisq[:,0:2] = np.array(tri)
	detTri = np.linalg.det(trisq)
	if detTri < 0.0:
		if allowReversed:
			a = trisq[2,:].copy()
			trisq[2,:] = trisq[1,:]
			trisq[1,:] = a
		else: raise ValueError("triangle has wrong winding direction")
	return trisq

def TriTri2D(t1, t2, eps = 0.0, allowReversed = False, onBoundary = True):
	#Trangles must be expressed anti-clockwise
	t1s = CheckTriWinding(t1, allowReversed)
	t2s = CheckTriWinding(t2, allowReversed)

	if onBoundary:
		#Points on the boundary are considered as colliding
		chkEdge = lambda x: np.linalg.det(x) < eps
	else:
		#Points on the boundary are not considered as colliding
		chkEdge = lambda x: np.linalg.det(x) <= eps

	#For edge E of trangle 1,
	for i in range(3):
		edge = np.roll(t1s, i, axis=0)[:2,:]

		#Check all points of trangle 2 lay on the external side of the edge E. If
		#they do, the triangles do not collide.
		if (chkEdge(np.vstack((edge, t2s[0]))) and
			chkEdge(np.vstack((edge, t2s[1]))) and
			chkEdge(np.vstack((edge, t2s[2])))):
			return False

	#For edge E of trangle 2,
	for i in range(3):
		edge = np.roll(t2s, i, axis=0)[:2,:]

		#Check all points of trangle 1 lay on the external side of the edge E. If
		#they do, the triangles do not collide.
		if (chkEdge(np.vstack((edge, t1s[0]))) and
			chkEdge(np.vstack((edge, t1s[1]))) and
			chkEdge(np.vstack((edge, t1s[2])))):
			return False

	#The triangles collide
	return True

if __name__=="__main__":
	t1 = [[0,0],[5,0],[0,5]]
	t2 = [[0,0],[5,0],[0,6]]
	print (TriTri2D(t1, t2), True)

	t1 = [[0,0],[0,5],[5,0]]
	t2 = [[0,0],[0,6],[5,0]]
	print (TriTri2D(t1, t2, allowReversed = True), True)

	t1 = [[0,0],[5,0],[0,5]]
	t2 = [[-10,0],[-5,0],[-1,6]]
	print (TriTri2D(t1, t2), False)

	t1 = [[0,0],[5,0],[2.5,5]]
	t2 = [[0,4],[2.5,-1],[5,4]]
	print (TriTri2D(t1, t2), True)

	t1 = [[0,0],[1,1],[0,2]]
	t2 = [[2,1],[3,0],[3,2]]
	print (TriTri2D(t1, t2), False)

	t1 = [[0,0],[1,1],[0,2]]
	t2 = [[2,1],[3,-2],[3,4]]
	print (TriTri2D(t1, t2), False)

	#Barely touching
	t1 = [[0,0],[1,0],[0,1]]
	t2 = [[1,0],[2,0],[1,1]]
	print (TriTri2D(t1, t2, onBoundary = True), True)

	#Barely touching
	t1 = [[0,0],[1,0],[0,1]]
	t2 = [[1,0],[2,0],[1,1]]
	print (TriTri2D(t1, t2, onBoundary = False), False)


DATA 0,0,5,0,0,5,0,0,5,0,0,6
DATA 0,0,0,5,5,0,0,0,0,5,5,0
DATA 0,0,5,0,0,5,-10,0,-5,0,-1,6
DATA 0,0,5,0,2.5,5,0,4,2.5,-1,5,4
DATA 0,0,1,1,0,2,2,1,3,0,3,2
DATA 0,0,1,1,0,2,2,1,3,-2,3,4

TYPE point
    x AS INTEGER
    y AS INTEGER
END TYPE

DIM coord(12, 3) AS point

workscreen = _NEWIMAGE(800, 800, 32)
backscreen = _NEWIMAGE(800, 800, 32)

SCREEN workscreen
FOR i = 1 TO 12 '12 triangles
    FOR j = 1 TO 3 'with 3 coordinates for each
        READ coord(i, j).x 'X coord
        READ coord(i, j).y 'Y coord
        FixCoord coord(i, j)
    NEXT

NEXT
_DELAY .5
_SCREENMOVE _MIDDLE

FOR i = 1 TO 12
    _DEST workscreen
    CLS
    _DEST backscreen
    _DONTBLEND
    CLS , 0
    PSET (coord(i, 1).x, coord(i, 1).y), _RGBA32(255, 255, 255, 128)
    FOR j = 2 TO 3
        LINE -(coord(i, j).x, coord(i, j).y), _RGBA32(255, 255, 255, 128)
    NEXT
    LINE -(coord(i, 1).x, coord(i, 1).y), _RGBA32(255, 255, 255, 128)
    xinside = (coord(i, 1).x + coord(i, 2).x + coord(i, 3).x) / 3
    yinside = (coord(i, 1).y + coord(i, 2).y + coord(i, 3).y) / 3
    PAINT (xinside, yinside), _RGBA32(255, 255, 255, 128)
    _BLEND
    _PUTIMAGE , backscreen, 0
    CLS , 0
    _DONTBLEND
    i = i + 1
    PSET (coord(i, 1).x, coord(i, 1).y), _RGBA32(255, 0, 0, 128)
    FOR j = 2 TO 3
        LINE -(coord(i, j).x, coord(i, j).y), _RGBA32(255, 0, 0, 128)
    NEXT
    LINE -(coord(i, 1).x, coord(i, 1).y), _RGBA32(255, 0, 0, 128)
    xinside = (coord(i, 1).x + coord(i, 2).x + coord(i, 3).x) / 3
    yinside = (coord(i, 1).y + coord(i, 2).y + coord(i, 3).y) / 3
    PAINT (xinside, yinside), _RGBA32(255, 0, 0, 128)
    _BLEND
    _PUTIMAGE , backscreen, 0
    _DEST workscreen
    _SOURCE workscreen
    overlap = 0
    FOR x = 0 TO 999
        FOR y = 0 TO 999
            IF POINT(x, y) = _RGBA32(190, 63, 63, 255) THEN overlap = -1: GOTO overlap
        NEXT
    NEXT
    overlap:
    IF overlap THEN PRINT "OVERLAP" ELSE PRINT "NO OVERLAP"
    SLEEP
NEXT
SYSTEM

SUB FixCoord (p AS point)
    p.x = (10 + p.x) * 30 + 100
    p.y = (10 + p.y) * 30
END SUB


#lang racket

;; A triangle is a list of three pairs of points: '((x . y) (x . y) (x . y))
(define (to-tri x1 y1 x2 y2 x3 y3) `((,x1 . ,y1) (,x2 . ,y2) (,x3 . ,y3)))

(define det-2D
  (match-lambda
    [`((,x1 . ,y1) (,x2 . ,y2) (,x3 . ,y3)) (+ (* x1 (- y2 y3)) (* x2 (- y3 y1)) (* x3 (- y1 y2)))]))

(define (assert-triangle-winding triangle allow-reversed?)
  (cond
    [(>= (det-2D triangle) 0) triangle]
    [allow-reversed? (match triangle [(list p1 p2 p3) (list p1 p3 p2)])]
    [else (error 'assert-triangle-winding "triangle is wound in wrong direction")]))

(define (tri-tri-2d? triangle1 triangle2
                     #:ϵ (ϵ 0)
                     #:allow-reversed? (allow-reversed? #f)
                     #:on-boundary? (on-boundary? #t))
  (define check-edge
    (if on-boundary? ; Points on the boundary are considered as colliding
        (λ (triangle) (< (det-2D triangle) ϵ))
        (λ (triangle) (<= (det-2D triangle) ϵ))))

  (define (inr t1 t2)
    (for*/and ((i (in-range 3)))
      ;; Check all points of trangle 2 lay on the external side
      ;; of the edge E. If they do, the triangles do not collide.
      (define t1.i (list-ref t1 i))
      (define t1.j (list-ref t1 (modulo (add1 i) 3)))
      (not (for/and ((k (in-range 3))) (check-edge (list (list-ref t2 k) t1.i t1.j))))))

  (let (;; Trangles must be expressed anti-clockwise
        (tri1 (assert-triangle-winding triangle1 allow-reversed?))
        (tri2 (assert-triangle-winding triangle2 allow-reversed?)))
    (and (inr tri1 tri2) (inr tri2 tri1))))

;; ---------------------------------------------------------------------------------------------------
(module+ test
  (require rackunit)

  (define triangleses ; pairs of triangles
    (for/list ((a.b (in-list '(((0 0  5 0  0   5) (  0 0   5    0   0 6))
                               ((0 0  0 5  5   0) (  0 0   0    5   5 0))
                               ((0 0  5 0  0   5) (-10 0  -5    0  -1 6))
                               ((0 0  5 0  2.5 5) (  0 4   2.5 -1   5 4))
                               ((0 0  1 1  0   2) (  2 1   3    0   3 2))
                               ((0 0  1 1  0   2) (  2 1   3   -2   3 4))))))
      (map (curry apply to-tri) a.b)))

  (check-equal?
   (for/list ((t1.t2 (in-list triangleses)))
     (define t1 (first t1.t2))
     (define t2 (second t1.t2))
     (define-values (r reversed?)
       (with-handlers ([exn:fail? (λ (_) (values (tri-tri-2d? t1 t2 #:allow-reversed? #t) #t))])
         (values (tri-tri-2d? t1 t2) #f)))
     (cons r reversed?))
   '((#t . #f) (#t . #t) (#f . #f) (#t . #f) (#f . #f) (#f . #f)))

  (let ((c1 (to-tri 0 0  1 0  0 1)) (c2 (to-tri 1 0  2 0  1 1)))
    (check-true (tri-tri-2d? c1 c2 #:on-boundary? #t))
    (check-false (tri-tri-2d? c1 c2 #:on-boundary? #f))))