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