1 // ****************************************************************************** 2 // 3 // Title: Force Field X. 4 // Description: Force Field X - Software for Molecular Biophysics. 5 // Copyright: Copyright (c) Michael J. Schnieders 2001-2025. 6 // 7 // This file is part of Force Field X. 8 // 9 // Force Field X is free software; you can redistribute it and/or modify it 10 // under the terms of the GNU General Public License version 3 as published by 11 // the Free Software Foundation. 12 // 13 // Force Field X is distributed in the hope that it will be useful, but WITHOUT 14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 // details. 17 // 18 // You should have received a copy of the GNU General Public License along with 19 // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple 20 // Place, Suite 330, Boston, MA 02111-1307 USA 21 // 22 // Linking this library statically or dynamically with other modules is making a 23 // combined work based on this library. Thus, the terms and conditions of the 24 // GNU General Public License cover the whole combination. 25 // 26 // As a special exception, the copyright holders of this library give you 27 // permission to link this library with independent modules to produce an 28 // executable, regardless of the license terms of these independent modules, and 29 // to copy and distribute the resulting executable under terms of your choice, 30 // provided that you also meet, for each linked independent module, the terms 31 // and conditions of the license of that module. An independent module is a 32 // module which is not derived from or based on this library. If you modify this 33 // library, you may extend this exception to your version of the library, but 34 // you are not obligated to do so. If you do not wish to do so, delete this 35 // exception statement from your version. 36 // 37 // ****************************************************************************** 38 package ffx.numerics.quickhull; 39 40 import java.util.Random; 41 42 /** 43 * A three-element vector. This class is actually a reduced version of the 44 * Vector3d class contained in the author's matlib package (which was partly 45 * inspired by javax.vecmath). Only a mininal number of methods which are 46 * relevant to convex hull generation are supplied here. 47 * 48 * @author John E. Lloyd, Fall 2004 49 * @author Michael J. Schnieders 50 * @since 1.0 51 */ 52 public class Vector3d { 53 54 /** 55 * Precision of a double. 56 */ 57 static private final double DOUBLE_PREC = 2.2204460492503131e-16; 58 59 /** 60 * First element 61 */ 62 public double x; 63 64 /** 65 * Second element 66 */ 67 public double y; 68 69 /** 70 * Third element 71 */ 72 public double z; 73 74 /** 75 * Creates a 3-vector and initializes its elements to 0. 76 */ 77 public Vector3d() { 78 } 79 80 /** 81 * Creates a 3-vector by copying an existing one. 82 * 83 * @param v vector to be copied 84 */ 85 public Vector3d(Vector3d v) { 86 set(v); 87 } 88 89 /** 90 * Creates a 3-vector with the supplied element values. 91 * 92 * @param x first element 93 * @param y second element 94 * @param z third element 95 */ 96 public Vector3d(double x, double y, double z) { 97 set(x, y, z); 98 } 99 100 /** 101 * Gets a single element of this vector. Elements 0, 1, and 2 correspond to 102 * x, y, and z. 103 * 104 * @param i element index 105 * @return element value throws ArrayIndexOutOfBoundsException if i is not 106 * in the range 0 to 2. 107 */ 108 public double get(int i) { 109 return switch (i) { 110 case 0 -> x; 111 case 1 -> y; 112 case 2 -> z; 113 default -> throw new ArrayIndexOutOfBoundsException(i); 114 }; 115 } 116 117 /** 118 * Sets a single element of this vector. Elements 0, 1, and 2 correspond to 119 * x, y, and z. Element value throws ArrayIndexOutOfBoundsException if i is not 120 * in the range 0 to 2. 121 * 122 * @param i element index 123 * @param value element value 124 */ 125 public void set(int i, double value) { 126 switch (i) { 127 case 0: { 128 x = value; 129 break; 130 } 131 case 1: { 132 y = value; 133 break; 134 } 135 case 2: { 136 z = value; 137 break; 138 } 139 default: { 140 throw new ArrayIndexOutOfBoundsException(i); 141 } 142 } 143 } 144 145 /** 146 * Sets the values of this vector to those of v1. 147 * 148 * @param v1 vector whose values are copied 149 */ 150 public void set(Vector3d v1) { 151 x = v1.x; 152 y = v1.y; 153 z = v1.z; 154 } 155 156 /** 157 * Adds vector v1 to v2 and places the result in this vector. 158 * 159 * @param v1 left-hand vector 160 * @param v2 right-hand vector 161 */ 162 public void add(Vector3d v1, Vector3d v2) { 163 x = v1.x + v2.x; 164 y = v1.y + v2.y; 165 z = v1.z + v2.z; 166 } 167 168 /** 169 * Adds this vector to v1 and places the result in this vector. 170 * 171 * @param v1 right-hand vector 172 */ 173 public void add(Vector3d v1) { 174 x += v1.x; 175 y += v1.y; 176 z += v1.z; 177 } 178 179 /** 180 * Subtracts vector v1 from v2 and places the result in this vector. 181 * 182 * @param v1 left-hand vector 183 * @param v2 right-hand vector 184 */ 185 public void sub(Vector3d v1, Vector3d v2) { 186 x = v1.x - v2.x; 187 y = v1.y - v2.y; 188 z = v1.z - v2.z; 189 } 190 191 /** 192 * Subtracts v1 from this vector and places the result in this vector. 193 * 194 * @param v1 right-hand vector 195 */ 196 public void sub(Vector3d v1) { 197 x -= v1.x; 198 y -= v1.y; 199 z -= v1.z; 200 } 201 202 /** 203 * Scales the elements of this vector by <code>s</code>. 204 * 205 * @param s scaling factor 206 */ 207 public void scale(double s) { 208 x = s * x; 209 y = s * y; 210 z = s * z; 211 } 212 213 /** 214 * Scales the elements of vector v1 by <code>s</code> and places the results 215 * in this vector. 216 * 217 * @param s scaling factor 218 * @param v1 vector to be scaled 219 */ 220 public void scale(double s, Vector3d v1) { 221 x = s * v1.x; 222 y = s * v1.y; 223 z = s * v1.z; 224 } 225 226 /** 227 * Returns the 2 norm of this vector. This is the square root of the sum of 228 * the squares of the elements. 229 * 230 * @return vector 2 norm 231 */ 232 public double norm() { 233 return Math.sqrt(x * x + y * y + z * z); 234 } 235 236 /** 237 * Returns the square of the 2 norm of this vector. This is the sum of the 238 * squares of the elements. 239 * 240 * @return square of the 2 norm 241 */ 242 public double normSquared() { 243 return x * x + y * y + z * z; 244 } 245 246 /** 247 * Returns the Euclidean distance between this vector and vector v. 248 * 249 * @return distance between this vector and v 250 */ 251 public double distance(Vector3d v) { 252 double dx = x - v.x; 253 double dy = y - v.y; 254 double dz = z - v.z; 255 256 return Math.sqrt(dx * dx + dy * dy + dz * dz); 257 } 258 259 /** 260 * Returns the squared of the Euclidean distance between this vector and 261 * vector v. 262 * 263 * @return squared distance between this vector and v 264 */ 265 public double distanceSquared(Vector3d v) { 266 double dx = x - v.x; 267 double dy = y - v.y; 268 double dz = z - v.z; 269 270 return dx * dx + dy * dy + dz * dz; 271 } 272 273 /** 274 * Returns the dot product of this vector and v1. 275 * 276 * @param v1 right-hand vector 277 * @return dot product 278 */ 279 public double dot(Vector3d v1) { 280 return x * v1.x + y * v1.y + z * v1.z; 281 } 282 283 /** 284 * Normalizes this vector in place. 285 */ 286 public void normalize() { 287 double lenSqr = x * x + y * y + z * z; 288 double err = lenSqr - 1; 289 if (err > (2 * DOUBLE_PREC) || err < -(2 * DOUBLE_PREC)) { 290 double len = Math.sqrt(lenSqr); 291 x /= len; 292 y /= len; 293 z /= len; 294 } 295 } 296 297 /** 298 * Sets the elements of this vector to zero. 299 */ 300 public void setZero() { 301 x = 0; 302 y = 0; 303 z = 0; 304 } 305 306 /** 307 * Sets the elements of this vector to the prescribed values. 308 * 309 * @param x value for first element 310 * @param y value for second element 311 * @param z value for third element 312 */ 313 public void set(double x, double y, double z) { 314 this.x = x; 315 this.y = y; 316 this.z = z; 317 } 318 319 /** 320 * Computes the cross product of v1 and v2 and places the result in this 321 * vector. 322 * 323 * @param v1 left-hand vector 324 * @param v2 right-hand vector 325 */ 326 public void cross(Vector3d v1, Vector3d v2) { 327 double tmpx = v1.y * v2.z - v1.z * v2.y; 328 double tmpy = v1.z * v2.x - v1.x * v2.z; 329 double tmpz = v1.x * v2.y - v1.y * v2.x; 330 331 x = tmpx; 332 y = tmpy; 333 z = tmpz; 334 } 335 336 /** 337 * Sets the elements of this vector to uniformly distributed random values 338 * in a specified range, using a supplied random number generator. 339 * 340 * @param lower lower random value (inclusive) 341 * @param upper upper random value (exclusive) 342 * @param generator random number generator 343 */ 344 protected void setRandom(double lower, double upper, Random generator) { 345 double range = upper - lower; 346 347 x = generator.nextDouble() * range + lower; 348 y = generator.nextDouble() * range + lower; 349 z = generator.nextDouble() * range + lower; 350 } 351 352 /** 353 * Returns a string representation of this vector, consisting of the x, y, 354 * and z coordinates. 355 * 356 * @return string representation 357 */ 358 public String toString() { 359 return x + " " + y + " " + z; 360 } 361 }