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 }