View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.geometry.euclidean.oned;
18  
19  import java.util.Arrays;
20  import java.util.Comparator;
21  import java.util.List;
22  import java.util.regex.Pattern;
23  
24  import org.apache.commons.geometry.core.GeometryTestUtils;
25  import org.apache.commons.numbers.core.Precision;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Test;
28  
29  class Vector1DTest {
30  
31      private static final double TEST_TOLERANCE = 1e-15;
32  
33      @Test
34      void testConstants() {
35          // act/assert
36          checkVector(Vector1D.ZERO, 0.0);
37          checkVector(Vector1D.Unit.PLUS, 1.0);
38          checkVector(Vector1D.Unit.MINUS, -1.0);
39          checkVector(Vector1D.NaN, Double.NaN);
40          checkVector(Vector1D.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
41          checkVector(Vector1D.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
42      }
43  
44      @Test
45      void testConstants_normalize() {
46          // act/assert
47          Assertions.assertThrows(IllegalArgumentException.class, Vector1D.ZERO::normalize);
48          Assertions.assertThrows(IllegalArgumentException.class, Vector1D.NaN::normalize);
49          Assertions.assertThrows(IllegalArgumentException.class, Vector1D.POSITIVE_INFINITY::normalize);
50          Assertions.assertThrows(IllegalArgumentException.class, Vector1D.NEGATIVE_INFINITY::normalize);
51  
52          Assertions.assertSame(Vector1D.Unit.PLUS, Vector1D.Unit.PLUS.normalize());
53          Assertions.assertSame(Vector1D.Unit.MINUS, Vector1D.Unit.MINUS.normalize());
54      }
55  
56      @Test
57      void testCoordinateAscendingOrderComparator() {
58          // arrange
59          final Comparator<Vector1D> cmp = Vector1D.COORDINATE_ASCENDING_ORDER;
60  
61          // act/assert
62          Assertions.assertEquals(0, cmp.compare(Vector1D.of(1), Vector1D.of(1)));
63          Assertions.assertEquals(1, cmp.compare(Vector1D.of(2), Vector1D.of(1)));
64          Assertions.assertEquals(-1, cmp.compare(Vector1D.of(0), Vector1D.of(1)));
65  
66          Assertions.assertEquals(0, cmp.compare(Vector1D.of(0), Vector1D.of(0)));
67          Assertions.assertEquals(1, cmp.compare(Vector1D.of(1e-15), Vector1D.of(0)));
68          Assertions.assertEquals(-1, cmp.compare(Vector1D.of(-1e-15), Vector1D.of(0)));
69  
70          Assertions.assertEquals(-1, cmp.compare(Vector1D.of(1), null));
71          Assertions.assertEquals(1, cmp.compare(null, Vector1D.of(1)));
72          Assertions.assertEquals(0, cmp.compare(null, null));
73      }
74  
75      @Test
76      void testCoordinates() {
77          // act/assert
78          Assertions.assertEquals(-1, Vector1D.of(-1).getX(), 0.0);
79          Assertions.assertEquals(0, Vector1D.of(0).getX(), 0.0);
80          Assertions.assertEquals(1, Vector1D.of(1).getX(), 0.0);
81      }
82  
83      @Test
84      void testDimension() {
85          // arrange
86          final Vector1D v = Vector1D.of(2);
87  
88          // act/assert
89          Assertions.assertEquals(1, v.getDimension());
90      }
91  
92      @Test
93      void testNaN() {
94          // act/assert
95          Assertions.assertTrue(Vector1D.of(Double.NaN).isNaN());
96  
97          Assertions.assertFalse(Vector1D.of(1).isNaN());
98          Assertions.assertFalse(Vector1D.of(Double.NEGATIVE_INFINITY).isNaN());
99      }
100 
101     @Test
102     void testInfinite() {
103         // act/assert
104         Assertions.assertTrue(Vector1D.of(Double.NEGATIVE_INFINITY).isInfinite());
105         Assertions.assertTrue(Vector1D.of(Double.POSITIVE_INFINITY).isInfinite());
106 
107         Assertions.assertFalse(Vector1D.of(1).isInfinite());
108         Assertions.assertFalse(Vector1D.of(Double.NaN).isInfinite());
109     }
110 
111     @Test
112     void testFinite() {
113         // act/assert
114         Assertions.assertTrue(Vector1D.ZERO.isFinite());
115         Assertions.assertTrue(Vector1D.of(1).isFinite());
116 
117         Assertions.assertFalse(Vector1D.of(Double.NEGATIVE_INFINITY).isFinite());
118         Assertions.assertFalse(Vector1D.of(Double.POSITIVE_INFINITY).isFinite());
119 
120         Assertions.assertFalse(Vector1D.of(Double.NaN).isFinite());
121     }
122 
123     @Test
124     void testZero() {
125         // act
126         final Vector1D zero = Vector1D.of(1).getZero();
127 
128         // assert
129         checkVector(zero, 0.0);
130         checkVector(Vector1D.Unit.PLUS.add(zero), 1.0);
131     }
132 
133     @Test
134     void testNorm() {
135         // act/assert
136         Assertions.assertEquals(0.0, Vector1D.ZERO.norm(), TEST_TOLERANCE);
137         Assertions.assertEquals(3.0, Vector1D.of(3).norm(), TEST_TOLERANCE);
138         Assertions.assertEquals(3.0, Vector1D.of(-3).norm(), TEST_TOLERANCE);
139     }
140 
141     @Test
142     void testNorm_unitVectors() {
143         // arrange
144         final Vector1D v = Vector1D.of(2.0).normalize();
145 
146         // act/assert
147         Assertions.assertEquals(1.0, v.norm(), 0.0);
148     }
149 
150     @Test
151     void testNormSq() {
152         // act/assert
153         Assertions.assertEquals(0.0, Vector1D.of(0).normSq(), TEST_TOLERANCE);
154         Assertions.assertEquals(9.0, Vector1D.of(3).normSq(), TEST_TOLERANCE);
155         Assertions.assertEquals(9.0, Vector1D.of(-3).normSq(), TEST_TOLERANCE);
156     }
157 
158     @Test
159     void testNormSq_unitVectors() {
160         // arrange
161         final Vector1D v = Vector1D.of(2.0).normalize();
162 
163         // act/assert
164         Assertions.assertEquals(1.0, v.normSq(), 0.0);
165     }
166 
167     @Test
168     void testWithNorm() {
169         // act/assert
170         checkVector(Vector1D.Unit.PLUS.withNorm(0.0), 0.0);
171 
172         checkVector(Vector1D.of(0.5).withNorm(2.0), 2.0);
173         checkVector(Vector1D.of(5).withNorm(3.0), 3.0);
174 
175         checkVector(Vector1D.of(-0.5).withNorm(2.0), -2.0);
176         checkVector(Vector1D.of(-5).withNorm(3.0), -3.0);
177     }
178 
179     @Test
180     void testWithNorm_illegalNorm() {
181         // act/assert
182         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.ZERO.withNorm(2.0));
183         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.NaN.withNorm(2.0));
184         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.POSITIVE_INFINITY.withNorm(2.0));
185         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.NEGATIVE_INFINITY.withNorm(2.0));
186     }
187 
188     @Test
189     void testWithNorm_unitVectors() {
190         // arrange
191         final Vector1D v = Vector1D.of(2.0).normalize();
192 
193         // act/assert
194         checkVector(Vector1D.Unit.PLUS.withNorm(2.5), 2.5);
195         checkVector(Vector1D.Unit.MINUS.withNorm(3.14), -3.14);
196 
197         for (double mag = -10.0; mag <= 10.0; ++mag) {
198             Assertions.assertEquals(Math.abs(mag), v.withNorm(mag).norm(), TEST_TOLERANCE);
199         }
200     }
201 
202     @Test
203     void testAdd() {
204         // arrange
205         final Vector1D v1 = Vector1D.of(1);
206         final Vector1D v2 = Vector1D.of(-3);
207         final Vector1D v3 = Vector1D.of(3);
208 
209         // act/assert
210         checkVector(v1.add(v1), 2);
211         checkVector(v1.add(v2), -2);
212         checkVector(v2.add(v1), -2);
213         checkVector(v2.add(v3), 0);
214     }
215 
216     @Test
217     void testAdd_scaled() {
218         // arrange
219         final Vector1D v1 = Vector1D.of(1);
220         final Vector1D v2 = Vector1D.of(-3);
221         final Vector1D v3 = Vector1D.of(3);
222 
223         // act/assert
224         checkVector(v1.add(1, v1), 2);
225         checkVector(v1.add(0.5, v1), 1.5);
226         checkVector(v1.add(-1, v1), 0);
227 
228         checkVector(v1.add(0, v2), 1);
229         checkVector(v2.add(3, v1), 0);
230         checkVector(v2.add(2, v3), 3);
231     }
232 
233     @Test
234     void testSubtract() {
235         // arrange
236         final Vector1D v1 = Vector1D.of(1);
237         final Vector1D v2 = Vector1D.of(-3);
238         final Vector1D v3 = Vector1D.of(3);
239 
240         // act/assert
241         checkVector(v1.subtract(v1), 0);
242         checkVector(v1.subtract(v2), 4);
243         checkVector(v2.subtract(v1), -4);
244         checkVector(v2.subtract(v3), -6);
245     }
246 
247     @Test
248     void testSubtract_scaled() {
249         // arrange
250         final Vector1D v1 = Vector1D.of(1);
251         final Vector1D v2 = Vector1D.of(-3);
252         final Vector1D v3 = Vector1D.of(3);
253 
254         // act/assert
255         checkVector(v1.subtract(1, v1), 0);
256         checkVector(v1.subtract(0.5, v1), 0.5);
257         checkVector(v1.subtract(-1, v1), 2);
258 
259         checkVector(v1.subtract(0, v2), 1);
260         checkVector(v2.subtract(3, v1), -6);
261         checkVector(v2.subtract(2, v3), -9);
262     }
263 
264     @Test
265     void testNormalize() {
266         // act/assert
267         checkVector(Vector1D.of(1).normalize(), 1);
268         checkVector(Vector1D.of(-1).normalize(), -1);
269         checkVector(Vector1D.of(5).normalize(), 1);
270         checkVector(Vector1D.of(-5).normalize(), -1);
271 
272         checkVector(Vector1D.of(Double.MIN_VALUE).normalize(), 1);
273         checkVector(Vector1D.of(-Double.MIN_VALUE).normalize(), -1);
274 
275         checkVector(Vector1D.of(Double.MAX_VALUE).normalize(), 1);
276         checkVector(Vector1D.of(-Double.MAX_VALUE).normalize(), -1);
277     }
278 
279     @Test
280     void testNormalize_illegalNorm() {
281         // arrange
282         final Pattern illegalNorm = Pattern.compile("^Illegal norm: (0\\.0|-?Infinity|NaN)");
283 
284         // act/assert
285         GeometryTestUtils.assertThrowsWithMessage(Vector1D.ZERO::normalize,
286                 IllegalArgumentException.class, illegalNorm);
287         GeometryTestUtils.assertThrowsWithMessage(Vector1D.NaN::normalize,
288                 IllegalArgumentException.class, illegalNorm);
289         GeometryTestUtils.assertThrowsWithMessage(Vector1D.POSITIVE_INFINITY::normalize,
290                 IllegalArgumentException.class, illegalNorm);
291         GeometryTestUtils.assertThrowsWithMessage(Vector1D.NEGATIVE_INFINITY::normalize,
292                 IllegalArgumentException.class, illegalNorm);
293     }
294 
295     @Test
296     void testNormalize_isIdempotent() {
297         // arrange
298         final Vector1D v = Vector1D.of(2).normalize();
299 
300         // act/assert
301         Assertions.assertSame(v, v.normalize());
302         checkVector(v.normalize(), 1.0);
303     }
304 
305     @Test
306     void testNormalizeOrNull() {
307         // act/assert
308         checkVector(Vector1D.of(100).normalizeOrNull(), 1);
309         checkVector(Vector1D.of(-100).normalizeOrNull(), -1);
310 
311         checkVector(Vector1D.of(2).normalizeOrNull(), 1);
312         checkVector(Vector1D.of(-2).normalizeOrNull(), -1);
313 
314         checkVector(Vector1D.of(Double.MIN_VALUE).normalizeOrNull(), 1);
315         checkVector(Vector1D.of(-Double.MIN_VALUE).normalizeOrNull(), -1);
316 
317         checkVector(Vector1D.of(Double.MAX_VALUE).normalizeOrNull(), 1);
318         checkVector(Vector1D.of(-Double.MAX_VALUE).normalizeOrNull(), -1);
319 
320         Assertions.assertNull(Vector1D.ZERO.normalizeOrNull());
321         Assertions.assertNull(Vector1D.NaN.normalizeOrNull());
322         Assertions.assertNull(Vector1D.POSITIVE_INFINITY.normalizeOrNull());
323         Assertions.assertNull(Vector1D.NEGATIVE_INFINITY.normalizeOrNull());
324     }
325 
326     @Test
327     void testNormalizeOrNull_isIdempotent() {
328         // arrange
329         final Vector1D v = Vector1D.of(2).normalizeOrNull();
330 
331         // act/assert
332         Assertions.assertSame(v, v.normalizeOrNull());
333         checkVector(v.normalizeOrNull(), 1.0);
334     }
335 
336     @Test
337     void testNegate() {
338         // act/assert
339         checkVector(Vector1D.of(0.1).negate(), -0.1);
340         checkVector(Vector1D.of(-0.1).negate(), 0.1);
341     }
342 
343     @Test
344     void testNegate_unitVectors() {
345         // arrange
346         final Vector1D v1 = Vector1D.of(0.1).normalize();
347         final Vector1D v2 = Vector1D.of(-0.1).normalize();
348 
349         // act/assert
350         checkVector(v1.negate(), -1);
351         checkVector(v2.negate(), 1);
352     }
353 
354     @Test
355     void testScalarMultiply() {
356         // act/assert
357         checkVector(Vector1D.of(1).multiply(3), 3);
358         checkVector(Vector1D.of(1).multiply(-3), -3);
359 
360         checkVector(Vector1D.of(1.5).multiply(7), 10.5);
361         checkVector(Vector1D.of(-1.5).multiply(7), -10.5);
362     }
363 
364     @Test
365     void testDistance() {
366         // arrange
367         final Vector1D v1 = Vector1D.of(1);
368         final Vector1D v2 = Vector1D.of(-4);
369 
370         // act/assert
371         Assertions.assertEquals(0.0, v1.distance(v1), TEST_TOLERANCE);
372 
373         Assertions.assertEquals(5.0, v1.distance(v2), TEST_TOLERANCE);
374         Assertions.assertEquals(5.0, v2.distance(v1), TEST_TOLERANCE);
375         Assertions.assertEquals(v1.subtract(v2).norm(), v1.distance(v2), TEST_TOLERANCE);
376 
377         Assertions.assertEquals(0.0, Vector1D.of(-1).distance(Vector1D.of(-1)), TEST_TOLERANCE);
378     }
379 
380     @Test
381     void testDistanceSq() {
382         // arrange
383         final Vector1D v1 = Vector1D.of(1);
384         final Vector1D v2 = Vector1D.of(-4);
385 
386         // act/assert
387         Assertions.assertEquals(0.0, Vector1D.of(-1).distanceSq(Vector1D.of(-1)), TEST_TOLERANCE);
388         Assertions.assertEquals(25.0, v1.distanceSq(v2), TEST_TOLERANCE);
389         Assertions.assertEquals(25.0, v2.distanceSq(v1), TEST_TOLERANCE);
390     }
391 
392     @Test
393     void testDotProduct() {
394         // arrange
395         final Vector1D v1 = Vector1D.of(2);
396         final Vector1D v2 = Vector1D.of(-3);
397         final Vector1D v3 = Vector1D.of(3);
398 
399         // act/assert
400         Assertions.assertEquals(-6.0, v1.dot(v2), TEST_TOLERANCE);
401         Assertions.assertEquals(-6.0, v2.dot(v1), TEST_TOLERANCE);
402 
403         Assertions.assertEquals(6.0, v1.dot(v3), TEST_TOLERANCE);
404         Assertions.assertEquals(6.0, v3.dot(v1), TEST_TOLERANCE);
405     }
406 
407     @Test
408     void testAngle() {
409         // arrange
410         final Vector1D v1 = Vector1D.of(2);
411         final Vector1D v2 = Vector1D.of(-3);
412         final Vector1D v3 = Vector1D.of(4);
413         final Vector1D v4 = Vector1D.of(-5);
414 
415         // act/assert
416         Assertions.assertEquals(0.0, v1.angle(v1), TEST_TOLERANCE);
417         Assertions.assertEquals(Math.PI, v1.angle(v2), TEST_TOLERANCE);
418         Assertions.assertEquals(0.0, v1.angle(v3), TEST_TOLERANCE);
419         Assertions.assertEquals(Math.PI, v1.angle(v4), TEST_TOLERANCE);
420 
421         Assertions.assertEquals(Math.PI, v2.angle(v1), TEST_TOLERANCE);
422         Assertions.assertEquals(0.0, v2.angle(v2), TEST_TOLERANCE);
423         Assertions.assertEquals(Math.PI, v2.angle(v3), TEST_TOLERANCE);
424         Assertions.assertEquals(0.0, v2.angle(v4), TEST_TOLERANCE);
425 
426         Assertions.assertEquals(0.0, v3.angle(v1), TEST_TOLERANCE);
427         Assertions.assertEquals(Math.PI, v3.angle(v2), TEST_TOLERANCE);
428         Assertions.assertEquals(0.0, v3.angle(v3), TEST_TOLERANCE);
429         Assertions.assertEquals(Math.PI, v3.angle(v4), TEST_TOLERANCE);
430 
431         Assertions.assertEquals(Math.PI, v4.angle(v1), TEST_TOLERANCE);
432         Assertions.assertEquals(0.0, v4.angle(v2), TEST_TOLERANCE);
433         Assertions.assertEquals(Math.PI, v4.angle(v3), TEST_TOLERANCE);
434         Assertions.assertEquals(0.0, v4.angle(v4), TEST_TOLERANCE);
435     }
436 
437     @Test
438     void testAngle_illegalNorm() {
439         // arrange
440         final Vector1D v = Vector1D.of(1.0);
441 
442         // act/assert
443         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.ZERO.angle(v));
444         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.NaN.angle(v));
445         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.POSITIVE_INFINITY.angle(v));
446         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.NEGATIVE_INFINITY.angle(v));
447         Assertions.assertThrows(IllegalArgumentException.class, () -> v.angle(Vector1D.ZERO));
448         Assertions.assertThrows(IllegalArgumentException.class, () -> v.angle(Vector1D.NaN));
449         Assertions.assertThrows(IllegalArgumentException.class, () -> v.angle(Vector1D.POSITIVE_INFINITY));
450         Assertions.assertThrows(IllegalArgumentException.class, () -> v.angle(Vector1D.NEGATIVE_INFINITY));
451     }
452 
453     @Test
454     void testVectorTo() {
455         // arrange
456         final Vector1D v1 = Vector1D.of(1);
457         final Vector1D v2 = Vector1D.of(-4);
458         final Vector1D v3 = Vector1D.of(10);
459 
460         // act/assert
461         checkVector(v1.vectorTo(v1), 0.0);
462         checkVector(v2.vectorTo(v2), 0.0);
463         checkVector(v3.vectorTo(v3), 0.0);
464 
465         checkVector(v1.vectorTo(v2), -5.0);
466         checkVector(v2.vectorTo(v1), 5.0);
467 
468         checkVector(v1.vectorTo(v3), 9.0);
469         checkVector(v3.vectorTo(v1), -9.0);
470 
471         checkVector(v2.vectorTo(v3), 14.0);
472         checkVector(v3.vectorTo(v2), -14.0);
473     }
474 
475     @Test
476     void testDirectionTo() {
477         // act/assert
478         final Vector1D v1 = Vector1D.of(1);
479         final Vector1D v2 = Vector1D.of(5);
480         final Vector1D v3 = Vector1D.of(-2);
481 
482         // act/assert
483         checkVector(v1.directionTo(v2), 1);
484         checkVector(v2.directionTo(v1), -1);
485 
486         checkVector(v1.directionTo(v3), -1);
487         checkVector(v3.directionTo(v1), 1);
488     }
489 
490     @Test
491     void testDirectionTo_illegalNorm() {
492         // arrange
493         final Vector1D v = Vector1D.of(2);
494 
495         // act/assert
496         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.ZERO.directionTo(Vector1D.ZERO));
497         Assertions.assertThrows(IllegalArgumentException.class, () -> v.directionTo(v));
498         Assertions.assertThrows(IllegalArgumentException.class, () -> v.directionTo(Vector1D.NaN));
499         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.NEGATIVE_INFINITY.directionTo(v));
500         Assertions.assertThrows(IllegalArgumentException.class, () -> v.directionTo(Vector1D.POSITIVE_INFINITY));
501     }
502 
503     @Test
504     void testLerp() {
505         // arrange
506         final Vector1D v1 = Vector1D.of(1);
507         final Vector1D v2 = Vector1D.of(-4);
508         final Vector1D v3 = Vector1D.of(10);
509 
510         // act/assert
511         checkVector(v1.lerp(v1, 0), 1);
512         checkVector(v1.lerp(v1, 1), 1);
513 
514         checkVector(v1.lerp(v2, -0.25), 2.25);
515         checkVector(v1.lerp(v2, 0), 1);
516         checkVector(v1.lerp(v2, 0.25), -0.25);
517         checkVector(v1.lerp(v2, 0.5), -1.5);
518         checkVector(v1.lerp(v2, 0.75), -2.75);
519         checkVector(v1.lerp(v2, 1), -4);
520         checkVector(v1.lerp(v2, 1.25), -5.25);
521 
522         checkVector(v1.lerp(v3, 0), 1);
523         checkVector(v1.lerp(v3, 0.25), 3.25);
524         checkVector(v1.lerp(v3, 0.5), 5.5);
525         checkVector(v1.lerp(v3, 0.75), 7.75);
526         checkVector(v1.lerp(v3, 1), 10);
527     }
528 
529     @Test
530     void testTransform() {
531         // arrange
532         final AffineTransformMatrix1D transform = AffineTransformMatrix1D.identity()
533                 .scale(2)
534                 .translate(1);
535 
536         final Vector1D v1 = Vector1D.of(1);
537         final Vector1D v2 = Vector1D.of(-4);
538 
539         // act/assert
540         checkVector(v1.transform(transform), 3);
541         checkVector(v2.transform(transform), -7);
542     }
543 
544     @Test
545     void testPrecisionEquals() {
546         // arrange
547         final Precision.DoubleEquivalence smallEps = Precision.doubleEquivalenceOfEpsilon(1e-6);
548         final Precision.DoubleEquivalence largeEps = Precision.doubleEquivalenceOfEpsilon(1e-1);
549 
550         final Vector1D vec = Vector1D.of(1);
551 
552         // act/assert
553         Assertions.assertTrue(vec.eq(vec, smallEps));
554         Assertions.assertTrue(vec.eq(vec, largeEps));
555 
556         Assertions.assertTrue(vec.eq(Vector1D.of(1.0000007), smallEps));
557         Assertions.assertTrue(vec.eq(Vector1D.of(1.0000007), largeEps));
558 
559         Assertions.assertFalse(vec.eq(Vector1D.of(1.004), smallEps));
560         Assertions.assertTrue(vec.eq(Vector1D.of(1.004), largeEps));
561 
562         Assertions.assertFalse(vec.eq(Vector1D.of(2), smallEps));
563         Assertions.assertFalse(vec.eq(Vector1D.of(-2), largeEps));
564     }
565 
566     @Test
567     void testIsZero() {
568         // arrange
569         final Precision.DoubleEquivalence smallEps = Precision.doubleEquivalenceOfEpsilon(1e-6);
570         final Precision.DoubleEquivalence largeEps = Precision.doubleEquivalenceOfEpsilon(1e-1);
571 
572         // act/assert
573         Assertions.assertTrue(Vector1D.of(0.0).isZero(smallEps));
574         Assertions.assertTrue(Vector1D.of(-0.0).isZero(largeEps));
575 
576         Assertions.assertTrue(Vector1D.of(1e-7).isZero(smallEps));
577         Assertions.assertTrue(Vector1D.of(-1e-7).isZero(largeEps));
578 
579         Assertions.assertFalse(Vector1D.of(1e-2).isZero(smallEps));
580         Assertions.assertTrue(Vector1D.of(-1e-2).isZero(largeEps));
581 
582         Assertions.assertFalse(Vector1D.of(0.2).isZero(smallEps));
583         Assertions.assertFalse(Vector1D.of(-0.2).isZero(largeEps));
584     }
585 
586     @Test
587     void testHashCode() {
588         // arrange
589         final Vector1D u = Vector1D.of(1);
590         final Vector1D v = Vector1D.of(1 + 10 * Precision.EPSILON);
591         final Vector1D w = Vector1D.of(1);
592 
593         // act/assert
594         Assertions.assertTrue(u.hashCode() != v.hashCode());
595         Assertions.assertEquals(u.hashCode(), w.hashCode());
596 
597         Assertions.assertEquals(Vector1D.of(Double.NaN).hashCode(), Vector1D.NaN.hashCode());
598         Assertions.assertEquals(Vector1D.of(Double.NaN).hashCode(), Vector1D.of(Double.NaN).hashCode());
599     }
600 
601     @Test
602     void testEquals() {
603         // arrange
604         final Vector1D u1 = Vector1D.of(1);
605         final Vector1D u2 = Vector1D.of(1);
606 
607         // act/assert
608         GeometryTestUtils.assertSimpleEqualsCases(u1);
609         Assertions.assertEquals(u1, u2);
610 
611         Assertions.assertNotEquals(u1, Vector1D.of(-1));
612         Assertions.assertNotEquals(u1, Vector1D.of(1 + 10 * Precision.EPSILON));
613 
614         Assertions.assertEquals(Vector1D.of(Double.NaN), Vector1D.of(Double.NaN));
615         Assertions.assertEquals(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.POSITIVE_INFINITY));
616         Assertions.assertEquals(Vector1D.of(Double.NEGATIVE_INFINITY), Vector1D.of(Double.NEGATIVE_INFINITY));
617     }
618 
619     @Test
620     void testEqualsAndHashCode_signedZeroConsistency() {
621         // arrange
622         final Vector1D a = Vector1D.of(0.0);
623         final Vector1D b = Vector1D.of(-0.0);
624         final Vector1D c = Vector1D.of(0.0);
625         final Vector1D d = Vector1D.of(-0.0);
626 
627         // act/assert
628         Assertions.assertFalse(a.equals(b));
629         Assertions.assertNotEquals(a.hashCode(), b.hashCode());
630 
631         Assertions.assertTrue(a.equals(c));
632         Assertions.assertEquals(a.hashCode(), c.hashCode());
633 
634         Assertions.assertTrue(b.equals(d));
635         Assertions.assertEquals(b.hashCode(), d.hashCode());
636     }
637 
638     @Test
639     void testToString() {
640         // arrange
641         final Vector1D v = Vector1D.of(3);
642         final Pattern pattern = Pattern.compile("\\(3.{0,2}\\)");
643 
644         // act
645         final String str = v.toString();
646 
647         // assert
648         Assertions.assertTrue(pattern.matcher(str).matches(), "Expected string " + str + " to match regex " + pattern);
649     }
650 
651     @Test
652     void testParse() {
653         // act/assert
654         checkVector(Vector1D.parse("(1)"), 1);
655         checkVector(Vector1D.parse("(-1)"), -1);
656 
657         checkVector(Vector1D.parse("(0.01)"), 1e-2);
658         checkVector(Vector1D.parse("(-1e-3)"), -1e-3);
659 
660         checkVector(Vector1D.parse("(NaN)"), Double.NaN);
661 
662         checkVector(Vector1D.parse(Vector1D.ZERO.toString()), 0);
663         checkVector(Vector1D.parse(Vector1D.Unit.PLUS.toString()), 1);
664     }
665 
666     @Test
667     void testParse_failure() {
668         // act/assert
669         Assertions.assertThrows(IllegalArgumentException.class, () ->  Vector1D.parse("abc"));
670     }
671 
672     @Test
673     void testOf() {
674         // act/assert
675         checkVector(Vector1D.of(0), 0.0);
676         checkVector(Vector1D.of(-1), -1.0);
677         checkVector(Vector1D.of(1), 1.0);
678         checkVector(Vector1D.of(Math.PI), Math.PI);
679         checkVector(Vector1D.of(Double.NaN), Double.NaN);
680         checkVector(Vector1D.of(Double.NEGATIVE_INFINITY), Double.NEGATIVE_INFINITY);
681         checkVector(Vector1D.of(Double.POSITIVE_INFINITY), Double.POSITIVE_INFINITY);
682     }
683 
684     @Test
685     void testUnitFrom_coordinates() {
686         // act/assert
687         checkVector(Vector1D.Unit.from(2.0), 1);
688         checkVector(Vector1D.Unit.from(-4.0), -1);
689     }
690 
691     @Test
692     void testUnitFrom_vector() {
693         // arrange
694         final Vector1D vec = Vector1D.of(2);
695         final Vector1D unitVec = Vector1D.Unit.from(2);
696 
697         // act/assert
698         checkVector(Vector1D.Unit.from(vec), 1);
699         Assertions.assertSame(unitVec, Vector1D.Unit.from(unitVec));
700     }
701 
702     @Test
703     void testUnitFrom_illegalNorm() {
704         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.Unit.from(0.0));
705         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.Unit.from(Double.NaN));
706         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.Unit.from(Double.NEGATIVE_INFINITY));
707         Assertions.assertThrows(IllegalArgumentException.class, () -> Vector1D.Unit.from(Double.POSITIVE_INFINITY));
708     }
709 
710     @Test
711     void testSum_factoryMethods() {
712         // act/assert
713         checkVector(Vector1D.Sum.create().get(), 0);
714         checkVector(Vector1D.Sum.of(Vector1D.of(2)).get(), 2);
715         checkVector(Vector1D.Sum.of(
716                 Vector1D.of(-2),
717                 Vector1D.Unit.PLUS).get(), -1);
718     }
719 
720     @Test
721     void testSum_instanceMethods() {
722         // arrange
723         final Vector1D p1 = Vector1D.of(-1);
724         final Vector1D p2 = Vector1D.of(4);
725 
726         // act/assert
727         checkVector(Vector1D.Sum.create()
728                 .add(p1)
729                 .addScaled(0.5, p2)
730                 .get(), 1);
731     }
732 
733     @Test
734     void testSum_accept() {
735         // arrange
736         final Vector1D p1 = Vector1D.of(2);
737         final Vector1D p2 = Vector1D.of(-3);
738 
739         final List<Vector1D.Unit> units = Arrays.asList(
740                 Vector1D.Unit.MINUS);
741 
742         final Vector1D.Sum s = Vector1D.Sum.create();
743 
744         // act/assert
745         Arrays.asList(p1, Vector1D.ZERO, p2).forEach(s);
746         units.forEach(s);
747 
748         // assert
749         checkVector(s.get(), -2);
750     }
751 
752     @Test
753     void testUnitFactoryOptimization() {
754         // An already normalized vector will avoid unnecessary creation.
755         final Vector1D v = Vector1D.of(3).normalize();
756         Assertions.assertSame(v, v.normalize());
757     }
758 
759     private void checkVector(final Vector1D v, final double x) {
760         Assertions.assertEquals(x, v.getX(), TEST_TOLERANCE);
761     }
762 }