1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.geometry.euclidean.threed;
24
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.exception.MathRuntimeException;
28 import org.hipparchus.geometry.Point;
29 import org.hipparchus.geometry.Space;
30 import org.hipparchus.geometry.Vector;
31 import org.hipparchus.util.FastMath;
32 import org.hipparchus.util.MathArrays;
33 import org.hipparchus.util.MathUtils;
34 import org.hipparchus.util.SinCos;
35
36 import java.io.Serializable;
37 import java.text.NumberFormat;
38
39
40
41
42
43 public class Vector3D implements Serializable, Vector<Euclidean3D, Vector3D> {
44
45
46 public static final Vector3D ZERO = new Vector3D(0, 0, 0);
47
48
49 public static final Vector3D PLUS_I = new Vector3D(1, 0, 0);
50
51
52 public static final Vector3D MINUS_I = new Vector3D(-1, 0, 0);
53
54
55 public static final Vector3D PLUS_J = new Vector3D(0, 1, 0);
56
57
58 public static final Vector3D MINUS_J = new Vector3D(0, -1, 0);
59
60
61 public static final Vector3D PLUS_K = new Vector3D(0, 0, 1);
62
63
64 public static final Vector3D MINUS_K = new Vector3D(0, 0, -1);
65
66
67
68 public static final Vector3D NaN = new Vector3D(Double.NaN, Double.NaN, Double.NaN);
69
70
71
72 public static final Vector3D POSITIVE_INFINITY =
73 new Vector3D(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
74
75
76 public static final Vector3D NEGATIVE_INFINITY =
77 new Vector3D(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
78
79
80 private static final long serialVersionUID = 1313493323784566947L;
81
82
83 private final double x;
84
85
86 private final double y;
87
88
89 private final double z;
90
91
92
93
94
95
96
97
98
99
100 public Vector3D(double x, double y, double z) {
101 this.x = x;
102 this.y = y;
103 this.z = z;
104 }
105
106
107
108
109
110
111
112 public Vector3D(double[] v) throws MathIllegalArgumentException {
113 if (v.length != 3) {
114 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
115 v.length, 3);
116 }
117 this.x = v[0];
118 this.y = v[1];
119 this.z = v[2];
120 }
121
122
123
124
125
126
127
128
129
130 public Vector3D(double alpha, double delta) {
131 SinCos sinCosAlpha = FastMath.sinCos(alpha);
132 SinCos sinCosDelta = FastMath.sinCos(delta);
133 this.x = sinCosAlpha.cos() * sinCosDelta.cos();
134 this.y = sinCosAlpha.sin() * sinCosDelta.cos();
135 this.z = sinCosDelta.sin();
136 }
137
138
139
140
141
142
143
144 public Vector3D(double a, Vector3D u) {
145 this.x = a * u.x;
146 this.y = a * u.y;
147 this.z = a * u.z;
148 }
149
150
151
152
153
154
155
156
157
158 public Vector3D(double a1, Vector3D u1, double a2, Vector3D u2) {
159 this.x = MathArrays.linearCombination(a1, u1.x, a2, u2.x);
160 this.y = MathArrays.linearCombination(a1, u1.y, a2, u2.y);
161 this.z = MathArrays.linearCombination(a1, u1.z, a2, u2.z);
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public Vector3D(double a1, Vector3D u1, double a2, Vector3D u2,
175 double a3, Vector3D u3) {
176 this.x = MathArrays.linearCombination(a1, u1.x, a2, u2.x, a3, u3.x);
177 this.y = MathArrays.linearCombination(a1, u1.y, a2, u2.y, a3, u3.y);
178 this.z = MathArrays.linearCombination(a1, u1.z, a2, u2.z, a3, u3.z);
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193 public Vector3D(double a1, Vector3D u1, double a2, Vector3D u2,
194 double a3, Vector3D u3, double a4, Vector3D u4) {
195 this.x = MathArrays.linearCombination(a1, u1.x, a2, u2.x, a3, u3.x, a4, u4.x);
196 this.y = MathArrays.linearCombination(a1, u1.y, a2, u2.y, a3, u3.y, a4, u4.y);
197 this.z = MathArrays.linearCombination(a1, u1.z, a2, u2.z, a3, u3.z, a4, u4.z);
198 }
199
200
201
202
203
204 public double getX() {
205 return x;
206 }
207
208
209
210
211
212 public double getY() {
213 return y;
214 }
215
216
217
218
219
220 public double getZ() {
221 return z;
222 }
223
224
225
226
227
228 public double[] toArray() {
229 return new double[] { x, y, z };
230 }
231
232
233 @Override
234 public Space getSpace() {
235 return Euclidean3D.getInstance();
236 }
237
238
239 @Override
240 public Vector3D getZero() {
241 return ZERO;
242 }
243
244
245 @Override
246 public double getNorm1() {
247 return FastMath.abs(x) + FastMath.abs(y) + FastMath.abs(z);
248 }
249
250
251 @Override
252 public double getNorm() {
253
254 return FastMath.sqrt (x * x + y * y + z * z);
255 }
256
257
258 @Override
259 public double getNormSq() {
260
261 return x * x + y * y + z * z;
262 }
263
264
265 @Override
266 public double getNormInf() {
267 return FastMath.max(FastMath.max(FastMath.abs(x), FastMath.abs(y)), FastMath.abs(z));
268 }
269
270
271
272
273
274 public double getAlpha() {
275 return FastMath.atan2(y, x);
276 }
277
278
279
280
281
282 public double getDelta() {
283 return FastMath.asin(z / getNorm());
284 }
285
286
287 @Override
288 public Vector3D add(final Vector<Euclidean3D, Vector3D> v) {
289 final Vector3D v3 = (Vector3D) v;
290 return new Vector3D(x + v3.x, y + v3.y, z + v3.z);
291 }
292
293
294 @Override
295 public Vector3D add(double factor, final Vector<Euclidean3D, Vector3D> v) {
296 return new Vector3D(1, this, factor, (Vector3D) v);
297 }
298
299
300 @Override
301 public Vector3D subtract(final Vector<Euclidean3D, Vector3D> v) {
302 final Vector3D v3 = (Vector3D) v;
303 return new Vector3D(x - v3.x, y - v3.y, z - v3.z);
304 }
305
306
307 @Override
308 public Vector3D subtract(final double factor, final Vector<Euclidean3D, Vector3D> v) {
309 return new Vector3D(1, this, -factor, (Vector3D) v);
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 public Vector3D orthogonal() throws MathRuntimeException {
329
330 double threshold = 0.6 * getNorm();
331 if (threshold == 0) {
332 throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
333 }
334
335 if (FastMath.abs(x) <= threshold) {
336 double inverse = 1 / FastMath.sqrt(y * y + z * z);
337 return new Vector3D(0, inverse * z, -inverse * y);
338 } else if (FastMath.abs(y) <= threshold) {
339 double inverse = 1 / FastMath.sqrt(x * x + z * z);
340 return new Vector3D(-inverse * z, 0, inverse * x);
341 }
342 double inverse = 1 / FastMath.sqrt(x * x + y * y);
343 return new Vector3D(inverse * y, -inverse * x, 0);
344
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358 public static double angle(Vector3D v1, Vector3D v2) throws MathRuntimeException {
359
360 double normProduct = v1.getNorm() * v2.getNorm();
361 if (normProduct == 0) {
362 throw new MathRuntimeException(LocalizedCoreFormats.ZERO_NORM);
363 }
364
365 double dot = v1.dotProduct(v2);
366 double threshold = normProduct * 0.9999;
367 if ((dot < -threshold) || (dot > threshold)) {
368
369 Vector3D v3 = crossProduct(v1, v2);
370 if (dot >= 0) {
371 return FastMath.asin(v3.getNorm() / normProduct);
372 }
373 return FastMath.PI - FastMath.asin(v3.getNorm() / normProduct);
374 }
375
376
377 return FastMath.acos(dot / normProduct);
378
379 }
380
381
382 @Override
383 public Vector3D negate() {
384 return new Vector3D(-x, -y, -z);
385 }
386
387
388 @Override
389 public Vector3D scalarMultiply(double a) {
390 return new Vector3D(a * x, a * y, a * z);
391 }
392
393
394 @Override
395 public boolean isNaN() {
396 return Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z);
397 }
398
399
400 @Override
401 public boolean isInfinite() {
402 return !isNaN() && (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z));
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 @Override
425 public boolean equals(Object other) {
426
427 if (this == other) {
428 return true;
429 }
430
431 if (other instanceof Vector3D) {
432 final Vector3D rhs = (Vector3D)other;
433 return x == rhs.x && y == rhs.y && z == rhs.z || isNaN() && rhs.isNaN();
434 }
435
436 return false;
437
438 }
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459 public boolean equalsIeee754(Object other) {
460
461 if (this == other && !isNaN()) {
462 return true;
463 }
464
465 if (other instanceof Vector3D) {
466 final Vector3D rhs = (Vector3D) other;
467 return x == rhs.x && y == rhs.y && z == rhs.z;
468 }
469
470 return false;
471
472 }
473
474
475
476
477
478
479
480
481 @Override
482 public int hashCode() {
483 if (isNaN()) {
484 return 642;
485 }
486 return 643 * (164 * MathUtils.hash(x) + 3 * MathUtils.hash(y) + MathUtils.hash(z));
487 }
488
489
490
491
492
493
494
495
496
497 @Override
498 public double dotProduct(final Vector<Euclidean3D, Vector3D> v) {
499 final Vector3D v3 = (Vector3D) v;
500 return MathArrays.linearCombination(x, v3.x, y, v3.y, z, v3.z);
501 }
502
503
504
505
506
507 public Vector3D crossProduct(final Vector<Euclidean3D, Vector3D> v) {
508 final Vector3D v3 = (Vector3D) v;
509 return new Vector3D(MathArrays.linearCombination(y, v3.z, -z, v3.y),
510 MathArrays.linearCombination(z, v3.x, -x, v3.z),
511 MathArrays.linearCombination(x, v3.y, -y, v3.x));
512 }
513
514
515 @Override
516 public double distance1(Vector<Euclidean3D, Vector3D> v) {
517 final Vector3D v3 = (Vector3D) v;
518 final double dx = FastMath.abs(v3.x - x);
519 final double dy = FastMath.abs(v3.y - y);
520 final double dz = FastMath.abs(v3.z - z);
521 return dx + dy + dz;
522 }
523
524
525 @Override
526 public double distance(Point<Euclidean3D> v) {
527 final Vector3D v3 = (Vector3D) v;
528 final double dx = v3.x - x;
529 final double dy = v3.y - y;
530 final double dz = v3.z - z;
531 return FastMath.sqrt(dx * dx + dy * dy + dz * dz);
532 }
533
534
535 @Override
536 public double distanceInf(Vector<Euclidean3D, Vector3D> v) {
537 final Vector3D v3 = (Vector3D) v;
538 final double dx = FastMath.abs(v3.x - x);
539 final double dy = FastMath.abs(v3.y - y);
540 final double dz = FastMath.abs(v3.z - z);
541 return FastMath.max(FastMath.max(dx, dy), dz);
542 }
543
544
545 @Override
546 public double distanceSq(Vector<Euclidean3D, Vector3D> v) {
547 final Vector3D v3 = (Vector3D) v;
548 final double dx = v3.x - x;
549 final double dy = v3.y - y;
550 final double dz = v3.z - z;
551 return dx * dx + dy * dy + dz * dz;
552 }
553
554
555
556
557
558
559 public static double dotProduct(Vector3D v1, Vector3D v2) {
560 return v1.dotProduct(v2);
561 }
562
563
564
565
566
567
568 public static Vector3D crossProduct(final Vector3D v1, final Vector3D v2) {
569 return v1.crossProduct(v2);
570 }
571
572
573
574
575
576
577
578
579
580 public static double distance1(Vector3D v1, Vector3D v2) {
581 return v1.distance1(v2);
582 }
583
584
585
586
587
588
589
590
591
592 public static double distance(Vector3D v1, Vector3D v2) {
593 return v1.distance(v2);
594 }
595
596
597
598
599
600
601
602
603
604 public static double distanceInf(Vector3D v1, Vector3D v2) {
605 return v1.distanceInf(v2);
606 }
607
608
609
610
611
612
613
614
615
616 public static double distanceSq(Vector3D v1, Vector3D v2) {
617 return v1.distanceSq(v2);
618 }
619
620
621
622
623 @Override
624 public String toString() {
625 return Vector3DFormat.getVector3DFormat().format(this);
626 }
627
628
629 @Override
630 public String toString(final NumberFormat format) {
631 return new Vector3DFormat(format).format(this);
632 }
633
634 }