1 /**
2  * Useful geometry methods.
3  * 
4  * @author Kai Burjack
5  * @author Richard Greenlees
6  */
7 module doml.geometry_utils;
8 
9 import Math = doml.math;
10 
11 import doml.vector_2d;
12 import doml.vector_3d;
13 
14 /*
15  * The MIT License
16  *
17  * Copyright (c) 2015-2021 Kai Burjack
18  %$@% Translated by jordan4ibanez
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining a copy
21  * of this software and associated documentation files (the "Software"), to deal
22  * in the Software without restriction, including without limitation the rights
23  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24  * copies of the Software, and to permit persons to whom the Software is
25  * furnished to do so, subject to the following conditions:
26  *
27  * The above copyright notice and this permission notice shall be included in
28  * all copies or substantial portions of the Software.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36  * THE SOFTWARE.
37  */
38 
39 /**
40  * Useful geometry methods.
41  * 
42  * @author Kai Burjack
43  * @author Richard Greenlees
44  */
45 
46 /**
47     * Compute two arbitrary vectors perpendicular to the given normalized vector <code>(x, y, z)</code>, and store them in <code>dest1</code> and <code>dest2</code>,
48     * respectively.
49     * <p>
50     * The computed vectors will themselves be perpendicular to each another and normalized. So the tree vectors <code>(x, y, z)</code>, <code>dest1</code> and
51     * <code>dest2</code> form an orthonormal basis.
52     * 
53     * @param x
54     *            the x coordinate of the normalized input vector
55     * @param y
56     *            the y coordinate of the normalized input vector
57     * @param z
58     *            the z coordinate of the normalized input vector
59     * @param dest1
60     *            will hold the first perpendicular vector
61     * @param dest2
62     *            will hold the second perpendicular vector
63     */
64 public static void perpendicular(double x, double y, double z, ref Vector3d dest1, ref Vector3d dest2) {
65     double magX = z * z + y * y;
66     double magY = z * z + x * x;
67     double magZ = y * y + x * x;
68     double mag;
69     if (magX > magY && magX > magZ) {
70         dest1.x = 0;
71         dest1.y = z;
72         dest1.z = -y;
73         mag = magX;
74     } else if (magY > magZ) {
75         dest1.x = -z;
76         dest1.y = 0;
77         dest1.z = x;
78         mag = magY;
79     } else {
80         dest1.x = y;
81         dest1.y = -x;
82         dest1.z = 0;
83         mag = magZ;
84     }
85     double len = Math.invsqrt(mag);
86     dest1.x *= len;
87     dest1.y *= len;
88     dest1.z *= len;
89     dest2.x = y * dest1.z - z * dest1.y;
90     dest2.y = z * dest1.x - x * dest1.z;
91     dest2.z = x * dest1.y - y * dest1.x;
92 }
93 
94 /**
95     * Compute two arbitrary vectors perpendicular to the given normalized vector <code>v</code>, and store them in <code>dest1</code> and <code>dest2</code>,
96     * respectively.
97     * <p>
98     * The computed vectors will themselves be perpendicular to each another and normalized. So the tree vectors <code>v</code>, <code>dest1</code> and
99     * <code>dest2</code> form an orthonormal basis.
100     * 
101     * @param v
102     *            the {@link Vector3d#normalize() normalized} input vector
103     * @param dest1
104     *            will hold the first perpendicular vector
105     * @param dest2
106     *            will hold the second perpendicular vector
107     */
108 public static void perpendicular(ref Vector3d v, ref Vector3d dest1, ref Vector3d dest2) {
109     perpendicular(v.x, v.y, v.z, dest1, dest2);
110 }
111 
112 /**
113     * Calculate the normal of a surface defined by points <code>v1</code>, <code>v2</code> and <code>v3</code> and store it in <code>dest</code>.
114     * 
115     * @param v0
116     *            the first position
117     * @param v1
118     *            the second position
119     * @param v2
120     *            the third position
121     * @param dest
122     *            will hold the result
123     */
124 public static void normal(Vector3d v0, Vector3d v1, Vector3d v2, ref Vector3d dest) {
125     normal(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, dest);
126 }
127 
128 /**
129     * Calculate the normal of a surface defined by points <code>(v1X, v1Y, v1Z)</code>, <code>(v2X, v2Y, v2Z)</code> and <code>(v3X, v3Y, v3Z)</code>
130     * and store it in <code>dest</code>.
131     * 
132     * @param v0X
133     *            the x coordinate of the first position
134     * @param v0Y
135     *            the y coordinate of the first position
136     * @param v0Z
137     *            the z coordinate of the first position
138     * @param v1X
139     *            the x coordinate of the second position
140     * @param v1Y
141     *            the y coordinate of the second position
142     * @param v1Z
143     *            the z coordinate of the second position
144     * @param v2X
145     *            the x coordinate of the third position
146     * @param v2Y
147     *            the y coordinate of the third position
148     * @param v2Z
149     *            the z coordinate of the third position
150     * @param dest
151     *            will hold the result
152     */
153 public static void normal(double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, ref Vector3d dest) {
154     dest.x = ((v1Y - v0Y) * (v2Z - v0Z)) - ((v1Z - v0Z) * (v2Y - v0Y));
155     dest.y = ((v1Z - v0Z) * (v2X - v0X)) - ((v1X - v0X) * (v2Z - v0Z));
156     dest.z = ((v1X - v0X) * (v2Y - v0Y)) - ((v1Y - v0Y) * (v2X - v0X));
157     dest.normalize();
158 }
159 
160 /**
161     * Calculate the surface tangent for the three supplied vertices and UV coordinates and store the result in <code>dest</code>.
162     *
163     * @param v1
164     *            XYZ of first vertex
165     * @param uv1
166     *            UV of first vertex
167     * @param v2
168     *            XYZ of second vertex
169     * @param uv2
170     *            UV of second vertex
171     * @param v3
172     *            XYZ of third vertex
173     * @param uv3
174     *            UV of third vertex
175     * @param dest
176     *            the tangent will be stored here
177     */
178 public static void tangent(ref Vector3d v1, ref Vector2d uv1, ref Vector3d v2, ref Vector2d uv2, ref Vector3d v3, ref Vector2d uv3, ref Vector3d dest) {
179     double DeltaV1 = uv2.y - uv1.y;
180     double DeltaV2 = uv3.y - uv1.y;
181 
182     double f = 1.0f / ((uv2.x - uv1.x) * DeltaV2 - (uv3.x - uv1.x) * DeltaV1);
183 
184     dest.x = f * (DeltaV2 * (v2.x - v1.x) - DeltaV1 * (v3.x - v1.x));
185     dest.y = f * (DeltaV2 * (v2.y - v1.y) - DeltaV1 * (v3.y - v1.y));
186     dest.z = f * (DeltaV2 * (v2.z - v1.z) - DeltaV1 * (v3.z - v1.z));
187     dest.normalize();
188 }
189 
190 /**
191     * Calculate the surface bitangent for the three supplied vertices and UV coordinates and store the result in <code>dest</code>.
192     *
193     * @param v1
194     *            XYZ of first vertex
195     * @param uv1
196     *            UV of first vertex
197     * @param v2
198     *            XYZ of second vertex
199     * @param uv2
200     *            UV of second vertex
201     * @param v3
202     *            XYZ of third vertex
203     * @param uv3
204     *            UV of third vertex
205     * @param dest
206     *            the binormal will be stored here
207     */
208 public static void bitangent(ref Vector3d v1, ref Vector2d uv1, ref Vector3d v2, ref Vector2d uv2, ref Vector3d v3, ref Vector2d uv3, ref Vector3d dest) {
209     double DeltaU1 = uv2.x - uv1.x;
210     double DeltaU2 = uv3.x - uv1.x;
211 
212     double f = 1.0f / (DeltaU1 * (uv3.y - uv1.y) - DeltaU2 * (uv2.y - uv1.y));
213 
214     dest.x = f * (-DeltaU2 * (v2.x - v1.x) + DeltaU1 * (v3.x - v1.x));
215     dest.y = f * (-DeltaU2 * (v2.y - v1.y) + DeltaU1 * (v3.y - v1.y));
216     dest.z = f * (-DeltaU2 * (v2.z - v1.z) + DeltaU1 * (v3.z - v1.z));
217     dest.normalize();
218 }
219 
220 /**
221     * Calculate the surface tangent and bitangent for the three supplied vertices and UV coordinates and store the result in <code>dest</code>.
222     *
223     * @param v1
224     *            XYZ of first vertex
225     * @param uv1
226     *            UV of first vertex
227     * @param v2
228     *            XYZ of second vertex
229     * @param uv2
230     *            UV of second vertex
231     * @param v3
232     *            XYZ of third vertex
233     * @param uv3
234     *            UV of third vertex
235     * @param destTangent
236     *            the tangent will be stored here
237     * @param destBitangent
238     *            the bitangent will be stored here
239     */
240 public static void tangentBitangent(ref Vector3d v1, ref Vector2d uv1, ref Vector3d v2, ref Vector2d uv2, ref Vector3d v3, ref Vector2d uv3, ref Vector3d destTangent, ref Vector3d destBitangent) {
241     double DeltaV1 = uv2.y - uv1.y;
242     double DeltaV2 = uv3.y - uv1.y;
243     double DeltaU1 = uv2.x - uv1.x;
244     double DeltaU2 = uv3.x - uv1.x;
245 
246     double f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
247 
248     destTangent.x = f * (DeltaV2 * (v2.x - v1.x) - DeltaV1 * (v3.x - v1.x));
249     destTangent.y = f * (DeltaV2 * (v2.y - v1.y) - DeltaV1 * (v3.y - v1.y));
250     destTangent.z = f * (DeltaV2 * (v2.z - v1.z) - DeltaV1 * (v3.z - v1.z));
251     destTangent.normalize();
252 
253     destBitangent.x = f * (-DeltaU2 * (v2.x - v1.x) + DeltaU1 * (v3.x - v1.x));
254     destBitangent.y = f * (-DeltaU2 * (v2.y - v1.y) + DeltaU1 * (v3.y - v1.y));
255     destBitangent.z = f * (-DeltaU2 * (v2.z - v1.z) + DeltaU1 * (v3.z - v1.z));
256     destBitangent.normalize();
257 }