Find if a point is within a triangle: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(44 intermediate revisions by 22 users not shown)
Line 28:
:* Wolfram entry [[https://mathworld.wolfram.com/TriangleInterior.html]]
<br><br>
 
=={{header|11l}}==
{{trans|Kotlin}}
 
<syntaxhighlight lang="11l">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
(Float, Float) p1, p2, p3
 
F (p1, p2, p3)
.p1 = p1
.p2 = p2
.p3 = 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)</syntaxhighlight>
 
{{out}}
<pre>
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
</pre>
 
 
=={{header|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.
 
<syntaxhighlight lang="ada">-- 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;
</syntaxhighlight>
<syntaxhighlight lang="ada">-- 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;
</syntaxhighlight>
<syntaxhighlight lang="ada">-- 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;
</syntaxhighlight>
 
{{out}}
<pre>
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
</pre>
 
=={{header|ALGOL 68}}==
Line 33 ⟶ 214:
With additional material
{{Trans|Wren}}
<syntaxhighlight lang="algol68">BEGIN # determine whether a point is within a triangle or not #
The Common Lisp algorithm (at least, as translated to Algol 68) does not handle the additional Wren test cases. The more accurate algorithm translated from the Wren sample does handle these cases.
<lang algol68>BEGIN # determine whether a point is within a triangle or not #
# tolerance for the accurate test #
REAL eps = 0.001;
Line 107 ⟶ 287:
, ( 0.1, 0.11111111111111 ), ( 12.5, 33.333333333333 ), ( -12.5, 16.666666666667 )
)
END</langsyntaxhighlight>
{{out}}
<pre>
Line 118 ⟶ 298:
[ 5.4143, 14.3492] in ( [ 0.1000, 0.1111], [ 12.5000, 33.3333], [-12.5000, 16.6667]) -> false
</pre>
 
=={{header|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.
 
<syntaxhighlight lang="ats">
(* 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
</syntaxhighlight>
 
{{out}}
<pre>$ 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</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="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"
Line 135 ⟶ 516:
TriArea(x1, y1, x2, y2, x3, y3){
return Abs((x1 * (y2-y3) + x2 * (y3-y1) + x3 * (y1-y2)) / 2)
}</langsyntaxhighlight>
{{out}}
<pre>[0, 0] is within triangle? ture
Line 144 ⟶ 525:
=={{header|C}}==
{{trans|Go}}
<langsyntaxhighlight lang="c">#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
Line 241 ⟶ 622:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>Triangle is [(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Line 258 ⟶ 639:
=={{header|C++}}==
{{trans|C}}
<langsyntaxhighlight lang="cpp">#include <iostream>
 
const double EPS = 0.001;
Line 353 ⟶ 734:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Line 370 ⟶ 751:
 
=={{header|Common Lisp}}==
<syntaxhighlight lang="lisp">
<lang 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
Line 401 ⟶ 782:
(- (car P) (car A)) ))))
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 421 ⟶ 802:
 
=={{header|D}}==
 
{{trans|C++}}
<syntaxhighlight lang="d">
<lang d>import std.algorithm; //.comparison for min and max
import std.algorithm;
import std.stdio;
 
Line 503 ⟶ 885:
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;
Line 512 ⟶ 898:
test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348);
writeln;
}
}</lang>
</syntaxhighlight>
 
{{out}}
<pre>
<pre>Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
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
Line 525 ⟶ 916:
 
Triangle is [(0.1, 0.111111), (12.5, 33.3333), (-12.5, 16.6667)]
Point (5.41429, 14.3492) is within triangle? true</pre>
</pre>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|Types,StdCtrls,ExtCtrls,SysUtils,Graphics}}
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.
 
<syntaxhighlight lang="Delphi">
{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;
 
</syntaxhighlight>
{{out}}
 
[[File:PintInTriangle.png|frame|none]]
<pre>
 
</pre>
 
 
=={{header|Dart}}==
{{trans|C++}}
<syntaxhighlight lang="dart">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('');
}</syntaxhighlight>
 
=={{header|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.
 
[[File:Evaldraw points in triangle.png|thumb|alt=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]]
 
<syntaxhighlight lang="c">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; }</syntaxhighlight>
 
=={{header|Factor}}==
Uses the parametric equations method from [https://totologic.blogspot.com/2014/01/accurate-point-in-triangle-test.html].
<langsyntaxhighlight lang="factor">USING: accessors fry io kernel locals math math.order sequences ;
 
TUPLE: point x y ;
Line 554 ⟶ 1,294:
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 '#'
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 578 ⟶ 1,318:
....................
</pre>
 
=={{header|Fortran}}==
<syntaxhighlight lang="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
</syntaxhighlight>
{{out}}<pre>
Point ( 0.0000000000000000 , 0.0000000000000000 ) is within triangle [( 1.5000000000000000 , 2.4000000953674316 ), ( 5.0999999046325684 , -3.0999999046325684 ), ( -3.7999999523162842 , 1.2000000476837158 )].
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="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
</syntaxhighlight>
{{out}}<pre>........................................
........................................
................@.......................
................@@@.....................
...............@@@@@@...................
..............@@@@@@@@@.................
..............@@@@@@@@@@@...............
.............@@@@@@@@@@@@@@@............
.............@@@@@@@@@@@@@@@@@..........
............@@@@@@@@@@@@@@@@@@@@........
...........@@@@@@@@@@@@@@@@@@@..........
...........@@@@@@@@@@@@@@@@.............
..........@@@@@@@@@@@@@@................
.........@@@@@@@@@@@@...................
.........@@@@@@@@@......................
........@@@@@@@.........................
.......@@@@@............................
.......@@...............................
........................................
........................................
</pre>
 
 
 
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="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
</syntaxhighlight>
{{output}}
[[File:FB Find Point in a Triangle.png]]
 
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 672 ⟶ 1,588:
within = accuratePointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
fmt.Println("Point", pt, "is within triangle ?", within)
}</langsyntaxhighlight>
 
{{out}}
Line 687 ⟶ 1,603:
Point [5.414285714285714 14.349206349206348] is within triangle ? true
</pre>
 
=={{header|GW-BASIC}}==
<syntaxhighlight lang="gwbasic">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</syntaxhighlight>
{{out}}<pre>.........................................
.........................................
.......##................................
.......#####.............................
.......########..........................
........###########......................
........##############...................
........#################................
........####################.............
.........#######################.........
.........##########################......
.........#######################.........
..........###################............
..........################...............
..........##############.................
...........##########....................
...........#######.......................
...........####..........................
...........#.............................
.........................................
</pre>
 
=={{header|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.
 
<syntaxhighlight lang="haskell">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</syntaxhighlight>
 
Testing
<syntaxhighlight lang="haskell">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)</syntaxhighlight>
 
<pre>λ> tests
[Boundary,Boundary,Boundary,Boundary,Boundary,Boundary]
[Inside,Inside,Inside,Inside,Inside]
[Outside,Outside,Outside,Outside]
[Boundary,Boundary,Outside,Outside]
 
λ> putStrLn test2
·····················
·····················
··+··················
···+∗∗+··············
····+∗∗∗∗∗+··········
·····+∗∗∗∗∗∗∗∗+······
······+∗∗∗∗∗∗∗∗∗∗∗+··
·······+∗∗∗∗∗∗∗+·····
········+∗∗∗+········
·········+···········
·····················</pre>
 
=={{header|J}}==
Implementation, using complex numbers to represent x,y coordinates:
<syntaxhighlight lang="j">area=: [:| 0.5-/ .*@,.+. NB. signed area of triangle
I3=: =i.3 NB. identity matrix
inside=: {{ (area y)=+/area"1|:(I3*x)+(1-I3)*y }}</syntaxhighlight>
 
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:<syntaxhighlight lang="j"> 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</syntaxhighlight>
 
=={{header|Java}}==
{{trans|Go}}
<langsyntaxhighlight lang="java">import java.util.Objects;
 
public class FindTriangle {
Line 825 ⟶ 1,887:
test(tri, pt);
}
}</langsyntaxhighlight>
{{out}}
<pre>Triangle[(1.500000, 2.400000), (5.100000, -3.100000), (-3.800000, 1.200000)]
Line 839 ⟶ 1,901:
Triangle[(0.100000, 0.111111), (12.500000, 33.333333), (-12.500000, 16.666667)]
Point (5.414286, 14.349206) is within triangle? true</pre>
 
=={{header|JavaScript}}==
{{trans|C++}}
<syntaxhighlight lang="javascript">
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();
</syntaxhighlight>
 
=={{header|jq}}==
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
 
'''Adapted from [[#Wren|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'''
<syntaxhighlight lang="jq">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; </syntaxhighlight>
<syntaxhighlight lang="jq">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;</syntaxhighlight>
'''Examples'''
<syntaxhighlight lang="jq">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)</syntaxhighlight>
{{out}}
<pre>
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
</pre>
 
=={{header|Julia}}==
{{trans|Python}}
Using the Wren examples.
<langsyntaxhighlight lang="julia">Point(x, y) = [x, y]
Triangle(a, b, c) = [a, b, c]
LEzero(x) = x < 0 || isapprox(x, 0, atol=0.00000001)
Line 889 ⟶ 2,165:
end
end
</langsyntaxhighlight>{{out}}
<pre>
Using triangle [[1.5, 2.4], [0.51, -0.31], [-0.38, 1.2]]:
Line 912 ⟶ 2,188:
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">import kotlin.math.max
import kotlin.math.min
 
Line 1,007 ⟶ 2,283:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>Triangle[(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Line 1,024 ⟶ 2,300:
=={{header|Lua}}==
{{trans|C++}}
<langsyntaxhighlight lang="lua">EPS = 0.001
EPS_SQUARE = EPS * EPS
 
Line 1,108 ⟶ 2,384:
 
test(0.1, 0.1111111111111111, 12.5, 33.333333333333336, -12.5, 16.666666666666668, 5.414285714285714, 14.349206349206348)
print()</langsyntaxhighlight>
{{out}}
<pre>Triangle is [(1.5, 2.4), (5.1, -3.1), (-3.8, 1.2)]
Line 1,124 ⟶ 2,400:
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">RegionMember[Polygon[{{1, 2}, {3, 1}, {2, 4}}], {2, 2}]</langsyntaxhighlight>
{{out}}
<pre>True</pre>
Line 1,130 ⟶ 2,406:
=={{header|Nim}}==
{{trans|Kotlin}}
<langsyntaxhighlight Nimlang="nim">import strformat
 
const
Line 1,215 ⟶ 2,491:
p3 = (-100 / 8, 100 / 6)
tri = initTriangle(p1, p2, p3)
test(tri, pt)</langsyntaxhighlight>
 
{{out}}
Line 1,233 ⟶ 2,509:
=={{header|Perl}}==
Translate the Java program at [https://totologic.blogspot.com/2014/01/accurate-point-in-triangle-test.html this blog post] and data set is taken from the [[Find_if_a_point_is_within_a_triangle#Raku|Raku]] entry.
<langsyntaxhighlight Perllang="perl"># 20201123 added Perl programming solution
 
use strict;
Line 1,295 ⟶ 2,571:
while ( my @vertex = $iter->()) { print '(',join(',',@vertex),') ' }
print ': ',naivePointInTriangle (@DATA, @$point) ? 'True' : 'False', "\n" ;
}</langsyntaxhighlight>
{{out}}
<pre>Point (0,0) is within triangle (1.5,2.4) (5.1,-3.1) (-3.8,0.5) : True
Line 1,302 ⟶ 2,578:
 
=={{header|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]]
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>constant p0 = {0,0},
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
p1 = {0,1},
<span style="color: #008080;">constant</span> <span style="color: #000000;">p0</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
p2 = {3,1},
<span style="color: #000000;">p1</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
triangle = {{3/2, 12/5}, {51/10, -31/10}, {-19/5, 1/2}}
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
function inside(sequence p) return sort(convex_hull({p}&triangle))==sort(triangle) end function
<span style="color: #000000;">triangle</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">/</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">51</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">31</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">19</span><span style="color: #0000FF;">/</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}}</span>
printf(1,"Point %v is with triangle %v?:%t\n",{p0,triangle,inside(p0)})
<span style="color: #008080;">function</span> <span style="color: #000000;">inside</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
printf(1,"Point %v is with triangle %v?:%t\n",{p1,triangle,inside(p1)})
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">convex_hull</span><span style="color: #0000FF;">({</span><span style="color: #000000;">p</span><span style="color: #0000FF;">}&</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">))==</span><span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">))</span>
printf(1,"Point %v is with triangle %v?:%t\n",{p2,triangle,inside(p2)})</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">inside</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p0</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">inside</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">inside</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">)})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,320 ⟶ 2,602:
 
===trans python===
(same output)
(using the same p0/p1/p2/triangle constants from above, same output)
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function side(sequence p1, p2, p3)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
-- which side of plane cut by line (p2, p3) is p1 on?
<span style="color: #008080;">constant</span> <span style="color: #000000;">p0</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
atom {x1, y1} = p1,
<span style="color: #000000;">p1</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
{x2, y2} = p2,
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
{x3, y3} = p3
<span style="color: #000000;">triangle</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">/</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">51</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">31</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">19</span><span style="color: #0000FF;">/</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}}</span>
return (x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3)
end function
<span style="color: #008080;">function</span> <span style="color: #000000;">side</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p3</span><span style="color: #0000FF;">)</span>
function iswithin(sequence point, triangle)
<span style="color: #000080;font-style:italic;">-- which side of plane cut by line (p2, p3) is p1 on?</span>
--
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span>
-- Determine if point is within triangle.
<span style="color: #0000FF;">{</span><span style="color: #000000;">x2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span>
-- If so, the point will be on the same side of each of the half planes
<span style="color: #0000FF;">{</span><span style="color: #000000;">x3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y3</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p3</span>
-- defined by vectors p1p2, p2p3, and p3p1. zval is positive if outside,
<span style="color: #008080;">return</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x3</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">y2</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">y3</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x2</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x3</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">y1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">y3</span><span style="color: #0000FF;">)</span>
-- negative if inside such a plane. All should be positive or all negative
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
-- if point is within the triangle.
--
<span style="color: #008080;">function</span> <span style="color: #000000;">iswithin</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">point</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">triangle</span><span style="color: #0000FF;">)</span>
sequence {pt1, pt2, pt3} = triangle
<span style="color: #000080;font-style:italic;">--
atom zval1 = side(point, pt1, pt2),
-- Determine if point is within triangle.
zval2 = side(point, pt2, pt3),
-- If so, the point will be on zval3the =same side(point, pt3,of each of the half pt1)planes
-- defined by vectors p1p2, p2p3, and p3p1. side is positive if outside,
bool notanyneg = zval1 >= 0 and zval2 >= 0 and zval3 >= 0,
-- negative if inside such a plane. All should be non-negative or all
notanypos = zval1 <= 0 and zval2 <= 0 and zval3 <= 0
-- non-positive if the point is within the triangle.
return notanyneg or notanypos
--</span>
end function
<span style="color: #004080;">sequence</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">pt1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt3</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">triangle</span>
 
<span style="color: #004080;">atom</span> <span style="color: #000000;">side12</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">side</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt2</span><span style="color: #0000FF;">),</span>
printf(1,"point %v is with triangle %v?:%t\n",{p0,triangle,iswithin(p0,triangle)})
<span style="color: #000000;">side23</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">side</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt3</span><span style="color: #0000FF;">),</span>
printf(1,"point %v is with triangle %v?:%t\n",{p1,triangle,iswithin(p1,triangle)})
<span style="color: #000000;">side31</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">side</span><span style="color: #0000FF;">(</span><span style="color: #000000;">point</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pt1</span><span style="color: #0000FF;">)</span>
printf(1,"point %v is with triangle %v?:%t\n",{p2,triangle,iswithin(p2,triangle)})</lang>
<span style="color: #004080;">bool</span> <span style="color: #000000;">all_non_neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">side12</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">side23</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">side31</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">all_non_pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">side12</span> <span style="color: #0000FF;"><=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">side23</span> <span style="color: #0000FF;"><=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">side31</span> <span style="color: #0000FF;"><=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">all_non_neg</span> <span style="color: #008080;">or</span> <span style="color: #000000;">all_non_pos</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">iswithin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">iswithin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"point %v is with triangle %v?:%t\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">iswithin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">triangle</span><span style="color: #0000FF;">)})</span>
<!--</syntaxhighlight>-->
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">
""" find if point is in a triangle """
 
Line 1,383 ⟶ 2,673:
isornot = "is" if iswithin(pnt, a, b, c) else "is not"
print("Point", pnt, isornot, "within the triangle", TRI)
</langsyntaxhighlight>{{out}}
<pre>
Point Point2D(0, 0) is within the triangle Triangle(Point2D(3/2, 12/5), Point2D(51/10, -31/10), Point2D(-19/5, 1/2))
Line 1,397 ⟶ 2,687:
I would probably use the dot-product version, if only because it requires less (no) division.
 
<langsyntaxhighlight lang="racket">#lang racket/base
 
(define-syntax-rule (all-between-0..1? x ...)
Line 1,444 ⟶ 2,734:
(run-tests point-in-triangle?/barycentric)
(run-tests point-in-triangle?/parametric)
(run-tests point-in-triangle?/dot-product))</langsyntaxhighlight>
 
{{out}}
Line 1,454 ⟶ 2,744:
Reusing code from the [[Convex_hull#Raku|Convex hull]] task and some logic from the [[Determine_if_two_triangles_overlap#Raku|Determine if two triangles overlap]] task.
 
<syntaxhighlight lang="raku" perl6line>class Point {
has Real $.x is rw;
has Real $.y is rw;
Line 1,481 ⟶ 2,771:
say "Point {$point.gist} is within triangle {join ', ', @triangle».gist}: ",
$point.&is-within: @triangle
}</langsyntaxhighlight>
{{out}}
<pre>Point (0, 0) is within triangle (1.5, 2.4), (5.1, -3.1), (-3.8, 0.5): True
Line 1,491 ⟶ 2,781:
 
<br>Extra certification code was added to verify that the &nbsp; '''X,Y''' &nbsp; coördinates for the points are not missing and are numeric.
<langsyntaxhighlight lang="rexx">/*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.*/
Line 1,507 ⟶ 2,797:
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)</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default triangle and the point at: &nbsp; <tt> (0,0) </tt>}}
<pre>
Line 1,519 ⟶ 2,809:
<pre>
point (3,1) isn't within the triangle (1.5,2.4) , (5.1,-3.1) , (-3.8,0.5)
</pre>
 
=={{header|RPL}}==
{{trans|Ada}}
{{works with|HP|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'''
+ + ==
≫ ≫ '<span style="color:blue">INTRI?</span>' STO
 
(1 0) (2 0) (0 2) (0 0) <span style="color:blue">INTRI?</span>
(-1 0) (-1 -1) (2 2) (0 0) <span style="color:blue">INTRI?</span>
{{out}}
<pre>
2: 0
1: 1
</pre>
 
=={{header|Ruby}}==
{{trans|Go}}
<langsyntaxhighlight lang="ruby">EPS = 0.001
EPS_SQUARE = EPS * EPS
 
Line 1,610 ⟶ 2,924:
end
 
main()</langsyntaxhighlight>
{{out}}
<pre>Triangle is [[1.5, 2.4], [5.1, -3.1], [-3.8, 1.2]]
Line 1,622 ⟶ 2,936:
Triangle is [[0.1, 0.1111111111111111], [12.5, 33.333333333333336], [-12.5, 16.666666666666668]]
Point [5.414285714285714, 14.349206349206348] is within triangle? true</pre>
 
=={{header|Rust}}==
{{works with|Rust|1.7.3}}
{{trans|D}}
 
<syntaxhighlight lang="rust">
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!();
}
</syntaxhighlight>
 
{{out}}
<pre>
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
</pre>
 
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">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")
}</syntaxhighlight>
 
{{out}}
<pre>
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
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-math}}
This is a translation of the ActionScript code for the 'accurate' method in the first referenced article above.
<syntaxhighlight lang="wren">var EPS = 0.001
<lang ecmascript>import "/math" for Math
 
var EPS = 0.001
var EPS_SQUARE = EPS * EPS
 
Line 1,643 ⟶ 3,175:
 
var pointInTriangleBoundingBox = Fn.new { |x1, y1, x2, y2, x3, y3, x, y|
var xMin = Mathx1.min(x1, Mathx2.min(x2, x3)) - EPS
var xMax = Mathx1.max(x1, Mathx2.max(x2, x3)) + EPS
var yMin = Mathy1.min(y1, Mathy2.min(y2, y3)) - EPS
var yMax = Mathy1.max(y1, Mathy2.max(y2, y3)) + EPS
return !(x < xMin || xMax < x || y < yMin || yMax < y)
}
Line 1,708 ⟶ 3,240:
y3 = tri[2][1]
within = accuratePointInTriangle.call(x1, y1, x2, y2, x3, y3, x, y)
System.print("Point %(pt) is within triangle ? %(within)")</langsyntaxhighlight>
 
{{out}}
Line 1,725 ⟶ 3,257:
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="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);
Line 1,748 ⟶ 3,280:
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);
]</langsyntaxhighlight>
 
{{out}}
9,476

edits