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 }