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