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 org.apache.commons.geometry.core.RegionLocation;
    20  import org.apache.commons.geometry.core.partitioning.Split;
    21  import org.apache.commons.geometry.core.partitioning.SplitLocation;
    22  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
    23  import org.apache.commons.numbers.core.Precision;
    24  import org.junit.jupiter.api.Assertions;
    25  import org.junit.jupiter.api.Test;
    26
    27  class IntervalTest {
    28
    29      private static final double TEST_EPS = 1e-15;
    30
    31      private static final Precision.DoubleEquivalence TEST_PRECISION =
    32              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
    33
    34      @Test
    35      void testOf_doubles() {
    36          // act/assert
    37          checkInterval(Interval.of(0, 0, TEST_PRECISION), 0, 0);
    38
    39          checkInterval(Interval.of(1, 2, TEST_PRECISION), 1, 2);
    40          checkInterval(Interval.of(2, 1, TEST_PRECISION), 1, 2);
    41
    42          checkInterval(Interval.of(-2, -1, TEST_PRECISION), -2, -1);
    43          checkInterval(Interval.of(-1, -2, TEST_PRECISION), -2, -1);
    44
    45          checkInterval(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION),
    46                  1, Double.POSITIVE_INFINITY);
    47          checkInterval(Interval.of(Double.POSITIVE_INFINITY, 1, TEST_PRECISION),
    48                  1, Double.POSITIVE_INFINITY);
    49
    50          checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION),
    51                  Double.NEGATIVE_INFINITY, 1);
    52          checkInterval(Interval.of(1, Double.NEGATIVE_INFINITY, TEST_PRECISION),
    53                  Double.NEGATIVE_INFINITY, 1);
    54
    55          checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION),
    56                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    57
    58          checkInterval(Interval.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION),
    59                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    60      }
    61
    62      @Test
    63      void testOf_doubles_invalidIntervals() {
    64
    65          // act/assert
    66          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(1, Double.NaN, TEST_PRECISION));
    67          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NaN, 1, TEST_PRECISION));
    68          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NaN, Double.NaN, TEST_PRECISION));
    69          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION));
    70          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, TEST_PRECISION));
    71      }
    72
    73      @Test
    74      void testOf_points() {
    75          // act/assert
    76          checkInterval(Interval.of(Vector1D.of(1), Vector1D.of(2), TEST_PRECISION), 1, 2);
    77          checkInterval(Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.NEGATIVE_INFINITY), TEST_PRECISION),
    78                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    79      }
    80
    81      @Test
    82      void testOf_points_invalidIntervals() {
    83
    84          // act/assert
    85          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Vector1D.of(1), Vector1D.of(Double.NaN), TEST_PRECISION));
    86          Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(Vector1D.of(Double.POSITIVE_INFINITY), Vector1D.of(Double.POSITIVE_INFINITY), TEST_PRECISION));
    87      }
    88
    89      @Test
    90      void testOf_hyperplanes() {
    91          // act/assert
    92          Assertions.assertSame(Interval.full(), Interval.of(null, null));
    93
    94          checkInterval(Interval.of(
    95                  OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION),
    96                  OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)), 1, 1);
    97          checkInterval(Interval.of(
    98                  OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
    99                  OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)), 1, 1);
    100
    101         checkInterval(Interval.of(
    102                 OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION),
    103                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), -2, 5);
    104         checkInterval(Interval.of(
    105                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
    106                 OrientedPoints.fromLocationAndDirection(-2, false, TEST_PRECISION)), -2, 5);
    107
    108         checkInterval(Interval.of(
    109                 null,
    110                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
    111         checkInterval(Interval.of(
    112                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION),
    113                 null), Double.NEGATIVE_INFINITY, 5);
    114         checkInterval(Interval.of(
    115                 OrientedPoints.fromLocationAndDirection(Double.NEGATIVE_INFINITY, false, TEST_PRECISION),
    116                 OrientedPoints.fromLocationAndDirection(5, true, TEST_PRECISION)), Double.NEGATIVE_INFINITY, 5);
    117
    118         checkInterval(Interval.of(
    119                 null,
    120                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
    121         checkInterval(Interval.of(
    122                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION),
    123                 null), 5, Double.POSITIVE_INFINITY);
    124         checkInterval(Interval.of(
    125                 OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION),
    126                 OrientedPoints.fromLocationAndDirection(5, false, TEST_PRECISION)), 5, Double.POSITIVE_INFINITY);
    127     }
    128
    129     @Test
    130     void testOf_hyperplanes_invalidArgs() {
    131         // act/assert
    132         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    133                 OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
    134                 OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION)));
    135         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    136                 OrientedPoints.fromLocationAndDirection(2, false, TEST_PRECISION),
    137                 OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)));
    138         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    139                 OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, false, TEST_PRECISION),
    140                 OrientedPoints.fromLocationAndDirection(Double.POSITIVE_INFINITY, true, TEST_PRECISION)));
    141         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    142                 OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
    143                 OrientedPoints.fromLocationAndDirection(1, true, TEST_PRECISION)));
    144         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    145                 OrientedPoints.fromLocationAndDirection(1, false, TEST_PRECISION),
    146                 OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
    147         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    148                 OrientedPoints.fromLocationAndDirection(Double.NaN, false, TEST_PRECISION),
    149                 OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
    150         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.of(
    151                 null,
    152                 OrientedPoints.fromLocationAndDirection(Double.NaN, true, TEST_PRECISION)));
    153     }
    154
    155     @Test
    156     void testPoint() {
    157         // act/assert
    158         checkInterval(Interval.point(0, TEST_PRECISION), 0, 0);
    159         checkInterval(Interval.point(1, TEST_PRECISION), 1, 1);
    160         checkInterval(Interval.point(-1, TEST_PRECISION), -1, -1);
    161     }
    162
    163     @Test
    164     void testPoint_invalidArgs() {
    165         // act/assert
    166         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.NEGATIVE_INFINITY, TEST_PRECISION));
    167         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.POSITIVE_INFINITY, TEST_PRECISION));
    168         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.point(Double.NaN, TEST_PRECISION));
    169     }
    170
    171     @Test
    172     void testMin() {
    173         // act/assert
    174         checkInterval(Interval.min(Double.NEGATIVE_INFINITY, TEST_PRECISION),
    175                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    176
    177         checkInterval(Interval.min(0, TEST_PRECISION), 0, Double.POSITIVE_INFINITY);
    178         checkInterval(Interval.min(1, TEST_PRECISION), 1, Double.POSITIVE_INFINITY);
    179         checkInterval(Interval.min(-1, TEST_PRECISION), -1, Double.POSITIVE_INFINITY);
    180     }
    181
    182     @Test
    183     void testMin_invalidArgs() {
    184         // act/assert
    185         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.min(Double.POSITIVE_INFINITY, TEST_PRECISION));
    186         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.min(Double.NaN, TEST_PRECISION));
    187     }
    188
    189     @Test
    190     void testMax() {
    191         // act/assert
    192         checkInterval(Interval.max(Double.POSITIVE_INFINITY, TEST_PRECISION),
    193                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    194
    195         checkInterval(Interval.max(0, TEST_PRECISION), Double.NEGATIVE_INFINITY, 0);
    196         checkInterval(Interval.max(1, TEST_PRECISION), Double.NEGATIVE_INFINITY, 1);
    197         checkInterval(Interval.max(-1, TEST_PRECISION), Double.NEGATIVE_INFINITY, -1);
    198     }
    199
    200     @Test
    201     void testMax_invalidArgs() {
    202         // act/assert
    203         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.max(Double.NEGATIVE_INFINITY, TEST_PRECISION));
    204         Assertions.assertThrows(IllegalArgumentException.class, () -> Interval.max(Double.NaN, TEST_PRECISION));
    205     }
    206
    207     @Test
    208     void testIsInfinite() {
    209         // act/assert
    210         Assertions.assertFalse(Interval.of(1, 2, TEST_PRECISION).isInfinite());
    211
    212         Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isInfinite());
    213         Assertions.assertTrue(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
    214         Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isInfinite());
    215     }
    216
    217     @Test
    218     void testIsFinite() {
    219         // act/assert
    220         Assertions.assertTrue(Interval.of(1, 2, TEST_PRECISION).isFinite());
    221
    222         Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).isFinite());
    223         Assertions.assertFalse(Interval.of(2, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
    224         Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFinite());
    225     }
    226
    227     @Test
    228     void testClassify_finite() {
    229         // arrange
    230         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    231         final Interval interval = Interval.of(-1, 1, precision);
    232
    233         // act/assert
    234         checkClassify(interval, RegionLocation.OUTSIDE,
    235                 Double.NEGATIVE_INFINITY, -2, -1.1,
    236                 1.1, 2, Double.POSITIVE_INFINITY);
    237
    238         checkClassify(interval, RegionLocation.BOUNDARY,
    239                 -1.001, -1, -0.999,
    240                 0.999, 1, 1.001);
    241
    242         checkClassify(interval, RegionLocation.INSIDE, -0.9, 0, 0.9);
    243
    244         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    245     }
    246
    247     @Test
    248     void testClassify_singlePoint() {
    249         // arrange
    250         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    251         final Interval interval = Interval.of(1, 1, precision);
    252
    253         // act/assert
    254         checkClassify(interval, RegionLocation.OUTSIDE,
    255                 Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
    256
    257         checkClassify(interval, RegionLocation.BOUNDARY,
    258                 0.999, 1, 1.0001);
    259
    260         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    261     }
    262
    263     @Test
    264     void testClassify_maxInfinite() {
    265         // arrange
    266         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    267         final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
    268
    269         // act/assert
    270         checkClassify(interval, RegionLocation.OUTSIDE,
    271                 Double.NEGATIVE_INFINITY, -2, -1.1);
    272
    273         checkClassify(interval, RegionLocation.BOUNDARY,
    274                 -1.001, -1, -0.999);
    275
    276         checkClassify(interval, RegionLocation.INSIDE,
    277                 -0.9, 0, 1.0, Double.POSITIVE_INFINITY);
    278
    279         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    280     }
    281
    282     @Test
    283     void testClassify_minInfinite() {
    284         // arrange
    285         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    286         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
    287
    288         // act/assert
    289         checkClassify(interval, RegionLocation.INSIDE,
    290                 Double.NEGATIVE_INFINITY, 0, 0.9);
    291
    292         checkClassify(interval, RegionLocation.BOUNDARY,
    293                 0.999, 1, 1.001);
    294
    295         checkClassify(interval, RegionLocation.OUTSIDE,
    296                 1.1, 2, Double.POSITIVE_INFINITY);
    297
    298         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    299     }
    300
    301     @Test
    302     void testClassify_minMaxInfinite() {
    303         // arrange
    304         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    305         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
    306
    307         // act/assert
    308         checkClassify(interval, RegionLocation.INSIDE,
    309                 Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
    310
    311         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    312     }
    313
    314     @Test
    315     void testContains_finite() {
    316         // arrange
    317         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    318         final Interval interval = Interval.of(-1, 1, precision);
    319
    320         // act/assert
    321         checkContains(interval, true,
    322                 -1.001, -1, -0.999,
    323                 0.999, 1, 1.001,
    324
    325                 -0.9, 0, 0.9);
    326
    327         checkContains(interval, false,
    328                 Double.NEGATIVE_INFINITY, -2, -1.1,
    329                 1.1, 2, Double.POSITIVE_INFINITY);
    330
    331         checkContains(interval, false, Double.NaN);
    332     }
    333
    334     @Test
    335     void testIsFull() {
    336         // act/assert
    337         Assertions.assertFalse(Interval.of(1, 1, TEST_PRECISION).isFull());
    338         Assertions.assertFalse(Interval.of(-2, 2, TEST_PRECISION).isFull());
    339
    340         Assertions.assertFalse(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
    341         Assertions.assertFalse(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).isFull());
    342
    343         Assertions.assertTrue(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).isFull());
    344     }
    345
    346     @Test
    347     void testGetSize() {
    348         // act/assert
    349         Assertions.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getSize(), TEST_EPS);
    350
    351         Assertions.assertEquals(4, Interval.of(-2, 2, TEST_PRECISION).getSize(), TEST_EPS);
    352         Assertions.assertEquals(5, Interval.of(2, -3, TEST_PRECISION).getSize(), TEST_EPS);
    353
    354         Assertions.assertEquals(Double.POSITIVE_INFINITY,
    355                 Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
    356         Assertions.assertEquals(Double.POSITIVE_INFINITY,
    357                 Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getSize(), TEST_EPS);
    358
    359         Assertions.assertEquals(Double.POSITIVE_INFINITY,
    360                 Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getSize(), TEST_EPS);
    361     }
    362
    363     @Test
    364     void testGetBoundarySize() {
    365         // act/assert
    366         Assertions.assertEquals(0, Interval.of(1, 1, TEST_PRECISION).getBoundarySize(), TEST_EPS);
    367         Assertions.assertEquals(0, Interval.of(-2, 5, TEST_PRECISION).getBoundarySize(), TEST_EPS);
    368         Assertions.assertEquals(0, Interval.full().getBoundarySize(), TEST_EPS);
    369     }
    370
    371     @Test
    372     void testGetCentroid() {
    373         // act/assert
    374         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.ZERO,
    375                 Interval.of(-1, 1, TEST_PRECISION).getCentroid(), TEST_EPS);
    376         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(10),
    377                 Interval.of(10, 10, TEST_PRECISION).getCentroid(), TEST_EPS);
    378
    379         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(2),
    380                 Interval.of(1, 3, TEST_PRECISION).getCentroid(), TEST_EPS);
    381         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(-1),
    382                 Interval.of(-2, 0, TEST_PRECISION).getCentroid(), TEST_EPS);
    383
    384         Assertions.assertNull(Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
    385         Assertions.assertNull(Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION).getCentroid());
    386         Assertions.assertNull(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).getCentroid());
    387     }
    388
    389     @Test
    390     void checkToTree_finite() {
    391         // arrange
    392         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    393         final Interval interval = Interval.of(-1, 1, precision);
    394
    395         // act
    396         final RegionBSPTree1D tree = interval.toTree();
    397
    398         // assert
    399         Assertions.assertEquals(5, tree.count());
    400
    401         checkClassify(tree, RegionLocation.OUTSIDE,
    402                 Double.NEGATIVE_INFINITY, -2, -1.1,
    403                 1.1, 2, Double.POSITIVE_INFINITY);
    404
    405         checkClassify(tree, RegionLocation.BOUNDARY,
    406                 -1.001, -1, -0.999,
    407                 0.999, 1, 1.001);
    408
    409         checkClassify(tree, RegionLocation.INSIDE, -0.9, 0, 0.9);
    410
    411         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
    412     }
    413
    414     @Test
    415     void checkToTree_singlePoint() {
    416         // arrange
    417         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    418         final Interval interval = Interval.of(1, 1, precision);
    419
    420         // act
    421         final RegionBSPTree1D tree = interval.toTree();
    422
    423         // assert
    424         Assertions.assertEquals(5, tree.count());
    425
    426         checkClassify(tree, RegionLocation.OUTSIDE,
    427                 Double.NEGATIVE_INFINITY, 0, 0.9, 1.1, 2, Double.POSITIVE_INFINITY);
    428
    429         checkClassify(tree, RegionLocation.BOUNDARY,
    430                 0.999, 1, 1.0001);
    431
    432         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
    433     }
    434
    435     @Test
    436     void checkToTree_maxInfinite() {
    437         // arrange
    438         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    439         final Interval interval = Interval.of(-1, Double.POSITIVE_INFINITY, precision);
    440
    441         // act
    442         final RegionBSPTree1D tree = interval.toTree();
    443
    444         // assert
    445         Assertions.assertEquals(3, tree.count());
    446
    447         checkClassify(tree, RegionLocation.OUTSIDE,
    448                 Double.NEGATIVE_INFINITY, -2, -1.1);
    449
    450         checkClassify(tree, RegionLocation.BOUNDARY,
    451                 -1.001, -1, -0.999);
    452
    453         checkClassify(tree, RegionLocation.INSIDE,
    454                 -0.9, 0, 1.0, Double.POSITIVE_INFINITY);
    455
    456         checkClassify(interval, RegionLocation.OUTSIDE, Double.NaN);
    457     }
    458
    459     @Test
    460     void checkToTree_minInfinite() {
    461         // arrange
    462         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    463         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, precision);
    464
    465         // act
    466         final RegionBSPTree1D tree = interval.toTree();
    467
    468         // assert
    469         Assertions.assertEquals(3, tree.count());
    470
    471         checkClassify(tree, RegionLocation.INSIDE,
    472                 Double.NEGATIVE_INFINITY, 0, 0.9);
    473
    474         checkClassify(tree, RegionLocation.BOUNDARY,
    475                 0.999, 1, 1.001);
    476
    477         checkClassify(tree, RegionLocation.OUTSIDE,
    478                 1.1, 2, Double.POSITIVE_INFINITY);
    479
    480         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
    481     }
    482
    483     @Test
    484     void checkToTree_minMaxInfinite() {
    485         // arrange
    486         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    487         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, precision);
    488
    489         // act
    490         final RegionBSPTree1D tree = interval.toTree();
    491
    492         // assert
    493         Assertions.assertEquals(1, tree.count());
    494
    495         checkClassify(tree, RegionLocation.INSIDE,
    496                 Double.NEGATIVE_INFINITY, -1, 0, 1, Double.POSITIVE_INFINITY);
    497
    498         checkClassify(tree, RegionLocation.OUTSIDE, Double.NaN);
    499     }
    500
    501     @Test
    502     void testProjectToBoundary_full() {
    503         // arrange
    504         final Interval full = Interval.full();
    505
    506
    507         // act/assert
    508         Assertions.assertNull(full.project(Vector1D.of(Double.NEGATIVE_INFINITY)));
    509         Assertions.assertNull(full.project(Vector1D.of(0)));
    510         Assertions.assertNull(full.project(Vector1D.of(Double.POSITIVE_INFINITY)));
    511     }
    512
    513     @Test
    514     void testProjectToBoundary_singlePoint() {
    515         // arrange
    516         final Interval interval = Interval.point(1, TEST_PRECISION);
    517
    518         // act/assert
    519         checkBoundaryProjection(interval, -1, 1);
    520         checkBoundaryProjection(interval, 0, 1);
    521
    522         checkBoundaryProjection(interval, 1, 1);
    523
    524         checkBoundaryProjection(interval, 2, 1);
    525         checkBoundaryProjection(interval, 3, 1);
    526
    527         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
    528         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
    529     }
    530
    531     @Test
    532     void testProjectToBoundary_closedInterval() {
    533         // arrange
    534         final Interval interval = Interval.of(1, 3, TEST_PRECISION);
    535
    536         // act/assert
    537         checkBoundaryProjection(interval, -1, 1);
    538         checkBoundaryProjection(interval, 0, 1);
    539         checkBoundaryProjection(interval, 1, 1);
    540
    541         checkBoundaryProjection(interval, 1.9, 1);
    542         checkBoundaryProjection(interval, 2, 1);
    543         checkBoundaryProjection(interval, 2.1, 3);
    544
    545         checkBoundaryProjection(interval, 3, 3);
    546         checkBoundaryProjection(interval, 4, 3);
    547         checkBoundaryProjection(interval, 5, 3);
    548
    549         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
    550         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 3);
    551     }
    552
    553     @Test
    554     void testProjectToBoundary_noMinBoundary() {
    555         // arrange
    556         final Interval interval = Interval.of(Double.NEGATIVE_INFINITY, 1, TEST_PRECISION);
    557
    558         // act/assert
    559         checkBoundaryProjection(interval, -1, 1);
    560         checkBoundaryProjection(interval, 0, 1);
    561         checkBoundaryProjection(interval, 1, 1);
    562         checkBoundaryProjection(interval, 2, 1);
    563         checkBoundaryProjection(interval, 3, 1);
    564
    565         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
    566         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
    567     }
    568
    569     @Test
    570     void testProjectToBoundary_noMaxBoundary() {
    571         // arrange
    572         final Interval interval = Interval.of(1, Double.POSITIVE_INFINITY, TEST_PRECISION);
    573
    574         // act/assert
    575         checkBoundaryProjection(interval, -1, 1);
    576         checkBoundaryProjection(interval, 0, 1);
    577         checkBoundaryProjection(interval, 1, 1);
    578         checkBoundaryProjection(interval, 2, 1);
    579         checkBoundaryProjection(interval, 3, 1);
    580
    581         checkBoundaryProjection(interval, Double.NEGATIVE_INFINITY, 1);
    582         checkBoundaryProjection(interval, Double.POSITIVE_INFINITY, 1);
    583     }
    584
    585     @Test
    586     void testTransform() {
    587         // arrange
    588         final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(2);
    589
    590         // act/assert
    591         checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 4);
    592
    593         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
    594                 Double.NEGATIVE_INFINITY, 4);
    595
    596         checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform), -2,
    597                 Double.POSITIVE_INFINITY);
    598
    599         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
    600                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    601     }
    602
    603     @Test
    604     void testTransform_reflection() {
    605         // arrange
    606         final AffineTransformMatrix1D transform = AffineTransformMatrix1D.createScale(-1);
    607
    608         // act/assert
    609         checkInterval(Interval.of(-1, 2, TEST_PRECISION).transform(transform), -2, 1);
    610
    611         checkInterval(Interval.of(Double.NEGATIVE_INFINITY, 2, TEST_PRECISION).transform(transform),
    612                 -2, Double.POSITIVE_INFINITY);
    613
    614         checkInterval(Interval.of(-1, Double.POSITIVE_INFINITY, TEST_PRECISION).transform(transform),
    615                 Double.NEGATIVE_INFINITY, 1);
    616     }
    617
    618     @Test
    619     void testSplit_full_positiveFacingSplitter() {
    620         // arrange
    621         final Interval interval = Interval.full();
    622         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    623                 Vector1D.of(1), true, TEST_PRECISION);
    624
    625         // act
    626         final Split<Interval> split = interval.split(splitter);
    627
    628         // assert
    629         Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
    630
    631         checkInterval(split.getMinus(), Double.NEGATIVE_INFINITY, 1);
    632         checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
    633     }
    634
    635     @Test
    636     void testSplit_full_negativeFacingSplitter() {
    637         // arrange
    638         final Interval interval = Interval.full();
    639         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    640                 Vector1D.of(1), true, TEST_PRECISION);
    641
    642         // act
    643         final Split<Interval> split = interval.split(splitter);
    644
    645         // assert
    646         Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
    647
    648         checkInterval(split.getMinus(), Double.NEGATIVE_INFINITY, 1);
    649         checkInterval(split.getPlus(), 1, Double.POSITIVE_INFINITY);
    650     }
    651
    652     @Test
    653     void testSplit_halfSpace_positiveFacingSplitter() {
    654         // arrange
    655         final Interval interval = Interval.min(-1, TEST_PRECISION);
    656         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    657                 Vector1D.of(1), false, TEST_PRECISION);
    658
    659         // act
    660         final Split<Interval> split = interval.split(splitter);
    661
    662         // assert
    663         Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
    664
    665         checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
    666         checkInterval(split.getPlus(), -1, 1);
    667     }
    668
    669
    670     @Test
    671     void testSplit_halfSpace_negativeFacingSplitter() {
    672         // arrange
    673         final Interval interval = Interval.min(-1, TEST_PRECISION);
    674         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    675                 Vector1D.of(1), false, TEST_PRECISION);
    676
    677         // act
    678         final Split<Interval> split = interval.split(splitter);
    679
    680         // assert
    681         Assertions.assertEquals(SplitLocation.BOTH, split.getLocation());
    682
    683         checkInterval(split.getMinus(), 1, Double.POSITIVE_INFINITY);
    684         checkInterval(split.getPlus(), -1, 1);
    685     }
    686
    687     @Test
    688     void testSplit_splitterBelowInterval() {
    689         // arrange
    690         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
    691         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    692                 Vector1D.of(1), true, TEST_PRECISION);
    693
    694         // act
    695         final Split<Interval> split = interval.split(splitter);
    696
    697         // assert
    698         Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
    699
    700         Assertions.assertSame(interval, split.getPlus());
    701     }
    702
    703     @Test
    704     void testSplit_splitterOnMinBoundary() {
    705         // arrange
    706         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
    707         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    708                 Vector1D.of(5), false, TEST_PRECISION);
    709
    710         // act
    711         final Split<Interval> split = interval.split(splitter);
    712
    713         // assert
    714         Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
    715
    716         Assertions.assertSame(interval, split.getMinus());
    717     }
    718
    719     @Test
    720     void testSplit_splitterAboveInterval() {
    721         // arrange
    722         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
    723         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    724                 Vector1D.of(11), true, TEST_PRECISION);
    725
    726         // act
    727         final Split<Interval> split = interval.split(splitter);
    728
    729         // assert
    730         Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
    731
    732         Assertions.assertSame(interval, split.getMinus());
    733     }
    734
    735     @Test
    736     void testSplit_splitterOnMaxBoundary() {
    737         // arrange
    738         final Interval interval = Interval.of(5, 10, TEST_PRECISION);
    739         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    740                 Vector1D.of(10), false, TEST_PRECISION);
    741
    742         // act
    743         final Split<Interval> split = interval.split(splitter);
    744
    745         // assert
    746         Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
    747
    748         Assertions.assertSame(interval, split.getPlus());
    749     }
    750
    751     @Test
    752     void testSplit_point_minusOnly() {
    753         // arrange
    754         final Interval interval = Interval.point(2, TEST_PRECISION);
    755         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    756                 Vector1D.of(1), false, TEST_PRECISION);
    757
    758         // act
    759         final Split<Interval> split = interval.split(splitter);
    760
    761         // assert
    762         Assertions.assertEquals(SplitLocation.MINUS, split.getLocation());
    763
    764         checkInterval(split.getMinus(), 2, 2);
    765         Assertions.assertNull(split.getPlus());
    766     }
    767
    768     @Test
    769     void testSplit_point_plusOnly() {
    770         // arrange
    771         final Interval interval = Interval.point(2, TEST_PRECISION);
    772         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    773                 Vector1D.of(1), true, TEST_PRECISION);
    774
    775         // act
    776         final Split<Interval> split = interval.split(splitter);
    777
    778         // assert
    779         Assertions.assertEquals(SplitLocation.PLUS, split.getLocation());
    780
    781         Assertions.assertNull(split.getMinus());
    782         checkInterval(split.getPlus(), 2, 2);
    783     }
    784
    785     @Test
    786     void testSplit_point_onPoint() {
    787         // arrange
    788         final Interval interval = Interval.point(1, TEST_PRECISION);
    789         final OrientedPoint splitter = OrientedPoints.fromPointAndDirection(
    790                 Vector1D.of(1), true, TEST_PRECISION);
    791
    792         // act
    793         final Split<Interval> split = interval.split(splitter);
    794
    795         // assert
    796         Assertions.assertEquals(SplitLocation.NEITHER, split.getLocation());
    797
    798         Assertions.assertNull(split.getMinus());
    799         Assertions.assertNull(split.getPlus());
    800     }
    801
    802     @Test
    803     void testToString() {
    804         // arrange
    805         final Interval interval = Interval.of(2, 1, TEST_PRECISION);
    806
    807         // act
    808         final String str = interval.toString();
    809
    810         // assert
    811         Assertions.assertTrue(str.contains("Interval"));
    812         Assertions.assertTrue(str.contains("min= 1.0"));
    813         Assertions.assertTrue(str.contains("max= 2.0"));
    814     }
    815
    816     @Test
    817     void testFull() {
    818         // act
    819         final Interval full = Interval.full();
    820
    821         // assert
    822         Assertions.assertTrue(full.isFull());
    823         Assertions.assertFalse(full.isEmpty());
    824         Assertions.assertFalse(full.hasMinBoundary());
    825         Assertions.assertFalse(full.hasMaxBoundary());
    826         Assertions.assertTrue(full.isInfinite());
    827
    828         Assertions.assertEquals(RegionLocation.INSIDE, full.classify(Double.NEGATIVE_INFINITY));
    829         Assertions.assertEquals(RegionLocation.INSIDE, full.classify(Double.POSITIVE_INFINITY));
    830     }
    831
    832     private static void checkContains(final Interval interval, final boolean contains, final double... points) {
    833         for (final double x : points) {
    834             final String msg = "Unexpected contains status for point " + x;
    835
    836             Assertions.assertEquals(contains, interval.contains(x), msg);
    837             Assertions.assertEquals(contains, interval.contains(Vector1D.of(x)), msg);
    838         }
    839     }
    840
    841     private static void checkClassify(final Interval interval, final RegionLocation loc, final double... points) {
    842         for (final double x : points) {
    843             final String msg = "Unexpected location for point " + x;
    844
    845             Assertions.assertEquals(loc, interval.classify(x), msg);
    846             Assertions.assertEquals(loc, interval.classify(Vector1D.of(x)), msg);
    847         }
    848     }
    849
    850     private static void checkClassify(final RegionBSPTree1D tree, final RegionLocation loc, final double... points) {
    851         for (final double x : points) {
    852             final String msg = "Unexpected location for point " + x;
    853
    854             Assertions.assertEquals(loc, tree.classify(x), msg);
    855             Assertions.assertEquals(loc, tree.classify(Vector1D.of(x)), msg);
    856         }
    857     }
    858
    859     private static void checkBoundaryProjection(final Interval interval, final double location, final double projectedLocation) {
    860         final Vector1D pt = Vector1D.of(location);
    861
    862         final Vector1D proj = interval.project(pt);
    863
    864         Assertions.assertEquals(projectedLocation, proj.getX(), TEST_EPS);
    865     }
    866
    867     /** Check that the given interval matches the arguments and is internally consistent.
    868      * @param interval
    869      * @param min
    870      * @param max
    871      */
    872     private static void checkInterval(final Interval interval, final double min, final double max) {
    873         checkInterval(interval, min, max, TEST_PRECISION);
    874     }
    875
    876     /** Check that the given interval matches the arguments and is internally consistent.
    877      * @param interval
    878      * @param min
    879      * @param max
    880      * @param precision
    881      */
    882     private static void checkInterval(final Interval interval, final double min, final double max, final Precision.DoubleEquivalence precision) {
    883         Assertions.assertEquals(min, interval.getMin(), TEST_EPS);
    884         Assertions.assertEquals(max, interval.getMax(), TEST_EPS);
    885
    886         final boolean finiteMin = Double.isFinite(min);
    887         final boolean finiteMax = Double.isFinite(max);
    888
    889         Assertions.assertEquals(finiteMin, interval.hasMinBoundary());
    890         Assertions.assertEquals(finiteMax, interval.hasMaxBoundary());
    891
    892         if (finiteMin) {
    893             Assertions.assertEquals(min, interval.getMinBoundary().getLocation(), TEST_EPS);
    894         } else {
    895             Assertions.assertNull(interval.getMinBoundary());
    896         }
    897
    898         if (finiteMax) {
    899             Assertions.assertEquals(max, interval.getMaxBoundary().getLocation(), TEST_EPS);
    900         } else {
    901             Assertions.assertNull(interval.getMaxBoundary());
    902         }
    903
    904         Assertions.assertFalse(interval.isEmpty()); // always false
    905     }
    906 }