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.spherical.oned;
    18
    19  import java.util.List;
    20
    21  import org.apache.commons.geometry.core.RegionLocation;
    22  import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
    23  import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
    24  import org.apache.commons.geometry.core.partitioning.Split;
    25  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    26  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
    27  import org.apache.commons.geometry.spherical.SphericalTestUtils;
    28  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    29  import org.junit.Assert;
    30  import org.junit.Test;
    31
    32  public class CutAngleTest {
    33
    34      private static final double TEST_EPS = 1e-10;
    35
    36      private static final DoublePrecisionContext TEST_PRECISION =
    37              new EpsilonDoublePrecisionContext(TEST_EPS);
    38
    39      @Test
    40      public void testFromAzimuthAndDirection() {
    41          // act/assert
    42          checkCutAngle(CutAngles.fromAzimuthAndDirection(0.0, true, TEST_PRECISION),
    43                  0.0, true);
    44          checkCutAngle(CutAngles.fromAzimuthAndDirection(PlaneAngleRadians.PI, true, TEST_PRECISION),
    45                  PlaneAngleRadians.PI, true);
    46          checkCutAngle(CutAngles.fromAzimuthAndDirection(-PlaneAngleRadians.PI_OVER_TWO, true, TEST_PRECISION),
    47                  -PlaneAngleRadians.PI_OVER_TWO, true);
    48
    49          checkCutAngle(CutAngles.fromAzimuthAndDirection(0.0, false, TEST_PRECISION),
    50                  0.0, false);
    51          checkCutAngle(CutAngles.fromAzimuthAndDirection(PlaneAngleRadians.PI, false, TEST_PRECISION),
    52                  PlaneAngleRadians.PI, false);
    53          checkCutAngle(CutAngles.fromAzimuthAndDirection(-PlaneAngleRadians.PI_OVER_TWO, false, TEST_PRECISION),
    54                  -PlaneAngleRadians.PI_OVER_TWO, false);
    55      }
    56
    57      @Test
    58      public void testFromPointAndDirection() {
    59          // arrange
    60          final Point1S pt = Point1S.of(-PlaneAngleRadians.PI_OVER_TWO);
    61
    62          // act/assert
    63          checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION),
    64                  0.0, true);
    65          checkCutAngle(CutAngles.fromPointAndDirection(Point1S.PI, true, TEST_PRECISION),
    66                  PlaneAngleRadians.PI, true);
    67          checkCutAngle(CutAngles.fromPointAndDirection(pt, true, TEST_PRECISION),
    68                  -PlaneAngleRadians.PI_OVER_TWO, true);
    69
    70          checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, false, TEST_PRECISION),
    71                  0.0, false);
    72          checkCutAngle(CutAngles.fromPointAndDirection(Point1S.PI, false, TEST_PRECISION),
    73                  PlaneAngleRadians.PI, false);
    74          checkCutAngle(CutAngles.fromPointAndDirection(pt, false, TEST_PRECISION),
    75                  -PlaneAngleRadians.PI_OVER_TWO, false);
    76      }
    77
    78      @Test
    79      public void testCreatePositiveFacing() {
    80          // act/assert
    81          checkCutAngle(CutAngles.createPositiveFacing(Point1S.ZERO, TEST_PRECISION),
    82                  0.0, true);
    83          checkCutAngle(CutAngles.createPositiveFacing(Point1S.PI, TEST_PRECISION),
    84                  PlaneAngleRadians.PI, true);
    85          checkCutAngle(CutAngles.createPositiveFacing(-PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION),
    86                  -PlaneAngleRadians.PI_OVER_TWO, true);
    87      }
    88
    89      @Test
    90      public void testCreateNegativeFacing() {
    91          // act/assert
    92          checkCutAngle(CutAngles.createNegativeFacing(Point1S.ZERO, TEST_PRECISION),
    93                  0.0, false);
    94          checkCutAngle(CutAngles.createNegativeFacing(Point1S.PI, TEST_PRECISION),
    95                  PlaneAngleRadians.PI, false);
    96          checkCutAngle(CutAngles.createNegativeFacing(-PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION),
    97                  -PlaneAngleRadians.PI_OVER_TWO, false);
    98      }
    99
    100     @Test
    101     public void testOffset() {
    102         // arrange
    103         final CutAngle zeroPos = CutAngles.createPositiveFacing(0.0, TEST_PRECISION);
    104         final CutAngle zeroNeg = CutAngles.createNegativeFacing(0.0, TEST_PRECISION);
    105         final CutAngle negPiPos = CutAngles.createPositiveFacing(-PlaneAngleRadians.PI, TEST_PRECISION);
    106
    107         final CutAngle piNeg = CutAngles.createNegativeFacing(PlaneAngleRadians.PI, TEST_PRECISION);
    108         final CutAngle twoAndAHalfPiPos = CutAngles.createPositiveFacing(2.5 * PlaneAngleRadians.PI, TEST_PRECISION);
    109
    110         // act/assert
    111         checkOffset(zeroPos, 0, 0);
    112         checkOffset(zeroPos, PlaneAngleRadians.TWO_PI, 0);
    113         checkOffset(zeroPos, 2.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO);
    114         checkOffset(zeroPos, PlaneAngleRadians.PI, PlaneAngleRadians.PI);
    115         checkOffset(zeroPos, 3.5 * PlaneAngleRadians.PI, 1.5 * PlaneAngleRadians.PI);
    116
    117         checkOffset(zeroNeg, 0, 0);
    118         checkOffset(zeroNeg, PlaneAngleRadians.TWO_PI, 0);
    119         checkOffset(zeroNeg, 2.5 * PlaneAngleRadians.PI, -PlaneAngleRadians.PI_OVER_TWO);
    120         checkOffset(zeroNeg, PlaneAngleRadians.PI, -PlaneAngleRadians.PI);
    121         checkOffset(zeroNeg, 3.5 * PlaneAngleRadians.PI, -1.5 * PlaneAngleRadians.PI);
    122
    123         checkOffset(negPiPos, 0, -PlaneAngleRadians.PI);
    124         checkOffset(negPiPos, PlaneAngleRadians.TWO_PI, -PlaneAngleRadians.PI);
    125         checkOffset(negPiPos, 2.5 * PlaneAngleRadians.PI, -PlaneAngleRadians.PI_OVER_TWO);
    126         checkOffset(negPiPos, PlaneAngleRadians.PI, 0);
    127         checkOffset(negPiPos, 3.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO);
    128
    129         checkOffset(piNeg, 0, PlaneAngleRadians.PI);
    130         checkOffset(piNeg, PlaneAngleRadians.TWO_PI, PlaneAngleRadians.PI);
    131         checkOffset(piNeg, 2.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO);
    132         checkOffset(piNeg, PlaneAngleRadians.PI, 0);
    133         checkOffset(piNeg, 3.5 * PlaneAngleRadians.PI, -PlaneAngleRadians.PI_OVER_TWO);
    134
    135         checkOffset(twoAndAHalfPiPos, 0, -PlaneAngleRadians.PI_OVER_TWO);
    136         checkOffset(twoAndAHalfPiPos, PlaneAngleRadians.TWO_PI, -PlaneAngleRadians.PI_OVER_TWO);
    137         checkOffset(twoAndAHalfPiPos, 2.5 * PlaneAngleRadians.PI, 0);
    138         checkOffset(twoAndAHalfPiPos, PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO);
    139         checkOffset(twoAndAHalfPiPos, 3.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI);
    140     }
    141
    142     @Test
    143     public void testClassify() {
    144         // arrange
    145         final CutAngle zeroPos = CutAngles.createPositiveFacing(0.0, TEST_PRECISION);
    146         final CutAngle zeroNeg = CutAngles.createNegativeFacing(0.0, TEST_PRECISION);
    147         final CutAngle negPiPos = CutAngles.createPositiveFacing(-PlaneAngleRadians.PI, TEST_PRECISION);
    148
    149         // act/assert
    150         checkClassify(zeroPos, HyperplaneLocation.ON,
    151                 0, 1e-16, -1e-16,
    152                 PlaneAngleRadians.TWO_PI - 1e-11, PlaneAngleRadians.TWO_PI + 1e-11);
    153         checkClassify(zeroPos, HyperplaneLocation.PLUS,
    154                 0.5, 2.5 * PlaneAngleRadians.PI,
    155                 -0.5, -PlaneAngleRadians.PI_OVER_TWO);
    156
    157         checkClassify(zeroNeg, HyperplaneLocation.ON,
    158                 0, 1e-16, -1e-16,
    159                 PlaneAngleRadians.TWO_PI - 1e-11, PlaneAngleRadians.TWO_PI + 1e-11);
    160         checkClassify(zeroNeg, HyperplaneLocation.MINUS,
    161                 0.5, 2.5 * PlaneAngleRadians.PI,
    162                 -0.5, -PlaneAngleRadians.PI_OVER_TWO);
    163
    164         checkClassify(negPiPos, HyperplaneLocation.ON, PlaneAngleRadians.PI, PlaneAngleRadians.PI + 1e-11);
    165         checkClassify(negPiPos, HyperplaneLocation.MINUS, 0.5, 2.5 * PlaneAngleRadians.PI,
    166                 0, 1e-11, PlaneAngleRadians.TWO_PI, PlaneAngleRadians.TWO_PI - 1e-11);
    167         checkClassify(negPiPos, HyperplaneLocation.PLUS, -0.5, -PlaneAngleRadians.PI_OVER_TWO);
    168     }
    169
    170     @Test
    171     public void testContains() {
    172         // arrange
    173         final CutAngle pt = CutAngles.createNegativeFacing(PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION);
    174
    175         // act/assert
    176         Assert.assertFalse(pt.contains(Point1S.ZERO));
    177         Assert.assertFalse(pt.contains(Point1S.of(PlaneAngleRadians.TWO_PI)));
    178
    179         Assert.assertFalse(pt.contains(Point1S.of(PlaneAngleRadians.PI)));
    180         Assert.assertFalse(pt.contains(Point1S.of(0.25 * PlaneAngleRadians.PI)));
    181         Assert.assertFalse(pt.contains(Point1S.of(-0.25 * PlaneAngleRadians.PI)));
    182
    183         Assert.assertTrue(pt.contains(Point1S.of(PlaneAngleRadians.PI_OVER_TWO)));
    184         Assert.assertTrue(pt.contains(Point1S.of(PlaneAngleRadians.PI_OVER_TWO + 1e-11)));
    185         Assert.assertTrue(pt.contains(Point1S.of(2.5 * PlaneAngleRadians.PI)));
    186         Assert.assertTrue(pt.contains(Point1S.of(-3.5 * PlaneAngleRadians.PI)));
    187     }
    188
    189     @Test
    190     public void testReverse() {
    191         // arrange
    192         final CutAngle pt = CutAngles.createNegativeFacing(PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION);
    193
    194         // act
    195         final CutAngle result = pt.reverse();
    196
    197         // assert
    198         checkCutAngle(result, PlaneAngleRadians.PI_OVER_TWO, true);
    199         Assert.assertSame(TEST_PRECISION, result.getPrecision());
    200
    201         checkCutAngle(result.reverse(), PlaneAngleRadians.PI_OVER_TWO, false);
    202     }
    203
    204     @Test
    205     public void testProject() {
    206         // arrange
    207         final CutAngle pt = CutAngles.createNegativeFacing(PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION);
    208
    209         // act/assert
    210         for (double az = -PlaneAngleRadians.TWO_PI; az <= PlaneAngleRadians.TWO_PI; az += 0.2) {
    211             Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, pt.project(Point1S.of(az)).getAzimuth(), TEST_EPS);
    212         }
    213     }
    214
    215     @Test
    216     public void testSimilarOrientation() {
    217         // arrange
    218         final CutAngle a = CutAngles.createPositiveFacing(0.0, TEST_PRECISION);
    219         final CutAngle b = CutAngles.createNegativeFacing(0.0, TEST_PRECISION);
    220         final CutAngle c = CutAngles.createPositiveFacing(-PlaneAngleRadians.PI_OVER_TWO, TEST_PRECISION);
    221
    222         // act/assert
    223         Assert.assertTrue(a.similarOrientation(a));
    224         Assert.assertFalse(a.similarOrientation(b));
    225         Assert.assertTrue(a.similarOrientation(c));
    226     }
    227
    228     @Test
    229     public void testTransform_rotate() {
    230         // arrange
    231         final Transform1S transform = Transform1S.createRotation(PlaneAngleRadians.PI_OVER_TWO);
    232
    233         // act
    234         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION).transform(transform),
    235                 PlaneAngleRadians.PI_OVER_TWO, true);
    236         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, false, TEST_PRECISION).transform(transform),
    237                 PlaneAngleRadians.PI_OVER_TWO, false);
    238
    239         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.of(1.5 * PlaneAngleRadians.PI), true, TEST_PRECISION).transform(transform),
    240                 PlaneAngleRadians.TWO_PI, true);
    241         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.of(-PlaneAngleRadians.PI_OVER_TWO), false, TEST_PRECISION).transform(transform),
    242                 0.0, false);
    243     }
    244
    245     @Test
    246     public void testTransform_negate() {
    247         // arrange
    248         final Transform1S transform = Transform1S.createNegation();
    249
    250         // act
    251         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION).transform(transform),
    252                 0.0, false);
    253         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.ZERO, false, TEST_PRECISION).transform(transform),
    254                 0.0, true);
    255
    256         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.of(1.5 * PlaneAngleRadians.PI), true, TEST_PRECISION).transform(transform),
    257                 -1.5 * PlaneAngleRadians.PI, false);
    258         checkCutAngle(CutAngles.fromPointAndDirection(Point1S.of(-PlaneAngleRadians.PI_OVER_TWO), false, TEST_PRECISION).transform(transform),
    259                 PlaneAngleRadians.PI_OVER_TWO, true);
    260     }
    261
    262     @Test
    263     public void testSpan() {
    264         // arrange
    265         final CutAngle pt = CutAngles.fromPointAndDirection(Point1S.of(1.0), false, TEST_PRECISION);
    266
    267         // act
    268         final HyperplaneConvexSubset<Point1S> result = pt.span();
    269
    270         // assert
    271         Assert.assertSame(pt, result.getHyperplane());
    272     }
    273
    274     @Test
    275     public void testEq() {
    276         // arrange
    277         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    278
    279         final CutAngle a = CutAngles.fromPointAndDirection(Point1S.ZERO, true, precision);
    280
    281         final CutAngle b = CutAngles.fromPointAndDirection(Point1S.PI, true, precision);
    282         final CutAngle c = CutAngles.fromPointAndDirection(Point1S.ZERO, false, precision);
    283         final CutAngle d = CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION);
    284
    285         final CutAngle e = CutAngles.fromPointAndDirection(Point1S.ZERO, true, precision);
    286         final CutAngle f = CutAngles.fromPointAndDirection(Point1S.of(PlaneAngleRadians.TWO_PI), true, precision);
    287         final CutAngle g = CutAngles.fromPointAndDirection(Point1S.of(1e-4), true, precision);
    288         final CutAngle h = CutAngles.fromPointAndDirection(Point1S.of(-1e-4), true, precision);
    289
    290         // act/assert
    291         Assert.assertTrue(a.eq(a, precision));
    292
    293         Assert.assertFalse(a.eq(b, precision));
    294         Assert.assertFalse(a.eq(c, precision));
    295
    296         Assert.assertTrue(a.eq(d, precision));
    297         Assert.assertTrue(a.eq(e, precision));
    298         Assert.assertTrue(a.eq(f, precision));
    299         Assert.assertTrue(a.eq(g, precision));
    300         Assert.assertTrue(a.eq(h, precision));
    301     }
    302
    303     @Test
    304     public void testHashCode() {
    305         // arrange
    306         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    307
    308         final CutAngle a = CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION);
    309         final CutAngle b = CutAngles.fromPointAndDirection(Point1S.PI, true, TEST_PRECISION);
    310         final CutAngle c = CutAngles.fromPointAndDirection(Point1S.ZERO, false, TEST_PRECISION);
    311         final CutAngle d = CutAngles.fromPointAndDirection(Point1S.ZERO, true, precision);
    312         final CutAngle e = CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION);
    313
    314         final int hash = a.hashCode();
    315
    316         // act/assert
    317         Assert.assertEquals(hash, a.hashCode());
    318
    319         Assert.assertNotEquals(hash, b.hashCode());
    320         Assert.assertNotEquals(hash, c.hashCode());
    321         Assert.assertNotEquals(hash, d.hashCode());
    322
    323         Assert.assertEquals(hash, e.hashCode());
    324     }
    325
    326     @Test
    327     public void testEquals() {
    328         // arrange
    329         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    330
    331         final CutAngle a = CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION);
    332         final CutAngle b = CutAngles.fromPointAndDirection(Point1S.PI, true, TEST_PRECISION);
    333         final CutAngle c = CutAngles.fromPointAndDirection(Point1S.ZERO, false, TEST_PRECISION);
    334         final CutAngle d = CutAngles.fromPointAndDirection(Point1S.ZERO, true, precision);
    335         final CutAngle e = CutAngles.fromPointAndDirection(Point1S.ZERO, true, TEST_PRECISION);
    336
    337         // act/assert
    338         Assert.assertFalse(a.equals(null));
    339         Assert.assertFalse(a.equals(new Object()));
    340
    341         Assert.assertEquals(a, a);
    342
    343         Assert.assertNotEquals(a, b);
    344         Assert.assertNotEquals(a, c);
    345         Assert.assertNotEquals(a, d);
    346
    347         Assert.assertEquals(a, e);
    348     }
    349
    350     @Test
    351     public void testToString() {
    352         // arrange
    353         final CutAngle pt = CutAngles.createPositiveFacing(0.0, TEST_PRECISION);
    354
    355         // act
    356         final String str = pt.toString();
    357
    358         // assert
    359         Assert.assertTrue(str.startsWith("CutAngle["));
    360         Assert.assertTrue(str.contains("point= ") && str.contains("positiveFacing= "));
    361     }
    362
    363     @Test
    364     public void testSubset_split() {
    365         // arrange
    366         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    367
    368         final CutAngle pt = CutAngles.createPositiveFacing(-1.5, precision);
    369         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    370
    371         // act/assert
    372         checkSplit(sub, CutAngles.createPositiveFacing(1.0, precision), false, true);
    373         checkSplit(sub, CutAngles.createPositiveFacing(-1.5 + 1e-2, precision), true, false);
    374
    375         checkSplit(sub, CutAngles.createNegativeFacing(1.0, precision), true, false);
    376         checkSplit(sub, CutAngles.createNegativeFacing(-1.5 + 1e-2, precision), false, true);
    377
    378         checkSplit(sub, CutAngles.createNegativeFacing(-1.5, precision), false, false);
    379         checkSplit(sub, CutAngles.createNegativeFacing(-1.5 + 1e-4, precision), false, false);
    380         checkSplit(sub, CutAngles.createNegativeFacing(-1.5 - 1e-4, precision), false, false);
    381     }
    382
    383     private void checkSplit(final HyperplaneConvexSubset<Point1S> sub, final CutAngle splitter, final boolean minus, final boolean plus) {
    384         final Split<? extends HyperplaneConvexSubset<Point1S>> split = sub.split(splitter);
    385
    386         Assert.assertSame(minus ? sub : null, split.getMinus());
    387         Assert.assertSame(plus ? sub : null, split.getPlus());
    388     }
    389
    390     @Test
    391     public void testSubset_simpleMethods() {
    392         // arrange
    393         final CutAngle pt = CutAngles.createPositiveFacing(1, TEST_PRECISION);
    394         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    395
    396         // act/assert
    397         Assert.assertSame(pt, sub.getHyperplane());
    398         Assert.assertFalse(sub.isFull());
    399         Assert.assertFalse(sub.isEmpty());
    400         Assert.assertFalse(sub.isInfinite());
    401         Assert.assertTrue(sub.isFinite());
    402         Assert.assertEquals(0.0, sub.getSize(), TEST_EPS);
    403         SphericalTestUtils.assertPointsEqual(Point1S.of(1), sub.getCentroid(), TEST_EPS);
    404
    405         final List<? extends HyperplaneConvexSubset<Point1S>> list = sub.toConvex();
    406         Assert.assertEquals(1, list.size());
    407         Assert.assertSame(sub, list.get(0));
    408     }
    409
    410     @Test
    411     public void testSubset_classify() {
    412         // arrange
    413         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
    414         final CutAngle pt = CutAngles.createPositiveFacing(1, precision);
    415         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    416
    417         // act/assert
    418         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Point1S.of(0.95)));
    419         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Point1S.of(1)));
    420         Assert.assertEquals(RegionLocation.BOUNDARY, sub.classify(Point1S.of(1.05)));
    421
    422         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Point1S.of(1.11)));
    423         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Point1S.of(0.89)));
    424
    425         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Point1S.of(-3)));
    426         Assert.assertEquals(RegionLocation.OUTSIDE, sub.classify(Point1S.of(10)));
    427     }
    428
    429     @Test
    430     public void testSubset_contains() {
    431         // arrange
    432         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
    433         final CutAngle pt = CutAngles.createPositiveFacing(1, precision);
    434         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    435
    436         // act/assert
    437         Assert.assertTrue(sub.contains(Point1S.of(0.95)));
    438         Assert.assertTrue(sub.contains(Point1S.of(1)));
    439         Assert.assertTrue(sub.contains(Point1S.of(1.05)));
    440
    441         Assert.assertFalse(sub.contains(Point1S.of(1.11)));
    442         Assert.assertFalse(sub.contains(Point1S.of(0.89)));
    443
    444         Assert.assertFalse(sub.contains(Point1S.of(-3)));
    445         Assert.assertFalse(sub.contains(Point1S.of(10)));
    446     }
    447
    448     @Test
    449     public void testSubset_closestContained() {
    450         // arrange
    451         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-1);
    452         final CutAngle pt = CutAngles.createPositiveFacing(1, precision);
    453         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    454
    455         final Point1S expected = Point1S.of(1);
    456
    457         // act/assert
    458         Assert.assertEquals(expected, sub.closest(Point1S.ZERO));
    459         Assert.assertEquals(expected, sub.closest(Point1S.of(PlaneAngleRadians.PI_OVER_TWO)));
    460         Assert.assertEquals(expected, sub.closest(Point1S.PI));
    461         Assert.assertEquals(expected, sub.closest(Point1S.of(-PlaneAngleRadians.PI_OVER_TWO)));
    462         Assert.assertEquals(expected, sub.closest(Point1S.of(PlaneAngleRadians.TWO_PI)));
    463     }
    464
    465     @Test
    466     public void testSubset_transform() {
    467         // arrange
    468         final CutAngle pt = CutAngles.fromPointAndDirection(Point1S.of(PlaneAngleRadians.PI_OVER_TWO), true, TEST_PRECISION);
    469
    470         final Transform1S transform = Transform1S.createNegation().rotate(PlaneAngleRadians.PI);
    471
    472         // act
    473         final HyperplaneConvexSubset<Point1S> result = pt.span().transform(transform);
    474
    475         // assert
    476         checkCutAngle((CutAngle) result.getHyperplane(), PlaneAngleRadians.PI_OVER_TWO, false);
    477     }
    478
    479     @Test
    480     public void testSubset_reverse() {
    481         // arrange
    482         final CutAngle pt = CutAngles.createPositiveFacing(2.0, TEST_PRECISION);
    483         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    484
    485         // act
    486         final HyperplaneConvexSubset<Point1S> result = sub.reverse();
    487
    488         // assert
    489         Assert.assertEquals(2.0, ((CutAngle) result.getHyperplane()).getAzimuth(), TEST_EPS);
    490         Assert.assertFalse(((CutAngle) result.getHyperplane()).isPositiveFacing());
    491
    492         Assert.assertEquals(sub.getHyperplane(), result.reverse().getHyperplane());
    493     }
    494
    495     @Test
    496     public void testSubset_toString() {
    497         // arrange
    498         final CutAngle pt = CutAngles.createPositiveFacing(2, TEST_PRECISION);
    499         final HyperplaneConvexSubset<Point1S> sub = pt.span();
    500
    501         // act
    502         final String str = sub.toString();
    503
    504         //assert
    505         Assert.assertTrue(str.contains("CutAngleConvexSubset["));
    506         Assert.assertTrue(str.contains("point= "));
    507         Assert.assertTrue(str.contains("positiveFacing= "));
    508     }
    509
    510     private static void checkCutAngle(final CutAngle angle, final double az, final boolean positiveFacing) {
    511         checkCutAngle(angle, az, positiveFacing, TEST_PRECISION);
    512     }
    513
    514     private static void checkCutAngle(final CutAngle angle, final double az, final boolean positiveFacing, final DoublePrecisionContext precision) {
    515         Assert.assertEquals(az, angle.getAzimuth(), TEST_EPS);
    516         Assert.assertEquals(PlaneAngleRadians.normalizeBetweenZeroAndTwoPi(az), angle.getNormalizedAzimuth(), TEST_EPS);
    517         Assert.assertEquals(az, angle.getPoint().getAzimuth(), TEST_EPS);
    518         Assert.assertEquals(positiveFacing, angle.isPositiveFacing());
    519
    520         Assert.assertSame(precision, angle.getPrecision());
    521     }
    522
    523     private static void checkOffset(final CutAngle pt, final double az, final double offset) {
    524         Assert.assertEquals(offset, pt.offset(Point1S.of(az)), TEST_EPS);
    525     }
    526
    527     private static void checkClassify(final CutAngle pt, final HyperplaneLocation loc, final double... azimuths) {
    528         for (final double az : azimuths) {
    529             Assert.assertEquals("Unexpected location for azimuth " + az, loc, pt.classify(Point1S.of(az)));
    530         }
    531     }
    532 }