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 }