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 }