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 }