1 /*
2 Copyright (c) 2011-2021 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Copyright: Timur Gafarov 2011-2021.
31  * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
32  * Authors: Timur Gafarov
33  */
34 module dlib.geometry.plane;
35 
36 import std.math;
37 import dlib.math.vector;
38 import dlib.math.utils;
39 
40 /// Infinite plane
41 struct Plane
42 {
43     /// Return a Plane with all values at zero
44     static Plane opCall()
45     {
46         return Plane(0.0f, 0.0f, 0.0f, 0.0f);
47     }
48 
49     /// Return a Plane with the Vec3f component of n and distance of d
50     static Plane opCall(Vector3f n, float d)
51     {
52         return Plane(n.x, n.y, n.z, d);
53     }
54 
55     /// Return a Plane with a Vec3f component of x, y, z and distance of d
56     static Plane opCall(float x, float y, float z, float d)
57     {
58         Plane p;
59         p.x = x;
60         p.y = y;
61         p.z = z;
62         p.d = d;
63         return p;
64     }
65 
66     void fromPoints(Vector3f p0, Vector3f p1, Vector3f p2)
67     {
68         Vector3f v0 = p0 - p1;
69         Vector3f v1 = p2 - p1;
70         Vector3f n = cross(v1, v0);
71         n.normalize();
72         x = n.x;
73         y = n.y;
74         z = n.z;
75         d = -(p0.x * x + p0.y * y + p0.z * z);
76     }
77 
78     void fromPointAndNormal(Vector3f p, Vector3f n)
79     {
80         n.normalize();
81         x = n.x;
82         y = n.y;
83         z = n.z;
84         d = -(p.x * x + p.y * y + p.z * z);
85     }
86 
87     float dot(Vector3f p)
88     {
89         return x * p.x + y * p.y + z * p.z;
90     }
91 
92     void normalize()
93     {
94         float len = sqrt(x * x + y * y + z * z);
95         x /= len;
96         y /= len;
97         z /= len;
98         d /= len;
99     }
100 
101     Plane normalized()
102     {
103         Plane res;
104         float len = sqrt(x * x + y * y + z * z);
105         return Plane(x / len, y / len, z / len, d / len);
106     }
107 
108    /**
109     * Get the distance from the center of the plane to the given point.
110     * This is useful for determining which side of the plane the point is on.
111     */
112     float distance(Vector3f p)
113     {
114         return x * p.x + y * p.y + z * p.z + d;
115     }
116 
117     Vector3f reflect(Vector3f vec)
118     {
119         float d = distance(vec);
120         return vec + Vector3f(-x, -y, -z) * 2 * d;
121     }
122 
123     Vector3f project(Vector3f p)
124     {
125         float h = distance(p);
126         return Vector3f(p.x - x * h,
127                         p.y - y * h,
128                         p.z - z * h);
129     }
130 
131     bool isOnPlane(Vector3f p, float threshold = 0.001f)
132     {
133         float d = distance(p);
134         if (d < threshold && d > -threshold)
135             return true;
136         return false;
137     }
138 
139    /**
140     * Calculate the intersection between this plane and a line
141     * If the plane and the line are parallel, false is returned
142     */
143     bool intersectsLine(Vector3f p0, Vector3f p1, ref float t)
144     {
145         Vector3f dir = p1 - p0;
146         float div = dot(dir);
147         if (div == 0.0)
148             return false;
149         t = -distance(p0) / div;
150         return true;
151     }
152 
153     bool intersectsLine(Vector3f p0, Vector3f p1, ref Vector3f ip)
154     {
155         Vector3f dir = p1 - p0;
156         float div = dot(dir);
157         if (div == 0.0)
158         {
159             ip = (p0 + p1) * 0.5f;
160             return false;
161         }
162         float u = -distance(p0) / div;
163         ip = p0 + (p1 - p0) * u;
164         return true;
165     }
166 
167     bool intersectsLineSegment(Vector3f p0, Vector3f p1, ref Vector3f ip)
168     {
169         Vector3f ray = p1 - p0;
170 
171         // calculate plane
172         float d = dot(position);
173         float dr = dot(ray);
174 
175         if (abs(dr) < EPSILON)
176             return false; // avoid divide by zero
177 
178         // Compute the t value for the directed line ray intersecting the plane
179         float t = (d - dot(p0)) / dr;
180 
181         // scale the ray by t
182         Vector3f newRay = ray * t;
183 
184         // calc contact point
185         ip = p0 + newRay;
186 
187         if (t >= 0.0 && t <= 1.0)
188             return true; // line intersects plane
189 
190         return false; // line does not
191     }
192 
193     float opIndex(size_t i)
194     {
195         return arrayof[i];
196     }
197 
198     float opIndexAssign(float value, size_t i)
199     {
200         return (arrayof[i] = value);
201     }
202 
203     union
204     {
205         float[4] arrayof;// = [0, 0, 0, 0];
206 
207         Vector4f vectorof;
208 
209         struct
210         {
211             float a, b, c, d;
212         }
213 
214         Vector3f normal;
215     }
216 
217     alias vectorof this;
218 
219     @property Vector3f position()
220     {
221         return -(normal * d);
222     }
223 }