1 module evael.utils.math.Functions;
2 
3 import std.math;
4 
5 import dnogc.DynamicArray;
6 
7 import evael.utils.Math;
8 
9 enum degToRad = (PI * 2) / 360;
10 enum pi = 180 / PI;
11 
12 alias PolygonDefinition = DynamicArray!vec3;
13 
14 /**
15  * Returns angle between two points.
16  */
17 @nogc
18 float getAngle(in float deltaX, in float deltaY) nothrow
19 {
20 	return atan2(deltaX, deltaY) * pi;
21 }
22 
23 /**
24  * Returns angle between two points.
25  */
26 @nogc
27 float getAngle()(in auto ref vec3 a, in auto ref vec3 b) nothrow
28 {
29 	return getAngle(b.x - a.x, b.z - a.z);
30 }
31 
32 /**
33  * Returns distance between two points.
34  */
35 @nogc
36 int getDistance()(in auto ref vec2 a, in auto ref vec2 b) nothrow
37 {
38 	return cast(int)ceil(sqrt(cast(float)(pow(a.x - b.x, 2) + pow(a.y - b.y, 2))));
39 }
40 
41 /**
42  * Returns distance between two points.
43  */
44 @nogc
45 int getDistance()(in auto ref vec3 a, in auto ref vec3 b) nothrow
46 {
47 	return cast(int)ceil(sqrt(cast(float)(pow(a.x - b.x, 2) + pow(a.z - b.z, 2))));
48 }
49 
50 @nogc
51 bool isPointInTriangle()(in auto ref vec3 p, in auto ref vec3 p0, in auto ref vec3 p1, in auto ref vec3 p2)	 nothrow 
52 {
53 	auto s = p0.z * p2.x - p0.x * p2.z + (p2.z - p0.z) * p.x + (p0.x - p2.x) * p.z;
54 	auto t = p0.x * p1.z - p0.z * p1.x + (p0.z - p1.z) * p.x + (p1.x - p0.x) * p.z;
55 
56 	if ((s < 0) != (t < 0))
57 		return false;
58 
59 	auto A = -p1.z * p2.x + p0.z * (p2.x - p1.x) + p0.x * (p1.z - p2.z) + p1.x * p2.z;
60 	if (A < 0.0)
61 	{
62 		s = -s;
63 		t = -t;
64 		A = -A;
65 	}
66 	return s > 0 && t > 0 && (s + t) < A;
67 }
68 
69 @nogc
70 bool isPointInTriangle2()(in auto ref vec3 p, in auto ref vec3 p0, in auto ref vec3 p1, in auto ref vec3 p2) nothrow
71 {
72 	if ((p.x == p0.x && p.z == p0.z) || (p.x == p1.x && p.z == p1.z) || (p.x == p2.x && p.z == p2.z))
73 		return true;
74 
75 	return isPointInTriangle(p, p0, p1, p2);
76 }
77 
78 /**
79  * Checks if a point is inside a polygon
80  * Note : im using z axis instead of y axis
81  */
82 @nogc
83 bool isPointInPolygon()(in auto ref vec3 p, in auto ref PolygonDefinition polygon) nothrow
84 {
85 	// http://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-point-is-within-a-polygon
86     // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
87     bool inside = false;
88     for(int i = 0, j = polygon.length - 1 ; i < polygon.length; j = i++)
89     {
90         if ( ( polygon[ i ].z > p.z ) != ( polygon[ j ].z > p.z ) &&
91              p.x < ( polygon[ j ].x - polygon[ i ].x ) * ( p.z - polygon[ i ].z ) / ( polygon[ j ].z - polygon[ i ].z ) + polygon[ i ].x )
92         {
93             inside = !inside;
94         }
95     }
96 
97     return inside;
98 }
99 
100 
101 /**
102  * Checks if two segments interesect
103  */
104 bool intersect()(in auto ref vec3 p1, in auto ref vec3 p2, in auto ref vec3 p3, in auto ref vec3 p4, out vec3 intersection) nothrow @nogc
105 {
106 	// Get the segments' parameters.
107 	immutable float dx12 = p2.x - p1.x;
108 	immutable float dy12 = p2.z - p1.z;
109 	immutable float dx34 = p4.x - p3.x;
110 	immutable float dy34 = p4.z - p3.z;
111 
112 	// Solve for t1 and t2
113 	immutable float denominator = (dy12 * dx34 - dx12 * dy34);
114 	immutable float t1 = ((p1.x - p3.x) * dy34 + (p3.z - p1.z) * dx34) / denominator;
115 	immutable float t2 = ((p3.x - p1.x) * dy12 + (p1.z - p3.z) * dx12) / -denominator;
116 
117 	// Find the point of intersection.
118 	intersection = vec3(p1.x + dx12 * t1, 0, p1.z + dy12 * t1);
119 
120 	// The segments intersect if t1 and t2 are between 0 and 1.
121 	return ((t1 >= 0) && (t1 <= 1) && (t2 >= 0) && (t2 <= 1));
122 }
123 
124 /**
125  * Checks if a ray intersect with polygon
126  */
127 bool intersectPolygon()(in auto ref vec3 p1, in auto ref vec3 p2, ref PolygonDefinition polygonVertices, out vec3 intersection) nothrow @nogc
128 {
129 	for(int i = 0; i < polygonVertices.length; i++)
130 	{
131 		int j = ( i + 1 ) % polygonVertices.length;
132 
133 		if((polygonVertices[i] == p2 || polygonVertices[j] == p2) || (polygonVertices[i] == p1 || polygonVertices[j] == p1))
134 			continue;
135 
136 		if(intersect(p1, p2, polygonVertices[i], polygonVertices[j], intersection))
137 		{
138 			return true;
139 		}
140 	}
141 
142 	return false;
143 }