Jump to content

Find if a point is within a triangle

From Rosetta Code
Task
Find if a point is within a triangle
You are encouraged to solve this task according to the task description, using any language you may know.

Find if a point is within a triangle.


Task
  •   Assume points are on a plane defined by (x, y) real number coordinates.
  •   Given a point P(x, y) and a triangle formed by points A, B, and C, determine if P is within triangle ABC.
  •   You may use any algorithm.
  •   Bonus: explain why the algorithm you chose works.


Related tasks


Also see
  • Discussion of several methods. [[1]]
  • Determine if a point is in a polygon [[2]]
  • Triangle based coordinate systems [[3]]
  • Wolfram entry [[4]]



11l

Translation of: Kotlin
V EPS = 0.001
V EPS_SQUARE = EPS * EPS

F side(p1, p2, p)
   R (p2.y - p1.y) * (p.x - p1.x) + (-p2.x + p1.x) * (p.y - p1.y)

F distanceSquarePointToSegment(p1, p2, p)
   V p1P2SquareLength = sqlen(p2 - p1)
   V dotProduct = dot(p - p1, p2 - p1) / p1P2SquareLength
   I dotProduct < 0
      R sqlen(p - p1)
   I dotProduct <= 1
      V pP1SquareLength = sqlen(p1 - p)
      R pP1SquareLength - dotProduct * dotProduct * p1P2SquareLength
   R sqlen(p - p2)

T Triangle((DVec2 p1, DVec2 p2, DVec2 p3))
   F String()
      R ‘Triangle[’(.p1)‘, ’(.p2)‘, ’(.p3)‘]’

   F.const pointInTriangleBoundingBox(p)
      V xMin = min(.p1.x, min(.p2.x, .p3.x)) - :EPS
      V xMax = max(.p1.x, max(.p2.x, .p3.x)) + :EPS
      V yMin = min(.p1.y, min(.p2.y, .p3.y)) - :EPS
      V yMax = max(.p1.y, max(.p2.y, .p3.y)) + :EPS
      R !(p.x < xMin | xMax < p.x | p.y < yMin | yMax < p.y)

   F.const nativePointInTriangle(p)
      V checkSide1 = side(.p1, .p2, p) >= 0
      V checkSide2 = side(.p2, .p3, p) >= 0
      V checkSide3 = side(.p3, .p1, p) >= 0
      R checkSide1 & checkSide2 & checkSide3

   F.const accuratePointInTriangle(p)
      I !.pointInTriangleBoundingBox(p)
         R 0B
      I .nativePointInTriangle(p)
         R 1B
      I distanceSquarePointToSegment(.p1, .p2, p) <= :EPS_SQUARE
         R 1B
      I distanceSquarePointToSegment(.p2, .p3, p) <= :EPS_SQUARE
         R 1B
      R distanceSquarePointToSegment(.p3, .p1, p) <= :EPS_SQUARE

F test(t, p)
   print(t)
   print(‘Point ’p‘ is within triangle ? ’(I t.accuratePointInTriangle(p) {‘true’} E ‘false’))

V p1 = (1.5, 2.4)
V p2 = (5.1, -3.1)
V p3 = (-3.8, 1.2)
V tri = Triangle(p1, p2, p3)
test(tri, (0.0, 0.0))
test(tri, (0.0, 1.0))
test(tri, (3.0, 1.0))
print()
p1 = (1.0 / 10, 1.0 / 9)
p2 = (100.0 / 8, 100.0 / 3)
p3 = (100.0 / 4, 100.0 / 9)
tri = Triangle(p1, p2, p3)
V pt = (p1.x + 3.0 / 7 * (p2.x - p1.x), p1.y + 3.0 / 7 * (p2.y - p1.y))
test(tri, pt)
print()
p3 = (-100.0 / 8, 100.0 / 6)
tri = Triangle(p1, p2, p3)
test(tri, pt)
Output:
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 0) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 1) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3, 1) is within triangle ? false

Triangle[(0.1, 0.111111111), (12.5, 33.333333333), (25, 11.111111111)]
Point (5.414285714, 14.349206349) is within triangle ? true

Triangle[(0.1, 0.111111111), (12.5, 33.333333333), (-12.5, 16.666666667)]
Point (5.414285714, 14.349206349) is within triangle ? true

Ada

This uses a determinant method to calculate the area of triangles, and tests whether or not a point is in a triangle by adding up the areas of the triangles formed by each side of the triangle with the point in question, and seeing if the sum matches the whole.

It uses a generic two-dimensional geometry, that could be affine, euclidean, or a lot stranger than that. You only need to specify the type of one dimension, and the library should handle the rest. Edge cases probably exist where they shouldn't, as the area formula might add some imprecision.

-- triangle.ads
generic
	type Dimension is private;
	Zero, Two: Dimension;
	with function "*"(Left, Right: in Dimension) return Dimension is <>;
	with function "/"(Left, Right: in Dimension) return Dimension is <>;
	with function "+"(Left, Right: in Dimension) return Dimension is <>;
	with function "-"(Left, Right: in Dimension) return Dimension is <>;
	with function ">"(Left, Right: in Dimension) return Boolean is <>;
	with function "="(Left, Right: in Dimension) return Boolean is <>;
	with function Image(D: in Dimension) return String is <>;
package Triangle is

	type Point is record
		X: Dimension;
		Y: Dimension;
	end record;

	type Triangle_T is record
		A,B,C: Point;
	end record;

	function Area(T: in Triangle_T) return Dimension;

	function IsPointInTriangle(P: Point; T: Triangle_T) return Boolean;

	function Image(P: Point) return String is
		("(X="&Image(P.X)&", Y="&Image(P.Y)&")")
		with Inline;

	function Image(T: Triangle_T) return String is
		("(A="&Image(T.A)&", B="&Image(T.B)&", C="&Image(T.C)&")")
		with Inline;
end;
-- triangle.adb

package body Triangle is
	function Area(T: in Triangle_T) return Dimension
	is
		tmp: Dimension;
	begin
		tmp:=((T.B.X*T.C.Y-T.C.X*T.B.Y)-(T.A.X*T.C.Y-T.C.X*T.A.Y)+(T.A.X*T.B.Y-T.B.X*T.A.Y))/Two;
		if tmp>Zero then
			return tmp;
		else
			return Zero-tmp;
		end if;
	end Area;

	function IsPointInTriangle(P: Point; T: Triangle_T) return Boolean
	is
	begin
		return Area(T)=Area((T.A,T.B,P))+Area((T.A,P,T.C))+Area((P,T.B,T.C));
	end IsPointInTriangle;
end;
-- test_triangle.adb
with Ada.Text_IO;
use Ada.Text_IO;
with Triangle;

procedure test_triangle
is
	package affine_tri is new Triangle(Dimension=>Integer, Zero=>0,Two=>2, Image=>Integer'Image);
	use affine_tri;
	tri1: Triangle_T:=((1,0),(2,0),(0,2));
	tri2: Triangle_T:=((-1,0),(-1,-1),(2,2));
	origin: Point:=(0,0);
begin
	Put_Line("IsPointInTriangle("&Image(origin)&", "&Image(tri1)&") yields "&IsPointInTriangle(origin,tri1)'Image);
	Put_Line("IsPointInTriangle("&Image(origin)&", "&Image(tri2)&") yields "&IsPointInTriangle(origin,tri2)'Image);
end test_triangle;
Output:
IsPointInTriangle((X= 0, Y= 0), (A=(X= 1, Y= 0), B=(X= 2, Y= 0), C=(X= 0, Y= 2))) yields FALSE
IsPointInTriangle((X= 0, Y= 0), (A=(X=-1, Y= 0), B=(X=-1, Y=-1), C=(X= 2, Y= 2))) yields TRUE

ALGOL 68

Started out as

Translation of: Common Lisp

With additional material

Translation of: Wren
BEGIN # determine whether a point is within a triangle or not #
    # tolerance for the accurate test #
    REAL eps         = 0.001;
    REAL eps squared = eps * eps;
    # mode to hold a point #
    MODE POINT = STRUCT( REAL x, y );
    # returns a readable representation of p #
    OP    TOSTRING = ( POINT p )STRING: "[" + fixed( x OF p, -8, 4 ) + "," + fixed( y OF p, -8, 4 ) + "]"; 
    # returns 1 if p is to the right of the line ( a, b ), -1 if it is to the left and 0 if it is on it #
    PROC side of line = ( POINT p, a, b )INT:
         SIGN ( ( ( x OF b - x OF a ) * ( y OF p - y OF a ) )
              - ( ( y OF b - y OF a ) * ( x OF p - x OF a ) )
              );
    # returns the minimum of a and b #
    PROC min = ( REAL a, b )REAL: IF a < b THEN a ELSE b FI;
    # returns the maximum of a and b #
    PROC max = ( REAL a, b )REAL: IF a > b THEN a ELSE b FI;
    # returns TRUE if p is within the bounding box of the triangle a, b, c, FALSE otherwise #
    PROC point inside bounding box of triangle = ( POINT p, a, b, c )BOOL:
         BEGIN
            REAL x min = min( x OF a, min( x OF b, x OF c ) );
            REAL y min = min( y OF a, min( y OF b, y OF c ) );
            REAL x max = max( x OF a, max( x OF b, x OF c ) );
            REAL y max = max( y OF a, max( y OF b, y OF c ) );
            x min <= x OF p AND x OF p <= x max AND y min <= y OF p AND y OF p <= y max
         END # point inside bounding box of triangle # ;
    # returns the squared distance between p and the line a, b #
    PROC distance square point to segment = ( POINT p, a, b )REAL:
         IF REAL a b square length = ( ( x OF b - x OF a ) ^ 2 ) + ( ( y OF b - y OF a ) ^ 2 );
            REAL dot product = ( ( ( x OF p - x OF a ) ^ 2 ) + ( ( y OF p - y OF a ) ^ 2 ) ) / a b square length;
            dot product < 0
         THEN ( ( x OF p - x OF a ) ^ 2 ) + ( ( y OF p - y OF a ) ^ 2 )
         ELIF dot product <= 1
         THEN ( ( x OF a - x OF p ) ^ 2 ) + ( ( y OF a - y OF p ) ^ 2 )
            - ( dot product * dot product * a b square length )
         ELSE ( ( x OF p - x OF b ) ^ 2 ) + ( ( y OF p - y OF b ) ^ 2 )
         FI # distance square point to segment # ;
    # returns TRUE if p is within the triangle defined by a, b and c, FALSE otherwise #
    PROC point inside triangle = ( POINT p, a, b, c )BOOL:
         IF NOT point inside bounding box of triangle( p, a, b, c )
         THEN FALSE
         ELIF INT side of ab = side of line( p, a, b );
              INT side of bc = side of line( p, b, c );
              side of ab /= side of bc
         THEN FALSE
         ELIF side of ab = side of line( p, c, a )
         THEN TRUE
         ELIF distance square point to segment( p, a, b ) <= eps squared
         THEN TRUE
         ELIF distance square point to segment( p, b, c ) <= eps squared
         THEN TRUE
         ELSE distance square point to segment( p, c, a ) <= eps squared
         FI # point inside triangle # ;
    # test the point inside triangle procedure #
    PROC test point = ( POINT p, a, b, c )VOID:
         print( ( TOSTRING p, " in ( ", TOSTRING a, ", ", TOSTRING b, ", ", TOSTRING c, ") -> "
                , IF point inside triangle( p, a, b, c ) THEN "true" ELSE "false" FI
                , newline
                )
              );
    # test cases as in Commpn Lisp #
    test point( ( 0, 0 ), ( 1.5, 2.4 ), ( 5.1, -3.1 ), ( -3.8, 1.2 ) );
    test point( ( 0, 1 ), ( 1.5, 2.4 ), ( 5.1, -3.1 ), ( -3.8, 1.2 ) );
    test point( ( 3, 1 ), ( 1.5, 2.4 ), ( 5.1, -3.1 ), ( -3.8, 1.2 ) );
    test point( ( 5.414286, 14.349206 ), ( 0.1, 0.111111 ), ( 12.5, 33.333333 ), (  25.0, 11.111111 ) );
    test point( ( 5.414286, 14.349206 ), ( 0.1, 0.111111 ), ( 12.5, 33.333333 ), ( -12.5, 16.666667 ) );
    # additional Wren test cases #
    test point( ( 5.4142857142857, 14.349206349206 )
              , ( 0.1, 0.11111111111111 ), ( 12.5, 33.333333333333 ), ( 25, 11.111111111111 )
              );
    test point( ( 5.4142857142857, 14.349206349206 )
              , ( 0.1, 0.11111111111111 ), ( 12.5, 33.333333333333 ), ( -12.5, 16.666666666667 )
              )
END
Output:
[  0.0000,  0.0000] in ( [  1.5000,  2.4000], [  5.1000, -3.1000], [ -3.8000,  1.2000]) -> true
[  0.0000,  1.0000] in ( [  1.5000,  2.4000], [  5.1000, -3.1000], [ -3.8000,  1.2000]) -> true
[  3.0000,  1.0000] in ( [  1.5000,  2.4000], [  5.1000, -3.1000], [ -3.8000,  1.2000]) -> false
[  5.4143, 14.3492] in ( [  0.1000,  0.1111], [ 12.5000, 33.3333], [ 25.0000, 11.1111]) -> true
[  5.4143, 14.3492] in ( [  0.1000,  0.1111], [ 12.5000, 33.3333], [-12.5000, 16.6667]) -> false
[  5.4143, 14.3492] in ( [  0.1000,  0.1111], [ 12.5000, 33.3333], [ 25.0000, 11.1111]) -> true
[  5.4143, 14.3492] in ( [  0.1000,  0.1111], [ 12.5000, 33.3333], [-12.5000, 16.6667]) -> false

ATS

This is the same algorithm as the Common Lisp, although not a translation of the Common Lisp. I merely discovered the similarity while searching for Rosetta Code examples that had obtained similar outputs.

The algorithm is widely used for testing whether a point is inside a convex hull of any size. For each side of the hull, one computes the geometric product of some vectors and observes the sign of a component in the result. The test takes advantage of the sine (or cosine) being positive in two adjacent quadrants and negative in the other two. Two quadrants will represent the inside of the hull and two the outside, relative to any given side of the hull. More details are described in the comments of the program.

(* The principle employed here is to treat the triangle as a convex
   hull oriented counterclockwise. Then a point is inside the hull if
   it is to the left of every side of the hull.

   This will prove easy to determine. Because the sine is positive in
   quadrants 1 and 2 and negative in quadrants 3 and 4, the ‘sideness’
   of a point can be determined by the sign of an outer product of
   vectors. Or you can use any such trigonometric method, including
   those that employ an inner product.

   Suppose one side of the triangle goes from point p0 to point p1,
   and that the point we are testing for ‘leftness’ is p2. Then we
   compute the geometric outer product

      (p1 - p0)∧(p2 - p0)

   (or equivalently the cross product of Gibbs vector analysis) and
   test the sign of its grade-2 component (or the sign of the
   right-hand-rule Gibbs pseudovector along the z-axis). If the sign
   is positive, then p2 is left of the side, because the sine of the
   angle between the vectors is positive.

   The algorithm considers the vertices and sides of the triangle as
   as NOT inside the triangle.

   Our algorithm is the same as that of the Common Lisp. We merely
   have dressed it up in prêt-à-porter fashion and costume jewelry. *)

#include "share/atspre_staload.hats"

#define COUNTERCLOCKWISE 1
#define COLLINEAR 0
#define CLOCKWISE ~1

(* We will use some simple Euclidean geometric algebra. *)

typedef vector =
  (* This type will represent either a point relative to the origin or
     the difference between two points. The e1 component is the x-axis
     and the e2 component is the y-axis. *)
  @{e1 = double, e2 = double}

typedef rotor =
  (* This type is analogous to a pseudovectors, complex numbers, and
     so forth. It will be used to represent the outer product. *)
  @{scalar = double, e1_e2 = double}

typedef triangle = @(vector, vector, vector)

fn
vector_sub (a : vector, b : vector) : vector =
  @{e1 = a.e1 - b.e1, e2 = a.e2 - b.e2}

overload - with vector_sub

fn
outer_product (a : vector, b : vector) : rotor =
  @{scalar = 0.0,               (* The scalar term vanishes. *)
    e1_e2 = a.e1 * b.e2 - a.e2 * b.e1}

fn
is_left_of (pt        : vector,
            side      : @(vector, vector)) =
  let
    val r = outer_product (side.1 - side.0, pt - side.0)
  in
    r.e1_e2 > 0.0
  end

fn
orient_triangle {orientation : int | abs (orientation) == 1}
                (t           : triangle,
                 orientation : int orientation) : triangle =
  (* Return an equivalent triangle that is definitely either
     counterclockwise or clockwise, unless the original was
     collinear. If the original was collinear, return it unchanged. *)
  let
    val @(p1, p2, p3) = t
    (* If the triangle is counterclockwise, the grade-2 component of
       the following outer product will be positive. *)
    val r = outer_product (p2 - p1, p3 - p1)
  in
    if r.e1_e2 = 0.0 then
      t
    else
      let
        val sign =
          (if r.e1_e2 > 0.0 then COUNTERCLOCKWISE else CLOCKWISE)
            : [sign : int | abs sign == 1] int sign
      in
        if orientation = sign then t else @(p1, p3, p2)
      end
  end

fn
is_inside_triangle (pt : vector,
                    t  : triangle) : bool =
  let
    val @(p1, p2, p3) = orient_triangle (t, COUNTERCLOCKWISE)
  in
    is_left_of (pt, @(p1, p2))
      && is_left_of (pt, @(p2, p3))
      && is_left_of (pt, @(p3, p1))
  end

fn
fprint_vector (outf : FILEref,
               v    : vector) : void =
  fprint! (outf, "(", v.e1, ",", v.e2, ")")

fn
fprint_triangle (outf : FILEref,
                 t    : triangle) : void =
  begin
    fprint_vector (outf, t.0);
    fprint! (outf, "--");
    fprint_vector (outf, t.1);
    fprint! (outf, "--");
    fprint_vector (outf, t.2);
    fprint! (outf, "--cycle")
  end

fn
try_it (outf : FILEref,
        pt   : vector,
        t    : triangle) : void =
  begin
    fprint_vector (outf, pt);
    fprint! (outf, " is inside ");
    fprint_triangle (outf, t);
    fprintln! (outf);
    fprintln! (outf, is_inside_triangle (pt, t))
  end

implement
main () =
  let
    val outf = stdout_ref
    val t1 = @(@{e1 =  1.5, e2 =  2.4},
               @{e1 =  5.1, e2 = ~3.1},
               @{e1 = ~3.8, e2 =  1.2})
    val p1 = @{e1 = 0.0, e2 = 0.0}
    val p2 = @{e1 = 0.0, e2 = 1.0}
    val p3 = @{e1 = 3.0, e2 = 1.0}
    val p4 = @{e1 = 1.5, e2 = 2.4}

    val p5 = @{e1 = 5.414286, e2 = 14.349206}
    val t2 = @(@{e1 =  0.100000, e2 =  0.111111},
               @{e1 = 12.500000, e2 = 33.333333},
               @{e1 = 25.000000, e2 = 11.111111})
    val t3 = @(@{e1 =   0.100000, e2 =  0.111111},
               @{e1 =  12.500000, e2 = 33.333333},
               @{e1 = ~12.500000, e2 = 16.666667})
  in
    try_it (outf, p1, t1);
    try_it (outf, p2, t1);
    try_it (outf, p3, t1);
    try_it (outf, p4, t1);

    fprintln! (outf);    
    try_it (outf, p5, t2);

    fprintln! (outf);
    fprintln! (outf, "Some programs are returning TRUE for ",
               "the following. The Common Lisp uses");
    fprintln! (outf, "the same",
               " algorithm we do (presented differently),",
               " and returns FALSE.");
    fprintln! (outf);
    try_it (outf, p5, t3);
    0
  end
Output:
$ patscc -g -O3 -march=native -pipe -std=gnu2x point_inside_triangle.dats && ./a.out
(0.000000,0.000000) is inside (1.500000,2.400000)--(5.100000,-3.100000)--(-3.800000,1.200000)--cycle
true
(0.000000,1.000000) is inside (1.500000,2.400000)--(5.100000,-3.100000)--(-3.800000,1.200000)--cycle
true
(3.000000,1.000000) is inside (1.500000,2.400000)--(5.100000,-3.100000)--(-3.800000,1.200000)--cycle
false
(1.500000,2.400000) is inside (1.500000,2.400000)--(5.100000,-3.100000)--(-3.800000,1.200000)--cycle
false

(5.414286,14.349206) is inside (0.100000,0.111111)--(12.500000,33.333333)--(25.000000,11.111111)--cycle
true

Some programs are returning TRUE for the following. The Common Lisp uses
the same algorithm we do (presented differently), and returns FALSE.

(5.414286,14.349206) is inside (0.100000,0.111111)--(12.500000,33.333333)--(-12.500000,16.666667)--cycle
false

AutoHotkey

T := [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
for i, p in [[0, 0], [0, 1], [3, 1], [5.4142857, 14.349206]]
    result .= "[" p.1 ", " p.2 "]  is within triangle?`t" (TriHasP(T, p) ? "ture" : "false") "`n"
MsgBox % result
return

TriHasP(T, P){
    Ax := TriArea(T.1.1, T.1.2,  T.2.1, T.2.2,  T.3.1, T.3.2)
    A1 := TriArea(P.1  , P.2  ,  T.2.1, T.2.2,  T.3.1, T.3.2)
    A2 := TriArea(T.1.1, T.1.2,  P.1  , P.2  ,  T.3.1, T.3.2)
    A3 := TriArea(T.1.1, T.1.2,  T.2.1, T.2.2,  P.1  , P.2)
    return (Ax = A1 + A2 + A3)
}
TriArea(x1, y1, x2, y2, x3, y3){
    return Abs((x1 * (y2-y3) + x2 * (y3-y1) + x3 * (y1-y2)) / 2)
}
Output:
[0, 0]  is within triangle?	ture
[0, 1]  is within triangle?	ture
[3, 1]  is within triangle?	false
[5.4142857, 14.349206]  is within triangle?	false

C

Translation of: Go
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

const double EPS = 0.001;
const double EPS_SQUARE = 0.000001;

double side(double x1, double y1, double x2, double y2, double x, double y) {
    return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1);
}

bool naivePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double checkSide1 = side(x1, y1, x2, y2, x, y) >= 0;
    double checkSide2 = side(x2, y2, x3, y3, x, y) >= 0;
    double checkSide3 = side(x3, y3, x1, y1, x, y) >= 0;
    return checkSide1 && checkSide2 && checkSide3;
}

bool pointInTriangleBoundingBox(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double xMin = min(x1, min(x2, x3)) - EPS;
    double xMax = max(x1, max(x2, x3)) + EPS;
    double yMin = min(y1, min(y2, y3)) - EPS;
    double yMax = max(y1, max(y2, y3)) + EPS;
    return !(x < xMin || xMax < x || y < yMin || yMax < y);
}

double distanceSquarePointToSegment(double x1, double y1, double x2, double y2, double x, double y) {
    double p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    double dotProduct = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength;
    if (dotProduct < 0) {
        return (x - x1) * (x - x1) + (y - y1) * (y - y1);
    } else if (dotProduct <= 1) {
        double p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
    } else {
        return (x - x2) * (x - x2) + (y - y2) * (y - y2);
    }
}

bool accuratePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    if (!pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)) {
        return false;
    }
    if (naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
        return true;
    }
    if (distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE) {
        return true;
    }
    return false;
}

void printPoint(double x, double y) {
    printf("(%f, %f)", x, y);
}

void printTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
    printf("Triangle is [");
    printPoint(x1, y1);
    printf(", ");
    printPoint(x2, y2);
    printf(", ");
    printPoint(x3, y3);
    printf("] \n");
}

void test(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    printTriangle(x1, y1, x2, y2, x3, y3);
    printf("Point ");
    printPoint(x, y);
    printf(" is within triangle? ");
    if (accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
        printf("true\n");
    } else {
        printf("false\n");
    }
}

int main() {
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0);
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1);
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1);
    printf("\n");

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25, 11.11111111111111, 5.414285714285714, 14.349206349206348);
    printf("\n");

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348);
    printf("\n");

    return 0;
}
Output:
Triangle is [(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (0.000000, 0.000000) is within triangle? true
Triangle is [(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (0.000000, 1.000000) is within triangle? true
Triangle is [(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (3.000000, 1.000000) is within triangle? false

Triangle is [(0.100000, 0.111111), (12.500000, 33.333333), (25.000000, 11.111111)]
Point (5.414286, 14.349206) is within triangle? true

Triangle is [(0.100000, 0.111111), (12.500000, 33.333333), (-12.500000, 16.666667)]
Point (5.414286, 14.349206) is within triangle? true

C++

Translation of: C
#include <iostream>

const double EPS = 0.001;
const double EPS_SQUARE = EPS * EPS;

double side(double x1, double y1, double x2, double y2, double x, double y) {
    return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1);
}

bool naivePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double checkSide1 = side(x1, y1, x2, y2, x, y) >= 0;
    double checkSide2 = side(x2, y2, x3, y3, x, y) >= 0;
    double checkSide3 = side(x3, y3, x1, y1, x, y) >= 0;
    return checkSide1 && checkSide2 && checkSide3;
}

bool pointInTriangleBoundingBox(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double xMin = std::min(x1, std::min(x2, x3)) - EPS;
    double xMax = std::max(x1, std::max(x2, x3)) + EPS;
    double yMin = std::min(y1, std::min(y2, y3)) - EPS;
    double yMax = std::max(y1, std::max(y2, y3)) + EPS;
    return !(x < xMin || xMax < x || y < yMin || yMax < y);
}

double distanceSquarePointToSegment(double x1, double y1, double x2, double y2, double x, double y) {
    double p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    double dotProduct = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength;
    if (dotProduct < 0) {
        return (x - x1) * (x - x1) + (y - y1) * (y - y1);
    } else if (dotProduct <= 1) {
        double p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
    } else {
        return (x - x2) * (x - x2) + (y - y2) * (y - y2);
    }
}

bool accuratePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    if (!pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)) {
        return false;
    }
    if (naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
        return true;
    }
    if (distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE) {
        return true;
    }
    return false;
}

void printPoint(double x, double y) {
    std::cout << '(' << x << ", " << y << ')';
}

void printTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
    std::cout << "Triangle is [";
    printPoint(x1, y1);
    std::cout << ", ";
    printPoint(x2, y2);
    std::cout << ", ";
    printPoint(x3, y3);
    std::cout << "]\n";
}

void test(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    printTriangle(x1, y1, x2, y2, x3, y3);
    std::cout << "Point ";
    printPoint(x, y);
    std::cout << " is within triangle? ";
    if (accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
        std::cout << "true\n";
    } else {
        std::cout << "false\n";
    }
}

int main() {
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0);
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1);
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1);
    std::cout << '\n';

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25, 11.11111111111111, 5.414285714285714, 14.349206349206348);
    std::cout << '\n';

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348);
    std::cout << '\n';

    return 0;
}
Output:
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 0) is within triangle? true
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 1) is within triangle? true
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3, 1) is within triangle? false

Triangle is [(0.1, 0.111111), (12.5, 33.3333), (25, 11.1111)]
Point (5.41429, 14.3492) is within triangle? true

Triangle is [(0.1, 0.111111), (12.5, 33.3333), (-12.5, 16.6667)]
Point (5.41429, 14.3492) is within triangle? true


Common Lisp

; There are different algorithms to solve this problem, such as adding areas, adding angles, etc... but these
; solutions are sensitive to rounding errors intrinsic to float operations. We want to avoid these issues, therefore we
; use the following algorithm which only uses multiplication and subtraction: we consider one side of the triangle
; and see on which side of it is the point P located. We can give +1 if it is on the right hand side, -1 for the 
; left side, or 0 if it is on the line. If the point is located on the same side relative to all three sides of the triangle
; then the point is inside of it. This has an added advantage that it can be scaled up to other more complicated figures
; (even concave ones, with some minor modifications).

(defun point-inside-triangle (P A B C)
"Is the point P inside the triangle formed by ABC?"
  (= (side-of-line P A B)
     (side-of-line P B C)
     (side-of-line P C A) ))


; This is the version to include those points which are on one of the sides 
(defun point-inside-or-on-triangle (P A B C)
"Is the point P inside the triangle formed by ABC or on one of the sides?"
  (apply #'= (remove 0 (list (side-of-line P A B) (side-of-line P B C) (side-of-line P C A)))) )


(defun side-of-line (P A B)
"Return +1 if it is on the right side, -1 for the left side, or 0 if it is on the line"
; We use the sign of the determinant of vectors (AB,AM), where M(X,Y) is the query point:
; position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax))
(signum (- (* (- (car B) (car A))
              (- (cdr P) (cdr A)) )
           (* (- (cdr B) (cdr A))
              (- (car P) (car A)) ))))
Output:
(point-inside-triangle '(0 . 0) '(1.5 . 2.4) '(5.1 . -3.1) '(-3.8 . 1.2))
T

(point-inside-triangle '(0 . 1) '(1.5 . 2.4) '(5.1 . -3.1) '(-3.8 . 1.2))
T

(point-inside-triangle '(3 . 1) '(1.5 . 2.4) '(5.1 . -3.1) '(-3.8 . 1.2))
NIL

(point-inside-triangle '(5.414286 . 14.349206) '(0.1 . 0.111111) '(12.5 . 33.333333) '(25.0 . 11.111111))
T

(point-inside-triangle '(5.414286 . 14.349206) '(0.1 . 0.111111) '(12.5 . 33.333333) '(-12.5 . 16.666667))
NIL

D

import std.algorithm;
import std.stdio;

immutable EPS = 0.001;
immutable EPS_SQUARE = EPS * EPS;

double side(double x1, double y1, double x2, double y2, double x, double y) {
    return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1);
}

bool naivePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double checkSide1 = side(x1, y1, x2, y2, x, y) >= 0;
    double checkSide2 = side(x2, y2, x3, y3, x, y) >= 0;
    double checkSide3 = side(x3, y3, x1, y1, x, y) >= 0;
    return checkSide1 && checkSide2 && checkSide3;
}

bool pointInTriangleBoundingBox(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    double xMin = min(x1, x2, x3) - EPS;
    double xMax = max(x1, x2, x3) + EPS;
    double yMin = min(y1, y2, y3) - EPS;
    double yMax = max(y1, y2, y3) + EPS;
    return !(x < xMin || xMax < x || y < yMin || yMax < y);
}

double distanceSquarePointToSegment(double x1, double y1, double x2, double y2, double x, double y) {
    double p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    double dotProduct = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength;
    if (dotProduct < 0) {
        return (x - x1) * (x - x1) + (y - y1) * (y - y1);
    } else if (dotProduct <= 1) {
        double p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
    } else {
        return (x - x2) * (x - x2) + (y - y2) * (y - y2);
    }
}

bool accuratePointInTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    if (!pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)) {
        return false;
    }
    if (naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
        return true;
    }
    if (distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE) {
        return true;
    }
    if (distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE) {
        return true;
    }
    return false;
}

void printPoint(double x, double y) {
    write('(', x, ", ", y, ')');
}

void printTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
    write("Triangle is [");
    printPoint(x1, y1);
    write(", ");
    printPoint(x2, y2);
    write(", ");
    printPoint(x3, y3);
    writeln(']');
}

void test(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) {
    printTriangle(x1, y1, x2, y2, x3, y3);
    write("Point ");
    printPoint(x, y);
    write(" is within triangle? ");
    writeln(accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y));
}

void main() {
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0);
	writeln;
	
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1);
	writeln;
	
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1);
    writeln;

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25, 11.11111111111111, 5.414285714285714, 14.349206349206348);
    writeln;

    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348);
    writeln;
}
Output:
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 0) is within triangle? true

Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 1) is within triangle? true

Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3, 1) is within triangle? false

Triangle is [(0.1, 0.111111), (12.5, 33.3333), (25, 11.1111)]
Point (5.41429, 14.3492) is within triangle? true

Triangle is [(0.1, 0.111111), (12.5, 33.3333), (-12.5, 16.6667)]
Point (5.41429, 14.3492) is within triangle? true

Delphi

Works with: Delphi version 6.0

This routine works by taking each line in the triangle and determining which side of the line the point is on. This is done using the "determinant" of the three points. If a point is on the same side of all sides in the triangle, the point is inside the triangle. Conversely, if a point isn't on the same side, it is out of side the triangle. Since there are only three points in a triangle, this applies no matter the order in which the points are presented, as long as the points are traversed in order. Points that fall on a line are treated as though they have the same "inside" sense when combined with other lines.

{Vector structs and operations - these would normally be in}
{a library, but are produced here so everything is explicit}

type T2DVector=packed record
  X,Y: double;
  end;

type T2DLine = packed record
 P1,P2: T2DVector;
 end;

type T2DTriangle = record
 P1,P2,P3: T2DVector;
 end;



function MakeVector2D(const X,Y: double): T2DVector;
begin
Result.X:=X;
Result.Y:=Y;
end;


function Make2DLine(const P1,P2: T2DVector): T2DLine; overload;
begin
Result.P1:=P1;
Result.P2:=P2;
end;



function MakeTriangle2D(P1,P2,P3: T2DVector): T2DTriangle;
begin
Result.P1:=P1; Result.P2:=P2; Result.P3:=P3;
end;


{Point-Line position constants}

const RightPos = -1;
const LeftPos = +1;
const ColinearPos = 0;

function LinePointPosition(Line: T2DLine; Point: T2DVector): integer;
{Test the position of point relative to the line}
{Returns +1 = right side, -1 = left side, 0 = on the line}
var Side: double;
begin
{ Use the determinate to find which side of the line a point is on }
Side := (Line.P2.X - Line.P1.X) * (Point.Y - Line.P1.Y) - (Point.X - Line.P1.X) * (Line.P2.Y - Line.P1.Y);
{Return +1 = right side, -1 = left side, 0 = on the line}
if Side > 0 then Result := LeftPos
else if Side < 0 then Result := RightPos
else Result := ColinearPos;
end;


function PointInTriangle2D(P: T2DVector; Tri: T2DTriangle): boolean; overload;
{Check if specified point is inside the specified Triangle}
var Side1,Side2,Side3: integer;
var L: T2DLine;
begin
{Get the side the point falls on for the first two sides of triangle}
Side1 := LinePointPosition(Make2DLine(Tri.P1,Tri.P2),P);
Side2 := LinePointPosition(Make2DLine(Tri.P2,Tri.P3),P);

{If they are on different sides, the point must be outside}
if (Side1 * Side2) = -1 then Result := False
else
	begin
	{The point is inside the first two sides, so check the third side}
	Side3 := LinePointPosition(Make2DLine(Tri.P3,Tri.P1),P);
	{Use the three}
	if (Side1 = Side3) or (Side3 = 0) then Result := True
	else if Side1 = 0 then Result := (Side2 * Side3) >= 0
	else if Side2 = 0 then Result := (Side1 * Side3) >= 0
	else Result := False;
	end;
end;

{-------------- Test routines -------------------------------------------------}


procedure DrawTriangle(Canvas: TCanvas; T: T2DTriangle);
{Draw triangles on any canvas}
begin
Canvas.Pen.Color:=clBlack;
Canvas.Pen.Mode:=pmCopy;
Canvas.Pen.Style:=psSolid;
Canvas.Pen.Width:=2;
Canvas.MoveTo(Trunc(T.P1.X),Trunc(T.P1.Y));
Canvas.LineTo(Trunc(T.P2.X),Trunc(T.P2.Y));
Canvas.LineTo(Trunc(T.P3.X),Trunc(T.P3.Y));
Canvas.LineTo(Trunc(T.P1.X),Trunc(T.P1.Y));
end;



procedure DrawPoint(Canvas: TCanvas; X,Y: integer; InTri: boolean);
{Draw a test point on a canvas and mark if "In" or "Out"}
begin
Canvas.Pen.Color:=clRed;
Canvas.Pen.Width:=8;
Canvas.MoveTo(X-1,Y);
Canvas.LineTo(X+1,Y);
Canvas.MoveTo(X,Y-1);
Canvas.LineTo(X,Y+1);
Canvas.Font.Size:=12;
Canvas.Font.Style:=[fsBold];
if InTri then Canvas.TextOut(X+5,Y,'In')
else Canvas.TextOut(X+5,Y,'Out');
end;



procedure TestPointInTriangle(Image: TImage);
{Draw triangle and display test points}
var Tri: T2DTriangle;
var P: TPoint;
begin
{Create and draw Triangle}
Tri:=MakeTriangle2D(MakeVector2D(50,50),MakeVector2D(300,80),MakeVector2D(150,250));
DrawTriangle(Image.Canvas,Tri);

{Draw six test points}
P:=Point(62,193);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
P:=Point(100,100);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
P:=Point(200,100);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
P:=Point(150,30);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
P:=Point(250,200);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
P:=Point(150,200);
DrawPoint(Image.Canvas,P.X,P.Y, PointInTriangle2D(MakeVector2D(P.X,P.Y),Tri));
end;
Output:


Dart

Translation of: C++
import 'dart:math';

const double EPS = 0.001;
const double EPS_SQUARE = EPS * EPS;

double side(double x1, double y1, double x2, double y2, double x, double y) {
  return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1);
}

bool naivePointInTriangle(double x1, double y1, double x2, double y2, double x3,
    double y3, double x, double y) {
  double checkSide1 = side(x1, y1, x2, y2, x, y); // >= 0;
  double checkSide2 = side(x2, y2, x3, y3, x, y); // >= 0;
  double checkSide3 = side(x3, y3, x1, y1, x, y); // >= 0;
  if (checkSide1 >= 0 && checkSide2 >= 0 && checkSide3 >= 0) {
    return true;
  } else {
    return false;
  }
}

bool pointInTriangleBoundingBox(double x1, double y1, double x2, double y2,
    double x3, double y3, double x, double y) {
  double xMin = min(x1, min(x2, x3)) - EPS;
  double xMax = max(x1, max(x2, x3)) + EPS;
  double yMin = min(y1, min(y2, y3)) - EPS;
  double yMax = max(y1, max(y2, y3)) + EPS;
  return !(x < xMin || xMax < x || y < yMin || yMax < y);
}

double distanceSquarePointToSegment(
    double x1, double y1, double x2, double y2, double x, double y) {
  double p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
  double dotProduct =
      ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength;
  if (dotProduct < 0) {
    return (x - x1) * (x - x1) + (y - y1) * (y - y1);
  } else if (dotProduct <= 1) {
    double p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
    return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
  } else {
    return (x - x2) * (x - x2) + (y - y2) * (y - y2);
  }
}

bool accuratePointInTriangle(double x1, double y1, double x2, double y2,
    double x3, double y3, double x, double y) {
  if (!pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)) {
    return false;
  }
  if (naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
    return true;
  }
  if (distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE) {
    return true;
  }
  if (distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE) {
    return true;
  }
  if (distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE) {
    return true;
  }
  return false;
}

void printTriangle(
    double x1, double y1, double x2, double y2, double x3, double y3) {
  print("Triangle is [($x1, $y1), ($x2, $y2), ($x3, $y3)]");
}

void test(double x1, double y1, double x2, double y2, double x3, double y3,
    double x, double y) {
  printTriangle(x1, y1, x2, y2, x3, y3);
  print("Point ($x, $y) is within triangle? ");
  if (accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
    print("true");
  } else {
    print("false");
  }
}

void main() {
  test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0);
  test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1);
  test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1);
  print('');

  test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25, 11.11111111111111,
      5.414285714285714, 14.349206349206348);
  print('');

  test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5,
      16.666666666666668, 5.414285714285714, 14.349206349206348);
  print('');
}

EasyLang

Run it

func sgn px py ax ay bx by .
   return sign ((px - bx) * (ay - by) - (ax - bx) * (py - by))
.
func isin px py ax ay bx by cx cy .
   z1 = sgn px py ax ay bx by
   z2 = sgn px py bx by cx cy
   z3 = sgn px py cx cy ax ay
   return if abs (z1 + z2 + z3) = 3
.
ax = 10 ; ay = 20
bx = 90 ; by = 30
cx = 50 ; cy = 80
# 
move 5 90
textsize 4
text "Move mouse into the triangle"
color 444
polygon [ ax ay bx by cx cy ]
# 
on mouse_move
   if isin mouse_x mouse_y ax ay bx by cx cy <> in
      in = 1 - in
      if in = 1
         color 822
      else
         color 444
      .
      polygon [ ax ay bx by cx cy ]
   .
.

Evaldraw

This solution makes use of the (x,y,t,&r,&g,&b) plotting function. It evaluates an function in the cartesian plane. Given x,y inputs, the function is expected to set r,g,b color channels. The program tests all points in the viewport. You may pan and zoom. The current mouse position shows the computed RGB at that point. The isPointInsideTriangle-function here works in similar way to other solutions here;

for the 3 points of a triangle we compute 3 line equations that will be evaluated to get the signed distance from the line to a point. We can use this to return early from isPointInsideTriangle. Only if all three lines give a result with the point on the same side (same sign) then the point can be classified as inside the triangle. We can use this property of sidedness and sign to make the method work for both clockwise and anti-clockwise specification of the triangle vertices. If the triangle is clockwise, then the area function returns a positive value. If the triangle is anti clockwise, then the area function returns a negative value, and we can multiply the sgn checks by -1 so a point can still be considered inside. A point with distance 0 is also considered inside.

A triangle with vertices set to red, green and blue with interpolation over surface.
plot mode (x,y,&r,&g,&b) allows for plotting of arbitrary functions of (x,y) and return rgb
struct vec2{x,y;};
struct line_t{a,b,c;};
struct triangle_calc_t{
  vec2 origin;
  line_t lines[3];
  vec2 min,max;
  double area2;
  winding_dir; // +1 if clockwise (positive angle) -1 if negative.
};
//static vec2 vertices[3] = {0,-2, -2,2, 4,0};
static vec2 vertices[3] = {-3,7, -6,-5, 2,2};
enum{TRI_OUT, TRI_ZERO, TRI_EDGE, TRI_INSIDE}
static triangle_calc_t triangle;
(x,y,t,&r,&g,&b)
{
  if (numframes==0) {
    precalc_tri( triangle, vertices);
  }
  d0 = d1 = d2 = 0; // Distances of point to lines
  vec2 point = {x, y};
  side = isPointInsideTriangle(point,triangle,d0,d1,d2);
  if (side == TRI_INSIDE) {
    if (triangle.winding_dir == -1) {
      swap(d1,d2);
      swap(d1,d0);
    }
    r_area = 1.0 / (triangle.winding_dir * triangle.area2);
    r = 255 * r_area * d2; 
    g = 255 * r_area * d0; 
    b = 255 * r_area * d1; return 1;
  }
  r=0; g=0; b=0; return 0; // Set color to 0 if outside.
}

precalc_tri(triangle_calc_t t, vec2 verts[3]) {
  t.area2 = triangleAreaTimes2(verts[0], verts[1], verts[2]);
  if (t.area2 == 0) return;
  t.winding_dir = sgn(t.area2);
  t.origin = verts[0];
  vec2 relative_vertices[3];
  t.min.x = 1e32;
  t.min.y = 1e32;
  t.max.x = -1e32;
  t.max.y = -1e32;
  for(i=0; i<3; i++) {
    t.min.x = min(t.min.x, verts[i].x);
    t.min.y = min(t.min.y, verts[i].y);
    t.max.x = max(t.max.x, verts[i].x);
    t.max.y = max(t.max.y, verts[i].y);
    relative_vertices[i].x = verts[i].x + t.origin.x;
    relative_vertices[i].y = verts[i].y + t.origin.y;
  }
  makeLine(t.lines[0], relative_vertices[0], relative_vertices[1]);
  makeLine(t.lines[1], relative_vertices[1], relative_vertices[2]);
  makeLine(t.lines[2], relative_vertices[2], relative_vertices[0]);
}
triangleAreaTimes2(vec2 a, vec2 b, vec2 c) { // Same as the determinant, but dont div by 2
  return c.x*(a.y-b.y)+a.x*(b.y-c.y)+b.x*(-a.y+c.y);
}
isPointInsideTriangle( vec2 point, triangle_calc_t t, &d0,&d1,&d2) {
  if (t.area2 == 0) return TRI_ZERO;
  if (point.x < t.min.x) return TRI_OUT;
  if (point.y < t.min.y) return TRI_OUT;
  if (point.x > t.max.x) return TRI_OUT;
  if (point.y > t.max.y) return TRI_OUT;
  vec2 p = {point.x + t.origin.x, point.y + t.origin.y };
  d0 = t.winding_dir * lineDist( t.lines[0], p.x, p.y);
  if (d0==0) { return TRI_EDGE; }else if ( sgn(d0) < 0 ) return TRI_OUT;
  
  d1 = t.winding_dir * lineDist( t.lines[1], p.x, p.y);
  if (d1==0) { return TRI_EDGE; } else if ( sgn(d1) < 0 ) return TRI_OUT;
  
  d2 = t.winding_dir * lineDist( t.lines[2], p.x, p.y);
  if (d2==0) { return TRI_EDGE; } else if ( sgn(d2) < 0 ) return TRI_OUT;
  
  return TRI_INSIDE; // on inside
}

makeLine(line_t line, vec2 a, vec2 b) { // -dy,dx,axby-aybx
  line.a = -(b.y - a.y);
  line.b = (b.x - a.x);
  line.c = a.x*b.y - a.y*b.x;
}
lineDist(line_t line, x,y) { return x*line.a + y*line.b + line.c; }
swap(&a,&b) {tmp = a; a=b; b=tmp; }

Factor

Uses the parametric equations method from [5].

USING: accessors fry io kernel locals math math.order sequences ;

TUPLE: point x y ;
C: <point> point
: >point< ( point -- x y ) [ x>> ] [ y>> ] bi ;

TUPLE: triangle p1 p2 p3 ;
C: <triangle> triangle
: >triangle< ( triangle -- x1 y1 x2 y2 x3 y3 )
    [ p1>> ] [ p2>> ] [ p3>> ] tri [ >point< ] tri@ ;

:: point-in-triangle? ( point triangle -- ? )
    point >point< triangle >triangle< :> ( x y x1 y1 x2 y2 x3 y3 )
    y2 y3 - x1 * x3 x2 - y1 * + x2 y3 * + y2 x3 * - :> d
    y3 y1 - x * x1 x3 - y * + x1 y3 * - y1 x3 * + d / :> t1
    y2 y1 - x * x1 x2 - y * + x1 y2 * - y1 x2 * + d neg / :> t2
    t1 t2 + :> s
    
    t1 t2 [ 0 1 between? ] bi@ and s 1 <= and ;

! Test if it works.

20 <iota> dup [ swap <point> ] cartesian-map                     ! Make a matrix of points
3 3 <point> 16 10 <point> 10 16 <point> <triangle>               ! Make a triangle
'[ [ _ point-in-triangle? "#" "." ? write ] each nl ] each nl    ! Show points inside the triangle with '#'
Output:
....................
....................
....................
...#................
....#...............
.....##.............
.....####...........
......#####.........
......#######.......
.......########.....
.......##########...
........########....
........#######.....
.........#####......
.........####.......
..........##........
..........#.........
....................
....................
....................

Fortran

PROGRAM POINT_WITHIN_TRIANGLE

IMPLICIT NONE

REAL (KIND = SELECTED_REAL_KIND (8)) px, py, ax, ay, bx, by, cx, cy

px = 0.0
py = 0.0
ax = 1.5
ay = 2.4
bx = 5.1
by = -3.1
cx = -3.8
cy = 1.2

IF (IS_P_IN_ABC (px, py, ax, ay, bx, by, cx, cy)) THEN

    WRITE (*, *) 'Point (', px, ', ', py, ') is within triangle &
        [(', ax, ', ', ay,'), (', bx, ', ', by, '), (', cx, ', ', cy, ')].'

  ELSE

    WRITE (*, *) 'Point (', px, ', ', py, ') is not within triangle &
        [(', ax, ', ', ay,'), (', bx, ', ', by, '), (', cx, ', ', cy, ')].'

END IF

CONTAINS

  !Provide xy values of points P, A, B, C, respectively.
  LOGICAL FUNCTION IS_P_IN_ABC (px, py, ax, ay, bx, by, cx, cy)

    REAL (KIND = SELECTED_REAL_KIND (8)), INTENT (IN) :: px, py, ax, ay, bx, by, cx, cy
    REAL (KIND = SELECTED_REAL_KIND (8)) :: vabx, vaby, vacx, vacy, a, b

    vabx = bx - ax
    vaby = by - ay
    vacx = cx - ax
    vacy = cy - ay

    a = ((px * vacy - py * vacx) - (ax * vacy - ay * vacx)) / &
        (vabx * vacy - vaby * vacx)
    b = -((px * vaby - py * vabx) - (ax * vaby - ay * vabx)) / &
        (vabx * vacy - vaby * vacx)

    IF ((a .GT. 0) .AND. (b .GT. 0) .AND. (a + b < 1)) THEN

        IS_P_IN_ABC = .TRUE.

      ELSE

        IS_P_IN_ABC = .FALSE.

    END IF

  END FUNCTION IS_P_IN_ABC

END PROGRAM POINT_WITHIN_TRIANGLE
Output:

Point ( 0.0000000000000000 , 0.0000000000000000 ) is within triangle [( 1.5000000000000000 , 2.4000000953674316 ), ( 5.0999999046325684 , -3.0999999046325684 ), ( -3.7999999523162842 , 1.2000000476837158 )].

FreeBASIC

type p2d
    x as double   'define a two-dimensional point
    y as double
end type

function in_tri( A as p2d, B as p2d, C as p2d, P as p2d ) as boolean
    'uses barycentric coordinates to determine if point P is inside
    'the triangle defined by points A, B, C
    dim as double AreaD = (-B.y*C.x + A.y*(-B.x + C.x) + A.x*(B.y - C.y) + B.x*C.y)
    dim as double s = (A.y*C.x - A.x*C.y + (C.y - A.y)*P.x + (A.x - C.x)*P.y)/AreaD
    dim as double t = (A.x*B.y - A.y*B.x + (A.y - B.y)*P.x + (B.x - A.x)*P.y)/AreaD
    if s<=0 then return false
    if t<=0 then return false
    if s+t>=1 then return false
    return true
end function

dim as p2d A,B,C,P    'generate some arbitrary triangle
A.x = 4.14 : A.y = -1.12
B.x = 8.1 : B.y =-4.9 
C.x = 1.5: C.y = -9.3

for y as double = -0.25 to -9.75 step -0.5    'display a 10x10 square
    for x as double = 0.125 to 9.875 step 0.25
        P.x = x : P.y = y
        if in_tri(A,B,C,P) then print "@"; else print ".";   'with all the points inside the triangle indicated
    next x
    print
next y
Output:
........................................

........................................ ................@....................... ................@@@..................... ...............@@@@@@................... ..............@@@@@@@@@................. ..............@@@@@@@@@@@............... .............@@@@@@@@@@@@@@@............ .............@@@@@@@@@@@@@@@@@.......... ............@@@@@@@@@@@@@@@@@@@@........ ...........@@@@@@@@@@@@@@@@@@@.......... ...........@@@@@@@@@@@@@@@@............. ..........@@@@@@@@@@@@@@................ .........@@@@@@@@@@@@................... .........@@@@@@@@@...................... ........@@@@@@@......................... .......@@@@@............................ .......@@............................... ........................................ ........................................



FutureBasic

_window = 1
begin enum 1
  _textLabel
end enum

void local fn BuildWindow
  window _window, @"Find if a point is within a triangle", (0, 0, 340, 360 )
  WindowCenter(_window)
  WindowSubclassContentView(_window)
  ViewSetFlipped( _windowContentViewTag, YES )
  ViewSetNeedsDisplay( _windowContentViewTag )
  
  subclass textLabel _textLabel, @"", ( 20, 320, 300, 20 ), _window
end fn

void local fn DrawInView( tag as NSInteger )
  BezierPathRef path = fn BezierPathInit
  BezierPathMoveToPoint( path, fn CGPointMake(  30, 300 ) )
  BezierPathLineToPoint( path, fn CGPointMake( 300, 300 ) )
  BezierPathLineToPoint( path, fn CGPointMake( 150,  30 ) )
  BezierPathClose( path )
  BezierPathStrokeFill( path, 3.0, fn ColorBlack, fn ColorGreen )
  AppSetProperty( @"path", path )
end fn

void local fn DoMouse( tag as NSInteger )
  CGPoint pt = fn EventLocationInView( tag )
  if ( fn BezierPathContainsPoint( fn AppProperty( @"path" ), pt ) )
    ControlSetStringValue( _textLabel, fn StringWithFormat( @"Inside triangle:  x = %.f  y = %.f", pt.x, pt.y ) )
  else
    ControlSetStringValue( _textLabel, fn StringWithFormat( @"Outside triangle:  x = %.f  y = %.f", pt.x, pt.y ) )
  end if
end fn

void local fn DoDialog( ev as long, tag as long )
  select ( ev )
    case _viewDrawRect   : fn DrawInView(tag)
    case _viewMouseDown  : fn DoMouse( tag )
    case _viewMouseMoved : fn DoMouse( tag )
  end select
end fn

fn BuildWindow

on dialog fn DoDialog

HandleEvents
Output:

Go

Translation of: Wren
package main

import (
    "fmt"
    "math"
)

const EPS = 0.001
const EPS_SQUARE = EPS * EPS

func side(x1, y1, x2, y2, x, y float64) float64 {
    return (y2-y1)*(x-x1) + (-x2+x1)*(y-y1)
}

func naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y float64) bool {
    checkSide1 := side(x1, y1, x2, y2, x, y) >= 0
    checkSide2 := side(x2, y2, x3, y3, x, y) >= 0
    checkSide3 := side(x3, y3, x1, y1, x, y) >= 0
    return checkSide1 && checkSide2 && checkSide3
}

func pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y float64) bool {
    xMin := math.Min(x1, math.Min(x2, x3)) - EPS
    xMax := math.Max(x1, math.Max(x2, x3)) + EPS
    yMin := math.Min(y1, math.Min(y2, y3)) - EPS
    yMax := math.Max(y1, math.Max(y2, y3)) + EPS
    return !(x < xMin || xMax < x || y < yMin || yMax < y)
}

func distanceSquarePointToSegment(x1, y1, x2, y2, x, y float64) float64 {
    p1_p2_squareLength := (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)
    dotProduct := ((x-x1)*(x2-x1) + (y-y1)*(y2-y1)) / p1_p2_squareLength
    if dotProduct < 0 {
        return (x-x1)*(x-x1) + (y-y1)*(y-y1)
    } else if dotProduct <= 1 {
        p_p1_squareLength := (x1-x)*(x1-x) + (y1-y)*(y1-y)
        return p_p1_squareLength - dotProduct*dotProduct*p1_p2_squareLength
    } else {
        return (x-x2)*(x-x2) + (y-y2)*(y-y2)
    }
}

func accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y float64) bool {
    if !pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y) {
        return false
    }
    if naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) {
        return true
    }
    if distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE {
        return true
    }
    if distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE {
        return true
    }
    if distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE {
        return true
    }
    return false
}

func main() {
    pts := [][2]float64{{0, 0}, {0, 1}, {3, 1}}
    tri := [][2]float64{{3.0 / 2, 12.0 / 5}, {51.0 / 10, -31.0 / 10}, {-19.0 / 5, 1.2}}
    fmt.Println("Triangle is", tri)
    x1, y1 := tri[0][0], tri[0][1]
    x2, y2 := tri[1][0], tri[1][1]
    x3, y3 := tri[2][0], tri[2][1]
    for _, pt := range pts {
        x, y := pt[0], pt[1]
        within := accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
        fmt.Println("Point", pt, "is within triangle?", within)
    }
    fmt.Println()
    tri = [][2]float64{{1.0 / 10, 1.0 / 9}, {100.0 / 8, 100.0 / 3}, {100.0 / 4, 100.0 / 9}}
    fmt.Println("Triangle is", tri)
    x1, y1 = tri[0][0], tri[0][1]
    x2, y2 = tri[1][0], tri[1][1]
    x3, y3 = tri[2][0], tri[2][1]
    x := x1 + (3.0/7)*(x2-x1)
    y := y1 + (3.0/7)*(y2-y1)
    pt := [2]float64{x, y}
    within := accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    fmt.Println("Point", pt, "is within triangle ?", within)
    fmt.Println()
    tri = [][2]float64{{1.0 / 10, 1.0 / 9}, {100.0 / 8, 100.0 / 3}, {-100.0 / 8, 100.0 / 6}}
    fmt.Println("Triangle is", tri)
    x3 = tri[2][0]
    y3 = tri[2][1]
    within = accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    fmt.Println("Point", pt, "is within triangle ?", within)
}
Output:
Triangle is [[1.5 2.4] [5.1 -3.1] [-3.8 1.2]]
Point [0 0] is within triangle? true
Point [0 1] is within triangle? true
Point [3 1] is within triangle? false

Triangle is [[0.1 0.1111111111111111] [12.5 33.333333333333336] [25 11.11111111111111]]
Point [5.414285714285714 14.349206349206348] is within triangle ? true

Triangle is [[0.1 0.1111111111111111] [12.5 33.333333333333336] [-12.5 16.666666666666668]]
Point [5.414285714285714 14.349206349206348] is within triangle ? true

GW-BASIC

10 PIT1X! = 3 : PIT1Y! = 1.3 :    REM arbitrary triangle for demonstration
20 PIT2X! = 17.222 : PIT2Y! = 10
30 PIT3X! =  5.5 : PIT3Y! = 18.212
40 FOR PITPY! = 0 TO 19 STEP 1
50 FOR PITPX! = 0 TO 20 STEP .5
60 GOSUB 1000
70 IF PITRES% = 0 THEN PRINT "."; ELSE PRINT "#";
80 NEXT PITPX!
90 PRINT
100 NEXT PITPY!
110 END
1000 REM Detect if point is in triangle. Takes 8 double-precision
1010 REM values: (PIT1X!, PIT1Y!), (PIT2X!, PIT2Y!), (PIT3X!, PIT3Y!)
1020 REM for the coordinates of the corners of the triangle
1030 REM and (PITPX!, PITPY!) for the coordinates of the test point
1040 REM Returns PITRES%: 1=in triangle, 0=not in it
1050 PITDAR! = -PIT2Y!*PIT3X! + PIT1Y!*(-PIT2X! + PIT3X!) + PIT1X!*(PIT2Y - PIT3Y!) + PIT2X!*PIT3Y!
1060 PITXXS = (PIT1Y!*PIT3X! - PIT1X!*PIT3Y! + (PIT3Y! - PIT1Y!)*PITPX! + (PIT1X! - PIT3X!)*PITPY!)/PITDAR!
1070 PITXXT = (PIT1X!*PIT2Y! - PIT1Y!*PIT2X! + (PIT1Y! - PIT2Y!)*PITPX! + (PIT2X! - PIT1X!)*PITPY!)/PITDAR!
1080 PITRES% = 0
1090 IF PITXXS!<=0 THEN RETURN
1100 IF PITXXT!<=0 THEN RETURN
1110 IF PITXXS!+PITXXT!>=1 THEN RETURN
1120 PITRES% = 1
1130 RETURN
Output:
.........................................

......................................... .......##................................ .......#####............................. .......########.......................... ........###########...................... ........##############................... ........#################................ ........####################............. .........#######################......... .........##########################...... .........#######################......... ..........###################............ ..........################............... ..........##############................. ...........##########.................... ...........#######....................... ...........####.......................... ...........#............................. .........................................

Haskell

The point to be tested is transformed by affine transformation which turns given triangle to the simplex: Triangle (0,0) (0,s) (s,0), where s is half of the triangles' area. After that criteria of overlapping become trivial. Affinity allows to avoid division, so all functions work for points on the integer, or rational, or even modular meshes as well.

type Pt a = (a, a)

data Overlapping = Inside | Outside | Boundary
  deriving (Show, Eq)

data Triangle a = Triangle (Pt a) (Pt a) (Pt a)
  deriving Show

vertices (Triangle a b c) = [a, b, c]

-- Performs the affine transformation
-- which turns a triangle to Triangle (0,0) (0,s) (s,0)
-- where s is half of the triangles' area
toTriangle :: Num a => Triangle a -> Pt a -> (a, Pt a)
toTriangle t (x,y) = let
  [(x0,y0), (x1,y1), (x2,y2)] = vertices t
  s = x2*(y0-y1)+x0*(y1-y2)+x1*(-y0+y2)
  in  ( abs s
      , ( signum s * (x2*(-y+y0)+x0*(y-y2)+x*(-y0+y2))
        , signum s * (x1*(y-y0)+x*(y0-y1)+x0*(-y+y1))))

overlapping :: (Eq a, Ord a, Num a) =>
  Triangle a -> Pt a -> Overlapping
overlapping t p =  case toTriangle t p of
  (s, (x, y))
    | s == 0 && (x == 0 || y == 0)     -> Boundary
    | s == 0                           -> Outside
    | x > 0 && y > 0 && y < s - x      -> Inside
    | (x <= s && x >= 0) &&
      (y <= s && y >= 0) &&
      (x == 0 || y == 0 || y == s - x) -> Boundary         
    | otherwise                        -> Outside

Testing

tests = let
  t1 = Triangle (2,0) (-1,2) (-2,-2)
  bs = [(2,0), (-1,2), (-2,-2), (0,-1), (1/2,1), (-3/2,0)]
  is = [(0,0), (0,1), (-1,0), (-1,1), (-1,-1)]
  os = [(1,1), (-2,2), (100,100), (2.00000001, 0)]
  
  t2 = Triangle (1,2) (1,2) (-1,3)
  ps = [(1,2), (0,5/2), (0,2), (1,3)]

  in mapM_ print [ overlapping t1 <$> bs
                 , overlapping t1 <$> is
                 , overlapping t1 <$> os
                 , overlapping t2 <$> ps]
test2 = unlines
  [ [case overlapping t (i,j) of
        Inside -> '∗'
        Boundary -> '+'
        Outside -> '·'
    | i <- [-10..10] :: [Int] ]
  | j <- [-5..5] :: [Int] ]
  where t = Triangle (-8,-3) (8,1) (-1,4)
λ> tests
[Boundary,Boundary,Boundary,Boundary,Boundary,Boundary]
[Inside,Inside,Inside,Inside,Inside]
[Outside,Outside,Outside,Outside]
[Boundary,Boundary,Outside,Outside]

λ> putStrLn test2
·····················
·····················
··+··················
···+∗∗+··············
····+∗∗∗∗∗+··········
·····+∗∗∗∗∗∗∗∗+······
······+∗∗∗∗∗∗∗∗∗∗∗+··
·······+∗∗∗∗∗∗∗+·····
········+∗∗∗+········
·········+···········
·····················

J

Implementation, using complex numbers to represent x,y coordinates:

area=: [:| 0.5-/ .*@,.+. NB. signed area of triangle
I3=: =i.3 NB. identity matrix
inside=: {{ (area y)=+/area"1|:(I3*x)+(1-I3)*y }}

This is based on the algorithm documented for the ada implementation: compute the area of triangles using the determinant method (we want the absolute area here), and check whether the triangles formed with the test point and the sides of the test triangle matches the area of the test triangle.

Examples:

   0j0 inside 1.5j2.4 5.1j_3.1 _3.8j1.2
1
   0j1 inside 1.5j2.4 5.1j_3.1 _3.8j1.2
1
   3j1 inside 1.5j2.4 5.1j_3.1 _3.8j1.2
0
   5.414285714285714j14.349206349206348 inside 0.1j1r9 12.5j100r3 25j100r9
1
   5.414285714285714j14.349206349206348 inside 0.1j1r9 12.5j100r3 _12.5j100r6
1

Java

Translation of: Go
import java.util.Objects;

public class FindTriangle {
    private static final double EPS = 0.001;
    private static final double EPS_SQUARE = EPS * EPS;

    public static class Point {
        private final double x, y;

        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public double getX() {
            return x;
        }

        public double getY() {
            return y;
        }

        @Override
        public String toString() {
            return String.format("(%f, %f)", x, y);
        }
    }

    public static class Triangle {
        private final Point p1, p2, p3;

        public Triangle(Point p1, Point p2, Point p3) {
            this.p1 = Objects.requireNonNull(p1);
            this.p2 = Objects.requireNonNull(p2);
            this.p3 = Objects.requireNonNull(p3);
        }

        public Point getP1() {
            return p1;
        }

        public Point getP2() {
            return p2;
        }

        public Point getP3() {
            return p3;
        }

        private boolean pointInTriangleBoundingBox(Point p) {
            var xMin = Math.min(p1.getX(), Math.min(p2.getX(), p3.getX())) - EPS;
            var xMax = Math.max(p1.getX(), Math.max(p2.getX(), p3.getX())) + EPS;
            var yMin = Math.min(p1.getY(), Math.min(p2.getY(), p3.getY())) - EPS;
            var yMax = Math.max(p1.getY(), Math.max(p2.getY(), p3.getY())) + EPS;
            return !(p.getX() < xMin || xMax < p.getX() || p.getY() < yMin || yMax < p.getY());
        }

        private static double side(Point p1, Point p2, Point p) {
            return (p2.getY() - p1.getY()) * (p.getX() - p1.getX()) + (-p2.getX() + p1.getX()) * (p.getY() - p1.getY());
        }

        private boolean nativePointInTriangle(Point p) {
            boolean checkSide1 = side(p1, p2, p) >= 0;
            boolean checkSide2 = side(p2, p3, p) >= 0;
            boolean checkSide3 = side(p3, p1, p) >= 0;
            return checkSide1 && checkSide2 && checkSide3;
        }

        private double distanceSquarePointToSegment(Point p1, Point p2, Point p) {
            double p1_p2_squareLength = (p2.getX() - p1.getX()) * (p2.getX() - p1.getX()) + (p2.getY() - p1.getY()) * (p2.getY() - p1.getY());
            double dotProduct = ((p.getX() - p1.getX()) * (p2.getX() - p1.getX()) + (p.getY() - p1.getY()) * (p2.getY() - p1.getY())) / p1_p2_squareLength;
            if (dotProduct < 0) {
                return (p.getX() - p1.getX()) * (p.getX() - p1.getX()) + (p.getY() - p1.getY()) * (p.getY() - p1.getY());
            }
            if (dotProduct <= 1) {
                double p_p1_squareLength = (p1.getX() - p.getX()) * (p1.getX() - p.getX()) + (p1.getY() - p.getY()) * (p1.getY() - p.getY());
                return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
            }
            return (p.getX() - p2.getX()) * (p.getX() - p2.getX()) + (p.getY() - p2.getY()) * (p.getY() - p2.getY());
        }

        private boolean accuratePointInTriangle(Point p) {
            if (!pointInTriangleBoundingBox(p)) {
                return false;
            }
            if (nativePointInTriangle(p)) {
                return true;
            }
            if (distanceSquarePointToSegment(p1, p2, p) <= EPS_SQUARE) {
                return true;
            }
            if (distanceSquarePointToSegment(p2, p3, p) <= EPS_SQUARE) {
                return true;
            }
            return distanceSquarePointToSegment(p3, p1, p) <= EPS_SQUARE;
        }

        public boolean within(Point p) {
            Objects.requireNonNull(p);
            return accuratePointInTriangle(p);
        }

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

    private static void test(Triangle t, Point p) {
        System.out.println(t);
        System.out.printf("Point %s is within triangle? %s\n", p, t.within(p));
    }

    public static void main(String[] args) {
        var p1 = new Point(1.5, 2.4);
        var p2 = new Point(5.1, -3.1);
        var p3 = new Point(-3.8, 1.2);
        var tri = new Triangle(p1, p2, p3);
        test(tri, new Point(0, 0));
        test(tri, new Point(0, 1));
        test(tri, new Point(3, 1));
        System.out.println();

        p1 = new Point(1.0 / 10, 1.0 / 9);
        p2 = new Point(100.0 / 8, 100.0 / 3);
        p3 = new Point(100.0 / 4, 100.0 / 9);
        tri = new Triangle(p1, p2, p3);
        var pt = new Point(p1.getX() + (3.0 / 7) * (p2.getX() - p1.getX()), p1.getY() + (3.0 / 7) * (p2.getY() - p1.getY()));
        test(tri, pt);
        System.out.println();

        p3 = new Point(-100.0 / 8, 100.0 / 6);
        tri = new Triangle(p1, p2, p3);
        test(tri, pt);
    }
}
Output:
Triangle[(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (0.000000, 0.000000) is within triangle? true
Triangle[(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (0.000000, 1.000000) is within triangle? true
Triangle[(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Point (3.000000, 1.000000) is within triangle? false

Triangle[(0.100000, 0.111111), (12.500000, 33.333333), (25.000000, 11.111111)]
Point (5.414286, 14.349206) is within triangle? true

Triangle[(0.100000, 0.111111), (12.500000, 33.333333), (-12.500000, 16.666667)]
Point (5.414286, 14.349206) is within triangle? true

JavaScript

Translation of: C++
const EPS = 0.001;
const EPS_SQUARE = EPS * EPS;

function side(x1, y1, x2, y2, x, y) {
	return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1);
}

function naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) {
	const checkSide1 = side(x1, y1, x2, y2, x, y) >= 0;
	const checkSide2 = side(x2, y2, x3, y3, x, y) >= 0;
	const checkSide3 = side(x3, y3, x1, y1, x, y) >= 0;
	return checkSide1 && checkSide2 && checkSide3;
}

function pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y) {
	const xMin = Math.min(x1, Math.min(x2, x3)) - EPS;
	const xMax = Math.max(x1, Math.max(x2, x3)) + EPS;
	const yMin = Math.min(y1, Math.min(y2, y3)) - EPS;
	const yMax = Math.max(y1, Math.max(y2, y3)) + EPS;
	return !(x < xMin || xMax < x || y < yMin || yMax < y);
}

function distanceSquarePointToSegment(x1, y1, x2, y2, x, y) {
	const p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
	const dotProduct =
		((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength;
	if (dotProduct < 0) {
		return (x - x1) * (x - x1) + (y - y1) * (y - y1);
	} else if (dotProduct <= 1) {
		const p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
		return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
	} else {
		return (x - x2) * (x - x2) + (y - y2) * (y - y2);
	}
}

function accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) {
	if (!pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)) {
		return false;
	}
	if (naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)) {
		return true;
	}
	if (distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE) {
		return true;
	}
	if (distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE) {
		return true;
	}
	if (distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE) {
		return true;
	}
	return false;
}

function printPoint(x, y) {
	return "(" + x + ", " + y + ")";
}

function printTriangle(x1, y1, x2, y2, x3, y3) {
	return (
		"Triangle is [" +
		printPoint(x1, y1) +
		", " +
		printPoint(x2, y2) +
		", " +
		printPoint(x3, y3) +
		"]"
	);
}

function test(x1, y1, x2, y2, x3, y3, x, y) {
	console.log(
		printTriangle(x1, y1, x2, y2, x3, y3) +
		"Point " +
		printPoint(x, y) +
		" is within triangle? " +
		(accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) ? "true" : "false")
	);
}

test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0);
test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1);
test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1);
console.log();

test(
	0.1,
	0.1111111111111111,
	12.5,
	33.333333333333336,
	25,
	11.11111111111111,
	5.414285714285714,
	14.349206349206348
);
console.log();

test(
	0.1,
	0.1111111111111111,
	12.5,
	33.333333333333336,
	-12.5,
	16.666666666666668,
	5.414285714285714,
	14.349206349206348
);
console.log();

jq

Works with: jq

Works with gojq, the Go implementation of jq

Adapted from Wren

A point is represented by [x,y] and denoted by P1, P2, P3, or Q.

A triangle is represented by an array of points: [P1, P2, P3].

Preliminaries

def sum_of_squares(stream): reduce stream as $x (0; . + $x * $x);

def distanceSquared(P1; P2): sum_of_squares(P1[0]-P2[0], P1[1]-P2[1]);

# Emit {x1,y1, ...} for the input triangle
def xy:
  { x1: .[0][0],
    y1: .[0][1],
    x2: .[1][0],
    y2: .[1][1],
    x3: .[2][0],
    y3: .[2][1] };

def EPS: 0.001;
def EPS_SQUARE: EPS * EPS;
def side(P1; P2; Q):
  [P1, P2, Q] 
  | xy
  | (.y2 - .y1)*(.x3 - .x1) + (-.x2 + .x1)*(.y3 - .y1);

def naivePointInTriangle(P1; P2; P3; Q):
      side(P1; P2; Q) >= 0
  and side(P2; P3; Q) >= 0
  and side(P3; P1; Q) >= 0;
 
def pointInTriangleBoundingBox(P1; P2; P3; Q):
  [P1,P2,P3]
  | (map(.[0]) | min - EPS) as $xMin
  | (map(.[0]) | max + EPS) as $xMax
  | (map(.[1]) | min - EPS) as $yMin
  | (map(.[1]) | max + EPS) as $yMax
  | (Q[0] < $xMin or $xMax < Q[0] or Q[1] < $yMin or $yMax < Q[1]) | not;

def distanceSquarePointToSegment(P1; P2; Q):
  distanceSquared(P1; P2) as $p1_p2_squareLength
  | [P1, P2, Q]
  | xy    
  | (((.x3 - .x1)*(.x2 - .x1) + (.y3 - .y1)*(.y2 - .y1)) / $p1_p2_squareLength) as $dotProduct
  | if $dotProduct < 0
    then sum_of_squares(.x3 - .x1, .y3 - .y1)
    elif $dotProduct <= 1
    then sum_of_squares(.x1 - .x3, .y1 - .y3) as $p_p1_squareLength
    |  $p_p1_squareLength - $dotProduct * $dotProduct * $p1_p2_squareLength
    else sum_of_squares(.x3 - .x2, .y3 - .y2)
    end;

def accuratePointInTriangle(P1; P2; P3; Q):
      if (pointInTriangleBoundingBox(P1; P2; P3; Q) | not)     then false
    elif naivePointInTriangle(P1; P2; P3; Q)                   then true
    elif distanceSquarePointToSegment(P1; P2; Q) <= EPS_SQUARE then true
    elif distanceSquarePointToSegment(P2; P3; Q) <= EPS_SQUARE then true
    elif distanceSquarePointToSegment(P3; P1; Q) <= EPS_SQUARE then true
    else false
    end;

Examples

def task1:
  def pts: [ [0, 0], [0, 1], [3, 1]];
  "Triangle is \(.)",
   (. as [$P1, $P2, $P3]
    | pts[] as $Q
    | accuratePointInTriangle($P1; $P2; $P3; $Q) as $within
    | "Point \($Q) is within triangle ? \($within)"
   );

def task2:
  "Triangle is \(.)",
  (. as [$P1, $P2, $P3]
   | [ $P1[0] + (3/7)*($P2[0] - $P1[0]), $P1[1] + (3/7)*($P2[1] - $P1[1]) ] as $Q
   | accuratePointInTriangle($P1; $P2; $P3; $Q) as $within
   | "Point \($Q) is within triangle ? \($within)"
   );

([ [3/2, 12/5], [51/10, -31/10], [-19/5,   1.2] ] | task1), "",
([ [1/10, 1/9], [100/8,  100/3], [100/4, 100/9] ] | task2), "",
([ [1/10, 1/9], [100/8, 100/3], [-100/8, 100/6] ] | task2)
Output:
Triangle is [[1.5,2.4],[5.1,-3.1],[-3.8,1.2]]
Point [0,0] is within triangle ? true
Point [0,1] is within triangle ? true
Point [3,1] is within triangle ? false

Triangle is [[0.1,0.1111111111111111],[12.5,33.333333333333336],[25,11.11111111111111]]
Point [5.414285714285714,14.349206349206348] is within triangle ? true

Triangle is [[0.1,0.1111111111111111],[12.5,33.333333333333336],[-12.5,16.666666666666668]]
Point [5.414285714285714,14.349206349206348] is within triangle ? true

Julia

Translation of: Python

Using the Wren examples.

Point(x, y) = [x, y]
Triangle(a, b, c) = [a, b, c]
LEzero(x) =  x < 0 || isapprox(x, 0, atol=0.00000001)
GEzero(x) =  x > 0 || isapprox(x, 0, atol=0.00000001)

""" Determine which side of plane cut by line (p2, p3) p1 is on """
side(p1, p2, p3) = (p1[1] - p3[1]) * (p2[2] - p3[2]) - (p2[1] - p3[1]) * (p1[2] - p3[2])

"""
Determine if point is within triangle formed by points p1, p2, p3.
If so, the point will be on the same side of each of the half planes
defined by vectors p1p2, p2p3, and p3p1. Each z is positive if outside,
negative if inside such a plane. All should be positive or all negative
if point is within the triangle.
"""
function iswithin(point, p1, p2, p3)
    z1 = side(point, p1, p2)
    z2 = side(point, p2, p3)
    z3 = side(point, p3, p1)
    notanyneg = GEzero(z1) && GEzero(z2) && GEzero(z3)
    notanypos = LEzero(z1) && LEzero(z2) && LEzero(z3)
    return notanyneg || notanypos
end

const POINTS = [Point(0 // 1, 0 // 1), Point(0 // 1, 1 // 1), Point(3 // 1, 1 // 1),
    Point(1 // 10 + (3 // 7) * (100 // 8 - 1 // 10), 1 // 9 + (3 // 7) * (100 // 3 - 1 // 9)),
    Point(3 // 2, 12 // 5), Point(51 // 100, -31 // 100), Point(-19 // 50, 6 // 5),
    Point(1 // 10, 1 // 9), Point(25 / 2, 100 // 3), Point(25, 100 // 9),
    Point(-25 // 2, 50 // 3)
]

const TRI = [
    Triangle(POINTS[5], POINTS[6], POINTS[7]),
    Triangle(POINTS[8], POINTS[9], POINTS[10]),
    Triangle(POINTS[8], POINTS[9], POINTS[11])
]

for tri in TRI
    pstring(pt) = "[$(Float32(pt[1])), $(Float32(pt[2]))]"
    println("\nUsing triangle [", join([pstring(x) for x in tri], ", "), "]:")
    a, b, c = tri[1], tri[2], tri[3]
    for p in POINTS[1:4]
        isornot = iswithin(p, a, b, c) ? "is" : "is not"
        println("Point $(pstring(p)) $isornot within the triangle.")
    end
end
Output:
Using triangle [[1.5, 2.4], [0.51, -0.31], [-0.38, 1.2]]:
Point [0.0, 0.0] is not within the triangle.
Point [0.0, 1.0] is within the triangle.
Point [3.0, 1.0] is not within the triangle.
Point [5.4142857, 14.349206] is not within the triangle.

Using triangle [[0.1, 0.11111111], [12.5, 33.333332], [25.0, 11.111111]]:
Point [0.0, 0.0] is not within the triangle.
Point [0.0, 1.0] is not within the triangle.
Point [3.0, 1.0] is not within the triangle.
Point [5.4142857, 14.349206] is within the triangle.

Using triangle [[0.1, 0.11111111], [12.5, 33.333332], [-12.5, 16.666666]]:
Point [0.0, 0.0] is not within the triangle.
Point [0.0, 1.0] is within the triangle.
Point [3.0, 1.0] is not within the triangle.
Point [5.4142857, 14.349206] is within the triangle.

Kotlin

Translation of: Java
import kotlin.math.max
import kotlin.math.min

private const val EPS = 0.001
private const val EPS_SQUARE = EPS * EPS

private fun test(t: Triangle, p: Point) {
    println(t)
    println("Point $p is within triangle ? ${t.within(p)}")
}

fun main() {
    var p1 = Point(1.5, 2.4)
    var p2 = Point(5.1, -3.1)
    var p3 = Point(-3.8, 1.2)
    var tri = Triangle(p1, p2, p3)
    test(tri, Point(0.0, 0.0))
    test(tri, Point(0.0, 1.0))
    test(tri, Point(3.0, 1.0))
    println()
    p1 = Point(1.0 / 10, 1.0 / 9)
    p2 = Point(100.0 / 8, 100.0 / 3)
    p3 = Point(100.0 / 4, 100.0 / 9)
    tri = Triangle(p1, p2, p3)
    val pt = Point(p1.x + 3.0 / 7 * (p2.x - p1.x), p1.y + 3.0 / 7 * (p2.y - p1.y))
    test(tri, pt)
    println()
    p3 = Point(-100.0 / 8, 100.0 / 6)
    tri = Triangle(p1, p2, p3)
    test(tri, pt)
}

class Point(val x: Double, val y: Double) {
    override fun toString(): String {
        return "($x, $y)"
    }
}

class Triangle(private val p1: Point, private val p2: Point, private val p3: Point) {
    private fun pointInTriangleBoundingBox(p: Point): Boolean {
        val xMin = min(p1.x, min(p2.x, p3.x)) - EPS
        val xMax = max(p1.x, max(p2.x, p3.x)) + EPS
        val yMin = min(p1.y, min(p2.y, p3.y)) - EPS
        val yMax = max(p1.y, max(p2.y, p3.y)) + EPS
        return !(p.x < xMin || xMax < p.x || p.y < yMin || yMax < p.y)
    }

    private fun nativePointInTriangle(p: Point): Boolean {
        val checkSide1 = side(p1, p2, p) >= 0
        val checkSide2 = side(p2, p3, p) >= 0
        val checkSide3 = side(p3, p1, p) >= 0
        return checkSide1 && checkSide2 && checkSide3
    }

    private fun distanceSquarePointToSegment(p1: Point, p2: Point, p: Point): Double {
        val p1P2SquareLength = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)
        val dotProduct = ((p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y) * (p2.y - p1.y)) / p1P2SquareLength
        if (dotProduct < 0) {
            return (p.x - p1.x) * (p.x - p1.x) + (p.y - p1.y) * (p.y - p1.y)
        }
        if (dotProduct <= 1) {
            val pP1SquareLength = (p1.x - p.x) * (p1.x - p.x) + (p1.y - p.y) * (p1.y - p.y)
            return pP1SquareLength - dotProduct * dotProduct * p1P2SquareLength
        }
        return (p.x - p2.x) * (p.x - p2.x) + (p.y - p2.y) * (p.y - p2.y)
    }

    private fun accuratePointInTriangle(p: Point): Boolean {
        if (!pointInTriangleBoundingBox(p)) {
            return false
        }
        if (nativePointInTriangle(p)) {
            return true
        }
        if (distanceSquarePointToSegment(p1, p2, p) <= EPS_SQUARE) {
            return true
        }
        return if (distanceSquarePointToSegment(p2, p3, p) <= EPS_SQUARE) {
            true
        } else distanceSquarePointToSegment(p3, p1, p) <= EPS_SQUARE
    }

    fun within(p: Point): Boolean {
        return accuratePointInTriangle(p)
    }

    override fun toString(): String {
        return "Triangle[$p1, $p2, $p3]"
    }

    companion object {
        private fun side(p1: Point, p2: Point, p: Point): Double {
            return (p2.y - p1.y) * (p.x - p1.x) + (-p2.x + p1.x) * (p.y - p1.y)
        }
    }
}
Output:
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0.0, 0.0) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0.0, 1.0) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3.0, 1.0) is within triangle ? false

Triangle[(0.1, 0.1111111111111111), (12.5, 33.333333333333336), (25.0, 11.11111111111111)]
Point (5.414285714285714, 14.349206349206348) is within triangle ? true

Triangle[(0.1, 0.1111111111111111), (12.5, 33.333333333333336), (-12.5, 16.666666666666668)]
Point (5.414285714285714, 14.349206349206348) is within triangle ? true

Lua

Translation of: C++
EPS = 0.001
EPS_SQUARE = EPS * EPS

function side(x1, y1, x2, y2, x, y)
    return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1)
end

function naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    local checkSide1 = side(x1, y1, x2, y2, x, y) >= 0
    local checkSide2 = side(x2, y2, x3, y3, x, y) >= 0
    local checkSide3 = side(x3, y3, x1, y1, x, y) >= 0
    return checkSide1 and checkSide2 and checkSide3
end

function pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)
    local xMin = math.min(x1, x2, x3) - EPS
    local xMax = math.max(x1, x2, x3) + EPS
    local yMin = math.min(y1, y2, y3) - EPS
    local yMax = math.max(y1, y2, y3) + EPS
    return not (x < xMin or xMax < x or y < yMin or yMax < y)
end

function distanceSquarePointToSegment(x1, y1, x2, y2, x, y)
    local p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
    local dotProduct = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength
    if dotProduct < 0 then
        return (x - x1) * (x - x1) + (y - y1) * (y - y1)
    end
    if dotProduct <= 1 then
        local p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength
    end
    return (x - x2) * (x - x2) + (y - y2) * (y - y2)
end

function accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    if not pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y) then
        return false
    end
    if naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) then
        return true
    end
    if distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE then
        return true
    end
    if distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE then
        return true
    end
    if distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE then
        return true
    end
    return false
end

function printPoint(x, y)
    io.write('('..x..", "..y..')')
end

function printTriangle(x1, y1, x2, y2, x3, y3)
    io.write("Triangle is [")
    printPoint(x1, y1)
    io.write(", ")
    printPoint(x2, y2)
    io.write(", ")
    printPoint(x3, y3)
    print("]")
end

function test(x1, y1, x2, y2, x3, y3, x, y)
    printTriangle(x1, y1, x2, y2, x3, y3)
    io.write("Point ")
    printPoint(x, y)
    print(" is within triangle? " .. tostring(accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)))
end

test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 0)
test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0, 1)
test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3, 1)
print()

test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25, 11.11111111111111, 5.414285714285714, 14.349206349206348)
print()

test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348)
print()
Output:
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 0) is within triangle? true
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 1) is within triangle? true
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3, 1) is within triangle? false

Triangle is [(0.1, 0.11111111111111), (12.5, 33.333333333333), (25, 11.111111111111)]
Point (5.4142857142857, 14.349206349206) is within triangle? true

Triangle is [(0.1, 0.11111111111111), (12.5, 33.333333333333), (-12.5, 16.666666666667)]
Point (5.4142857142857, 14.349206349206) is within triangle? true

Mathematica /Wolfram Language

RegionMember[Polygon[{{1, 2}, {3, 1}, {2, 4}}], {2, 2}]
Output:
True

Nim

Translation of: Kotlin
import strformat

const
  Eps = 0.001
  Eps2 = Eps * Eps

type
  Point = tuple[x, y: float]
  Triangle = object
    p1, p2, p3: Point


func initTriangle(p1, p2, p3: Point): Triangle =
  Triangle(p1: p1, p2: p2, p3: p3)

func side(p1, p2, p: Point): float =
  (p2.y - p1.y) * (p.x - p1.x) + (-p2.x + p1.x) * (p.y - p1.y)


func distanceSquarePointToSegment(p1, p2, p: Point): float =
  let p1P2SquareLength = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)
  let dotProduct = ((p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y) * (p2.y - p1.y)) / p1P2SquareLength
  if dotProduct < 0:
    return (p.x - p1.x) * (p.x - p1.x) + (p.y - p1.y) * (p.y - p1.y)
  if dotProduct <= 1:
    let pP1SquareLength = (p1.x - p.x) * (p1.x - p.x) + (p1.y - p.y) * (p1.y - p.y)
    return pP1SquareLength - dotProduct * dotProduct * p1P2SquareLength
  result = (p.x - p2.x) * (p.x - p2.x) + (p.y - p2.y) * (p.y - p2.y)


func pointInTriangleBoundingBox(t: Triangle; p: Point): bool =
  let xMin = min(t.p1.x, min(t.p2.x, t.p3.x)) - EPS
  let xMax = max(t.p1.x, max(t.p2.x, t.p3.x)) + EPS
  let yMin = min(t.p1.y, min(t.p2.y, t.p3.y)) - EPS
  let yMax = max(t.p1.y, max(t.p2.y, t.p3.y)) + EPS
  result = p.x in xMin..xMax and p.y in yMin..yMax


func nativePointInTriangle(t: Triangle; p: Point): bool =
  let checkSide1 = side(t.p1, t.p2, p) >= 0
  let checkSide2 = side(t.p2, t.p3, p) >= 0
  let checkSide3 = side(t.p3, t.p1, p) >= 0
  result = checkSide1 and checkSide2 and checkSide3


func accuratePointInTriangle(t: Triangle; p: Point): bool =
  if not t.pointInTriangleBoundingBox(p):
    return false
  if t.nativePointInTriangle(p):
    return true
  if distanceSquarePointToSegment(t.p1, t.p2, p) <= Eps2 or
     distanceSquarePointToSegment(t.p3, t.p1, p) <= Eps2:
    return true


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

func `$`(t: Triangle): string = &"Triangle[{t.p1}, {t.p2}, {t.p3}]"

func contains(t: Triangle; p: Point): bool = t.accuratePointInTriangle(p)


when isMainModule:

  proc test(t: Triangle; p: Point) =
    echo t
    echo &"Point {p} is within triangle ? {p in t}"

  var p1: Point = (1.5, 2.4)
  var p2: Point = (5.1, -3.1)
  var p3: Point = (-3.8, 1.2)
  var tri = initTriangle(p1, p2, p3)
  test(tri, (0.0, 0.0))
  test(tri, (0.0, 1.0))
  test(tri, (3.0, 1.0))
  echo()
  p1 = (1 / 10, 1 / 9)
  p2 = (100 / 8, 100 / 3)
  p3 = (100 / 4, 100 / 9)
  tri = initTriangle(p1, p2, p3)
  let pt = (p1.x + 3.0 / 7 * (p2.x - p1.x), p1.y + 3.0 / 7 * (p2.y - p1.y))
  test(tri, pt)
  echo()
  p3 = (-100 / 8, 100 / 6)
  tri = initTriangle(p1, p2, p3)
  test(tri, pt)
Output:
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0.0, 0.0) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0.0, 1.0) is within triangle ? true
Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3.0, 1.0) is within triangle ? false

Triangle[(0.1, 0.1111111111111111), (12.5, 33.33333333333334), (25.0, 11.11111111111111)]
Point (5.414285714285714, 14.34920634920635) is within triangle ? true

Triangle[(0.1, 0.1111111111111111), (12.5, 33.33333333333334), (-12.5, 16.66666666666667)]
Point (5.414285714285714, 14.34920634920635) is within triangle ? true

PascalABC.NET

type Point = auto class
  x,y: real;
end;

function Sign(pt1,pt2,pt3: Point)
  := (pt1.x - pt3.x) * (pt2.y - pt3.y) - (pt2.x - pt3.x) * (pt1.y - pt3.y);
  
function InTriangle(p,pt1,pt2,pt3: Point): boolean;
begin
  var val1 := Sign(p, pt1, pt2);
  var val2 := Sign(p, pt2, pt3);
  var val3 := Sign(p, pt3, pt1);
  var notanyneg := (val1 >= 0) and (val2 >= 0) and (val3 >= 0);
  var notanypos := (val1 <= 0) and (val2 <= 0) and (val3 <= 0);
  Result := notanyneg or notanypos;  
end;  
  
begin
  var p1 := new Point(1.5, 2.4);
  var p2 := new Point(5.1, -3.1);
  var p3 := new Point(-3.8, 0.5);
  for var x := 0 to 5 do
  begin
    var p := new Point(x,0);
    Println($'{p} is in triangle ({p1},{p2},{p3}): {InTriangle(p,p1,p2,p3)}');
  end
end.
Output:
(0,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): True
(1,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): True
(2,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): True
(3,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): True
(4,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): False
(5,0) is in triangle ((1.5,2.4),(5.1,-3.1),(-3.8,0.5)): False

Perl

Translate the Java program at this blog post and data set is taken from the Raku entry.

# 20201123 added Perl programming solution

use strict;
use warnings;

use List::AllUtils qw(min max natatime);
use constant EPSILON        =>           0.001;
use constant EPSILON_SQUARE => EPSILON*EPSILON;

sub side {
   my ($x1, $y1, $x2, $y2, $x, $y) = @_;
   return ($y2 - $y1)*($x - $x1) + (-$x2 + $x1)*($y - $y1);
}

sub naivePointInTriangle {
   my ($x1, $y1, $x2, $y2, $x3, $y3, $x, $y) = @_;
   my $checkSide1 = side($x1, $y1, $x2, $y2, $x, $y) >= 0 ;
   my $checkSide2 = side($x2, $y2, $x3, $y3, $x, $y) >= 0 ;
   my $checkSide3 = side($x3, $y3, $x1, $y1, $x, $y) >= 0 ;
   return $checkSide1 && $checkSide2 && $checkSide3  || 0 ;
}

sub pointInTriangleBoundingBox {
   my ($x1, $y1, $x2, $y2, $x3, $y3, $x, $y) = @_;
   my $xMin = min($x1, min($x2, $x3)) - EPSILON;
   my $xMax = max($x1, max($x2, $x3)) + EPSILON;
   my $yMin = min($y1, min($y2, $y3)) - EPSILON;
   my $yMax = max($y1, max($y2, $y3)) + EPSILON;
   ( $x < $xMin || $xMax < $x || $y < $yMin || $yMax < $y ) ? 0 : 1
}

sub distanceSquarePointToSegment {
   my ($x1, $y1, $x2, $y2, $x, $y) = @_;
   my $p1_p2_squareLength = ($x2 - $x1)**2 + ($y2 - $y1)**2;
   my $dotProduct = ($x-$x1)*($x2-$x1)+($y-$y1)*($y2-$y1) ;
   if ( $dotProduct < 0 ) {
      return ($x - $x1)**2 + ($y - $y1)**2;
   } elsif ( $dotProduct <= $p1_p2_squareLength ) {
      my $p_p1_squareLength = ($x1 - $x)**2 + ($y1 - $y)**2;
      return $p_p1_squareLength - $dotProduct**2 / $p1_p2_squareLength;
   } else {
      return ($x - $x2)**2 + ($y - $y2)**2;
   }
}

sub accuratePointInTriangle {
   my ($x1, $y1, $x2, $y2, $x3, $y3, $x, $y) = @_;
   return 0 unless pointInTriangleBoundingBox($x1,$y1,$x2,$y2,$x3,$y3,$x,$y);
   return 1 if ( naivePointInTriangle($x1, $y1, $x2, $y2, $x3, $y3, $x, $y)
      or distanceSquarePointToSegment($x1, $y1, $x2, $y2, $x, $y) <= EPSILON_SQUARE
      or distanceSquarePointToSegment($x2, $y2, $x3, $y3, $x, $y) <= EPSILON_SQUARE
      or distanceSquarePointToSegment($x3, $y3, $x1, $y1, $x, $y) <= EPSILON_SQUARE);
   return 0
}

my @DATA = (1.5, 2.4, 5.1, -3.1, -3.8, 0.5);

for my $point ( [0,0] , [0,1] ,[3,1] ) {
   print "Point (", join(',',@$point), ") is within triangle ";
   my $iter = natatime 2, @DATA;
   while ( my @vertex = $iter->()) { print '(',join(',',@vertex),') ' }
   print ': ',naivePointInTriangle (@DATA, @$point) ? 'True' : 'False', "\n" ;
}
Output:
Point (0,0) is within triangle (1.5,2.4) (5.1,-3.1) (-3.8,0.5) : True
Point (0,1) is within triangle (1.5,2.4) (5.1,-3.1) (-3.8,0.5) : True
Point (3,1) is within triangle (1.5,2.4) (5.1,-3.1) (-3.8,0.5) : False

Phix

Both the following as well as some further experiments can be found in demo\rosetta\Within_triangle.exw

using convex_hull

Using convex_hull() from Convex_hull#Phix

with javascript_semantics
constant p0 = {0,0},
         p1 = {0,1},    
         p2 = {3,1},    
         triangle = {{3/2, 12/5}, {51/10, -31/10}, {-19/5, 1/2}}
function inside(sequence p)
    return sort(convex_hull({p}&triangle))==sort(deep_copy(triangle))
end function
printf(1,"Point %v is with triangle %v?:%t\n",{p0,triangle,inside(p0)})
printf(1,"Point %v is with triangle %v?:%t\n",{p1,triangle,inside(p1)})
printf(1,"Point %v is with triangle %v?:%t\n",{p2,triangle,inside(p2)})
Output:
Point {0,0} is with triangle {{1.5,2.4},{5.1,-3.1},{-3.8,0.5}}?:true
Point {0,1} is with triangle {{1.5,2.4},{5.1,-3.1},{-3.8,0.5}}?:true
Point {3,1} is with triangle {{1.5,2.4},{5.1,-3.1},{-3.8,0.5}}?:false

trans python

(same output)

with javascript_semantics
constant p0 = {0,0},
         p1 = {0,1},    
         p2 = {3,1},    
         triangle = {{3/2, 12/5}, {51/10, -31/10}, {-19/5, 1/2}}

function side(sequence p1, p2, p3)
    -- which side of plane cut by line (p2, p3) is p1 on?
    atom {x1, y1} = p1,
         {x2, y2} = p2,
         {x3, y3} = p3
    return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3)
end function 
 
function iswithin(sequence point, triangle)
--
--  Determine if point is within triangle.
--  If so, the point will be on the same side of each of the half planes
--  defined by vectors p1p2, p2p3, and p3p1. side is positive if outside,
--  negative if inside such a plane. All should be non-negative or all 
--  non-positive if the point is within the triangle.
--
    sequence {pt1, pt2, pt3} = triangle
    atom side12 = side(point, pt1, pt2),
         side23 = side(point, pt2, pt3),
         side31 = side(point, pt3, pt1)
    bool all_non_neg = side12 >= 0 and side23 >= 0 and side31 >= 0,
         all_non_pos = side12 <= 0 and side23 <= 0 and side31 <= 0
    return all_non_neg or all_non_pos
end function 
 
printf(1,"point %v is with triangle %v?:%t\n",{p0,triangle,iswithin(p0,triangle)})
printf(1,"point %v is with triangle %v?:%t\n",{p1,triangle,iswithin(p1,triangle)})
printf(1,"point %v is with triangle %v?:%t\n",{p2,triangle,iswithin(p2,triangle)})

Python

""" find if point is in a triangle """

from sympy.geometry import Point, Triangle

def sign(pt1, pt2, pt3):
    """ which side of plane cut by line (pt2, pt3) is pt1 on? """
    return (pt1.x - pt3.x) * (pt2.y - pt3.y) - (pt2.x - pt3.x) * (pt1.y - pt3.y)


def iswithin(point, pt1, pt2, pt3):
    """ 
    Determine if point is within triangle formed by points p1, p2, p3.
    If so, the point will be on the same side of each of the half planes
    defined by vectors p1p2, p2p3, and p3p1. zval is positive if outside,
    negative if inside such a plane. All should be positive or all negative
    if point is within the triangle.
    """
    zval1 = sign(point, pt1, pt2)
    zval2 = sign(point, pt2, pt3)
    zval3 = sign(point, pt3, pt1)
    notanyneg = zval1 >= 0 and zval2 >= 0 and zval3 >= 0
    notanypos = zval1 <= 0 and zval2 <= 0 and zval3 <= 0
    return notanyneg or notanypos

if __name__ == "__main__":
    POINTS = [Point(0, 0)]
    TRI = Triangle(Point(1.5, 2.4), Point(5.1, -3.1), Point(-3.8, 0.5))
    for pnt in POINTS:
        a, b, c = TRI.vertices
        isornot = "is" if iswithin(pnt, a, b, c) else "is not"
        print("Point", pnt, isornot, "within the triangle", TRI)
Output:
Point Point2D(0, 0) is within the triangle Triangle(Point2D(3/2, 12/5), Point2D(51/10, -31/10), Point2D(-19/5, 1/2))

Racket

Racket has exact numbers in its numerical tower... so I don't see much motivation to accomodate rounding errors. This is why the implementation _fails_ the second imprecise test, whereas other implementations pass it. That point is very close to the edge of the triange. If your edge is fat enough (epsilon), it will fall inside. If it is infinitessimal (i.e. exact), it is on the outside.

I would probably use the dot-product version, if only because it requires less (no) division.

#lang racket/base

(define-syntax-rule (all-between-0..1? x ...)
  (and (<= 0 x 1) ...))

(define (point-in-triangle?/barycentric x1 y1 x2 y2 x3 y3)
  (let* ((y2-y3 (- y2 y3))
         (x1-x3 (- x1 x3))
         (x3-x2 (- x3 x2))
         (y1-y3 (- y1 y3))
         (d (+ (* y2-y3 x1-x3) (* x3-x2 y1-y3))))
    (λ (x y)
      (define a (/ (+ (* x3-x2 (- y y3)) (* y2-y3 (- x x3))) d))
      (define b (/ (- (* x1-x3 (- y y3)) (* y1-y3 (- x x3))) d))
      (define c (- 1 a b))
      (all-between-0..1? a b c))))

(define (point-in-triangle?/parametric x1 y1 x2 y2 x3 y3)
  (let ((dp (+ (* x1 (- y2 y3)) (* y1 (- x3 x2)) (* x2 y3) (- (* y2 x3)))))
    (λ (x y)
      (define t1 (/ (+ (* x (- y3 y1)) (* y (- x1 x3)) (- (* x1 y3)) (* y1 x3)) dp))
      (define t2 (/ (+ (* x (- y2 y1)) (* y (- x1 x2)) (- (* x1 y2)) (* y1 x2)) (- dp)))
      (all-between-0..1? t1 t2 (+ t1 t2)))))

(define (point-in-triangle?/dot-product X1 Y1 X2 Y2 X3 Y3)
  (λ (x y)
    (define (check-side x1 y1 x2 y2)
      (>= (+ (* (- y2 y1) (- x x1)) (* (- x1 x2) (- y y1))) 0))
    (and
     (check-side X1 Y1 X2 Y2)
     (check-side X2 Y2 X3 Y3)
     (check-side X3 Y3 X1 Y1))))

(module+ main
  (require rackunit)

  (define (run-tests point-in-triangle?)
    (define pit?-1 (point-in-triangle? #e1.5 #e2.4 #e5.1 #e-3.1 #e-3.8 #e1.2))
    (check-true (pit?-1 0 0))
    (check-true (pit?-1 0 1))
    (check-false (pit?-1 3 1))
    (check-true ((point-in-triangle? 1/10 1/9 25/2 100/3  25   10/9) #e5.414285714285714 #e14.349206349206348))
    ; exactly speaking, point is _not_ in the triangle
    (check-false ((point-in-triangle? 1/10 1/9 25/2 100/3 -25/2 50/3) #e5.414285714285714 #e14.349206349206348)))

  (run-tests point-in-triangle?/barycentric)
  (run-tests point-in-triangle?/parametric)
  (run-tests point-in-triangle?/dot-product))
Output:

no output means all tests passed


Raku

Reusing code from the Convex hull task and some logic from the Determine if two triangles overlap task.

class Point {
    has Real $.x is rw;
    has Real $.y is rw;
    method gist { [~] '(', self.x,', ', self.y, ')' };
}

sub sign (Point $a, Point $b, Point $c) {
    ($b.x - $a.x)*($c.y - $a.y) - ($b.y - $a.y)*($c.x - $a.x);
}

sub triangle (*@points where *.elems == 6) {
    @points.batch(2).map: { Point.new(:x(.[0]),:y(.[1])) };
}

sub is-within ($point, @triangle is copy) {
   my @signs = sign($point, |(@triangle.=rotate)[0,1]) xx 3;
   so (all(@signs) >= 0) or so(all(@signs) <= 0);
}

my @triangle = triangle((1.5, 2.4), (5.1, -3.1), (-3.8, 0.5));

for Point.new(:x(0),:y(0)),
    Point.new(:x(0),:y(1)),
    Point.new(:x(3),:y(1))
  -> $point {
    say "Point {$point.gist} is within triangle {join ', ', @triangle».gist}: ",
        $point.&is-within: @triangle
}
Output:
Point (0, 0) is within triangle (1.5, 2.4), (5.1, -3.1), (-3.8, 0.5): True
Point (0, 1) is within triangle (1.5, 2.4), (5.1, -3.1), (-3.8, 0.5): True
Point (3, 1) is within triangle (1.5, 2.4), (5.1, -3.1), (-3.8, 0.5): False

REXX

Translation of: Python


Extra certification code was added to verify that the   X,Y   coördinates for the points are not missing and are numeric.

/*REXX program determines if a   specified point   is within a   specified triangle.    */
parse arg p a b c .                              /*obtain optional arguments from the CL*/
if p=='' | p==","  then p= '(0,0)'               /*Not specified?  Then use the default.*/
if a=='' | a==","  then a= '(1.5,2.4)'           /* "      "         "   "   "     "    */
if b=='' | b==","  then b= '(5.1,-3.1)'          /* "      "         "   "   "     "    */
if c=='' | c==","  then c= '(-3.8,0.5)'          /* "      "         "   "   "     "    */
if  ?(p, a, b, c)  then @= ' is '                /*Is the point  inside the triangle ?  */
                   else @= " isn't "             /* "  "    "   outside  "      "       */
say 'point'   p    @    " within the triangle "      a     ','       b       ","       c
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
cert: parse arg z,W; if datatype(z,'N')  then return z; call serr z /*return coördinate.*/
serr: say W 'data point '  z  " isn't numeric or missing."; exit 13 /*tell error message*/
x: procedure; parse arg "(" x ','      ;  return cert(x,"X")  /*return the X coördinate.*/
y: procedure; parse arg       ',' y ")";  return cert(y,"Y")  /*   "    "  Y      "     */
$: parse arg aa,bb,cc;  return (x(aa)-x(cc)) *(y(bb)-y(cc)) - (x(bb)-x(cc)) *(y(aa)-y(cc))
?: #1=$(p,a,b); #2=$(p,b,c); #3=$(p,c,a); return (#1>=0&#2>=0&#3>=0) | (#1<=0&#2<=0&#3<=0)
output   when using the default triangle and the point at:   (0,0)
point (0,0)   is   within the triangle  (1.5,2.4) , (5.1,-3.1) , (-3.8,0.5)
output   when using the default triangle and the point at:   (0,1)
point (0,1)   is   within the triangle  (1.5,2.4) , (5.1,-3.1) , (-3.8,0.5)
output   when using the default triangle and the point at:   (3,1)
point (3,1)   isn't   within the triangle  (1.5,2.4) , (5.1,-3.1) , (-3.8,0.5)

RPL

Translation of: Ada
Works with: HP version 48G
≪ { } → points
   ≪ 1 4 START C→R 1 →V3 'points' STO+ NEXT
      1 3 FOR j points j GET V→ NEXT
      { 3 3 } →ARRY DET ABS
      1 3 FOR j
         points j GET V→
         points j 1 + 4 MOD 1 MAX GET V→
         points 4 GET V→ 
         { 3 3 } →ARRY DET ABS
      NEXT
      + + ==
≫ ≫ 'INTRI?' STO
(1 0) (2 0) (0 2) (0 0) INTRI?
(-1 0) (-1 -1) (2 2) (0 0) INTRI?
Output:
2: 0
1: 1

Ruby

Translation of: Go
EPS = 0.001
EPS_SQUARE = EPS * EPS

def side(x1, y1, x2, y2, x, y)
    return (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1)
end

def naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    checkSide1 = side(x1, y1, x2, y2, x, y) >= 0
    checkSide2 = side(x2, y2, x3, y3, x, y) >= 0
    checkSide3 = side(x3, y3, x1, y1, x, y) >= 0
    return checkSide1 && checkSide2 && checkSide3
end

def pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y)
    xMin = [x1, x2, x3].min - EPS
    xMax = [x1, x2, x3].max + EPS
    yMin = [y1, y2, y3].min - EPS
    yMax = [y1, y2, y3].max + EPS
    return !(x < xMin || xMax < x || y < yMin || yMax < y)
end

def distanceSquarePointToSegment(x1, y1, x2, y2, x, y)
    p1_p2_squareLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
    dotProduct = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_squareLength
    if dotProduct < 0 then
        return (x - x1) * (x - x1) + (y - y1) * (y - y1)
    end
    if dotProduct <= 1 then
        p_p1_squareLength = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength
    end
    return (x - x2) * (x - x2) + (y - y2) * (y - y2)
end

def accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    if !pointInTriangleBoundingBox(x1, y1, x2, y2, x3, y3, x, y) then
        return false
    end
    if naivePointInTriangle(x1, y1, x2, y2, x3, y3, x, y) then
        return true
    end
    if distanceSquarePointToSegment(x1, y1, x2, y2, x, y) <= EPS_SQUARE then
        return true
    end
    if distanceSquarePointToSegment(x2, y2, x3, y3, x, y) <= EPS_SQUARE then
        return true
    end
    if distanceSquarePointToSegment(x3, y3, x1, y1, x, y) <= EPS_SQUARE then
        return true
    end
    return false
end

def main
    pts = [[0, 0], [0, 1], [3, 1]]
    tri = [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
    print "Triangle is ", tri, "\n"
    x1, y1 = tri[0][0], tri[0][1]
    x2, y2 = tri[1][0], tri[1][1]
    x3, y3 = tri[2][0], tri[2][1]
    for pt in pts
        x, y = pt[0], pt[1]
        within = accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
        print "Point ", pt, " is within triangle? ", within, "\n"
    end
    print "\n"

    tri = [[0.1, 1.0 / 9.0], [12.5, 100.0 / 3.0], [25.0, 100.0 / 9.0]]
    print "Triangle is ", tri, "\n"
    x1, y1 = tri[0][0], tri[0][1]
    x2, y2 = tri[1][0], tri[1][1]
    x3, y3 = tri[2][0], tri[2][1]
    x = x1 + (3.0 / 7.0) * (x2 - x1)
    y = y1 + (3.0 / 7.0) * (y2 - y1)
    pt = [x, y]
    within = accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    print "Point ", pt, " is within triangle? ", within, "\n"
    print "\n"

    tri = [[0.1, 1.0 / 9.0], [12.5, 100.0 / 3.0], [-12.5, 100.0 / 6.0]]
    print "Triangle is ", tri, "\n"
    x3, y3 = tri[2][0], tri[2][1]
    within = accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
    print "Point ", pt, " is within triangle? ", within, "\n"
end

main()
Output:
Triangle is [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
Point [0, 0] is within triangle? true
Point [0, 1] is within triangle? true
Point [3, 1] is within triangle? false

Triangle is [[0.1, 0.1111111111111111], [12.5, 33.333333333333336], [25.0, 11.11111111111111]]
Point [5.414285714285714, 14.349206349206348] is within triangle? true

Triangle is [[0.1, 0.1111111111111111], [12.5, 33.333333333333336], [-12.5, 16.666666666666668]]
Point [5.414285714285714, 14.349206349206348] is within triangle? true

Rust

Works with: Rust version 1.7.3
Translation of: D
const EPS: f64 = 0.001;
const EPS_SQUARE: f64 = EPS * EPS;

fn side(x1: f64, y1: f64, x2: f64, y2: f64, x: f64, y: f64) -> f64 {
    (y2 - y1) * (x - x1) + (-x2 + x1) * (y - y1)
}

fn naive_point_in_triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x: f64, y: f64) -> bool {
    let check_side1 = side(x1, y1, x2, y2, x, y) >= 0.0;
    let check_side2 = side(x2, y2, x3, y3, x, y) >= 0.0;
    let check_side3 = side(x3, y3, x1, y1, x, y) >= 0.0;
    check_side1 && check_side2 && check_side3
}

fn point_in_triangle_bounding_box(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x: f64, y: f64) -> bool {
    let x_min = f64::min(x1, f64::min(x2, x3)) - EPS;
    let x_max = f64::max(x1, f64::max(x2, x3)) + EPS;
    let y_min = f64::min(y1, f64::min(y2, y3)) - EPS;
    let y_max = f64::max(y1, f64::max(y2, y3)) + EPS;
    !(x < x_min || x_max < x || y < y_min || y_max < y)
}

fn distance_square_point_to_segment(x1: f64, y1: f64, x2: f64, y2: f64, x: f64, y: f64) -> f64 {
    let p1_p2_square_length = (x2 - x1).powi(2) + (y2 - y1).powi(2);
    let dot_product = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / p1_p2_square_length;
    if dot_product < 0.0 {
        (x - x1).powi(2) + (y - y1).powi(2)
    } else if dot_product <= 1.0 {
        let p_p1_square_length = (x1 - x).powi(2) + (y1 - y).powi(2);
        p_p1_square_length - dot_product.powi(2) * p1_p2_square_length
    } else {
        (x - x2).powi(2) + (y - y2).powi(2)
    }
}

fn accurate_point_in_triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x: f64, y: f64) -> bool {
    if !point_in_triangle_bounding_box(x1, y1, x2, y2, x3, y3, x, y) {
        return false;
    }
    if naive_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y) {
        return true;
    }
    if distance_square_point_to_segment(x1, y1, x2, y2, x, y) <= EPS_SQUARE {
        return true;
    }
    if distance_square_point_to_segment(x2, y2, x3, y3, x, y) <= EPS_SQUARE {
        return true;
    }
    if distance_square_point_to_segment(x3, y3, x1, y1, x, y) <= EPS_SQUARE {
        return true;
    }
    false
}

fn print_point(x: f64, y: f64) {
    print!("({}, {})", x, y);
}

fn print_triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
    print!("Triangle is [");
    print_point(x1, y1);
    print!(", ");
    print_point(x2, y2);
    print!(", ");
    print_point(x3, y3);
    println!("]");
}

fn test(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x: f64, y: f64) {
    print_triangle(x1, y1, x2, y2, x3, y3);
    print!("Point ");
    print_point(x, y);
    print!(" is within triangle? ");
    println!("{}", accurate_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y));
}

fn main() {
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0.0, 0.0);
    println!();
    
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 0.0, 1.0);
    println!();
    
    test(1.5, 2.4, 5.1, -3.1, -3.8, 1.2, 3.0, 1.0);
    println!();
    
    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, 25.0, 11.11111111111111, 5.414285714285714, 14.349206349206348);
    println!();
    
    test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348);
    println!();
}
Output:
Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 0) is within triangle? true

Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (0, 1) is within triangle? true

Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Point (3, 1) is within triangle? false

Triangle is [(0.1, 0.1111111111111111), (12.5, 33.333333333333336), (25, 11.11111111111111)]
Point (5.414285714285714, 14.349206349206348) is within triangle? true

Triangle is [(0.1, 0.1111111111111111), (12.5, 33.333333333333336), (-12.5, 16.666666666666668)]
Point (5.414285714285714, 14.349206349206348) is within triangle? true

V (Vlang)

Translation of: go
import math

const eps = 0.001
const eps_square = eps * eps
 
fn side(x1 f64, y1 f64, x2 f64, y2 f64, x f64, y f64) f64 {
    return (y2-y1)*(x-x1) + (-x2+x1)*(y-y1)
}
 
fn native_point_in_triangle(x1 f64, y1 f64, x2 f64, y2 f64, x3 f64, y3 f64, x f64, y f64) bool {
    check_side1 := side(x1, y1, x2, y2, x, y) >= 0
    check_side2 := side(x2, y2, x3, y3, x, y) >= 0
    check_side3 := side(x3, y3, x1, y1, x, y) >= 0
    return check_side1 && check_side2 && check_side3
}
 
fn point_in_triangle_bounding_box(x1 f64, y1 f64, x2 f64, y2 f64, x3 f64, y3 f64, x f64, y f64) bool {
    x_min := math.min(x1, math.min(x2, x3)) - eps
    x_max := math.max(x1, math.max(x2, x3)) + eps
    y_min := math.min(y1, math.min(y2, y3)) - eps
    y_max := math.max(y1, math.max(y2, y3)) + eps
    return !(x < x_min || x_max < x || y < y_min || y_max < y)
}
 
fn distance_square_point_to_segment(x1 f64, y1 f64, x2 f64, y2 f64, x f64, y f64) f64 {
    pq_p2_square_length := (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)
    dot_product := ((x-x1)*(x2-x1) + (y-y1)*(y2-y1)) / pq_p2_square_length
    if dot_product < 0 {
        return (x-x1)*(x-x1) + (y-y1)*(y-y1)
    } else if dot_product <= 1 {
        p_p1_square_length := (x1-x)*(x1-x) + (y1-y)*(y1-y)
        return p_p1_square_length - dot_product*dot_product*pq_p2_square_length
    } else {
        return (x-x2)*(x-x2) + (y-y2)*(y-y2)
    }
}
 
fn accurate_point_in_triangle(x1 f64, y1 f64, x2 f64, y2 f64, x3 f64, y3 f64, x f64, y f64) bool {
    if !point_in_triangle_bounding_box(x1, y1, x2, y2, x3, y3, x, y) {
        return false
    }
    if native_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y) {
        return true
    }
    if distance_square_point_to_segment(x1, y1, x2, y2, x, y) <= eps_square {
        return true
    }
    if distance_square_point_to_segment(x2, y2, x3, y3, x, y) <= eps_square {
        return true
    }
    if distance_square_point_to_segment(x3, y3, x1, y1, x, y) <= eps_square {
        return true
    }
    return false
}
 
fn main() {
    pts := [[f64(0), 0], [f64(0), 1], [f64(3), 1]]
    mut tri := [[3.0 / 2, 12.0 / 5], [51.0 / 10, -31.0 / 10], [-19.0 / 5, 1.2]]
    println("Triangle is $tri")
    mut x1, mut y1 := tri[0][0], tri[0][1]
    mut x2, mut y2 := tri[1][0], tri[1][1]
    mut x3, mut y3 := tri[2][0], tri[2][1]
    for pt in pts {
        x, y := pt[0], pt[1]
        within := accurate_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y)
        println("Point $pt is within triangle? $within")
    }
    println('')
    tri = [[1.0 / 10, 1.0 / 9], [100.0 / 8, 100.0 / 3], [100.0 / 4, 100.0 / 9]]
    println("Triangle is $tri")
    x1, y1 = tri[0][0], tri[0][1]
    x2, y2 = tri[1][0], tri[1][1]
    x3, y3 = tri[2][0], tri[2][1]
    x := x1 + (3.0/7)*(x2-x1)
    y := y1 + (3.0/7)*(y2-y1)
    pt := [x, y]
    mut within := accurate_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y)
    println("Point $pt is within triangle ? $within")
    println('')
    tri = [[1.0 / 10, 1.0 / 9], [100.0 / 8, 100.0 / 3], [-100.0 / 8, 100.0 / 6]]
    println("Triangle is $tri")
    x3 = tri[2][0]
    y3 = tri[2][1]
    within = accurate_point_in_triangle(x1, y1, x2, y2, x3, y3, x, y)
    println("Point $pt is within triangle ? $within")
}
Output:
Triangle is [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
Point [0, 0] is within triangle? true
Point [0, 1] is within triangle? true
Point [3, 1] is within triangle? false

Triangle is [[0.1, 0.1111111111111111], [12.5, 33.333333333333336], [25, 11.11111111111111]]
Point [5.414285714285714, 14.349206349206348] is within triangle ? true

Triangle is [[0.1, 0.1111111111111111], [12.5, 33.333333333333336], [-12.5, 16.666666666666668]]
Point [5.414285714285714, 14.349206349206348] is within triangle ? true

Wren

This is a translation of the ActionScript code for the 'accurate' method in the first referenced article above.

var EPS = 0.001
var EPS_SQUARE = EPS * EPS

var side = Fn.new { |x1, y1, x2, y2, x, y|
    return (y2 - y1)*(x - x1) + (-x2 + x1)*(y - y1)
}

var naivePointInTriangle = Fn.new { |x1, y1, x2, y2, x3, y3, x, y|
    var checkSide1 = side.call(x1, y1, x2, y2, x, y) >= 0
    var checkSide2 = side.call(x2, y2, x3, y3, x, y) >= 0
    var checkSide3 = side.call(x3, y3, x1, y1, x, y) >= 0
    return checkSide1 && checkSide2 && checkSide3
}

var pointInTriangleBoundingBox = Fn.new { |x1, y1, x2, y2, x3, y3, x, y|
    var xMin = x1.min(x2.min(x3)) - EPS
    var xMax = x1.max(x2.max(x3)) + EPS
    var yMin = y1.min(y2.min(y3)) - EPS
    var yMax = y1.max(y2.max(y3)) + EPS
    return !(x < xMin || xMax < x || y < yMin || yMax < y)
}

var distanceSquarePointToSegment = Fn.new { |x1, y1, x2, y2, x, y|
    var p1_p2_squareLength = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)
    var dotProduct = ((x - x1)*(x2 - x1) + (y - y1)*(y2 - y1)) / p1_p2_squareLength
    if (dotProduct < 0) {
        return (x - x1)*(x - x1) + (y - y1)*(y - y1)
    } else if (dotProduct <= 1) {
        var p_p1_squareLength = (x1 - x)*(x1 - x) + (y1 - y)*(y1 - y)
        return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength
    } else {
        return (x - x2)*(x - x2) + (y - y2)*(y - y2)
    }
}

var accuratePointInTriangle = Fn.new { |x1, y1, x2, y2, x3, y3, x, y|
    if (!pointInTriangleBoundingBox.call(x1, y1, x2, y2, x3, y3, x, y)) return false
    if (naivePointInTriangle.call(x1, y1, x2, y2, x3, y3, x, y)) return true
    if (distanceSquarePointToSegment.call(x1, y1, x2, y2, x, y) <= EPS_SQUARE) return true
    if (distanceSquarePointToSegment.call(x2, y2, x3, y3, x, y) <= EPS_SQUARE) return true
    if (distanceSquarePointToSegment.call(x3, y3, x1, y1, x, y) <= EPS_SQUARE) return true
    return false
}

var pts = [ [0, 0], [0, 1], [3, 1]]
var tri = [ [3/2, 12/5], [51/10, -31/10], [-19/5, 1.2] ]
System.print("Triangle is %(tri)")
var x1 = tri[0][0]
var y1 = tri[0][1]
var x2 = tri[1][0]
var y2 = tri[1][1]
var x3 = tri[2][0]
var y3 = tri[2][1]

for (pt in pts) {
    var x = pt[0]
    var y = pt[1]
    var within = accuratePointInTriangle.call(x1, y1, x2, y2, x3, y3, x, y)
    System.print("Point %(pt) is within triangle ? %(within)")
}
System.print()
tri = [ [1/10, 1/9], [100/8, 100/3], [100/4, 100/9] ]
System.print("Triangle is %(tri)")
x1 = tri[0][0]
y1 = tri[0][1]
x2 = tri[1][0]
y2 = tri[1][1]
x3 = tri[2][0]
y3 = tri[2][1]
var x = x1 + (3/7)*(x2 - x1)
var y = y1 + (3/7)*(y2 - y1)
var pt = [x, y]
var within = accuratePointInTriangle.call(x1, y1, x2, y2, x3, y3, x, y)
System.print("Point %(pt) is within triangle ? %(within)")
System.print()
tri = [ [1/10, 1/9], [100/8, 100/3], [-100/8, 100/6] ]
System.print("Triangle is %(tri)")
x3 = tri[2][0]
y3 = tri[2][1]
within = accuratePointInTriangle.call(x1, y1, x2, y2, x3, y3, x, y)
System.print("Point %(pt) is within triangle ? %(within)")
Output:
Triangle is [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
Point [0, 0] is within triangle ? true
Point [0, 1] is within triangle ? true
Point [3, 1] is within triangle ? false

Triangle is [[0.1, 0.11111111111111], [12.5, 33.333333333333], [25, 11.111111111111]]
Point [5.4142857142857, 14.349206349206] is within triangle ? true

Triangle is [[0.1, 0.11111111111111], [12.5, 33.333333333333], [-12.5, 16.666666666667]]
Point [5.4142857142857, 14.349206349206] is within triangle ? true

XPL0

func real Dot(W,X,Y,Z);         \Return the dot product of two 2D vectors
real W,X,Y,Z;                   \ (W-X) dot (Y-Z)
real WX(2), YZ(2);
[WX(0):= W(0)-X(0);  WX(1):= W(1)-X(1);
 YZ(0):= Y(0)-Z(0);  YZ(1):= Y(1)-Z(1);
return WX(0)*YZ(0) + WX(1)*YZ(1);
];

real A,B,C;                     \triangle

func PointInTri(P);             \Return 'true' if point P is inside triangle ABC
real P;
int  S0,S1,S2;          \signs
[S0:= Dot(P,A,B,A) >= 0.0;
 S1:= Dot(P,B,C,B) >= 0.0;
 S2:= Dot(P,C,A,C) >= 0.0;
return S0=S1 & S1=S2 & S2=S0;
];

[A:= [10.5, 6.3];  B:= [13.5, 3.6];  C:= [ 3.3, -1.6];
Text(0, if PointInTri([10.0, 3.0]) then "inside" else "outside");  CrLf(0);
Text(0, if PointInTri([-5.0,-2.2]) then "inside" else "outside");  CrLf(0);
Text(0, if PointInTri([10.5, 6.3]) then "inside" else "outside");  CrLf(0);
]
Output:
inside
outside
inside
Cookies help us deliver our services. By using our services, you agree to our use of cookies.