1 module inochi2d.math.triangle;
2 import inochi2d.math;
3 import inochi2d.core.meshdata;
4 import inmath;
5 import std.math;
6 import std.algorithm;
7 
8 
9 bool isPointInTriangle(vec2 pt, vec2[3] triangle) {
10     float sign (ref vec2 p1, ref vec2 p2, ref vec2 p3) {
11         return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
12     }
13     vec2 p1 = triangle[0];
14     vec2 p2 = triangle[1];
15     vec2 p3 = triangle[2];
16 
17     auto d1 = sign(pt, p1, p2);
18     auto d2 = sign(pt, p2, p3);
19     auto d3 = sign(pt, p3, p1);
20 
21     auto hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
22     auto hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
23 
24     return !(hasNeg && hasPos);
25 }
26 
27 
28 int[] findSurroundingTriangle(vec2 pt, ref MeshData bindingMesh) {
29     bool isPointInTriangle(vec2 pt, int[] triangle) {
30         float sign (ref vec2 p1, ref vec2 p2, ref vec2 p3) {
31             return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
32         }
33         vec2 p1 = bindingMesh.vertices[triangle[0]];
34         vec2 p2 = bindingMesh.vertices[triangle[1]];
35         vec2 p3 = bindingMesh.vertices[triangle[2]];
36 
37         auto d1 = sign(pt, p1, p2);
38         auto d2 = sign(pt, p2, p3);
39         auto d3 = sign(pt, p3, p1);
40 
41         auto hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
42         auto hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
43 
44         return !(hasNeg && hasPos);
45     }
46     int i = 0;
47     int[] triangle = [0, 1, 2];
48     while (i < bindingMesh.indices.length) {
49         triangle[0] = bindingMesh.indices[i];
50         triangle[1] = bindingMesh.indices[i+1];
51         triangle[2] = bindingMesh.indices[i+2];
52         if (isPointInTriangle(pt, triangle)) {
53             return triangle;
54         }
55         i += 3;
56     }
57     return null;
58 }
59 
60 
61 // Calculate offset of point in coordinates of triangle.
62 vec2 calcOffsetInTriangleCoords(vec2 pt, ref MeshData bindingMesh, ref int[] triangle) {
63     if( (pt - bindingMesh.vertices[triangle[0]]).lengthSquared > (pt - bindingMesh.vertices[triangle[1]]).lengthSquared) {
64         swap(triangle[0], triangle[1]);
65     }
66     if( (pt - bindingMesh.vertices[triangle[0]]).lengthSquared > (pt - bindingMesh.vertices[triangle[2]]).lengthSquared) {
67         swap(triangle[0], triangle[2]);
68     }
69     auto p1 = bindingMesh.vertices[triangle[0]];
70     auto p2 = bindingMesh.vertices[triangle[1]];
71     auto p3 = bindingMesh.vertices[triangle[2]];
72     vec2 axis0 = p2 - p1;
73     float axis0len = axis0.length;
74     axis0 /= axis0.length;
75     vec2 axis1 = p3 - p1;
76     float axis1len = axis1.length;
77     axis1 /= axis1.length;
78 
79     auto relPt = pt - p1;
80     if (relPt.lengthSquared == 0)
81         return vec2(0, 0);
82     float cosA = dot(axis0, axis1);
83     if (cosA == 0) {
84         return vec2(dot(relPt, axis0), dot(relPt, axis1));
85     } else {
86         float argA = acos(cosA);
87         float sinA = sin(argA);
88         float tanA = tan(argA);
89         float cosB = dot(axis0, relPt) / relPt.length;
90         float argB = acos(cosB);
91         float sinB = sin(argB);
92         
93         vec2 ortPt = vec2(relPt.length * cosB, relPt.length * sinB);
94         
95         mat2 H = mat2([1, -1/tanA, 0, 1/sinA]);
96         auto result = H * ortPt;
97 
98         return result;
99     }
100 }