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.twod;
    18
    19  import java.util.List;
    20
    21  import org.apache.commons.geometry.core.GeometryTestUtils;
    22  import org.apache.commons.geometry.core.RegionLocation;
    23  import org.apache.commons.geometry.core.partitioning.Split;
    24  import org.apache.commons.geometry.core.partitioning.SplitLocation;
    25  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    26  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
    27  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    28  import org.apache.commons.geometry.spherical.SphericalTestUtils;
    29  import org.apache.commons.geometry.spherical.oned.AngularInterval;
    30  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    31  import org.junit.Assert;
    32  import org.junit.Test;
    33
    34  public class GreatArcTest {
    35
    36      private static final double TEST_EPS = 1e-10;
    37
    38      private static final DoublePrecisionContext TEST_PRECISION =
    39              new EpsilonDoublePrecisionContext(TEST_EPS);
    40
    41      @Test
    42      public void testFromInterval_full() {
    43          // act
    44          final GreatArc arc = GreatCircles.arcFromInterval(
    45                  GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION),
    46                  AngularInterval.full());
    47
    48          // assert
    49          Assert.assertTrue(arc.isFull());
    50          Assert.assertFalse(arc.isEmpty());
    51          Assert.assertTrue(arc.isFinite());
    52          Assert.assertFalse(arc.isInfinite());
    53
    54          Assert.assertNull(arc.getStartPoint());
    55          Assert.assertNull(arc.getEndPoint());
    56
    57          Assert.assertEquals(PlaneAngleRadians.TWO_PI, arc.getSize(), TEST_EPS);
    58          Assert.assertNull(arc.getCentroid());
    59
    60          for (double az = 0; az < PlaneAngleRadians.TWO_PI; az += 0.1) {
    61              checkClassify(arc, RegionLocation.INSIDE, Point2S.of(az, PlaneAngleRadians.PI_OVER_TWO));
    62          }
    63
    64          checkClassify(arc, RegionLocation.OUTSIDE,
    65                  Point2S.PLUS_K, Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO + 0.1),
    66                  Point2S.MINUS_K, Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO - 0.1));
    67      }
    68
    69      @Test
    70      public void testFromInterval_partial() {
    71          // arrange
    72          final GreatArc arc = GreatCircles.arcFromInterval(
    73                  GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION),
    74                  AngularInterval.Convex.of(PlaneAngleRadians.PI_OVER_TWO, 1.5 * PlaneAngleRadians.PI, TEST_PRECISION));
    75
    76          // assert
    77          Assert.assertFalse(arc.isFull());
    78          Assert.assertFalse(arc.isEmpty());
    79          Assert.assertTrue(arc.isFinite());
    80          Assert.assertFalse(arc.isInfinite());
    81
    82          checkArc(arc, Point2S.PLUS_K, Point2S.MINUS_K);
    83      }
    84
    85      @Test
    86      public void testFromPoints() {
    87          // arrange
    88          final Point2S start = Point2S.PLUS_I;
    89          final Point2S end = Point2S.MINUS_K;
    90
    91          // act
    92          final GreatArc arc = GreatCircles.arcFromPoints(start, end, TEST_PRECISION);
    93
    94          // assert
    95          Assert.assertFalse(arc.isFull());
    96          Assert.assertFalse(arc.isEmpty());
    97          Assert.assertTrue(arc.isFinite());
    98          Assert.assertFalse(arc.isInfinite());
    99
    100         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Y, arc.getCircle().getPole(), TEST_EPS);
    101
    102         checkArc(arc, start, end);
    103
    104         checkClassify(arc, RegionLocation.INSIDE, Point2S.of(0, 0.75 * PlaneAngleRadians.PI));
    105         checkClassify(arc, RegionLocation.BOUNDARY, start, end);
    106         checkClassify(arc, RegionLocation.OUTSIDE,
    107                 Point2S.of(0, 0.25 * PlaneAngleRadians.PI), Point2S.of(PlaneAngleRadians.PI, 0.75 * PlaneAngleRadians.PI),
    108                 Point2S.of(PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI));
    109     }
    110
    111     @Test
    112     public void testFromPoints_almostPi() {
    113         // arrange
    114         final Point2S start = Point2S.PLUS_J;
    115         final Point2S end = Point2S.of(1.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO - 1e-5);
    116
    117         // act
    118         final GreatArc arc = GreatCircles.arcFromPoints(start, end, TEST_PRECISION);
    119
    120         // assert
    121         Assert.assertFalse(arc.isFull());
    122         Assert.assertFalse(arc.isEmpty());
    123         Assert.assertTrue(arc.isFinite());
    124         Assert.assertFalse(arc.isInfinite());
    125
    126         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_X, arc.getCircle().getPole(), TEST_EPS);
    127
    128         checkArc(arc, start, end);
    129
    130         checkClassify(arc, RegionLocation.INSIDE, Point2S.PLUS_K);
    131         checkClassify(arc, RegionLocation.BOUNDARY, start, end);
    132         checkClassify(arc, RegionLocation.OUTSIDE, Point2S.MINUS_K);
    133     }
    134
    135     @Test
    136     public void testFromPoints_usesShortestPath() {
    137         // act/assert
    138         SphericalTestUtils.assertVectorsEqual(
    139                 Vector3D.Unit.MINUS_Y,
    140                 GreatCircles.arcFromPoints(
    141                         Point2S.PLUS_I,
    142                         Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO - 1e-5),
    143                         TEST_PRECISION).getCircle().getPole(), TEST_EPS);
    144
    145         SphericalTestUtils.assertVectorsEqual(
    146                 Vector3D.Unit.PLUS_Y,
    147                 GreatCircles.arcFromPoints(
    148                         Point2S.PLUS_I,
    149                         Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO + 1e-5),
    150                         TEST_PRECISION).getCircle().getPole(), TEST_EPS);
    151     }
    152
    153     @Test
    154     public void testFromPoints_invalidPoints() {
    155         // act/assert
    156         GeometryTestUtils.assertThrows(() -> {
    157             GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.of(1e-12, PlaneAngleRadians.PI_OVER_TWO), TEST_PRECISION);
    158         }, IllegalArgumentException.class);
    159
    160         GeometryTestUtils.assertThrows(() -> {
    161             GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.MINUS_I, TEST_PRECISION);
    162         }, IllegalArgumentException.class);
    163     }
    164
    165     @Test
    166     public void testToConvex() {
    167         // arrange
    168         final GreatArc arc = GreatCircles.arcFromInterval(
    169                 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
    170                 AngularInterval.Convex.of(0.0, PlaneAngleRadians.PI, TEST_PRECISION));
    171
    172         // act
    173         final List<GreatArc> result = arc.toConvex();
    174
    175         // assert
    176         Assert.assertEquals(1, result.size());
    177         Assert.assertSame(arc, result.get(0));
    178     }
    179
    180     @Test
    181     public void testReverse_full() {
    182         // arrange
    183         final GreatArc arc = GreatCircles.arcFromInterval(
    184                 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
    185                 AngularInterval.full());
    186
    187         // act
    188         final GreatArc result = arc.reverse();
    189
    190         // assert
    191         checkGreatCircle(result.getCircle(), Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_Y);
    192
    193         Assert.assertTrue(result.isFull());
    194     }
    195
    196     @Test
    197     public void testReverse() {
    198         // arrange
    199         final GreatArc arc = GreatCircles.arcFromInterval(
    200                 GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION),
    201                 AngularInterval.Convex.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI, TEST_PRECISION));
    202
    203         // act
    204         final GreatArc result = arc.reverse();
    205
    206         // assert
    207         checkGreatCircle(result.getCircle(), Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_Y);
    208
    209         checkArc(result, Point2S.MINUS_J, Point2S.MINUS_I);
    210     }
    211
    212     @Test
    213     public void testTransform() {
    214         // arrange
    215         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_K, Point2S.MINUS_I, TEST_PRECISION)
    216                 .arc(PlaneAngleRadians.PI, -PlaneAngleRadians.PI_OVER_TWO);
    217
    218         final Transform2S t = Transform2S.createRotation(Point2S.PLUS_I, PlaneAngleRadians.PI_OVER_TWO)
    219                 .reflect(Point2S.of(-0.25 * PlaneAngleRadians.PI,  PlaneAngleRadians.PI_OVER_TWO));
    220
    221         // act
    222         final GreatArc result = arc.transform(t);
    223
    224         // assert
    225         checkArc(result, Point2S.PLUS_I, Point2S.PLUS_J);
    226     }
    227
    228     @Test
    229     public void testSplit_full() {
    230         // arrange
    231         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
    232         final GreatCircle splitter = GreatCircles.fromPole(Vector3D.of(-1, 0, 1), TEST_PRECISION);
    233
    234         // act
    235         final Split<GreatArc> split = arc.split(splitter);
    236
    237         // assert
    238         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
    239
    240         final GreatArc minus = split.getMinus();
    241         Assert.assertSame(arc.getCircle(), minus.getCircle());
    242         checkArc(minus, Point2S.PLUS_J, Point2S.MINUS_J);
    243         checkClassify(minus, RegionLocation.OUTSIDE, Point2S.PLUS_I);
    244         checkClassify(minus, RegionLocation.INSIDE, Point2S.MINUS_I);
    245
    246         final GreatArc plus = split.getPlus();
    247         Assert.assertSame(arc.getCircle(), plus.getCircle());
    248         checkArc(plus, Point2S.MINUS_J, Point2S.PLUS_J);
    249         checkClassify(plus, RegionLocation.INSIDE, Point2S.PLUS_I);
    250         checkClassify(plus, RegionLocation.OUTSIDE, Point2S.MINUS_I);
    251     }
    252
    253     @Test
    254     public void testSplit_both() {
    255         // arrange
    256         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
    257                 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
    258         final GreatCircle splitter = GreatCircles.fromPole(Vector3D.of(0, 1, 1), TEST_PRECISION);
    259
    260         // act
    261         final Split<GreatArc> split = arc.split(splitter);
    262
    263         // assert
    264         Assert.assertEquals(SplitLocation.BOTH, split.getLocation());
    265
    266         final GreatArc minus = split.getMinus();
    267         Assert.assertSame(arc.getCircle(), minus.getCircle());
    268         checkArc(minus, Point2S.of(0, 0), Point2S.of(1.5 * PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI));
    269
    270         final GreatArc plus = split.getPlus();
    271         Assert.assertSame(arc.getCircle(), plus.getCircle());
    272         checkArc(plus, Point2S.of(1.5 * PlaneAngleRadians.PI, 0.25 * PlaneAngleRadians.PI), Point2S.MINUS_J);
    273     }
    274
    275     @Test
    276     public void testSplit_minus() {
    277         // arrange
    278         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
    279                 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
    280         final GreatCircle splitter = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    281
    282
    283         // act
    284         final Split<GreatArc> split = arc.split(splitter);
    285
    286         // assert
    287         Assert.assertEquals(SplitLocation.MINUS, split.getLocation());
    288
    289         final GreatArc minus = split.getMinus();
    290         Assert.assertSame(arc, minus);
    291
    292         final GreatArc plus = split.getPlus();
    293         Assert.assertNull(plus);
    294     }
    295
    296     @Test
    297     public void testSplit_plus() {
    298         // arrange
    299         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION)
    300                 .arc(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI);
    301         final GreatCircle splitter = GreatCircles.fromPole(Vector3D.Unit.from(-1, 0, -1), TEST_PRECISION);
    302
    303         // act
    304         final Split<GreatArc> split = arc.split(splitter);
    305
    306         // assert
    307         Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
    308
    309         final GreatArc minus = split.getMinus();
    310         Assert.assertNull(minus);
    311
    312         final GreatArc plus = split.getPlus();
    313         Assert.assertSame(arc, plus);
    314     }
    315
    316     @Test
    317     public void testSplit_parallelAndAntiparallel() {
    318         // arrange
    319         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
    320
    321         // act/assert
    322         Assert.assertEquals(SplitLocation.NEITHER,
    323                 arc.split(GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION)).getLocation());
    324         Assert.assertEquals(SplitLocation.NEITHER,
    325                 arc.split(GreatCircles.fromPole(Vector3D.Unit.MINUS_Z, TEST_PRECISION)).getLocation());
    326     }
    327
    328     @Test
    329     public void testToString_full() {
    330         // arrange
    331         final GreatArc arc = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span();
    332
    333         // act
    334         final String str = arc.toString();
    335
    336         // assert
    337         GeometryTestUtils.assertContains("GreatArc[", str);
    338         GeometryTestUtils.assertContains("full= true", str);
    339         GeometryTestUtils.assertContains("circle= GreatCircle[", str);
    340     }
    341
    342     @Test
    343     public void testToString_notFull() {
    344         // arrange
    345         final GreatArc arc = GreatCircles.arcFromInterval(
    346                 GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION),
    347                 AngularInterval.Convex.of(1, 2, TEST_PRECISION));
    348
    349         // act
    350         final String str = arc.toString();
    351
    352         // assert
    353         GeometryTestUtils.assertContains("GreatArc[", str);
    354         GeometryTestUtils.assertContains("start= (", str);
    355         GeometryTestUtils.assertContains("end= (", str);
    356     }
    357
    358     private static void checkClassify(final GreatArc arc, final RegionLocation loc, final Point2S... pts) {
    359         for (final Point2S pt : pts) {
    360             Assert.assertEquals("Unexpected location for point " + pt, loc, arc.classify(pt));
    361         }
    362     }
    363
    364     private static void checkArc(final GreatArc arc, final Point2S start, final Point2S end) {
    365         SphericalTestUtils.assertPointsEq(start, arc.getStartPoint(), TEST_EPS);
    366         SphericalTestUtils.assertPointsEq(end, arc.getEndPoint(), TEST_EPS);
    367
    368         checkClassify(arc, RegionLocation.BOUNDARY, start, end);
    369
    370         final Point2S mid = arc.getCircle().toSpace(arc.getInterval().getMidPoint());
    371
    372         checkClassify(arc, RegionLocation.INSIDE, mid);
    373         checkClassify(arc, RegionLocation.OUTSIDE, mid.antipodal());
    374
    375         Assert.assertEquals(start.distance(end), arc.getSize(), TEST_EPS);
    376         SphericalTestUtils.assertPointsEq(mid, arc.getCentroid(), TEST_EPS);
    377     }
    378
    379     private static void checkGreatCircle(final GreatCircle circle, final Vector3D pole, final Vector3D x) {
    380         SphericalTestUtils.assertVectorsEqual(pole, circle.getPole(), TEST_EPS);
    381         SphericalTestUtils.assertVectorsEqual(x, circle.getU(), TEST_EPS);
    382         SphericalTestUtils.assertVectorsEqual(pole.cross(x), circle.getV(), TEST_EPS);
    383     }
    384 }