1 /**
2 Plane in hessian form.
3 
4 Copyright:
5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.  
6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)  
7 Copyright (c) 2017-2018 Godot-D contributors  
8 
9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
10 
11 
12 */
13 module godot.core.plane;
14 
15 import godot.core.defs;
16 import godot.core.vector3;
17 
18 import std.math;
19 
20 enum ClockDirection
21 {
22 	clockwise,
23 	counterClockwise,
24 	
25 	cw = clockwise,
26 	ccw = counterClockwise
27 }
28 
29 /**
30 Plane represents a normalized plane equation. Basically, “normal” is the normal of the plane (a,b,c normalized), and “d” is the distance from the origin to the plane (in the direction of “normal”). “Over” or “Above” the plane is considered the side of the plane towards where the normal is pointing.
31 */
32 struct Plane
33 {
34 	@nogc nothrow:
35 	
36 	Vector3 normal = Vector3(0,0,0);
37 	real_t d = 0;
38 	
39 	Vector3 center() const
40 	{
41 		return normal*d;
42 	}
43 	
44 	Plane opUnary(string op : "-")() const
45 	{
46 		return Plane(-normal, -d);
47 	}
48 	
49 	Vector3 project(in Vector3 p_point) const
50 	{
51 		return p_point - normal * distanceTo(p_point);
52 	}
53 	
54 	
55 	void normalize()
56 	{
57 		real_t l = normal.length();
58 		if (l==0)
59 		{
60 			this=Plane(Vector3(0,0,0),0);
61 			return;
62 		}
63 		normal/=l;
64 		d/=l;
65 	}
66 	
67 	Plane normalized() const
68 	{
69 		Plane p = this;
70 		p.normalize();
71 		return p;
72 	}
73 	
74 	Vector3 getAnyPoint() const
75 	{
76 		return normal*d;
77 	}
78 	
79 	Vector3 getAnyPerpendicularNormal() const
80 	{
81 		enum Vector3 p1 = Vector3(1,0,0);
82 		enum Vector3 p2 = Vector3(0,1,0);
83 		Vector3 p;
84 	
85 		if (fabs(normal.dot(p1)) > 0.99) // if too similar to p1
86 			p=p2; // use p2
87 		else
88 			p=p1; // use p1
89 	
90 		p-=normal * normal.dot(p);
91 		p.normalize();
92 	
93 		return p;
94 	}
95 	
96 	
97 	/* intersections */
98 	
99 	bool intersect3(in Plane p_plane1, in Plane p_plane2, Vector3* r_result = null) const
100 	{
101 		const Plane p_plane0 = this;
102 		Vector3 normal0=p_plane0.normal;
103 		Vector3 normal1=p_plane1.normal;
104 		Vector3 normal2=p_plane2.normal;
105 		
106 		real_t denom=normal0.cross(normal1).dot(normal2);
107 		
108 		if (fabs(denom)<=CMP_EPSILON)
109 			return false;
110 		
111 		if (r_result)
112 		{
113 			*r_result = ( (normal1.cross(normal2) * p_plane0.d) +
114 			              (normal2.cross(normal0) * p_plane1.d) +
115 			              (normal0.cross(normal1) * p_plane2.d) )/denom;
116 		}
117 		return true;
118 	}
119 	
120 	
121 	bool intersectsRay(in Vector3 p_from, in Vector3 p_dir, Vector3* p_intersection = null)  const
122 	{
123 		Vector3 segment=p_dir;
124 		real_t den=normal.dot( segment );
125 		
126 		//printf("den is %i\n",den);
127 		if (fabs(den)<=CMP_EPSILON)
128 		{
129 			return false;
130 		}
131 		
132 		real_t dist=(normal.dot( p_from ) - d) / den;
133 		//printf("dist is %i\n",dist);
134 		
135 		if (dist>CMP_EPSILON)
136 		{ //this is a ray, before the emiting pos (p_from) doesnt exist
137 			return false;
138 		}
139 		
140 		dist=-dist;
141 		if(p_intersection) *p_intersection = p_from + segment * dist;
142 		
143 		return true;
144 	}
145 	
146 	bool intersectsSegment(in Vector3 p_begin, in Vector3 p_end, Vector3* p_intersection) const
147 	{
148 		Vector3 segment= p_begin - p_end;
149 		real_t den=normal.dot( segment );
150 		
151 		//printf("den is %i\n",den);
152 		if (fabs(den)<=CMP_EPSILON) return false;
153 		
154 		real_t dist=(normal.dot( p_begin ) - d) / den;
155 		//printf("dist is %i\n",dist);
156 		
157 		if (dist<-CMP_EPSILON || dist > (1.0 +CMP_EPSILON)) return false;
158 		
159 		dist=-dist;
160 		if(p_intersection) *p_intersection = p_begin + segment * dist;
161 		
162 		return true;
163 	}
164 	
165 	/* misc */
166 	
167 	bool isAlmostLike(in Plane p_plane) const
168 	{
169 		return (normal.dot( p_plane.normal ) > _PLANE_EQ_DOT_EPSILON && fabs(d-p_plane.d) < _PLANE_EQ_D_EPSILON);
170 	}
171 	
172 	
173 	/+String opCast(T : String)() const
174 	{
175 		// return normal.operator String() + ", " + rtos(d);
176 		return String(); // @Todo
177 	}+/
178 	
179 	
180 	
181 	bool isPointOver(in Vector3 p_point) const
182 	{
183 		return (normal.dot(p_point) > d);
184 	}
185 	
186 	real_t distanceTo(in Vector3 p_point) const
187 	{
188 		return (normal.dot(p_point)-d);
189 	}
190 	
191 	bool hasPoint(in Vector3 p_point,real_t _epsilon = CMP_EPSILON) const
192 	{
193 		real_t dist=normal.dot(p_point) - d;
194 		dist=fabs(dist);
195 		return ( dist <= _epsilon);
196 	
197 	}
198 	
199 	this(in Vector3 p_normal, real_t p_d)
200 	{
201 		normal=p_normal;
202 		d=p_d;
203 	}
204 	
205 	this(in Vector3 p_point, in Vector3 p_normal)
206 	{
207 		normal=p_normal;
208 		d=p_normal.dot(p_point);
209 	}
210 	
211 	this(in Vector3 p_point1, in Vector3 p_point2, in Vector3 p_point3,ClockDirection p_dir = ClockDirection.ccw)
212 	{
213 		if (p_dir == ClockDirection.clockwise)
214 			normal=(p_point1-p_point3).cross(p_point1-p_point2);
215 		else
216 			normal=(p_point1-p_point2).cross(p_point1-p_point3);
217 		normal.normalize();
218 		d = normal.dot(p_point1);
219 	}
220 }
221