View Javadoc
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 }