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 }