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.UnitTestUtils;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.exception.MathRuntimeException;
28 import org.hipparchus.geometry.Space;
29 import org.hipparchus.random.Well1024a;
30 import org.hipparchus.util.FastMath;
31 import org.hipparchus.util.Precision;
32 import org.junit.jupiter.api.Test;
33
34 import java.text.DecimalFormat;
35 import java.text.DecimalFormatSymbols;
36 import java.text.NumberFormat;
37 import java.util.Locale;
38
39 import static org.junit.jupiter.api.Assertions.assertEquals;
40 import static org.junit.jupiter.api.Assertions.assertFalse;
41 import static org.junit.jupiter.api.Assertions.assertNotEquals;
42 import static org.junit.jupiter.api.Assertions.assertThrows;
43 import static org.junit.jupiter.api.Assertions.assertTrue;
44 import static org.junit.jupiter.api.Assertions.fail;
45
46 class Vector3DTest {
47 @Test
48 void testConstructors() throws MathIllegalArgumentException {
49 double r = FastMath.sqrt(2) /2;
50 checkVector(new Vector3D(2, new Vector3D(FastMath.PI / 3, -FastMath.PI / 4)),
51 r, r * FastMath.sqrt(3), -2 * r);
52 checkVector(new Vector3D(2, Vector3D.PLUS_I,
53 -3, Vector3D.MINUS_K),
54 2, 0, 3);
55 checkVector(new Vector3D(2, Vector3D.PLUS_I,
56 5, Vector3D.PLUS_J,
57 -3, Vector3D.MINUS_K),
58 2, 5, 3);
59 checkVector(new Vector3D(2, Vector3D.PLUS_I,
60 5, Vector3D.PLUS_J,
61 5, Vector3D.MINUS_J,
62 -3, Vector3D.MINUS_K),
63 2, 0, 3);
64 checkVector(new Vector3D(new double[] { 2, 5, -3 }),
65 2, 5, -3);
66 }
67
68 @Test
69 void testSpace() {
70 Space space = new Vector3D(1, 2, 2).getSpace();
71 assertEquals(3, space.getDimension());
72 assertEquals(2, space.getSubSpace().getDimension());
73 Space deserialized = (Space) UnitTestUtils.serializeAndRecover(space);
74 assertTrue(space == deserialized);
75 }
76
77 @Test
78 void testZero() {
79 assertEquals(0, new Vector3D(1, 2, 2).getZero().getNorm(), 1.0e-15);
80 }
81
82 @SuppressWarnings("unlikely-arg-type")
83 @Test
84 void testEquals() {
85 Vector3D u1 = new Vector3D(1, 2, 3);
86 Vector3D u2 = new Vector3D(1, 2, 3);
87 assertEquals(u1, u1);
88 assertEquals(u1, u2);
89 assertNotEquals(u1, new Rotation(1, 0, 0, 0, false));
90 assertNotEquals(u1, new Vector3D(1, 2, 3 + 10 * Precision.EPSILON));
91 assertNotEquals(u1, new Vector3D(1, 2 + 10 * Precision.EPSILON, 3));
92 assertNotEquals(u1, new Vector3D(1 + 10 * Precision.EPSILON, 2, 3));
93 assertEquals(new Vector3D(0, Double.NaN, 0), new Vector3D(0, 0, Double.NaN));
94 }
95
96 @Test
97 void testEqualsIeee754() {
98 Vector3D u1 = new Vector3D(1, 2, 3);
99 Vector3D u2 = new Vector3D(1, 2, 3);
100 assertTrue(u1.equalsIeee754(u1));
101 assertTrue(u1.equalsIeee754(u2));
102 assertFalse(u1.equalsIeee754(new Rotation(1, 0, 0, 0, false)));
103 assertFalse(u1.equalsIeee754(new Vector3D(1, 2, 3 + 10 * Precision.EPSILON)));
104 assertFalse(u1.equalsIeee754(new Vector3D(1, 2 + 10 * Precision.EPSILON, 3)));
105 assertFalse(u1.equalsIeee754(new Vector3D(1 + 10 * Precision.EPSILON, 2, 3)));
106 assertFalse(new Vector3D(0, Double.NaN, 0).equalsIeee754(new Vector3D(0, 0, Double.NaN)));
107 assertFalse(Vector3D.NaN.equalsIeee754(Vector3D.NaN));
108 }
109
110 @Test
111 void testHash() {
112 assertEquals(new Vector3D(0, Double.NaN, 0).hashCode(), new Vector3D(0, 0, Double.NaN).hashCode());
113 Vector3D u = new Vector3D(1, 2, 3);
114 Vector3D v = new Vector3D(1, 2, 3 + 10 * Precision.EPSILON);
115 assertTrue(u.hashCode() != v.hashCode());
116 }
117
118 @Test
119 void testInfinite() {
120 assertTrue(new Vector3D(1, 1, Double.NEGATIVE_INFINITY).isInfinite());
121 assertTrue(new Vector3D(1, Double.NEGATIVE_INFINITY, 1).isInfinite());
122 assertTrue(new Vector3D(Double.NEGATIVE_INFINITY, 1, 1).isInfinite());
123 assertFalse(new Vector3D(1, 1, 2).isInfinite());
124 assertFalse(new Vector3D(1, Double.NaN, Double.NEGATIVE_INFINITY).isInfinite());
125 }
126
127 @Test
128 void testNaN() {
129 assertTrue(new Vector3D(1, 1, Double.NaN).isNaN());
130 assertTrue(new Vector3D(1, Double.NaN, 1).isNaN());
131 assertTrue(new Vector3D(Double.NaN, 1, 1).isNaN());
132 assertFalse(new Vector3D(1, 1, 2).isNaN());
133 assertFalse(new Vector3D(1, 1, Double.NEGATIVE_INFINITY).isNaN());
134 }
135
136 @Test
137 void testToString() {
138 assertEquals("{3; 2; 1}", new Vector3D(3, 2, 1).toString());
139 NumberFormat format = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
140 assertEquals("{3.000; 2.000; 1.000}", new Vector3D(3, 2, 1).toString(format));
141 }
142
143 @Test
144 void testWrongDimension() throws MathIllegalArgumentException {
145 assertThrows(MathIllegalArgumentException.class, () -> {
146 new Vector3D(new double[]{2, 5});
147 });
148 }
149
150 @Test
151 void testCoordinates() {
152 Vector3D v = new Vector3D(1, 2, 3);
153 assertTrue(FastMath.abs(v.getX() - 1) < 1.0e-12);
154 assertTrue(FastMath.abs(v.getY() - 2) < 1.0e-12);
155 assertTrue(FastMath.abs(v.getZ() - 3) < 1.0e-12);
156 double[] coordinates = v.toArray();
157 assertTrue(FastMath.abs(coordinates[0] - 1) < 1.0e-12);
158 assertTrue(FastMath.abs(coordinates[1] - 2) < 1.0e-12);
159 assertTrue(FastMath.abs(coordinates[2] - 3) < 1.0e-12);
160 }
161
162 @Test
163 void testNorm1() {
164 assertEquals(0.0, Vector3D.ZERO.getNorm1(), 0);
165 assertEquals(6.0, new Vector3D(1, -2, 3).getNorm1(), 0);
166 }
167
168 @Test
169 void testNorm() {
170 assertEquals(0.0, Vector3D.ZERO.getNorm(), 0);
171 assertEquals(FastMath.sqrt(14), new Vector3D(1, 2, 3).getNorm(), 1.0e-12);
172 }
173
174 @Test
175 void testNormSq() {
176 assertEquals(0.0, new Vector3D(0, 0, 0).getNormSq(), 0);
177 assertEquals(14, new Vector3D(1, 2, 3).getNormSq(), 1.0e-12);
178 }
179
180 @Test
181 void testNormInf() {
182 assertEquals(0.0, Vector3D.ZERO.getNormInf(), 0);
183 assertEquals(3.0, new Vector3D(1, -2, 3).getNormInf(), 0);
184 }
185
186 @Test
187 void testDistance1() {
188 Vector3D v1 = new Vector3D(1, -2, 3);
189 Vector3D v2 = new Vector3D(-4, 2, 0);
190 assertEquals(0.0, Vector3D.distance1(Vector3D.MINUS_I, Vector3D.MINUS_I), 0);
191 assertEquals(12.0, Vector3D.distance1(v1, v2), 1.0e-12);
192 assertEquals(v1.subtract(v2).getNorm1(), Vector3D.distance1(v1, v2), 1.0e-12);
193 }
194
195 @Test
196 void testDistance() {
197 Vector3D v1 = new Vector3D(1, -2, 3);
198 Vector3D v2 = new Vector3D(-4, 2, 0);
199 assertEquals(0.0, Vector3D.distance(Vector3D.MINUS_I, Vector3D.MINUS_I), 0);
200 assertEquals(FastMath.sqrt(50), Vector3D.distance(v1, v2), 1.0e-12);
201 assertEquals(v1.subtract(v2).getNorm(), Vector3D.distance(v1, v2), 1.0e-12);
202 }
203
204 @Test
205 void testDistanceSq() {
206 Vector3D v1 = new Vector3D(1, -2, 3);
207 Vector3D v2 = new Vector3D(-4, 2, 0);
208 assertEquals(0.0, Vector3D.distanceSq(Vector3D.MINUS_I, Vector3D.MINUS_I), 0);
209 assertEquals(50.0, Vector3D.distanceSq(v1, v2), 1.0e-12);
210 assertEquals(Vector3D.distance(v1, v2) * Vector3D.distance(v1, v2),
211 Vector3D.distanceSq(v1, v2), 1.0e-12);
212 }
213
214 @Test
215 void testDistanceInf() {
216 Vector3D v1 = new Vector3D(1, -2, 3);
217 Vector3D v2 = new Vector3D(-4, 2, 0);
218 assertEquals(0.0, Vector3D.distanceInf(Vector3D.MINUS_I, Vector3D.MINUS_I), 0);
219 assertEquals(5.0, Vector3D.distanceInf(v1, v2), 1.0e-12);
220 assertEquals(v1.subtract(v2).getNormInf(), Vector3D.distanceInf(v1, v2), 1.0e-12);
221 }
222
223 @Test
224 void testSubtract() {
225 Vector3D v1 = new Vector3D(1, 2, 3);
226 Vector3D v2 = new Vector3D(-3, -2, -1);
227 v1 = v1.subtract(v2);
228 checkVector(v1, 4, 4, 4);
229
230 checkVector(v2.subtract(v1), -7, -6, -5);
231 checkVector(v2.subtract(3, v1), -15, -14, -13);
232 }
233
234 @Test
235 void testAdd() {
236 Vector3D v1 = new Vector3D(1, 2, 3);
237 Vector3D v2 = new Vector3D(-3, -2, -1);
238 v1 = v1.add(v2);
239 checkVector(v1, -2, 0, 2);
240
241 checkVector(v2.add(v1), -5, -2, 1);
242 checkVector(v2.add(3, v1), -9, -2, 5);
243 }
244
245 @Test
246 void testScalarProduct() {
247 Vector3D v = new Vector3D(1, 2, 3);
248 v = v.scalarMultiply(3);
249 checkVector(v, 3, 6, 9);
250
251 checkVector(v.scalarMultiply(0.5), 1.5, 3, 4.5);
252 }
253
254 @Test
255 void testVectorialProducts() {
256 Vector3D v1 = new Vector3D(2, 1, -4);
257 Vector3D v2 = new Vector3D(3, 1, -1);
258
259 assertTrue(FastMath.abs(Vector3D.dotProduct(v1, v2) - 11) < 1.0e-12);
260
261 Vector3D v3 = Vector3D.crossProduct(v1, v2);
262 checkVector(v3, 3, -10, -1);
263
264 assertTrue(FastMath.abs(Vector3D.dotProduct(v1, v3)) < 1.0e-12);
265 assertTrue(FastMath.abs(Vector3D.dotProduct(v2, v3)) < 1.0e-12);
266 }
267
268 @Test
269 void testCrossProductCancellation() {
270 Vector3D v1 = new Vector3D(9070467121.0, 4535233560.0, 1);
271 Vector3D v2 = new Vector3D(9070467123.0, 4535233561.0, 1);
272 checkVector(Vector3D.crossProduct(v1, v2), -1, 2, 1);
273
274 double scale = FastMath.scalb(1.0, 100);
275 Vector3D big1 = new Vector3D(scale, v1);
276 Vector3D small2 = new Vector3D(1 / scale, v2);
277 checkVector(Vector3D.crossProduct(big1, small2), -1, 2, 1);
278
279 }
280
281 @Test
282 void testAngular() {
283 assertEquals(0, Vector3D.PLUS_I.getAlpha(), 1.0e-10);
284 assertEquals(0, Vector3D.PLUS_I.getDelta(), 1.0e-10);
285 assertEquals(FastMath.PI / 2, Vector3D.PLUS_J.getAlpha(), 1.0e-10);
286 assertEquals(0, Vector3D.PLUS_J.getDelta(), 1.0e-10);
287 assertEquals(0, Vector3D.PLUS_K.getAlpha(), 1.0e-10);
288 assertEquals(FastMath.PI / 2, Vector3D.PLUS_K.getDelta(), 1.0e-10);
289
290 Vector3D u = new Vector3D(-1, 1, -1);
291 assertEquals(3 * FastMath.PI /4, u.getAlpha(), 1.0e-10);
292 assertEquals(-1.0 / FastMath.sqrt(3), FastMath.sin(u.getDelta()), 1.0e-10);
293 }
294
295 @Test
296 void testAngularSeparation() throws MathRuntimeException {
297 Vector3D v1 = new Vector3D(2, -1, 4);
298
299 Vector3D k = v1.normalize();
300 Vector3D i = k.orthogonal();
301 Vector3D v2 = k.scalarMultiply(FastMath.cos(1.2)).add(i.scalarMultiply(FastMath.sin(1.2)));
302
303 assertTrue(FastMath.abs(Vector3D.angle(v1, v2) - 1.2) < 1.0e-12);
304 }
305
306 @Test
307 void testNormalize() throws MathRuntimeException {
308 assertEquals(1.0, new Vector3D(5, -4, 2).normalize().getNorm(), 1.0e-12);
309 try {
310 Vector3D.ZERO.normalize();
311 fail("an exception should have been thrown");
312 } catch (MathRuntimeException ae) {
313
314 }
315 }
316
317 @Test
318 void testNegate() {
319 checkVector(new Vector3D(0.1, 2.5, 1.3).negate(), -0.1, -2.5, -1.3);
320 }
321
322 @Test
323 void testOrthogonal() throws MathRuntimeException {
324 Vector3D v1 = new Vector3D(0.1, 2.5, 1.3);
325 assertEquals(0.0, Vector3D.dotProduct(v1, v1.orthogonal()), 1.0e-12);
326 Vector3D v2 = new Vector3D(2.3, -0.003, 7.6);
327 assertEquals(0.0, Vector3D.dotProduct(v2, v2.orthogonal()), 1.0e-12);
328 Vector3D v3 = new Vector3D(-1.7, 1.4, 0.2);
329 assertEquals(0.0, Vector3D.dotProduct(v3, v3.orthogonal()), 1.0e-12);
330 Vector3D v4 = new Vector3D(4.2, 0.1, -1.8);
331 assertEquals(0.0, Vector3D.dotProduct(v4, v4.orthogonal()), 1.0e-12);
332 try {
333 new Vector3D(0, 0, 0).orthogonal();
334 fail("an exception should have been thrown");
335 } catch (MathRuntimeException ae) {
336
337 }
338 }
339
340 @Test
341 void testAngle() throws MathRuntimeException {
342 assertEquals(0.22572612855273393616,
343 Vector3D.angle(new Vector3D(1, 2, 3), new Vector3D(4, 5, 6)),
344 1.0e-12);
345 assertEquals(7.98595620686106654517199e-8,
346 Vector3D.angle(new Vector3D(1, 2, 3), new Vector3D(2, 4, 6.000001)),
347 1.0e-12);
348 assertEquals(3.14159257373023116985197793156,
349 Vector3D.angle(new Vector3D(1, 2, 3), new Vector3D(-2, -4, -6.000001)),
350 1.0e-12);
351 try {
352 Vector3D.angle(Vector3D.ZERO, Vector3D.PLUS_I);
353 fail("an exception should have been thrown");
354 } catch (MathRuntimeException ae) {
355
356 }
357 }
358
359 @Test
360 void testAccurateDotProduct() {
361
362
363
364 Vector3D u1 = new Vector3D(-1321008684645961.0 / 268435456.0,
365 -5774608829631843.0 / 268435456.0,
366 -7645843051051357.0 / 8589934592.0);
367 Vector3D u2 = new Vector3D(-5712344449280879.0 / 2097152.0,
368 -4550117129121957.0 / 2097152.0,
369 8846951984510141.0 / 131072.0);
370 double sNaive = u1.getX() * u2.getX() + u1.getY() * u2.getY() + u1.getZ() * u2.getZ();
371 double sAccurate = u1.dotProduct(u2);
372 assertEquals(0.0, sNaive, 1.0e-30);
373 assertEquals(-2088690039198397.0 / 1125899906842624.0, sAccurate, 1.0e-15);
374 }
375
376 @Test
377 void testDotProduct() {
378
379
380 Well1024a random = new Well1024a(553267312521321234L);
381 for (int i = 0; i < 10000; ++i) {
382 double ux = 10000 * random.nextDouble();
383 double uy = 10000 * random.nextDouble();
384 double uz = 10000 * random.nextDouble();
385 double vx = 10000 * random.nextDouble();
386 double vy = 10000 * random.nextDouble();
387 double vz = 10000 * random.nextDouble();
388 double sNaive = ux * vx + uy * vy + uz * vz;
389 double sAccurate = new Vector3D(ux, uy, uz).dotProduct(new Vector3D(vx, vy, vz));
390 assertEquals(sNaive, sAccurate, 2.5e-16 * sAccurate);
391 }
392 }
393
394 @Test
395 void testAccurateCrossProduct() {
396
397
398
399
400
401 final Vector3D u1 = new Vector3D(-1321008684645961.0 / 268435456.0,
402 -5774608829631843.0 / 268435456.0,
403 -7645843051051357.0 / 8589934592.0);
404 final Vector3D u2 = new Vector3D( 1796571811118507.0 / 2147483648.0,
405 7853468008299307.0 / 2147483648.0,
406 2599586637357461.0 / 17179869184.0);
407 final Vector3D u3 = new Vector3D(12753243807587107.0 / 18446744073709551616.0,
408 -2313766922703915.0 / 18446744073709551616.0,
409 -227970081415313.0 / 288230376151711744.0);
410 Vector3D cNaive = new Vector3D(u1.getY() * u2.getZ() - u1.getZ() * u2.getY(),
411 u1.getZ() * u2.getX() - u1.getX() * u2.getZ(),
412 u1.getX() * u2.getY() - u1.getY() * u2.getX());
413 Vector3D cAccurate = u1.crossProduct(u2);
414 assertTrue(u3.distance(cNaive) > 2.9 * u3.getNorm());
415 assertEquals(0.0, u3.distance(cAccurate), 1.0e-30 * cAccurate.getNorm());
416 }
417
418 @Test
419 void testCrossProduct() {
420
421
422 Well1024a random = new Well1024a(885362227452043214L);
423 for (int i = 0; i < 10000; ++i) {
424 double ux = 10000 * random.nextDouble();
425 double uy = 10000 * random.nextDouble();
426 double uz = 10000 * random.nextDouble();
427 double vx = 10000 * random.nextDouble();
428 double vy = 10000 * random.nextDouble();
429 double vz = 10000 * random.nextDouble();
430 Vector3D cNaive = new Vector3D(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
431 Vector3D cAccurate = new Vector3D(ux, uy, uz).crossProduct(new Vector3D(vx, vy, vz));
432 assertEquals(0.0, cAccurate.distance(cNaive), 6.0e-15 * cAccurate.getNorm());
433 }
434 }
435
436 @Test
437 void testArithmeticBlending() {
438
439
440 final Vector3D v1 = new Vector3D(1,2,3);
441 final Vector3D v2 = new Vector3D(4,5,6);
442
443 final double blendingValue = 0.7;
444
445
446 final Vector3D blendedVector = v1.blendArithmeticallyWith(v2, blendingValue);
447
448
449 checkVector(blendedVector, 3.1, 4.1, 5.1);
450 }
451
452 @Test
453 void testMoveTowards() {
454 checkVector(new Vector3D(5.0, -1.0, 2.0).moveTowards(new Vector3D(3.0, 4.0, 6.0), 0.0), 5.0, -1.0, 2.0);
455 checkVector(new Vector3D(5.0, -1.0, 2.0).moveTowards(new Vector3D(3.0, 4.0, 6.0), 0.5), 4.0, 1.5, 4.0);
456 checkVector(new Vector3D(5.0, -1.0, 2.0).moveTowards(new Vector3D(3.0, 4.0, 6.0), 1.0), 3.0, 4.0, 6.0);
457 }
458
459 private void checkVector(Vector3D v, double x, double y, double z) {
460 assertEquals(x, v.getX(), 1.0e-12);
461 assertEquals(y, v.getY(), 1.0e-12);
462 assertEquals(z, v.getZ(), 1.0e-12);
463 }
464 }