1 /**
2     Inochi2D Triangles and trigonometry
3 
4     Copyright: 
5         Copyright © 2020-2026, Inochi2D Project
6     
7     License:
8         $(LINK2 https://github.com/Inochi2D/inochi2d/blob/main/LICENSE, BSD 2-clause License)
9     
10     Authors:
11         Luna Nielsen
12 */
13 module inochi2d.core.math.trig;
14 import numath;
15 
16 /**
17     A 2D triangle
18 */
19 struct Triangle {
20 @nogc:
21     vec2 p1;
22     vec2 p2;
23     vec2 p3;
24 
25     /**
26         Gets the barycentric coordinates of the given point.
27 
28         Params:
29             pt = The point to check.
30 
31         Returns:
32             The barycentric coordinates in relation to each
33             vertex of the triangle.
34     */
35     pragma(inline, true)
36     vec3 barycentric(vec2 pt) nothrow pure {
37         vec2 v1 = p2 - p1;
38         vec2 v2 = p3 - p1;
39         vec2 v3 = pt - p1;
40         float den = v1.x * v2.y - v2.x * v1.y;
41         float v = (v3.x * v2.y - v2.x * v3.y) / den;
42         float w = (v1.x * v3.y - v3.x * v1.y) / den;
43         return vec3(
44                 1.0 - v - w,
45                 v,
46                 w,
47         );
48     }
49 
50     /**
51         Whether the triangle contains the given point.
52 
53         Params:
54             pt = The point to check.
55         
56         Returns:
57             $(D true) if the given point lies within this
58             triangle, $(D false) otherwise.
59     */
60     pragma(inline, true)
61     bool contains(vec2 pt) nothrow pure {
62         float d1 = sign(pt, p1, p2);
63         float d2 = sign(pt, p2, p3);
64         float d3 = sign(pt, p3, p1);
65         return !(
66                 ((d1 < 0) || (d2 < 0) || (d3 < 0)) &&
67                 ((d1 > 0) || (d2 > 0) || (d3 > 0))
68         );
69     }
70 }
71 
72 /**
73     Gets the sign between 3 points.
74 
75     Params:
76         p1 = The first point
77         p2 = The second point
78         p3 = The third point.
79     
80     Returns:
81         A float determining the sign between p1, p2 and p3.
82 */
83 pragma(inline, true)
84 float sign(ref vec2 p1, ref vec2 p2, ref vec2 p3) @nogc nothrow pure {
85     return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
86 }
87 
88 /**
89     Finds the closest 2 points to the given point.
90 
91     Param:
92         point = The point to find the closest 2 points to
93         mesh =  The mesh to index.
94 
95     Returns:
96         The vertex indices of the mesh of the 2 closest points
97         to the given point, or $(D -1) if there's fewer than 2
98         points in the mesh.
99 */
100 ptrdiff_t[2] findClosest2(inout(vec2) point, inout(vec2)[] mesh) @nogc nothrow pure {
101     ptrdiff_t p1 = -1;
102     ptrdiff_t p2 = -1;
103     float closestDist = float.max;
104     foreach (i, p; mesh) {
105         if (p.distance(point) < closestDist) {
106             p2 = p1;
107             p1 = i;
108         }
109     }
110     return [p1, p2];
111 }
112 
113 /**
114     Finds the closest point to the given point.
115 
116     Param:
117         point = The point to find the closest point to
118         mesh =  The mesh to index.
119 
120     Returns:
121         The vertex index of the closest point,
122         or $(D -1) if there is no points in the mesh.
123 */
124 ptrdiff_t findClosest(inout(vec2) point, inout(vec2)[] mesh) @nogc nothrow pure {
125     ptrdiff_t p1 = -1;
126     float closestDist = float.max;
127     foreach (i, p; mesh) {
128         if (p.distance(point) < closestDist) {
129             p1 = i;
130         }
131     }
132     return p1;
133 }