Determine if two triangles overlap: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Algol W)
Line 75: Line 75:
=={{header|ALGOL W}}==
=={{header|ALGOL W}}==
{{Trans|Kotlin}}
{{Trans|Kotlin}}
... with different output format.
... with different output format (based on Modula 2).
<lang algolw>begin % determine if two triangles overlap %
<lang algolw>begin % determine if two triangles overlap %
record Point ( real x, y );
record Point ( real x, y );

Revision as of 12:40, 23 August 2020

Task
Determine if two triangles overlap
You are encouraged to solve this task according to the task description, using any language you may know.

Determining if two triangles in the same plane overlap is an important topic in collision detection.


Task

Determine which of these pairs of triangles overlap in 2D:

  •   (0,0),(5,0),(0,5)     and   (0,0),(5,0),(0,6)
  •   (0,0),(0,5),(5,0)     and   (0,0),(0,5),(5,0)
  •   (0,0),(5,0),(0,5)     and   (-10,0),(-5,0),(-1,6)
  •   (0,0),(5,0),(2.5,5)   and   (0,4),(2.5,-1),(5,4)
  •   (0,0),(1,1),(0,2)     and   (2,1),(3,0),(3,2)
  •   (0,0),(1,1),(0,2)     and   (2,1),(3,-2),(3,4)


Optionally, see what the result is when only a single corner is in contact (there is no definitively correct answer):

  •   (0,0),(1,0),(0,1)   and   (1,0),(2,0),(1,1)



Ada

<lang ada> WITH Ada.Text_IO; USE Ada.Text_IO;

PROCEDURE Main IS

  TYPE Vertex IS MOD 3;
  TYPE Point IS ARRAY (0 .. 1) OF Float;
  TYPE Triangle IS ARRAY (Vertex) OF Point;
  TYPE Triangle_Vertices IS ARRAY (0 .. 5) OF Float;
  
  FUNCTION Same_Side (A, B, M, N : Point) RETURN Boolean IS
     FUNCTION Aff (U : Point) RETURN Float IS
       ((B (1) - A (1)) * (U (0) - A (0)) + (A (0) - B (0)) * (U (1) - A (1)));
  BEGIN
     RETURN Aff (M) * Aff (N) >= 0.0;
  END Same_Side;
  
  FUNCTION In_Side (T1 , T2 : Triangle) RETURN Boolean IS
    (FOR ALL V IN Vertex  =>
       (FOR Some P OF T2 => Same_Side (T1 (V + 1), T1 (V + 2), T1 (V), P)));
  
  FUNCTION Overlap (T1, T2 : Triangle) RETURN Boolean IS
    (In_Side (T1, T2) AND THEN  In_Side (T2, T1));
  
  FUNCTION "+" (T : Triangle_Vertices) RETURN Triangle IS
    ((T (0), T (1)), (T (2), T (3)), (T (4), T (5)));
  
  PROCEDURE Put (T1, T2 : Triangle_Vertices) IS
  BEGIN
     Put_Line (Overlap (+T1, +T2)'Img);
  END Put;
  

BEGIN

  Put ((0.0, 0.0, 5.0, 0.0, 0.0, 5.0), (0.0, 0.0, 5.0, 0.0, 0.0, 6.0));
  Put ((0.0, 0.0, 0.0, 5.0, 5.0, 0.0), (0.0, 0.0, 0.0, 5.0, 5.0, 0.0));
  Put ((0.0, 0.0, 5.0, 0.0, 0.0, 5.0), (-10.0, 0.0, -5.0, 0.0, -1.0, 6.0));
  Put ((0.0, 0.0, 5.0, 0.0, 2.5, 5.0), (0.0, 4.0, 2.5, -1.0, 5.0, 4.0));
  Put ((0.0, 0.0, 1.0, 1.0, 0.0, 2.0), (2.0, 1.0, 3.0, 0.0, 3.0, 2.0));
  Put ((0.0, 0.0, 1.0, 1.0, 0.0, 2.0), (2.0, 1.0, 3.0, -2.0, 3.0, 4.0));
  Put ((0.0, 0.0, 1.0, 0.0, 0.0, 1.0), (1.0, 0.0, 2.0, 0.0, 1.0, 1.0));

END Main; </lang>

Output:
true
true
false
true
false
false
true

ALGOL W

Translation of: Kotlin

... with different output format (based on Modula 2). <lang algolw>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.</lang>

Output:
Triangles (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and (0.0, 0.0), (5.0, 0.0), (0.0, 6.0) overlap
Triangles (0.0, 0.0), (0.0, 5.0), (5.0, 0.0) and (0.0, 0.0), (0.0, 5.0), (5.0, 0.0) overlap
Triangles (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and (-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0) do not overlap
Triangles (0.0, 0.0), (5.0, 0.0), (2.5, 5.0) and (0.0, 4.0), (2.5, -1.0), (5.0, 4.0) overlap
Triangles (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and (2.0, 1.0), (3.0, 0.0), (3.0, 2.0) do not overlap
Triangles (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and (2.0, 1.0), (3.0, -2.0), (3.0, 4.0) do not overlap
Triangles (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and (1.0, 0.0), (2.0, 0.0), (1.0, 1.1) overlap
Triangles (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and (1.0, 0.0), (2.0, 0.0), (1.0, 1.1) do not overlap

C

Translation of: C++

<lang c>#include <errno.h>

  1. include <stdbool.h>
  2. include <stdio.h>
  3. 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;

}</lang>

Output:
1,true
1,true
0,false
1,true
0,false
0,false
1,true
0,false

C#

<lang csharp>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);
       }
   }

}</lang>

Output:
Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (0, 0), (5, 0), (0, 6)
overlap

Triangle: (0, 0), (0, 5), (5, 0) and
Triangle: (0, 0), (0, 5), (5, 0)
overlap

Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (-10, 0), (-5, 0), (-1, 6)
do not overlap

Triangle: (0, 0), (5, 0), (2.5, 5) and
Triangle: (0, 4), (2.5, -1), (5, 4)
overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, 0), (3, 2)
do not overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, -2), (3, 4)
do not overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1.1)
which have only a single corner in contact, if boundary points collide
do not overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

C++

<lang cpp>#include <vector>

  1. include <iostream>
  2. 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;}

}</lang>

Output:
1,1
1,1
0,0
1,1
0,0
0,0
1,1
0,0

D

Translation of: Kotlin

<lang D>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);

}</lang>

Output:
Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(5, 0), Tuple!(real, real)(0, 5) and
Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(5, 0), Tuple!(real, real)(0, 6)
overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(0, 5), Tuple!(real, real)(5, 0) and
Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(0, 5), Tuple!(real, real)(5, 0)
overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(5, 0), Tuple!(real, real)(0, 5) and
Triangle: Tuple!(real, real)(-10, 0), Tuple!(real, real)(-5, 0), Tuple!(real, real)(-1, 6)
do not overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(5, 0), Tuple!(real, real)(2.5, 5) and
Triangle: Tuple!(real, real)(0, 4), Tuple!(real, real)(2.5, -1), Tuple!(real, real)(5, 4)
overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(1, 1), Tuple!(real, real)(0, 2) and
Triangle: Tuple!(real, real)(2, 1), Tuple!(real, real)(3, 0), Tuple!(real, real)(3, 2)
do not overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(1, 1), Tuple!(real, real)(0, 2) and
Triangle: Tuple!(real, real)(2, 1), Tuple!(real, real)(3, -2), Tuple!(real, real)(3, 4)
do not overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(1, 0), Tuple!(real, real)(0, 1) and
Triangle: Tuple!(real, real)(1, 0), Tuple!(real, real)(2, 0), Tuple!(real, real)(1, 1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: Tuple!(real, real)(0, 0), Tuple!(real, real)(1, 0), Tuple!(real, real)(0, 1) and
Triangle: Tuple!(real, real)(1, 0), Tuple!(real, real)(2, 0), Tuple!(real, real)(1, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

F#

Translation of: Kotlin

<lang fsharp>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</lang>
Output:
((0, 0), (5, 0), (0, 5)) and
((0, 0), (5, 0), (0, 6))
overlap

((0, 0), (0, 5), (5, 0)) and
((0, 0), (0, 5), (5, 0))
overlap (reversed)

((0, 0), (5, 0), (0, 5)) and
((-10, 0), (-5, 0), (-1, 6))
do not overlap

((0, 0), (5, 0), (2.5, 5)) and
((0, 4), (2.5, -1), (5, 4))
overlap

((0, 0), (1, 1), (0, 2)) and
((2, 1), (3, 0), (3, 2))
do not overlap

((0, 0), (1, 1), (0, 2)) and
((2, 1), (3, -2), (3, 4))
do not overlap

The following triangles which have only a single corner in contact, if boundary points collide
((0, 0), (1, 0), (0, 1)) and
((1, 0), (2, 0), (1, 1.1))
overlap

((0, 0), (1, 0), (0, 1)) and
((1, 0), (2, 0), (1, 1.1))
which have only a single corner in contact, if boundary points do not collide
do not overlap

Go

Translation of: Kotlin

<lang go>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"))

}</lang>

Output:
Same as Kotlin entry.

Groovy

Translation of: Java

<lang groovy>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")
       }
   }

}</lang>

Output:
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 6.0)
overlap

Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0) and
Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0)
overlap (reversed)

Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0)
do not overlap

Triangle: (0.0, 0.0), (5.0, 0.0), (2.5, 5.0) and
Triangle: (0.0, 4.0), (2.5, -1.0), (5.0, 4.0)
overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, 0.0), (3.0, 2.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, -2.0), (3.0, 4.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

Java

Translation of: Kotlin
Works with: Java version 8

<lang Java>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");
       }
   }

}</lang>

Output:
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 6.0)
overlap

Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0) and
Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0)
overlap (reversed)

Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0)
do not overlap

Triangle: (0.0, 0.0), (5.0, 0.0), (2.5, 5.0) and
Triangle: (0.0, 4.0), (2.5, -1.0), (5.0, 4.0)
overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, 0.0), (3.0, 2.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, -2.0), (3.0, 4.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

Julia

Translation of: Python

Module: <lang julia>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</lang>

Main: <lang julia>using .Triangles

t1 = [0 0; 5 0; 0 5] t2 = [0 0; 5 0; 0 6] @show Triangles.overlap(t1, t2)

t1 = [0 0; 0 5; 5 0] t2 = [0 0; 0 6; 5 0] @show Triangles.overlap(t1, t2, widing=Both())

t1 = [0 0; 5 0; 0 5] t2 = [-10 0; -5 0; -1 6] @show Triangles.overlap(t1, t2)

t1 = [0 0; 5 0; 2.5 5] t2 = [0 4; 2.5 -1; 5 4] @show Triangles.overlap(t1, t2)

t1 = [0 0; 1 1; 0 2] t2 = [2 1; 3 0; 3 2] @show Triangles.overlap(t1, t2)

t1 = [0 0; 1 1; 0 2] t2 = [2 1; 3 -2; 3 4] @show Triangles.overlap(t1, t2)

  1. Barely touching

t1 = [0 0; 1 0; 0 1] t2 = [1 0; 2 0; 1 1] @show Triangles.overlap(t1, t2, StrictCheck())

  1. Barely touching

t1 = [0 0; 1 0; 0 1] t2 = [1 0; 2 0; 1 1] @show Triangles.overlap(t1, t2, MildCheck())</lang>

Output:
Triangles.overlap(t1, t2) = true
Triangles.overlap(t1, t2, widing=Both()) = true
Triangles.overlap(t1, t2) = false
Triangles.overlap(t1, t2) = true
Triangles.overlap(t1, t2) = false
Triangles.overlap(t1, t2) = false
Triangles.overlap(t1, t2, StrictCheck()) = true
Triangles.overlap(t1, t2, MildCheck()) = false

Kotlin

Translation of: C++

<lang scala>// 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")

}</lang>

Output:
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 6.0)
overlap

Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0) and
Triangle: (0.0, 0.0), (0.0, 5.0), (5.0, 0.0)
overlap (reversed)

Triangle: (0.0, 0.0), (5.0, 0.0), (0.0, 5.0) and
Triangle: (-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0)
do not overlap

Triangle: (0.0, 0.0), (5.0, 0.0), (2.5, 5.0) and
Triangle: (0.0, 4.0), (2.5, -1.0), (5.0, 4.0)
overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, 0.0), (3.0, 2.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 1.0), (0.0, 2.0) and
Triangle: (2.0, 1.0), (3.0, -2.0), (3.0, 4.0)
do not overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: (0.0, 0.0), (1.0, 0.0), (0.0, 1.0) and
Triangle: (1.0, 0.0), (2.0, 0.0), (1.0, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

Lua

Translation of: C++

<lang lua>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))</lang>

Output:
Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (0, 0), (5, 0), (0, 6)
overlap

Triangle: (0, 0), (0, 5), (5, 0) and
Triangle: (0, 0), (0, 5), (5, 0)
overlap

Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (-10, 0), (-5, 0), (-1, 6)
do not overlap

Triangle: (0, 0), (5, 0), (2.5, 5) and
Triangle: (0, 4), (2.5, -1), (5, 4)
overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, 0), (3, 2)
do not overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, -2), (3, 4)
do not overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1)
overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1)
overlap

Modula-2

<lang modula2>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.</lang>

ooRexx

<lang oorexx>/*--------------------------------------------------------------------

  • Determine if two triangles overlap
  • Fully (?) tested with integer coordinates of the 6 corners
  • This was/is an exercise with ooRexx
  • Removed the fraction arithmetic
  • -------------------------------------------------------------------*/

Parse Version v

oid='trioo.txt'; 'erase' oid Call o v case=0 cc=0 Call trio_test '0 0 4 0 0 4 1 1 2 1 1 2' Call trio_test '0 0 0 6 8 3 8 0 8 8 0 3' Call trio_test '0 0 0 2 2 0 0 0 4 0 0 6' /* The task's specified input */ Call trio_test '0 0 5 0 0 5 0 0 5 0 0 6' Call trio_test '0 0 0 5 5 0 0 0 0 5 5 0' Call trio_test '0 0 5 0 0 5 -10 0 -5 0 -1 6' Call trio_test '0 0 5 0 2.5 5 0 4 2.5 -1 5 4' Call trio_test '0 0 1 1 0 2 2 1 3 0 3 2' Call trio_test '0 0 1 1 0 2 2 1 3 -2 3 4' Call trio_test '0 0 1 0 0 1 1 0 2 0 1 1' Exit /* Other test cases */ Call trio_test '0 0 0 4 4 0 0 2 2 2 2 0' Call trio_test '0 0 0 5 5 0 0 0 0 5 5 0' Call trio_test '0 0 0 5 5 0 0 0 0 5 7 0' Call trio_test '0 0 1 0 0 1 1 0 2 0 1 1' Call trio_test '0 0 1 1 0 2 2 1 3 0 3 2' Call trio_test '0 0 1 1 0 2 2 1 3 -2 3 4' Call trio_test '0 0 2 0 2 2 3 3 5 3 5 5' Call trio_test '0 0 2 0 2 3 0 0 2 0 2 3' Call trio_test '0 0 4 0 0 4 0 2 2 0 2 2' Call trio_test '0 0 4 0 0 4 1 1 2 1 1 2' Call trio_test '0 0 5 0 0 2 5 0 8 0 4 8' Call trio_test '0 0 5 0 0 5 0 0 5 0 0 6' Call trio_test '0 0 5 0 0 5 -10 0 -5 0 -1 6' Call trio_test '0 0 5 0 0 5 -5 0 -1 6 -3 0' Call trio_test '0 0 5 0 3 5 0 4 3 -1 5 4' Call trio_test '0 0 6 0 4 6 1 1 4 2 7 1' Call trio_test '0 1 0 4 2 2 3 1 3 4 5 2' Call trio_test '1 0 3 0 2 2 1 3 3 3 2 2' Call trio_test '1 0 3 0 2 2 1 3 3 3 2 5' Call trio_test '1 1 4 2 7 1 0 0 8 0 4 8' Call trio_test '2 0 2 6 1 8 0 1 0 5 8 3' Call trio_test '0 0 4 0 0 4 1 1 2 1 1 2' Say case 'cases tested' Say cc Exit

trio_test: Parse Arg tlist cc+=1 tlist=space(tlist) tl1=tlist  ; Call trio_t tl1 tl2=reversex(tlist)  ; Call trio_t tl2 tl3= tl=tlist Do While tl<>

 Parse Var tl x y tl
 tl3=tl3 y x
 End
                                        Call trio_t tl3

tl4=reversex(tl3)  ; Call trio_t tl4 tl5=subword(tl4,7) subword(tl4,1,6)  ; Call trio_t tl5 tl6=subword(tl5,7) subword(tl5,1,6)  ; Call trio_t tl6 Return

trio_t: Parse Arg tlist tlist=space(tlist) Say tlist case+=1 Parse Arg ax ay bx by cx cy dx dy ex ey fx fy /*---------------------------------------------------------------------

  • First build the objects needed
  • --------------------------------------------------------------------*/

a=.point~new(ax,ay); b=.point~new(bx,by); c=.point~new(cx,cy) d=.point~new(dx,dy); e=.point~new(ex,ey); f=.point~new(fx,fy) abc=.triangle~new(a,b,c) def=.triangle~new(d,e,f) Call o 'Triangle: ABC:' abc ,1 Call o 'Edges of ABC:'; Do i=1 To 3; Call o ' 'abc~edge(i); End Call o 'Triangle: DEF:' def ,1 Call o 'Edges of DEF:'; Do i=1 To 3; Call o ' 'def~edge(i); End pixl=' ' Do i=1 To 3

 pixl=pixl abc~draw(i,'O')
 pixl=pixl def~draw(i,'*')
 End

res=0 fc=0 touch=0 bordl= Do i=1 To 3

 p1=abc~point(i)
 p2=def~point(i)
 Do j=1 To 3
   e1=abc~edge(j)
   e2=def~edge(j)
   If e1~contains(p2) Then Do
     Call o e1 'contains' p2
     ps=p2~string
     If wordpos(ps,bordl)=0 Then Do
       bordl=bordl ps
       touch+=1
       End
     End
   Else
     Call o e1 'does not contain' p2 i j
   If e2~contains(p1) Then Do
     Call o e2 'contains' p1
     ps=p1~string
     If wordpos(ps,bordl)=0 Then Do
       bordl=bordl ps
       touch+=1
       End
     End
   Else
     Call o e2 'does not contain' p1
   End
 End

wb=words(bordl) /* how many of them? */ If wb>0 Then

 Call o 'Corner(s) that touch the other triangle:' bordl,1

/*---------------------------------------------------------------------

  • How many of them are corners of both triangles
  • --------------------------------------------------------------------*/

m=0 cmatch= do i=1 To 3

 If wordpos(abc~point(i),bordl)>0 &,
    wordpos(abc~point(i),def)>0 Then Do
   cmatch=cmatch abc~point(i)
   m+=1
   End
 End

/*---------------------------------------------------------------------

  • With two or three touching corners we show the result and return
  • --------------------------------------------------------------------*/

Select

 When wb=3 Then Do                 /* all three touch               */
   Call draw(pixl)
   Select
     When m=3 Then
       Call o 'Triangles are identical',1
     When m=2 Then
       Call o 'Triangles have an edge in common:' cmatch,1
     Otherwise
       Call o 'Triangles overlap and touch on' bordl,1
     End
   Call o ,1
--   Pull .
   Return
   End
 When wb=2 Then Do                 /* two of them match             */
   Call draw(pixl)
   If m=2 Then
     Call o 'Triangles have an edge in common:' cmatch,1
   Else
     Call o 'Triangles overlap and touch on' bordl,1
   Call o 
--   Pull .
   Return
   End
 When wb=1 Then Do                 /* one of them matches          */
   Call o 'Triangles touch on' bordl,1 /* other parts may overlap  */
   Call o '  we analyze further',1
   End
 Otherwise                         /* we know nothing yet           */
   Nop
 End

/*---------------------------------------------------------------------

  • Now we look for corners of abc that are within the triangle def
  • --------------------------------------------------------------------*/

in_def=0 Do i=1 To 3

 p=abc~point(i)
 Call o 'p  ='p
 Call o 'def='def
 If def~contains(p) &,
   wordpos(p,bordl)=0 Then Do
   Call o def 'contains' p
   in_def+=1
   End
 End

If in_def=3 Then Do

 Call o abc 'is fully contained in' def,1
 Call o ,1
 Call draw(pixl)
 fc=1
 End

res=(in_def>0) /*---------------------------------------------------------------------

  • Now we look for corners of def that are within the triangle abc
  • --------------------------------------------------------------------*/

If res=0 Then Do

 in_abc=0
 If res=0 Then Do
   Do i=1 To 3
     p=def~point(i)
     Call o 'p  ='p
     Call o 'def='def
     If abc~contains(p) &,
        wordpos(p,bordl)=0 Then Do
       Call o abc 'contains' p
       in_abc+=1
       End
     End
   End
 If in_abc=3 Then Do
   Call o def 'is fully contained in' abc,1
   Call o ,1
   Call draw(pixl)
   fc=1
   End
 res=(in_abc>0)
 End

/*---------------------------------------------------------------------

  • Now we check if some edge of abc crosses any edge of def
  • --------------------------------------------------------------------*/

If res=0 Then Do

 Do i=1 To 3
   Do j=1 To 3
     e1=abc~edge(i); Call o 'e1='e1
     e2=def~edge(j); Call o 'e2='e2
     Call o 'crossing???'
     res=e1~crosses(e2)

If res Then Do

 End
     If res Then
       Call o 'edges cross'
     Else
       Call o 'edges dont cross'
     End
   End
 End

If fc=0 Then Do /* no fully contained */

 Call draw(pixl)
 If res=0 Then                     /* no overlap                    */
   If wb=1 Then                    /* but one touching corner       */
     call o abc 'and' def 'dont overlap but touch on' bordl,1
   Else
     call o abc 'and' def 'dont overlap',1
 Else                              /* overlap                       */
   If wb>0 Then                    /* one touching corner           */
     call o abc 'and' def 'overlap and touch on' bordl,1
   Else
     call o abc 'and' def 'overlap',1
 Call o ,1

-- Pull .

 End

Return

/*---------------------------------------------------------------------

  • And here are all the classes and methods needed:
  • point init, x, y, string
  • triangle init, point, edge, contains, string
  • edge init, p1, p2, kdx, contains, crosses, string
  • --------------------------------------------------------------------*/
class point public
attribute x
attribute y
method init
 expose x y
 use arg x,y
method string
 expose x y
 return "("||x","y")"
class triangle public
method init
 expose point edge
 use arg p1,p2,p3
 point=.array~new
 point[1]=p1
 point[2]=p2
 point[3]=p3
 edge=.array~new
 Do i=1 To 3
   ia=i+1; If ia=4 Then ia=1
   edge[i]=.edge~new(point[i],point[ia])
   End
method point
 expose point
 use arg n
 Return point[n]
method edge
 expose edge
 use arg n
 Return edge[n]
method contains
 expose point edge
 use arg pp
 Call o self
 Call o 'pp='pp
 xmin=1.e9
 ymin=1.e9
 xmax=-1.e9
 ymax=-1.e9
 Do i=1 To 3
   e=edge[i]
   Parse Value e~kdx With ka.i da.i xa.i
   Call o show_g(ka.i,da.i,xa.i)
   p1=e~p1
   p2=e~p2
   xmin=min(xmin,p1~x,p2~x)
   xmax=max(xmax,p1~x,p2~x)
   ymin=min(ymin,p1~y,p2~y)
   ymax=max(ymax,p1~y,p2~y)
   End
 If pp~x<xmin|pp~x>xmax|pp~y<ymin|pp~y>ymax Then
   res=0
 Else Do
   e=edge[1]
   e2=edge[2]
   p1=e2~p1
   p2=e2~p2
   Call o 'e:' e
   Select
     When ka.1='*' Then Do
       y2=ka.2*pp~x+da.2
       y3=ka.3*pp~x+da.3
       res=between(y2,pp~y,y3)
       End
     When ka.2='*' Then Do
       y2=ka.1*pp~x+da.1
       res=between(p1~y,y2,p2~y)
       End
     Otherwise Do
       dap=pp~y-ka.1*pp~x
       If ka.3='*' Then
         x3=xa.3
       Else
         x3=(da.3-dap)/(ka.1-ka.3)
       x2=(da.2-dap)/(ka.1-ka.2)
       res=between(x2,pp~x,x3)
       End
     End
   End
 Return res
method string
 expose point
 ol=
 Do p over point
   ol=ol p~string
   End
 return ol
method draw
 expose point
 Use Arg i,c
 p=self~point(i)
 Return p~x p~y c
class edge public
method init
 expose edge p1 p2
 use arg p1,p2
 edge=.array~new
 edge[1]=p1
 edge[2]=p2
method p1
 expose edge p1 p2
 return p1
method p2
 expose edge p1 p2
 return p2
method kdx
 expose edge p1 p2
 x1=p1~x
 y1=p1~y
 x2=p2~x
 y2=p2~y
 If x1=x2 Then Do
   Parse Value '*' '-' x1 With ka da xa
     Call o show_g(ka,da,xa)
   End
 Else Do
   ka=(y2-y1)/(x2-x1)
   da=y2-ka*x2
   xa='*'
   End
 Return ka da xa
method contains
 Use Arg p
 p1=self~p1
 p2=self~p2
 parse Value self~kdx With k d x
 If k='*' Then Do
   res=(p~x=p1~x)&between(p1~y,p~y,p2~y,'I')
   End
 Else Do
   ey=k*p~x+d
   res=(ey=p~y)&between(p1~x,p~x,p2~x,'I')
   End
 If res Then Call o self 'contains' p
        Else Call o self 'does not contain' p
 Return res
method crosses
 expose p1 p2
 Use Arg e
 q1=e~p1
 q2=e~p2
 Call o 'Test if' e 'crosses' self
 Call o self~kdx
 Call o e~kdx
 Parse Value self~kdx With ka da xa; Call o ka da xa
   Call o show_g(ka,da,xa)
 Parse Value    e~kdx With kb db xb; Call o kb db xb
   Call o show_g(kb,db,xb)
 Call o 'ka='ka
 Call o 'kb='kb
 Select
   When ka='*' Then Do
     If kb='*' Then Do
       res=(xa=xb)
       End
     Else Do
       Call o 'kb='kb 'xa='||xa  'db='db
       yy=kb*xa+db
       res=between(q1~y,yy,q2~y)
       End
     End
   When kb='*' Then Do
     yy=ka*xb+da
     res=between(p1~y,yy,p2~y)
     End
   When ka=kb Then Do
     If da=db Then Do
       If min(p1~x,p2~x)>max(q1~x,q2~x) |,
          min(q1~x,q2~x)>max(p1~x,p2~x) Then
         res=0
       Else Do
         res=1
         End
       End
     Else
       res=0
     End
   Otherwise Do
     x=(db-da)/(ka-kb)
     y=ka*x+da
     Call o 'cross:' x y
     res=between(p1~x,x,p2~x)
     End
   End
 Return res
method string
 expose edge p1 p2
 ol=p1~string'-'p2~string
 return ol
routine between /* check if a number is between two others */
 Use Arg a,x,b,inc
 Call o 'between:' a x b
 Parse Var a anom '/' adenom
 Parse Var x xnom '/' xdenom
 Parse Var b bnom '/' bdenom
 If adenom= Then adenom=1
 If xdenom= Then xdenom=1
 If bdenom= Then bdenom=1
 aa=anom*xdenom*bdenom
 xx=xnom*adenom*bdenom
 bb=bnom*xdenom*adenom
 If inc='I' Then
   res=sign(xx-aa)<>sign(xx-bb)
 Else
   res=sign(xx-aa)<>sign(xx-bb) & (xx-aa)*(xx-bb)<>0
 Call o a x b 'res='res
 Return res
routine show_g /* show a straight line's forula */

/*---------------------------------------------------------------------

  • given slope, y-distance, and (special) x-value
  • compute y=k*x+d or, if a vertical line, k='*'; x=c
  • --------------------------------------------------------------------*/
 Use Arg k,d,x
 Select
   When k='*' Then res='x='||x       /* vertical line               */
   When k=0   Then res='y='d         /* horizontal line             */
   Otherwise Do                      /* ordinary line               */
     Select
       When k=1  Then res='y=x'dd(d)
       When k=-1 Then res='y=-x'dd(d)
       Otherwise      res='y='k'*x'dd(d)
       End
     End
   End
 Return res
routine dd /* prepare a displacement for presenting it in show_g */

/*---------------------------------------------------------------------

  • prepare y-distance for display
  • --------------------------------------------------------------------*/
 Use Arg dd
 Select
   When dd=0 Then dd=            /* omit dd if it's zero          */
   When dd<0 Then dd=dd            /* use dd as is (-value)         */
   Otherwise      dd='+'dd         /* prepend '+' to positive dd    */
   End
 Return dd
routine o /* debug output */
 Use Arg txt,say
 If say=1 Then
   Say txt
 oid='trioo.txt'
 Return lineout(oid,txt)
routine draw
 Use Arg pixl
   Return                       /* remove to see the triangle corners */
 Say 'pixl='pixl
 pix.=' '
 Do While pixl<>
   Parse Var pixl x y c pixl
   x=2*x+16; y=2*y+4
   If pix.x.y=' ' Then
     pix.x.y=c
   Else
     pix.x.y='+'
   End
 Do j= 20 To 0 By -1
   ol=
   Do i=0 To 40
     ol=ol||pix.i.j
     End
   Say ol
   End
   Return
routine reversex
 Use Arg list
 n=words(list)
 res=word(list,n)
 Do i=n-1 to 1 By -1
   res=res word(list,i)
   End
 Return res </lang>
Output:
0 0 4 0 0 4 1 1 2 1 1 2
Triangle: ABC:  (0,0) (4,0) (0,4)
Triangle: DEF:  (1,1) (2,1) (1,2)
 (1,1) (2,1) (1,2) is fully contained in  (0,0) (4,0) (0,4)

2 1 1 2 1 1 4 0 0 4 0 0
Triangle: ABC:  (2,1) (1,2) (1,1)
Triangle: DEF:  (4,0) (0,4) (0,0)
 (2,1) (1,2) (1,1) is fully contained in  (4,0) (0,4) (0,0)

1 2 2 1 1 1 0 4 4 0 0 0
Triangle: ABC:  (1,2) (2,1) (1,1)
Triangle: DEF:  (0,4) (4,0) (0,0)
 (1,2) (2,1) (1,1) is fully contained in  (0,4) (4,0) (0,0)

0 0 0 4 4 0 1 1 1 2 2 1
Triangle: ABC:  (0,0) (0,4) (4,0)
Triangle: DEF:  (1,1) (1,2) (2,1)
 (1,1) (1,2) (2,1) is fully contained in  (0,0) (0,4) (4,0)

1 1 1 2 2 1 0 0 0 4 4 0
Triangle: ABC:  (1,1) (1,2) (2,1)
Triangle: DEF:  (0,0) (0,4) (4,0)
 (1,1) (1,2) (2,1) is fully contained in  (0,0) (0,4) (4,0)

0 0 0 4 4 0 1 1 1 2 2 1
Triangle: ABC:  (0,0) (0,4) (4,0)
Triangle: DEF:  (1,1) (1,2) (2,1)
 (1,1) (1,2) (2,1) is fully contained in  (0,0) (0,4) (4,0)

0 0 0 6 8 3 8 0 8 8 0 3
Triangle: ABC:  (0,0) (0,6) (8,3)
Triangle: DEF:  (8,0) (8,8) (0,3)
Corner(s) that touch the other triangle:  (0,3) (8,3)
Triangles overlap and touch on  (0,3) (8,3)
3 0 8 8 0 8 3 8 6 0 0 0
Triangle: ABC:  (3,0) (8,8) (0,8)
Triangle: DEF:  (3,8) (6,0) (0,0)
Corner(s) that touch the other triangle:  (3,8) (3,0)
Triangles overlap and touch on  (3,8) (3,0)
0 3 8 8 8 0 8 3 0 6 0 0
Triangle: ABC:  (0,3) (8,8) (8,0)
Triangle: DEF:  (8,3) (0,6) (0,0)
Corner(s) that touch the other triangle:  (8,3) (0,3)
Triangles overlap and touch on  (8,3) (0,3)
0 0 6 0 3 8 0 8 8 8 3 0
Triangle: ABC:  (0,0) (6,0) (3,8)
Triangle: DEF:  (0,8) (8,8) (3,0)
Corner(s) that touch the other triangle:  (3,0) (3,8)
Triangles overlap and touch on  (3,0) (3,8)
0 8 8 8 3 0 0 0 6 0 3 8
Triangle: ABC:  (0,8) (8,8) (3,0)
Triangle: DEF:  (0,0) (6,0) (3,8)
Corner(s) that touch the other triangle:  (3,8) (3,0)
Triangles overlap and touch on  (3,8) (3,0)
0 0 6 0 3 8 0 8 8 8 3 0
Triangle: ABC:  (0,0) (6,0) (3,8)
Triangle: DEF:  (0,8) (8,8) (3,0)
Corner(s) that touch the other triangle:  (3,0) (3,8)
Triangles overlap and touch on  (3,0) (3,8)
0 0 0 2 2 0 0 0 4 0 0 6
Triangle: ABC:  (0,0) (0,2) (2,0)
Triangle: DEF:  (0,0) (4,0) (0,6)
Corner(s) that touch the other triangle:  (0,0) (0,2) (2,0)
Triangles overlap and touch on  (0,0) (0,2) (2,0)

6 0 0 4 0 0 0 2 2 0 0 0
Triangle: ABC:  (6,0) (0,4) (0,0)
Triangle: DEF:  (0,2) (2,0) (0,0)
Corner(s) that touch the other triangle:  (0,2) (2,0) (0,0)
Triangles overlap and touch on  (0,2) (2,0) (0,0)

0 6 4 0 0 0 2 0 0 2 0 0
Triangle: ABC:  (0,6) (4,0) (0,0)
Triangle: DEF:  (2,0) (0,2) (0,0)
Corner(s) that touch the other triangle:  (2,0) (0,2) (0,0)
Triangles overlap and touch on  (2,0) (0,2) (0,0)

0 0 2 0 0 2 0 0 0 4 6 0
Triangle: ABC:  (0,0) (2,0) (0,2)
Triangle: DEF:  (0,0) (0,4) (6,0)
Corner(s) that touch the other triangle:  (0,0) (2,0) (0,2)
Triangles overlap and touch on  (0,0) (2,0) (0,2)

0 0 0 4 6 0 0 0 2 0 0 2
Triangle: ABC:  (0,0) (0,4) (6,0)
Triangle: DEF:  (0,0) (2,0) (0,2)
Corner(s) that touch the other triangle:  (0,0) (2,0) (0,2)
Triangles overlap and touch on  (0,0) (2,0) (0,2)

0 0 2 0 0 2 0 0 0 4 6 0
Triangle: ABC:  (0,0) (2,0) (0,2)
Triangle: DEF:  (0,0) (0,4) (6,0)
Corner(s) that touch the other triangle:  (0,0) (2,0) (0,2)
Triangles overlap and touch on  (0,0) (2,0) (0,2)

0 0 5 0 0 5 0 0 5 0 0 6
Triangle: ABC:  (0,0) (5,0) (0,5)
Triangle: DEF:  (0,0) (5,0) (0,6)
Corner(s) that touch the other triangle:  (0,0) (5,0) (0,5)
Triangles have an edge in common:  (0,0) (5,0)

6 0 0 5 0 0 5 0 0 5 0 0
Triangle: ABC:  (6,0) (0,5) (0,0)
Triangle: DEF:  (5,0) (0,5) (0,0)
Corner(s) that touch the other triangle:  (5,0) (0,5) (0,0)
Triangles have an edge in common:  (0,5) (0,0)

0 6 5 0 0 0 0 5 5 0 0 0
Triangle: ABC:  (0,6) (5,0) (0,0)
Triangle: DEF:  (0,5) (5,0) (0,0)
Corner(s) that touch the other triangle:  (0,5) (5,0) (0,0)
Triangles have an edge in common:  (5,0) (0,0)

0 0 0 5 5 0 0 0 0 5 6 0
Triangle: ABC:  (0,0) (0,5) (5,0)
Triangle: DEF:  (0,0) (0,5) (6,0)
Corner(s) that touch the other triangle:  (0,0) (0,5) (5,0)
Triangles have an edge in common:  (0,0) (0,5)

0 0 0 5 6 0 0 0 0 5 5 0
Triangle: ABC:  (0,0) (0,5) (6,0)
Triangle: DEF:  (0,0) (0,5) (5,0)
Corner(s) that touch the other triangle:  (0,0) (0,5) (5,0)
Triangles have an edge in common:  (0,0) (0,5)

0 0 0 5 5 0 0 0 0 5 6 0
Triangle: ABC:  (0,0) (0,5) (5,0)
Triangle: DEF:  (0,0) (0,5) (6,0)
Corner(s) that touch the other triangle:  (0,0) (0,5) (5,0)
Triangles have an edge in common:  (0,0) (0,5)

0 0 0 5 5 0 0 0 0 5 5 0
Triangle: ABC:  (0,0) (0,5) (5,0)
Triangle: DEF:  (0,0) (0,5) (5,0)
Corner(s) that touch the other triangle:  (0,0) (0,5) (5,0)
Triangles are identical

0 5 5 0 0 0 0 5 5 0 0 0
Triangle: ABC:  (0,5) (5,0) (0,0)
Triangle: DEF:  (0,5) (5,0) (0,0)
Corner(s) that touch the other triangle:  (0,5) (5,0) (0,0)
Triangles are identical

5 0 0 5 0 0 5 0 0 5 0 0
Triangle: ABC:  (5,0) (0,5) (0,0)
Triangle: DEF:  (5,0) (0,5) (0,0)
Corner(s) that touch the other triangle:  (5,0) (0,5) (0,0)
Triangles are identical

0 0 5 0 0 5 0 0 5 0 0 5
Triangle: ABC:  (0,0) (5,0) (0,5)
Triangle: DEF:  (0,0) (5,0) (0,5)
Corner(s) that touch the other triangle:  (0,0) (5,0) (0,5)
Triangles are identical

0 0 5 0 0 5 0 0 5 0 0 5
Triangle: ABC:  (0,0) (5,0) (0,5)
Triangle: DEF:  (0,0) (5,0) (0,5)
Corner(s) that touch the other triangle:  (0,0) (5,0) (0,5)
Triangles are identical

0 0 5 0 0 5 0 0 5 0 0 5
Triangle: ABC:  (0,0) (5,0) (0,5)
Triangle: DEF:  (0,0) (5,0) (0,5)
Corner(s) that touch the other triangle:  (0,0) (5,0) (0,5)
Triangles are identical

0 0 5 0 0 5 -10 0 -5 0 -1 6
Triangle: ABC:  (0,0) (5,0) (0,5)
Triangle: DEF:  (-10,0) (-5,0) (-1,6)
 (0,0) (5,0) (0,5) and  (-10,0) (-5,0) (-1,6) don't overlap

6 -1 0 -5 0 -10 5 0 0 5 0 0
Triangle: ABC:  (6,-1) (0,-5) (0,-10)
Triangle: DEF:  (5,0) (0,5) (0,0)
 (6,-1) (0,-5) (0,-10) and  (5,0) (0,5) (0,0) don't overlap

-1 6 -5 0 -10 0 0 5 5 0 0 0
Triangle: ABC:  (-1,6) (-5,0) (-10,0)
Triangle: DEF:  (0,5) (5,0) (0,0)
 (-1,6) (-5,0) (-10,0) and  (0,5) (5,0) (0,0) don't overlap

0 0 0 5 5 0 0 -10 0 -5 6 -1
Triangle: ABC:  (0,0) (0,5) (5,0)
Triangle: DEF:  (0,-10) (0,-5) (6,-1)
 (0,0) (0,5) (5,0) and  (0,-10) (0,-5) (6,-1) don't overlap

0 -10 0 -5 6 -1 0 0 0 5 5 0
Triangle: ABC:  (0,-10) (0,-5) (6,-1)
Triangle: DEF:  (0,0) (0,5) (5,0)
 (0,-10) (0,-5) (6,-1) and  (0,0) (0,5) (5,0) don't overlap

0 0 0 5 5 0 0 -10 0 -5 6 -1
Triangle: ABC:  (0,0) (0,5) (5,0)
Triangle: DEF:  (0,-10) (0,-5) (6,-1)
 (0,0) (0,5) (5,0) and  (0,-10) (0,-5) (6,-1) don't overlap

0 0 5 0 2.5 5 0 4 2.5 -1 5 4
Triangle: ABC:  (0,0) (5,0) (2.5,5)
Triangle: DEF:  (0,4) (2.5,-1) (5,4)
 (0,0) (5,0) (2.5,5) and  (0,4) (2.5,-1) (5,4) overlap

4 5 -1 2.5 4 0 5 2.5 0 5 0 0
Triangle: ABC:  (4,5) (-1,2.5) (4,0)
Triangle: DEF:  (5,2.5) (0,5) (0,0)
 (4,5) (-1,2.5) (4,0) and  (5,2.5) (0,5) (0,0) overlap

5 4 2.5 -1 0 4 2.5 5 5 0 0 0
Triangle: ABC:  (5,4) (2.5,-1) (0,4)
Triangle: DEF:  (2.5,5) (5,0) (0,0)
 (5,4) (2.5,-1) (0,4) and  (2.5,5) (5,0) (0,0) overlap

0 0 0 5 5 2.5 4 0 -1 2.5 4 5
Triangle: ABC:  (0,0) (0,5) (5,2.5)
Triangle: DEF:  (4,0) (-1,2.5) (4,5)
 (0,0) (0,5) (5,2.5) and  (4,0) (-1,2.5) (4,5) overlap

4 0 -1 2.5 4 5 0 0 0 5 5 2.5
Triangle: ABC:  (4,0) (-1,2.5) (4,5)
Triangle: DEF:  (0,0) (0,5) (5,2.5)
 (4,0) (-1,2.5) (4,5) and  (0,0) (0,5) (5,2.5) overlap

0 0 0 5 5 2.5 4 0 -1 2.5 4 5
Triangle: ABC:  (0,0) (0,5) (5,2.5)
Triangle: DEF:  (4,0) (-1,2.5) (4,5)
 (0,0) (0,5) (5,2.5) and  (4,0) (-1,2.5) (4,5) overlap

0 0 1 1 0 2 2 1 3 0 3 2
Triangle: ABC:  (0,0) (1,1) (0,2)
Triangle: DEF:  (2,1) (3,0) (3,2)
 (0,0) (1,1) (0,2) and  (2,1) (3,0) (3,2) don't overlap

2 3 0 3 1 2 2 0 1 1 0 0
Triangle: ABC:  (2,3) (0,3) (1,2)
Triangle: DEF:  (2,0) (1,1) (0,0)
 (2,3) (0,3) (1,2) and  (2,0) (1,1) (0,0) don't overlap

3 2 3 0 2 1 0 2 1 1 0 0
Triangle: ABC:  (3,2) (3,0) (2,1)
Triangle: DEF:  (0,2) (1,1) (0,0)
 (3,2) (3,0) (2,1) and  (0,2) (1,1) (0,0) don't overlap

0 0 1 1 2 0 1 2 0 3 2 3
Triangle: ABC:  (0,0) (1,1) (2,0)
Triangle: DEF:  (1,2) (0,3) (2,3)
 (0,0) (1,1) (2,0) and  (1,2) (0,3) (2,3) don't overlap

1 2 0 3 2 3 0 0 1 1 2 0
Triangle: ABC:  (1,2) (0,3) (2,3)
Triangle: DEF:  (0,0) (1,1) (2,0)
 (1,2) (0,3) (2,3) and  (0,0) (1,1) (2,0) don't overlap

0 0 1 1 2 0 1 2 0 3 2 3
Triangle: ABC:  (0,0) (1,1) (2,0)
Triangle: DEF:  (1,2) (0,3) (2,3)
 (0,0) (1,1) (2,0) and  (1,2) (0,3) (2,3) don't overlap

0 0 1 1 0 2 2 1 3 -2 3 4
Triangle: ABC:  (0,0) (1,1) (0,2)
Triangle: DEF:  (2,1) (3,-2) (3,4)
 (0,0) (1,1) (0,2) and  (2,1) (3,-2) (3,4) don't overlap

4 3 -2 3 1 2 2 0 1 1 0 0
Triangle: ABC:  (4,3) (-2,3) (1,2)
Triangle: DEF:  (2,0) (1,1) (0,0)
 (4,3) (-2,3) (1,2) and  (2,0) (1,1) (0,0) don't overlap

3 4 3 -2 2 1 0 2 1 1 0 0
Triangle: ABC:  (3,4) (3,-2) (2,1)
Triangle: DEF:  (0,2) (1,1) (0,0)
 (3,4) (3,-2) (2,1) and  (0,2) (1,1) (0,0) don't overlap

0 0 1 1 2 0 1 2 -2 3 4 3
Triangle: ABC:  (0,0) (1,1) (2,0)
Triangle: DEF:  (1,2) (-2,3) (4,3)
 (0,0) (1,1) (2,0) and  (1,2) (-2,3) (4,3) don't overlap

1 2 -2 3 4 3 0 0 1 1 2 0
Triangle: ABC:  (1,2) (-2,3) (4,3)
Triangle: DEF:  (0,0) (1,1) (2,0)
 (1,2) (-2,3) (4,3) and  (0,0) (1,1) (2,0) don't overlap

0 0 1 1 2 0 1 2 -2 3 4 3
Triangle: ABC:  (0,0) (1,1) (2,0)
Triangle: DEF:  (1,2) (-2,3) (4,3)
 (0,0) (1,1) (2,0) and  (1,2) (-2,3) (4,3) don't overlap

0 0 1 0 0 1 1 0 2 0 1 1
Triangle: ABC:  (0,0) (1,0) (0,1)
Triangle: DEF:  (1,0) (2,0) (1,1)
Corner(s) that touch the other triangle:  (1,0)
Triangles touch on  (1,0)
  we analyze further
 (0,0) (1,0) (0,1) and  (1,0) (2,0) (1,1) don't overlap but touch on  (1,0)

1 1 0 2 0 1 1 0 0 1 0 0
Triangle: ABC:  (1,1) (0,2) (0,1)
Triangle: DEF:  (1,0) (0,1) (0,0)
Corner(s) that touch the other triangle:  (0,1)
Triangles touch on  (0,1)
  we analyze further
 (1,1) (0,2) (0,1) and  (1,0) (0,1) (0,0) don't overlap but touch on  (0,1)

1 1 2 0 1 0 0 1 1 0 0 0
Triangle: ABC:  (1,1) (2,0) (1,0)
Triangle: DEF:  (0,1) (1,0) (0,0)
Corner(s) that touch the other triangle:  (1,0)
Triangles touch on  (1,0)
  we analyze further
 (1,1) (2,0) (1,0) and  (0,1) (1,0) (0,0) overlap and touch on  (1,0)

0 0 0 1 1 0 0 1 0 2 1 1
Triangle: ABC:  (0,0) (0,1) (1,0)
Triangle: DEF:  (0,1) (0,2) (1,1)
Corner(s) that touch the other triangle:  (0,1)
Triangles touch on  (0,1)
  we analyze further
 (0,0) (0,1) (1,0) and  (0,1) (0,2) (1,1) don't overlap but touch on  (0,1)

0 1 0 2 1 1 0 0 0 1 1 0
Triangle: ABC:  (0,1) (0,2) (1,1)
Triangle: DEF:  (0,0) (0,1) (1,0)
Corner(s) that touch the other triangle:  (0,1)
Triangles touch on  (0,1)
  we analyze further
 (0,1) (0,2) (1,1) and  (0,0) (0,1) (1,0) don't overlap but touch on  (0,1)

0 0 0 1 1 0 0 1 0 2 1 1
Triangle: ABC:  (0,0) (0,1) (1,0)
Triangle: DEF:  (0,1) (0,2) (1,1)
Corner(s) that touch the other triangle:  (0,1)
Triangles touch on  (0,1)
  we analyze further
 (0,0) (0,1) (1,0) and  (0,1) (0,2) (1,1) don't overlap but touch on  (0,1)

Pascal

A console application in Free Pascal, created with the Lazarus IDE. It recognizes three possible outcomes: disjoint, positive overlap, and borderline (overlap at a point or line segment). <lang pascal> 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. } {$mode objfpc}{$H+}

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. </lang>

Output:
(0,0),(5,0),(0,5) and (0,0),(5,0),(0,6): Overlap
(0,0),(0,5),(5,0) and (0,0),(0,5),(5,0): Overlap
(0,0),(5,0),(0,5) and (-10,0),(-5,0),(-1,6): Disjoint
(0,0),(5,0),(2.5,5) and (0,4),(2.5,-1),(5,4): Overlap
(0,0),(1,1),(0,2) and (2,1),(3,0),(3,2): Disjoint
(0,0),(1,1),(0,2) and (2,1),(3,-2),(3,4): Disjoint
(0,0),(1,0),(0,1) and (1,0),(2,0),(1,1): Borderline

Perl

Port of Lua

<lang perl>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";
   }

}

  1. 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";

  1. 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";

  1. 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";</lang>

Output:
Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (0, 0), (5, 0), (0, 6)
overlap

Triangle: (0, 0), (0, 5), (5, 0) and
Triangle: (0, 0), (0, 5), (5, 0)
overlap

Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (-10, 0), (-5, 0), (-1, 6)
do not overlap

Triangle: (0, 0), (5, 0), (2.5, 5) and
Triangle: (0, 4), (2.5, -1), (5, 4)
overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, 0), (3, 2)
do not overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, -2), (3, 4)
do not overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1)
overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1)
do not overlap

More Idiomatic

<lang perl>use strict; use warnings; use feature 'say';

sub det2D {

   my($p1,$p2,$p3) = @_;
   return $p1->[0] * ($p2->[1] - $p3->[1])
        + $p2->[0] * ($p3->[1] - $p1->[1])
        + $p3->[0] * ($p1->[1] - $p2->[1]);

}

  1. triangles must be expressed anti-clockwise

sub checkTriWinding {

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

}

sub check_edge {

   our($t1,$t2,$eps,$onBoundary) = @_;
   # points on the boundary may be considered as colliding, or not
   my $chkEdge = $onBoundary ?  \&boundaryCollideChk : \&boundaryDoesntCollideChk;
   sub boundaryCollideChk       { return det2D($_[0], $_[1], $_[2]) <  $eps }
   sub boundaryDoesntCollideChk { return det2D($_[0], $_[1], $_[2]) <= $eps }
   # 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
       }
   }
   return 1;

}

sub triTri2D {

   my($t1,$t2,$eps,$allowReversed,$onBoundary) = @_;
   checkTriWinding($$t1->[0], \$$t1->[1], \$$t1->[2], $allowReversed);
   checkTriWinding($$t2->[0], \$$t2->[1], \$$t2->[2], $allowReversed);
   return check_edge($t1,$t2,$eps,$onBoundary) && check_edge($t2,$t1,$eps,$onBoundary);

}

sub formatTri {

   my $t = shift;
   my @pairs;
   push @pairs, sprintf "%8s", '(' . $$_[0] . ',' . $$_[1] . ')' for @$$t;
   join ', ', @pairs;

}

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 || 0;
   my $allowReversed = shift || 1;
   my $onBoundary    = shift || 1;
   my $triangles = formatTri($t1) . ' and ' . formatTri($t2);
   if (triTri2D($t1, $t2, $eps, $allowReversed, $onBoundary)) {
       return "       overlap:" . $triangles;
   } else {
       return "do not overlap:" . $triangles;
   }

}

my @tests = (

  [ [[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]] ],             # barely touching
  [ [[0,0], [1,0],   [0,1]], [   [1,0],    [2,0],  [1,1]], 0.0, 0, 0 ]   # barely touching

);

say overlap(\$_->[0], \$_->[1], $_->[2], $_->[3], $_->[4]) for @tests;</lang>

Output:
       overlap:   (0,0),    (5,0),    (0,5) and    (0,0),    (5,0),    (0,6)
       overlap:   (0,0),    (0,5),    (5,0) and    (0,0),    (0,5),    (5,0)
do not overlap:   (0,0),    (5,0),    (0,5) and  (-10,0),   (-5,0),   (-1,6)
       overlap:   (0,0),    (5,0),  (2.5,5) and    (0,4), (2.5,-1),    (5,4)
do not overlap:   (0,0),    (1,1),    (0,2) and    (2,1),    (3,0),    (3,2)
do not overlap:   (0,0),    (1,1),    (0,2) and    (2,1),   (3,-2),    (3,4)
       overlap:   (0,0),    (1,0),    (0,1) and    (1,0),    (2,0),    (1,1)

Phix

Library: Phix/pGUI
Translation of: zkl

Plus draw all eight pairs of triangles for visual confirmation. <lang Phix>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*/, integer /*posx*/, integer /*posy*/)

   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(NULL)
   IupSetAttribute(canvas, "RASTERSIZE", "1250x300")
   IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
   dlg = IupDialog(canvas,"DIALOGFRAME=YES")
   IupSetAttribute(dlg, "TITLE", "Triangle overlap")
   IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
   IupCloseOnEscape(dlg)
   IupMap(dlg)
   IupSetAttribute(canvas, "RASTERSIZE", NULL)
   IupShowXY(dlg,IUP_CENTER,IUP_CENTER)
   IupMainLoop()
   IupClose()

end procedure

main()</lang>

Python

Library: NumPy

Using numpy: <lang python>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)</lang>

Output:
True True
True True
False False
True True
False False
False False
True True
/False False
Library: Shapely

Using shapely: <lang python>from __future__ import print_function from shapely.geometry import Polygon

def PolyOverlaps(poly1, poly2): poly1s = Polygon(poly1) poly2s = Polygon(poly2) return poly1s.intersects(poly2s)

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

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

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

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

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

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

#Barely touching t1 = [[0,0],[1,0],[0,1]] t2 = [[1,0],[2,0],[1,1]] print (PolyOverlaps(t1, t2), "?")</lang>

Output:
True True
True True
False False
True True
False False
False False
True ?

QB64

<lang QB64> 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

Translation of: Zkl

<lang racket>#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))))

</lang>

No output → all tests passed

Raku

(formerly Perl 6) First, check if any vertex is inside each other triangle (that should cover most overlapping cases including enclosures). Then see if an edge of triangle A intersects any of two edges of B (for shapes like Star of David [1]) <lang perl6># Reference:

  1. https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle
  2. https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/

use v6;

sub if-overlap ($triangle-pair) {

  my (\A,\B) = $triangle-pair;
  my Bool $result = False;
  sub sign (\T) {
     return (T.[0][0] - T[2][0]) * (T[1][1] - T[2][1]) -
        (T[1][0] - T[2][0]) * (T[0][1] - T[2][1]);
  }
  sub point-in-triangle (\pt, \Y --> Bool) {
     my ($d1, $d2, $d3);
     my Bool ($has_neg, $has_pos);
     $d1 = sign (pt, Y.[0], Y.[1]);
     $d2 = sign (pt, Y.[1], Y.[2]);
     $d3 = sign (pt, Y.[2], Y.[0]);
     $has_neg = ($d1 < 0) || ($d2 < 0) || ($d3 < 0);
     $has_pos = ($d1 > 0) || ($d2 > 0) || ($d3 > 0);
     return !($has_neg && $has_pos);
  }
  sub orientation(\P, \Q, \R --> Int) {
     my \val = (Q.[1] - P.[1]) * (R.[0] - Q.[0]) -
        (Q.[0] - P.[0]) * (R.[1] - Q.[1]);
     return 0 if val == 0;  # colinear
     return (val > 0) ?? 1 !! 2; # clock or counterclock wise
  }
  sub onSegment(\P, \Q, \R --> Bool) {
     Q.[0] <= max(P.[0], R.[0]) && Q.[0] >= min(P.[0], R.[0]) &&
        Q.[1] <= max(P.[1], R.[1]) && Q.[1] >= min(P.[0], R.[1])
        ?? True !! False;
  }
  sub intersect(\A,\B,\C,\D --> Bool) {
     my \o1 = orientation A,C,D;
     my \o2 = orientation B,C,D;
     my \o3 = orientation A,B,C;
     my \o4 = orientation A,B,D;
     return True if o1 != o2 && o3 != o4;
     return True if (o1 == 0 && onSegment(A, C, D)) ;
     return True if (o2 == 0 && onSegment(B, C, D)) ;
     return True if (o3 == 0 && onSegment(A, B, C)) ;
     return True if (o4 == 0 && onSegment(A, B, D)) ;
     return False;
  }
  for ^3 {
     {$result = True; last } if point-in-triangle A.[$^i] , B or
         point-in-triangle B.[$^i] , A ;
  }
  unless $result {
     $result = True if intersect A.[0], A.[1], B.[0], B.[1] or
         intersect A.[0], A.[1], B.[0], B.[2]
  }
  say A, " and ", B, " do",  $result ?? "" !! " NOT" , " overlap.";

}

my \DATA = [

  [ [(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)]     ]

];

if-overlap $_ for DATA ;</lang>

Output:
[(0 0) (5 0) (0 5)] and [(0 0) (5 0) (0 6)] do overlap.

[(0 0) (0 5) (5 0)] and [(0 0) (0 5) (5 0)] do overlap. [(0 0) (5 0) (0 5)] and [(-10 0) (-5 0) (-1 6)] do NOT overlap. [(0 0) (5 0) (2.5 5)] and [(0 4) (2.5 -1) (5 4)] do overlap. [(0 0) (1 1) (0 2)] and [(2 1) (3 0) (3 2)] do NOT overlap. [(0 0) (1 1) (0 2)] and [(2 1) (3 -2) (3 4)] do NOT overlap. [(0 0) (1 0) (0 1)] and [(1 0) (2 0) (1 1)] do overlap.

REXX

Note: The triangles must be real triangles (no edge of length 0) <lang rexx>/* REXX */ Signal On Halt Signal On Novalue Signal On Syntax

fid='trio.in' oid='trio.txt'; 'erase' oid


Call trio_test '0 0 5 0 0 5 0 0 5 0 0 6' Call trio_test '0 0 0 5 5 0 0 0 0 5 5 0' Call trio_test '0 0 5 0 0 5 -10 0 -5 0 -1 6' Call trio_test '0 0 5 0 2.5 5 0 4 2.5 -1 5 4' Call trio_test '0 0 1 1 0 2 2 1 3 0 3 2' Call trio_test '0 0 1 1 0 2 2 1 3 -2 3 4' Call trio_test '0 0 1 0 0 1 1 0 2 0 1 1'

Call trio_test '1 0 3 0 2 2 1 3 3 3 2 5' Call trio_test '1 0 3 0 2 2 1 3 3 3 2 2' Call trio_test '0 0 2 0 2 2 3 3 5 3 5 5' Call trio_test '2 0 2 6 1 8 0 1 0 5 8 3' Call trio_test '0 0 4 0 0 4 0 2 2 0 2 2' Call trio_test '0 0 4 0 0 4 1 1 2 1 1 2' Exit

trio_test: parse Arg tlist tlist=space(tlist) Parse Arg ax ay bx by cx cy dx dy ex ey fx fy

Say 'ABC:' show_p(ax ay) show_p(bx by) show_p(cx cy) Say 'DEF:' show_p(dx dy) show_p(ex ey) show_p(fx fy)

bordl=bord(tlist) /* corners that are on the other triangle's edges */ If bordl<> Then

 Say 'Corners on the other triangles edges:' bordl

wb=words(bordl) /* how many of them? */ Select

 When wb=3 Then Do                 /* all three match               */
   If ident(ax ay,bx by,cx cy,dx dy,ex ey,fx fy) Then
     Say 'Triangles are identical'
   Else
     Say 'Triangles overlap'
   Say 
   Return
   End
 When wb=2 Then Do                 /* two of them match             */
   Say 'Triangles overlap'
   Say '  they have a common edge 'bordl
   Say 
   Return
   End
 When wb=1 Then Do                 /* one of them match             */
   Say 'Triangles touch on' bordl  /* other parts may overlap       */
   Say '  we analyze further'
   End
 Otherwise                         /* we know nothing yet           */
   Nop
 End

trio_result=trio(tlist) /* any other overlap? */

Select

 When trio_result=0 Then Do        /* none whatsoever               */
   If wb=1 Then
     Say 'Triangles touch (border case) at' show_p(bordl)
   Else
     Say 'Triangles dont overlap'
   End
 When trio_result>0 Then           /* plain overlapping case        */
   Say 'Triangles overlap'
 End

Say Return

trio: /*---------------------------------------------------------------------

  • Determine if two triangles overlap
  • --------------------------------------------------------------------*/

parse Arg tlist Parse Arg pax pay pbx pby pcx pcy pdx pdy pex pey pfx pfy

abc=subword(tlist,1,6) def=subword(tlist,7,6)

Do i=1 To 3

 s.i=subword(abc abc,i*2-1,4)
 t.i=subword(def def,i*2-1,4)
 End

abc_= def_=

Do i=1 To 3

 abc.i=subword(abc,i*2-1,2)   /* corners of ABC */
 def.i=subword(def,i*2-1,2)   /* corners of DEF */
 Parse Var abc.i x y; abc_=abc_ '('||x','y')'
 Parse Var def.i x y; def_=def_ '('||x','y')'
 End

Call o 'abc_='abc_ Call o 'def_='def_

over=0

 Do i=1 To 3 Until over
   Do j=1 To 3 Until over
     If ssx(s.i t.j) Then Do       /* intersection of two edges     */
       over=1
       Leave
       End
     End
   End

If over=0 Then Do /* no edge intersection found */

 Do ii=1 To 3 Until over           /* look for first possibility    */
   Call o '    '  'abc.'ii'='abc.ii 'def='def
   Call o 'ii='ii 'def.'ii'='def.ii 'abc='abc
   If in_tri(abc.ii,def) Then Do   /* a corner of ABC is in DEF     */
     Say abc.ii 'is within' def
     over=1
     End
   Else If in_tri(def.ii,abc) Then Do  /* a corner of DEF is in ABC */
     Say def.ii 'is within' abc
     over=1
     End
   End
 End

If over=0 Then rw='dont ' Else rw=

Call o 'Triangles' show_p(pax pay) show_p(pbx pby) show_p(pcx pcy),

            'and' show_p(pdx pdy) show_p(pex pey) show_p(pfx pfy),
                                                           rw'overlap'

Call o Return over

ssx: Procedure Expose oid bordl /*---------------------------------------------------------------------

  • Intersection of 2 line segments A-B and C-D
  • --------------------------------------------------------------------*/

Parse Arg xa ya xb yb xc yc xd yd

d=ggx(xa ya xb yb xc yc xd yd)

Call o 'ssx:' arg(1) d res=0 Select

 When d='-' Then res=0
 When d='I' Then Do
   If xa<>xb Then Do
     xab_min=min(xa,xb)
     xcd_min=min(xc,xd)
     xab_max=max(xa,xb)
     xcd_max=max(xc,xd)
     If xab_min>xcd_max |,
        xcd_min>xab_max Then
       res=0
     Else Do
       res=1
       Select
         When xa=xc & isb(xc,xb,xd)=0 Then Do; x=xa; y=ya; End
         When xb=xc & isb(xc,xa,xd)=0 Then Do; x=xb; y=yb; End
         When xa=xd & isb(xc,xb,xd)=0 Then Do; x=xa; y=ya; End
         When xb=xd & isb(xc,xa,xd)=0 Then Do; x=xb; y=yb; End
         Otherwise Do
           x='*'
           y=ya
           End
         End
       Call o  'ssx:' x y
       End
     End
   Else Do
     yab_min=min(ya,yb)
     ycd_min=min(yc,yd)
     yab_max=max(ya,yb)
     ycd_max=max(yc,yd)
     If yab_min>ycd_max |,
        ycd_min>yab_max Then
       res=0
     Else Do
       res=1
       x=xa
       y='*'
       Parse Var bordl x_bord '/' y_bord
       If x=x_bord Then Do
         Call o  xa'/* IGNORED'
         res=0
         End
       End
     End
   End
 Otherwise Do
   Parse Var d x y
   If is_between(xa,x,xb) &,
      is_between(xc,x,xd) &,
      is_between(ya,y,yb) &,
      is_between(yc,y,yd) Then Do
     If x'/'y<>bordl Then
       res=1
     End
   End
 End
 If res=1 Then Do
   Say 'Intersection of line segments: ('||x'/'y')'
   Parse Var bordl x_bord '/' y_bord
   If x=x_bord Then Do
     res=0
     Call o x'/'y 'IGNORED'
     End
   End
 Else Call o  'ssx: -'

Return res

ggx: Procedure Expose oid bordl /*---------------------------------------------------------------------

  • Intersection of 2 (straight) lines
  • --------------------------------------------------------------------*/

Parse Arg xa ya xb yb xc yc xd yd res= If xa=xb Then Do

 k1='*'
 x1=xa
 If ya=yb Then Do
   res='Points A and B are identical'
   rs='*'
   End
 End

Else Do

 k1=(yb-ya)/(xb-xa)
 d1=ya-k1*xa
 End

If xc=xd Then Do

 k2='*'
 x2=xc
 If yc=yd Then Do
   res='Points C and D are identical'
   rs='*'
   End
 End

Else Do

 k2=(yd-yc)/(xd-xc)
 d2=yc-k2*xc
 End

If res= Then Do

 If k1='*' Then Do
   If k2='*' Then Do
     If x1=x2 Then Do
       res='Lines AB and CD are identical'
       rs='I'
       End
     Else Do
       res='Lines AB and CD are parallel'
       rs='-'
       End
     End
   Else Do
     x=x1
     y=k2*x+d2
     End
   End
 Else Do
   If k2='*' Then Do
     x=x2
     y=k1*x+d1
     End
   Else Do
     If k1=k2 Then Do
       If d1=d2 Then Do
         res='Lines AB and CD are identical'
         rs='I'
         End
       Else Do
         res='Lines AB and CD are parallel'
         rs='-'
         End
       End
     Else Do
       x=(d2-d1)/(k1-k2)
       y=k1*x+d1
       End
     End
   End
 End
 If res= Then Do
   res='Intersection is ('||x'/'y')'
   rs=x y
   Call o 'line intersection' x y
   End
 Call o 'A=('xa'/'ya') B=('||xb'/'yb') C=('||xc'/'yc') D=('||xd'/'yd')' '-->' res
 Return rs

isb: Procedure

 Parse Arg a,b,c
 Return sign(b-a)<>sign(b-c)

is_between: Procedure Expose oid

 Parse Arg a,b,c
 Return diff_sign(b-a,b-c)

diff_sign: Procedure

 Parse Arg diff1,diff2
 Return (sign(diff1)<>sign(diff2))|(sign(diff1)=0)

o: /*y 'sigl='sigl */ Return lineout(oid,arg(1))

in_tri: Procedure Expose oid bordl /*---------------------------------------------------------------------

  • Determine if the point (px/py) is within the given triangle
  • --------------------------------------------------------------------*/

Parse Arg px py,ax ay bx by cx cy abc=ax ay bx by cx cy res=0 maxx=max(ax,bx,cx) minx=min(ax,bx,cx) maxy=max(ay,by,cy) miny=min(ay,by,cy)

If px>maxx|px<minx|py>maxy|py<miny Then

 Return 0

Parse Value mk_g(ax ay,bx by) With k.1 d.1 x.1 Parse Value mk_g(bx by,cx cy) With k.2 d.2 x.2 Parse Value mk_g(cx cy,ax ay) With k.3 d.3 x.3 /* say 'g1:' show_g(k.1,d.1,x.1) say 'g2:' show_g(k.2,d.2,x.2) say 'g3:' show_g(k.3,d.3,x.3) Say px py '-' ax ay bx by cx cy

  • /

Do i=1 To 3

 Select
   When k.i='*' Then
     Call o 'g.'i':' 'x='||x.i
   When k.i=0 Then
     Call o 'g.'i':' 'y='d.i
   Otherwise
     Call o 'g.'i':' 'y=' k.i'*x'dd(d.i)
   End
 End

If k.1='*' Then Do

 y2=k.2*px+d.2
 y3=k.3*px+d.3
 If is_between(y2,py,y3) Then
   res=1
 End

Else Do

 kp1=k.1
 dp1=py-kp1*px
 If k.2='*' Then
   x12=x.2
 Else
   x12=(d.2-dp1)/(kp1-k.2)
 If k.3='*' Then
   x13=x.3
 Else
   x13=(d.3-dp1)/(kp1-k.3)
 If is_between(x12,px,x13) Then
   res=1
 End

If res=1 Then rr=' '

        Else rr=' not '

If pos(px'/'py,bordl)>0 Then Do

 ignored=' but is IGNORED'
 res=0
 End

Else

 ignored=

Say 'P ('px','py') is'rr'in' abc ignored Return res

bord: /*---------------------------------------------------------------------

  • Look for corners of triangles that are situated
  • on the edges of the other triangle
  • --------------------------------------------------------------------*/

parse Arg tlist Parse Arg pax pay pbx pby pcx pcy pdx pdy pex pey pfx pfy bordl= abc=subword(tlist,1,6) def=subword(tlist,7,6)

Do i=1 To 3

 s.i=subword(abc abc,i*2-1,4)
 t.i=subword(def def,i*2-1,4)
 End

abc_= def_= Do i=1 To 3

 abc.i=subword(abc,i*2-1,2)
 def.i=subword(def,i*2-1,2)
 Parse Var abc.i x y; abc_=abc_ '('||x','y')'
 Parse Var def.i x y; def_=def_ '('||x','y')'
 End

Do i=1 To 3

 i1=i+1
 If i1=4 Then i1=1
 Parse Value mk_g(abc.i,abc.i1) With k.1.i d.1.i x.1.i
 Parse Value mk_g(def.i,def.i1) With k.2.i d.2.i x.2.i
 End

Do i=1 To 3

 Call o  show_g(k.1.i,d.1.i,x.1.i)
 End

Do i=1 To 3

 Call o  show_g(k.2.i,d.2.i,x.2.i)
 End

pl= Do i=1 To 3

 p=def.i
 Do j=1 To 3
   j1=j+1
   If j1=4 Then j1=1
   g='1.'j
   If in_segment(p,abc.j,abc.j1) Then Do
     pp=Translate(p,'/',' ')
     If wordpos(pp,bordl)=0 Then
       bordl=bordl pp
     End
   Call o  show_p(p) show_g(k.g,d.g,x.g) '->' bordl
   End
 End

Call o 'Points on abc:' pl

pl= Do i=1 To 3

 p=abc.i
 Do j=1 To 3
   j1=j+1
   If j1=4 Then j1=1
   g='2.'j
   If in_segment(p,def.j,def.j1)Then Do
     pp=Translate(p,'/',' ')
     If wordpos(pp,bordl)=0 Then
       bordl=bordl pp
     End
   Call o  show_p(p) show_g(k.g,d.g,x.g) '->' bordl
   End
 End

Call o 'Points on def:' pl

Return bordl

in_segment: Procedure Expose g. sigl /*---------------------------------------------------------------------

  • Determine if point x/y is on the line segment ax/ay bx/by
  • --------------------------------------------------------------------*/

Parse Arg x y,ax ay,bx by Call show_p(x y) show_p(ax ay) show_p(bx by) Parse Value mk_g(ax ay,bx by) With gk gd gx Select

 When gx<> Then
   res=(x=gx & is_between(ay,y,by))
 When gk='*' Then
   res=(y=gd & is_between(ax,x,bx))
 Otherwise Do
   yy=gk*x+gd
   res=(y=yy & is_between(ax,x,bx))
   End
 End

Return res

mk_g: Procedure Expose g. /*---------------------------------------------------------------------

  • given two points (a and b)
  • compute y=k*x+d or, if a vertical line, k='*'; x=c
  • --------------------------------------------------------------------*/

Parse Arg a,b /* 2 points */ Parse Var a ax ay Parse Var b bx by If ax=bx Then Do /* vertical line */

 gk='*'                            /* special slope                 */
 gx=ax                             /* x=ax is  the equation         */
 gd='*'                            /* not required                  */
 End

Else Do

 gk=(by-ay)/(bx-ax)                /* compute slope                 */
 gd=ay-gk*ax                       /* compute y-distance            */
 gx=                             /* not required                  */
 End

Return gk gd gx

is_between: Procedure

 Parse Arg a,b,c
 Return diff_sign(b-a,b-c)

diff_sign: Procedure

 Parse Arg diff1,diff2
 Return (sign(diff1)<>sign(diff2))|(sign(diff1)=0)

show_p: Procedure

 Call trace 'O'
 Parse Arg x y
 If pos('/',x)>0 Then
   Parse Var x x '/' y
 Return space('('||x'/'y')',0)

isb: Procedure Expose oid

 Parse Arg a,b,c
 Return sign(b-a)<>sign(b-c)

o: Call o arg(1)

  Return

show_g: Procedure /*---------------------------------------------------------------------

  • given slope, y-distance, and (special) x-value
  • compute y=k*x+d or, if a vertical line, k='*'; x=c
  • --------------------------------------------------------------------*/

Parse Arg k,d,x Select

 When k='*' Then res='x='||x       /* vertical line                 */
 When k=0   Then res='y='d         /* horizontal line               */
 Otherwise Do                      /* ordinary line                 */
   Select
     When k=1  Then res='y=x'dd(d)
     When k=-1 Then res='y=-x'dd(d)
     Otherwise      res='y='k'*x'dd(d)
     End
   End
 End

Return res

dd: Procedure /*---------------------------------------------------------------------

  • prepare y-distance for display
  • --------------------------------------------------------------------*/
 Parse Arg dd
 Select
   When dd=0 Then dd=            /* omit dd if it's zero          */
   When dd<0 Then dd=dd            /* use dd as is (-value)         */
   Otherwise      dd='+'dd         /* prepend '+' to positive dd    */
   End
 Return dd

ident: Procedure /*---------------------------------------------------------------------

  • Determine if the corners ABC match those of DEF (in any order)
  • --------------------------------------------------------------------*/
 cnt.=0
 Do i=1 To 6
   Parse Value Arg(i) With x y
   cnt.x.y=cnt.x.y+1
   End
 Do i=1 To 3
   Parse Value Arg(i) With x y
   If cnt.x.y<>2 Then
     Return 0
   End
 Return 1

Novalue:

 Say  'Novalue raised in line' sigl
 Say  sourceline(sigl)
 Say  'Variable' condition('D')
 Signal lookaround

Syntax:

 Say  'Syntax raised in line' sigl
 Say  sourceline(sigl)
 Say  'rc='rc '('errortext(rc)')'

halt: lookaround:

 If fore() Then Do
   Say  'You can look around now.'
   Trace ?R
   Nop
   End
 Exit 12</lang>
Output:
ABC: (0/0) (5/0) (0/5)
DEF: (0/0) (5/0) (0/6)
Corners on the other triangle's edges:  0/0 5/0 0/5
Triangles overlap

ABC: (0/0) (0/5) (5/0)
DEF: (0/0) (0/5) (5/0)
Corners on the other triangle's edges:  0/0 0/5 5/0
Triangles are identical

ABC: (0/0) (5/0) (0/5)
DEF: (-10/0) (-5/0) (-1/6)
Triangles don't overlap

ABC: (0/0) (5/0) (2.5/5)
DEF: (0/4) (2.5/-1) (5/4)
Intersection of line segments: (2/0)
Triangles overlap

ABC: (0/0) (1/1) (0/2)
DEF: (2/1) (3/0) (3/2)
Triangles don't overlap

ABC: (0/0) (1/1) (0/2)
DEF: (2/1) (3/-2) (3/4)
Triangles don't overlap

ABC: (0/0) (1/0) (0/1)
DEF: (1/0) (2/0) (1/1)
Corners on the other triangle's edges:  1/0
Triangles touch on  1/0
  we analyze further
Intersection of line segments: (1/0)
P (1,0) is in 0 0 1 0 0 1  but is IGNORED
P (1,0) is in 1 0 2 0 1 1  but is IGNORED
P (1,1) is not in 0 0 1 0 0 1
Triangles touch (border case) at (1/0)

ABC: (1/0) (3/0) (2/2)
DEF: (1/3) (3/3) (2/5)
Triangles don't overlap

ABC: (1/0) (3/0) (2/2)
DEF: (1/3) (3/3) (2/2)
Corners on the other triangle's edges:  2/2
Triangles touch on  2/2
  we analyze further
P (2,2) is in 1 3 3 3 2 2  but is IGNORED
P (2,2) is in 1 0 3 0 2 2  but is IGNORED
Triangles touch (border case) at (2/2)

ABC: (0/0) (2/0) (2/2)
DEF: (3/3) (5/3) (5/5)
Triangles don't overlap

ABC: (2/0) (2/6) (1/8)
DEF: (0/1) (0/5) (8/3)
Intersection of line segments: (2/4.50)
Triangles overlap

ABC: (0/0) (4/0) (0/4)
DEF: (0/2) (2/0) (2/2)
Corners on the other triangle's edges:  0/2 2/0 2/2
Triangles overlap

ABC: (0/0) (4/0) (0/4)
DEF: (1/1) (2/1) (1/2)
P (1,1) is in 0 0 4 0 0 4
1 1 is within 0 0 4 0 0 4
Triangles overlap

Ruby

Translation of: C

<lang ruby>require "matrix"

def det2D(p1, p2, p3)

   return p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1])

end

def checkTriWinding(p1, p2, p3, allowReversed)

   detTri = det2D(p1, p2, p3)
   if detTri < 0.0 then
       if allowReversed then
           p2[0], p3[0] = p3[0], p2[0]
           p2[1], p3[1] = p3[1], p2[1]
       else
           raise "Triangle has incorrect winding"
       end
   end

end

def boundaryCollideChk(p1, p2, p3, eps)

   return det2D(p1, p2, p3) < eps

end

def boundaryDoesntCollideChk(p1, p2, p3, eps)

   return det2D(p1, p2, p3) <= eps

end

def triTri2D(t1, t2, eps, allowReversed, onBoundary)

   # Triangles must be expressed anti-clockwise
   checkTriWinding(t1[0], t1[1], t1[2], allowReversed)
   checkTriWinding(t2[0], t2[1], t2[2], allowReversed)
   if onBoundary then
       # Points on the boundary are considered as colliding
       chkEdge = -> (p1, p2, p3, eps) { boundaryCollideChk(p1, p2, p3, eps) }
   else
       # Points on the boundary are not considered as colliding
       chkEdge = -> (p1, p2, p3, eps) { boundaryDoesntCollideChk(p1, p2, p3, eps) }
   end
   # For edge E of triangle 1
   for i in 0..2 do
       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) and chkEdge.(t1[i], t1[j], t2[1], eps) and chkEdge.(t1[i], t1[j], t2[2], eps) then
           return false
       end
   end
   # For edge E of triangle 2
   for i in 0..2 do
       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) and chkEdge.(t2[i], t2[j], t1[1], eps) and chkEdge.(t2[i], t2[j], t1[2], eps) then
           return false
       end
   end
   # The triangles collide
   return true

end

def main

   t1 = [Vector[0,0], Vector[5,0], Vector[0,5]]
   t2 = [Vector[0,0], Vector[5,0], Vector[0,6]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   t1 = [Vector[0,0], Vector[0,5], Vector[5,0]]
   t2 = [Vector[0,0], Vector[0,5], Vector[5,0]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, true, true)]
   t1 = [Vector[  0,0], Vector[ 5,0], Vector[ 0,5]]
   t2 = [Vector[-10,0], Vector[-5,0], Vector[-1,6]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   t1 = [Vector[0,0], Vector[  5, 0], Vector[2.5,5]]
   t2 = [Vector[0,4], Vector[2.5,-1], Vector[  5,4]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   t1 = [Vector[0,0], Vector[1,1], Vector[0,2]]
   t2 = [Vector[2,1], Vector[3,0], Vector[3,2]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   t1 = [Vector[0,0], Vector[1, 1], Vector[0,2]]
   t2 = [Vector[2,1], Vector[3,-2], Vector[3,4]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   # Barely touching
   t1 = [Vector[0,0], Vector[1,0], Vector[0,1]]
   t2 = [Vector[1,0], Vector[2,0], Vector[1,1]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, true)]
   # Barely touching
   t1 = [Vector[0,0], Vector[1,0], Vector[0,1]]
   t2 = [Vector[1,0], Vector[2,0], Vector[1,1]]
   print "Triangle: ", t1, "\n"
   print "Triangle: ", t2, "\n"
   print "overlap: %s\n\n" % [triTri2D(t1, t2, 0.0, false, false)]

end

main()</lang>

Output:
Triangle: [Vector[0, 0], Vector[5, 0], Vector[0, 5]]
Triangle: [Vector[0, 0], Vector[5, 0], Vector[0, 6]]
overlap: true

Triangle: [Vector[0, 0], Vector[0, 5], Vector[5, 0]]
Triangle: [Vector[0, 0], Vector[0, 5], Vector[5, 0]]
overlap: true

Triangle: [Vector[0, 0], Vector[5, 0], Vector[0, 5]]
Triangle: [Vector[-10, 0], Vector[-5, 0], Vector[-1, 6]]
overlap: false

Triangle: [Vector[0, 0], Vector[5, 0], Vector[2.5, 5]]
Triangle: [Vector[0, 4], Vector[2.5, -1], Vector[5, 4]]
overlap: true

Triangle: [Vector[0, 0], Vector[1, 1], Vector[0, 2]]
Triangle: [Vector[2, 1], Vector[3, 0], Vector[3, 2]]
overlap: false

Triangle: [Vector[0, 0], Vector[1, 1], Vector[0, 2]]
Triangle: [Vector[2, 1], Vector[3, -2], Vector[3, 4]]
overlap: false

Triangle: [Vector[0, 0], Vector[1, 0], Vector[0, 1]]
Triangle: [Vector[1, 0], Vector[2, 0], Vector[1, 1]]
overlap: true

Triangle: [Vector[0, 0], Vector[1, 0], Vector[0, 1]]
Triangle: [Vector[1, 0], Vector[2, 0], Vector[1, 1]]
overlap: false

Scala

Translation of: Kotlin

<lang scala>object Overlap {

 type Point = (Double, Double)
 class Triangle(var p1: Point, var p2: Point, var p3: Point) {
   override def toString: String = s"Triangle: $p1, $p2, $p3"
 }
 def det2D(t: Triangle): Double = {
   val (p1, p2, p3) = (t.p1, t.p2, t.p3)
   p1._1 * (p2._2 - p3._2) +
     p2._1 * (p3._2 - p1._2) +
     p3._1 * (p1._2 - p2._2)
 }
 def checkTriWinding(t: Triangle, allowReversed: Boolean): Unit = {
   val detTri = det2D(t)
   if (detTri < 0.0) {
     if (allowReversed) {
       val a = t.p3
       t.p3 = t.p2
       t.p2 = a
     } else throw new RuntimeException("Triangle has wrong winding direction")
   }
 }
 def boundaryCollideChk(t: Triangle, eps: Double): Boolean = det2D(t) < eps
 def boundaryDoesntCollideChk(t: Triangle, eps: Double): Boolean = det2D(t) <= eps
 def 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) Overlap.boundaryCollideChk _ else Overlap.boundaryDoesntCollideChk _
   val lp1 = Array(t1.p1, t1.p2, t1.p3)
   val lp2 = Array(t2.p1, t2.p2, t2.p3)
   // for each edge E of t1
   for (i <- 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(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 (i <- 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(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
   true
 }
 def main(args: Array[String]): Unit = {
   var t1 = new Triangle((0.0, 0.0), (5.0, 0.0), (0.0, 5.0))
   var t2 = new Triangle((0.0, 0.0), (5.0, 0.0), (0.0, 6.0))
   println(s"$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 = new Triangle((0.0, 0.0), (0.0, 5.0), (5.0, 0.0))
   t2 = t1
   println(s"\n$t1 and\n$t2")
   println(if (triTri2D(t1, t2, 0.0, allowReversed = true)) "overlap (reversed)" else "do not overlap")
   t1 = new Triangle((0.0, 0.0), (5.0, 0.0), (0.0, 5.0))
   t2 = new Triangle((-10.0, 0.0), (-5.0, 0.0), (-1.0, 6.0))
   println(s"\n$t1 and\n$t2")
   println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")
   t1.p3 = (2.5, 5.0)
   t2 = new Triangle((0.0, 4.0), (2.5, -1.0), (5.0, 4.0))
   println(s"\n$t1 and\n$t2")
   println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")
   t1 = new Triangle((0.0, 0.0), (1.0, 1.0), (0.0, 2.0))
   t2 = new Triangle((2.0, 1.0), (3.0, 0.0), (3.0, 2.0))
   println(s"\n$t1 and\n$t2")
   println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")
   t2 = new Triangle((2.0, 1.0), (3.0, -2.0), (3.0, 4.0))
   println(s"\n$t1 and\n$t2")
   println(if (triTri2D(t1, t2)) "overlap" else "do not overlap")
   t1 = new Triangle((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))
   t2 = new Triangle((1.0, 0.0), (2.0, 0.0), (1.0, 1.1))
   println(s"\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(s"\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, onBoundary = false)) "overlap" else "do not overlap")
 }

}</lang>

Output:
Triangle: (0.0,0.0), (5.0,0.0), (0.0,5.0) and
Triangle: (0.0,0.0), (5.0,0.0), (0.0,6.0)
overlap

Triangle: (0.0,0.0), (0.0,5.0), (5.0,0.0) and
Triangle: (0.0,0.0), (0.0,5.0), (5.0,0.0)
overlap (reversed)

Triangle: (0.0,0.0), (5.0,0.0), (0.0,5.0) and
Triangle: (-10.0,0.0), (-5.0,0.0), (-1.0,6.0)
do not overlap

Triangle: (0.0,0.0), (5.0,0.0), (2.5,5.0) and
Triangle: (0.0,4.0), (2.5,-1.0), (5.0,4.0)
overlap

Triangle: (0.0,0.0), (1.0,1.0), (0.0,2.0) and
Triangle: (2.0,1.0), (3.0,0.0), (3.0,2.0)
do not overlap

Triangle: (0.0,0.0), (1.0,1.0), (0.0,2.0) and
Triangle: (2.0,1.0), (3.0,-2.0), (3.0,4.0)
do not overlap

Triangle: (0.0,0.0), (1.0,0.0), (0.0,1.0) and
Triangle: (1.0,0.0), (2.0,0.0), (1.0,1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: (0.0,0.0), (1.0,0.0), (0.0,1.0) and
Triangle: (1.0,0.0), (2.0,0.0), (1.0,1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

Visual Basic .NET

Translation of: C#

<lang vbnet>Module Module1

   Class Triangle
       Property P1 As Tuple(Of Double, Double)
       Property P2 As Tuple(Of Double, Double)
       Property P3 As Tuple(Of Double, Double)
       Sub New(p1 As Tuple(Of Double, Double), p2 As Tuple(Of Double, Double), p3 As Tuple(Of Double, Double))
           Me.P1 = p1
           Me.P2 = p2
           Me.P3 = p3
       End Sub
       Function Det2D() As Double
           Return P1.Item1 * (P2.Item2 - P3.Item2) +
                  P2.Item1 * (P3.Item2 - P1.Item2) +
                  P3.Item1 * (P1.Item2 - P2.Item2)
       End Function
       Sub CheckTriWinding(allowReversed As Boolean)
           Dim detTri = Det2D()
           If detTri < 0.0 Then
               If allowReversed Then
                   Dim a = P3
                   P3 = P2
                   P2 = a
               Else
                   Throw New Exception("Triangle has wrong winding direction")
               End If
           End If
       End Sub
       Function BoundaryCollideChk(eps As Double) As Boolean
           Return Det2D() < eps
       End Function
       Function BoundaryDoesntCollideChk(eps As Double) As Boolean
           Return Det2D() <= eps
       End Function
       Public Overrides Function ToString() As String
           Return String.Format("Triangle: {0}, {1}, {2}", P1, P2, P3)
       End Function
   End Class
   Function TriTri2D(t1 As Triangle, t2 As Triangle, Optional eps As Double = 0.0, Optional alloweReversed As Boolean = False, Optional onBoundary As Boolean = True) As Boolean
       'Triangles must be expressed anti-clockwise
       t1.CheckTriWinding(alloweReversed)
       t2.CheckTriWinding(alloweReversed)
       '"onboundary" determines whether points on boundary are considered as colliding or not
       Dim chkEdge = If(onBoundary, Function(t As Triangle) t.BoundaryCollideChk(eps), Function(t As Triangle) t.BoundaryDoesntCollideChk(eps))
       Dim lp1 As New List(Of Tuple(Of Double, Double)) From {t1.P1, t1.P2, t1.P3}
       Dim lp2 As New List(Of Tuple(Of Double, Double)) From {t2.P1, t2.P2, t2.P3}
       'for each edge E of t1
       For i = 0 To 2
           Dim 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(New Triangle(lp1(i), lp1(j), lp2(0))) AndAlso
              chkEdge(New Triangle(lp1(i), lp1(j), lp2(1))) AndAlso
              chkEdge(New Triangle(lp1(i), lp1(j), lp2(2))) Then
               Return False
           End If
       Next
       'for each edge E of t2
       For i = 0 To 2
           Dim 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(New Triangle(lp2(i), lp2(j), lp1(0))) AndAlso
              chkEdge(New Triangle(lp2(i), lp2(j), lp1(1))) AndAlso
              chkEdge(New Triangle(lp2(i), lp2(j), lp1(2))) Then
               Return False
           End If
       Next
       'The triangles overlap
       Return True
   End Function
   Sub Overlap(t1 As Triangle, t2 As Triangle, Optional eps As Double = 0.0, Optional allowReversed As Boolean = False, Optional onBoundary As Boolean = True)
       If TriTri2D(t1, t2, eps, allowReversed, onBoundary) Then
           Console.WriteLine("overlap")
       Else
           Console.WriteLine("do not overlap")
       End If
   End Sub
   Sub Main()
       Dim t1 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(5.0, 0.0), Tuple.Create(0.0, 5.0))
       Dim t2 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(5.0, 0.0), Tuple.Create(0.0, 6.0))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2)
       Console.WriteLine()
       ' need to allow reversed for this pair to avoid exception
       t1 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(0.0, 5.0), Tuple.Create(5.0, 0.0))
       t2 = t1
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2, 0.0, True)
       Console.WriteLine()
       t1 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(5.0, 0.0), Tuple.Create(0.0, 5.0))
       t2 = New Triangle(Tuple.Create(-10.0, 0.0), Tuple.Create(-5.0, 0.0), Tuple.Create(-1.0, 6.0))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2)
       Console.WriteLine()
       t1.P3 = Tuple.Create(2.5, 5.0)
       t2 = New Triangle(Tuple.Create(0.0, 4.0), Tuple.Create(2.5, -1.0), Tuple.Create(5.0, 4.0))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2)
       Console.WriteLine()
       t1 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(1.0, 1.0), Tuple.Create(0.0, 2.0))
       t2 = New Triangle(Tuple.Create(2.0, 1.0), Tuple.Create(3.0, 0.0), Tuple.Create(3.0, 2.0))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2)
       Console.WriteLine()
       t2 = New Triangle(Tuple.Create(2.0, 1.0), Tuple.Create(3.0, -2.0), Tuple.Create(3.0, 4.0))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Overlap(t1, t2)
       Console.WriteLine()
       t1 = New Triangle(Tuple.Create(0.0, 0.0), Tuple.Create(1.0, 0.0), Tuple.Create(0.0, 1.0))
       t2 = New Triangle(Tuple.Create(1.0, 0.0), Tuple.Create(2.0, 0.0), Tuple.Create(1.0, 1.1))
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Console.WriteLine("which have only a single corner in contact, if boundary points collide")
       Overlap(t1, t2)
       Console.WriteLine()
       Console.WriteLine("{0} and", t1)
       Console.WriteLine("{0}", t2)
       Console.WriteLine("which have only a single corner in contact, if boundary points do not collide")
       Overlap(t1, t2, 0.0, False, False)
   End Sub

End Module</lang>

Output:
Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (0, 0), (5, 0), (0, 6)
overlap

Triangle: (0, 0), (0, 5), (5, 0) and
Triangle: (0, 0), (0, 5), (5, 0)
overlap

Triangle: (0, 0), (5, 0), (0, 5) and
Triangle: (-10, 0), (-5, 0), (-1, 6)
do not overlap

Triangle: (0, 0), (5, 0), (2.5, 5) and
Triangle: (0, 4), (2.5, -1), (5, 4)
overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, 0), (3, 2)
do not overlap

Triangle: (0, 0), (1, 1), (0, 2) and
Triangle: (2, 1), (3, -2), (3, 4)
do not overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1.1)
which have only a single corner in contact, if boundary points collide
overlap

Triangle: (0, 0), (1, 0), (0, 1) and
Triangle: (1, 0), (2, 0), (1, 1.1)
which have only a single corner in contact, if boundary points do not collide
do not overlap

zkl

Translation of: C++

<lang zkl>// A triangle is three pairs of points: ( (x,y), (x,y), (x,y) )

fcn det2D(triangle){

  p1,p2,p3 := triangle;
  p1[0]*(p2[1] - p3[1]) + p2[0]*(p3[1] - p1[1]) + p3[0]*(p1[1] - p2[1]);

} fcn checkTriWinding(triangle,allowReversed){ //-->triangle, maybe new

  detTri:=det2D(triangle);
  if(detTri<0.0){
     if(allowReversed){ p1,p2,p3 := triangle; return(p1,p3,p2); }  // reverse
     else throw(Exception.AssertionError(

"triangle has wrong winding direction"));

  }
  triangle	// no change

} fcn triTri2D(triangle1,triangle2, eps=0.0, allowReversed=False, onBoundary=True){

  // Trangles must be expressed anti-clockwise
  triangle1=checkTriWinding(triangle1, allowReversed);
  triangle2=checkTriWinding(triangle2, allowReversed);

  chkEdge:=
     if(onBoundary) // Points on the boundary are considered as colliding

fcn(triangle,eps){ det2D(triangle)<eps }

     else           // Points on the boundary are not considered as colliding

fcn(triangle,eps){ det2D(triangle)<=eps };; // first ; terminates if

  t1,t2 := triangle1,triangle2;	// change names to protect the typist
  do(2){				// check triangle1 and then triangle2
     foreach i in (3){	//For edge E of trangle 1,

j:=(i+1)%3; // 1,2,0 // 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(T(t1[i],t1[j],t2[0]), eps) and chkEdge(T(t1[i],t1[j],t2[1]), eps) and chkEdge(T(t1[i],t1[j],t2[2]), eps)) return(False); // no collision

     }
     t2,t1 = triangle1,triangle2; // flip and re-test
  }
  True   // The triangles collide

}</lang> <lang zkl>fcn toTri(ax,ay,bx,by,cx,cy){ //-->( (ax,ay),(bx,by),(cx,cy) )

  vm.arglist.apply("toFloat").pump(List,Void.Read)

} triangles:=T( // pairs of triangles

  T(toTri(0,0, 5,0, 0,  5), toTri(  0,0,  5,   0,  0,6)),
  T(toTri(0,0, 0,5, 5,  0), toTri(  0,0,  0,   5 , 5,0)),
  T(toTri(0,0, 5,0, 0,  5), toTri(-10,0, -5,   0, -1,6)),
  T(toTri(0,0, 5,0, 2.5,5), toTri(  0,4,  2.5,-1,  5,4)),
  T(toTri(0,0, 1,1, 0,  2), toTri(  2,1,  3,   0,  3,2)),
  T(toTri(0,0, 1,1, 0,  2), toTri(  2,1,  3,  -2,  3,4))

);

 // Expect: overlap, overlap (reversed), no overlap, overlap, no overlap, no overlap

foreach t1,t2 in (triangles){

  reg r, reversed=False;
  try{ r=triTri2D(t1,t2) }
  catch(AssertionError){ r=triTri2D(t1,t2,0.0,True); reversed=True; }
  print(t1,"\n",t2," ");
  println(r and "overlap" or "no overlap", reversed and " (reversed)" or "");
  println();

}

c1,c2 := toTri(0,0, 1,0, 0,1), toTri(1,0, 2,0, 1,1); println("Corner case (barely touching): ",triTri2D(c1,c2,0.0,False,True)); // True println("Corner case (barely touching): ",triTri2D(c1,c2,0.0,False,False)); // False</lang>

Output:
L(L(0,0),L(5,0),L(0,5))
L(L(0,0),L(5,0),L(0,6)) overlap

L(L(0,0),L(0,5),L(5,0))
L(L(0,0),L(0,5),L(5,0)) overlap (reversed)

L(L(0,0),L(5,0),L(0,5))
L(L(-10,0),L(-5,0),L(-1,6)) no overlap

L(L(0,0),L(5,0),L(2.5,5))
L(L(0,4),L(2.5,-1),L(5,4)) overlap

L(L(0,0),L(1,1),L(0,2))
L(L(2,1),L(3,0),L(3,2)) no overlap

L(L(0,0),L(1,1),L(0,2))
L(L(2,1),L(3,-2),L(3,4)) no overlap

Corner case (barely touching): True
Corner case (barely touching): False