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.regex.Pattern;
    20
    21  import org.apache.commons.geometry.core.GeometryTestUtils;
    22  import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
    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.threed.Vector3D;
    26  import org.apache.commons.geometry.spherical.SphericalTestUtils;
    27  import org.apache.commons.geometry.spherical.oned.AngularInterval;
    28  import org.apache.commons.geometry.spherical.oned.Point1S;
    29  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    30  import org.junit.Assert;
    31  import org.junit.Test;
    32
    33  public class GreatCircleTest {
    34
    35      private static final double TEST_EPS = 1e-10;
    36
    37      private static final DoublePrecisionContext TEST_PRECISION =
    38              new EpsilonDoublePrecisionContext(TEST_EPS);
    39
    40      private static final Vector3D.Unit X = Vector3D.Unit.PLUS_X;
    41      private static final Vector3D.Unit Y = Vector3D.Unit.PLUS_Y;
    42      private static final Vector3D.Unit Z = Vector3D.Unit.PLUS_Z;
    43
    44      @Test
    45      public void testFromPole() {
    46          // act/assert
    47          checkGreatCircle(GreatCircles.fromPole(X, TEST_PRECISION), X, Z);
    48          checkGreatCircle(GreatCircles.fromPole(Y, TEST_PRECISION), Y, Z.negate());
    49          checkGreatCircle(GreatCircles.fromPole(Z, TEST_PRECISION), Z, Y);
    50      }
    51
    52      @Test
    53      public void testFromPoleAndXAxis() {
    54          // act/assert
    55          checkGreatCircle(GreatCircles.fromPoleAndU(X, Y, TEST_PRECISION), X, Y);
    56          checkGreatCircle(GreatCircles.fromPoleAndU(X, Z, TEST_PRECISION), X, Z);
    57          checkGreatCircle(GreatCircles.fromPoleAndU(Y, Z, TEST_PRECISION), Y, Z);
    58      }
    59
    60      @Test
    61      public void testFromPoints() {
    62          // act/assert
    63          checkGreatCircle(GreatCircles.fromPoints(
    64                      Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    65                      Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    66                      TEST_PRECISION),
    67                  Z, X);
    68
    69          checkGreatCircle(GreatCircles.fromPoints(
    70                  Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    71                  Point2S.of(-0.1 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO),
    72                  TEST_PRECISION),
    73              Z.negate(), X);
    74
    75          checkGreatCircle(GreatCircles.fromPoints(
    76                  Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    77                  Point2S.of(1.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO),
    78                  TEST_PRECISION),
    79              Z.negate(), X);
    80
    81          checkGreatCircle(GreatCircles.fromPoints(
    82                  Point2S.of(0, 0),
    83                  Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    84                  TEST_PRECISION),
    85              Y, Z);
    86      }
    87
    88      @Test
    89      public void testFromPoints_invalidPoints() {
    90          // arrange
    91          final Point2S p1 = Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO);
    92          final Point2S p2 = Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO);
    93
    94          // act/assert
    95          GeometryTestUtils.assertThrows(() -> {
    96              GreatCircles.fromPoints(p1, p1, TEST_PRECISION);
    97          }, IllegalArgumentException.class, Pattern.compile("^.*points are equal$"));
    98
    99          GeometryTestUtils.assertThrows(() -> {
    100             GreatCircles.fromPoints(p1, Point2S.of(1e-12, PlaneAngleRadians.PI_OVER_TWO), TEST_PRECISION);
    101         }, IllegalArgumentException.class, Pattern.compile("^.*points are equal$"));
    102
    103         GeometryTestUtils.assertThrows(() -> {
    104             GreatCircles.fromPoints(
    105                     Point2S.from(Vector3D.Unit.PLUS_X),
    106                     Point2S.from(Vector3D.Unit.MINUS_X),
    107                     TEST_PRECISION);
    108         }, IllegalArgumentException.class, Pattern.compile("^.*points are antipodal$"));
    109
    110         GeometryTestUtils.assertThrows(() -> {
    111             GreatCircles.fromPoints(p1, Point2S.NaN, TEST_PRECISION);
    112         }, IllegalArgumentException.class);
    113
    114         GeometryTestUtils.assertThrows(() -> {
    115             GreatCircles.fromPoints(Point2S.NaN, p2, TEST_PRECISION);
    116         }, IllegalArgumentException.class);
    117
    118         GeometryTestUtils.assertThrows(() -> {
    119             GreatCircles.fromPoints(p1, Point2S.of(Double.POSITIVE_INFINITY, PlaneAngleRadians.PI_OVER_TWO), TEST_PRECISION);
    120         }, IllegalArgumentException.class);
    121
    122         GeometryTestUtils.assertThrows(() -> {
    123             GreatCircles.fromPoints(Point2S.of(Double.POSITIVE_INFINITY, PlaneAngleRadians.PI_OVER_TWO), p2, TEST_PRECISION);
    124         }, IllegalArgumentException.class);
    125     }
    126
    127     @Test
    128     public void testOffset_point() {
    129         // --- arrange
    130         final GreatCircle circle = GreatCircles.fromPoleAndU(
    131                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    132
    133         // --- act/assert
    134
    135         // on circle
    136         for (double polar = -PlaneAngleRadians.PI_OVER_TWO; polar <= PlaneAngleRadians.PI_OVER_TWO; polar += 0.1) {
    137             Assert.assertEquals(0, circle.offset(Point2S.of(PlaneAngleRadians.PI_OVER_TWO, polar)), TEST_EPS);
    138             Assert.assertEquals(0, circle.offset(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, polar)), TEST_EPS);
    139         }
    140
    141         // +1/-1
    142         Assert.assertEquals(-1, circle.offset(Point2S.of(PlaneAngleRadians.PI_OVER_TWO + 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    143         Assert.assertEquals(1, circle.offset(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO + 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    144
    145         // poles
    146         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, circle.offset(Point2S.of(PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    147         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.offset(Point2S.of(0.0, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    148     }
    149
    150     @Test
    151     public void testOffset_vector() {
    152         // --- arrange
    153         final GreatCircle circle = GreatCircles.fromPoleAndU(
    154                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    155
    156         // --- act/assert
    157
    158         // on circle
    159         Assert.assertEquals(0, circle.offset(Vector3D.of(0, 1, 0)), TEST_EPS);
    160         Assert.assertEquals(0, circle.offset(Vector3D.of(0, 0, 1)), TEST_EPS);
    161         Assert.assertEquals(0, circle.offset(Vector3D.of(0, -1, 0)), TEST_EPS);
    162         Assert.assertEquals(0, circle.offset(Vector3D.of(0, 0, -1)), TEST_EPS);
    163
    164         // +1/-1
    165         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(-1, 1, 0)), TEST_EPS);
    166         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(-1, 0, 1)), TEST_EPS);
    167         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(-1, -1, 0)), TEST_EPS);
    168         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(-1, 0, -1)), TEST_EPS);
    169
    170         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(1, 1, 0)), TEST_EPS);
    171         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(1, 0, 1)), TEST_EPS);
    172         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(1, -1, 0)), TEST_EPS);
    173         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, circle.offset(Vector3D.of(1, 0, -1)), TEST_EPS);
    174
    175         // poles
    176         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, circle.offset(Vector3D.Unit.MINUS_X), TEST_EPS);
    177         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.offset(Vector3D.Unit.PLUS_X), TEST_EPS);
    178     }
    179
    180     @Test
    181     public void testAzimuth_point() {
    182         // --- arrange
    183         final GreatCircle circle = GreatCircles.fromPoleAndU(
    184                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    185
    186         // --- act/assert
    187
    188         // on circle
    189         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(0, 1, 0))), TEST_EPS);
    190         Assert.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(0, 0, 1))), TEST_EPS);
    191         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(0, -1, 0))), TEST_EPS);
    192         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(0, 0, -1))), TEST_EPS);
    193
    194         // +1/-1
    195         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(-1, 1, 0))), TEST_EPS);
    196         Assert.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(-1, 0, 1))), TEST_EPS);
    197         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(-1, -1, 0))), TEST_EPS);
    198         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(-1, 0, -1))), TEST_EPS);
    199
    200         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Point2S.from(Vector3D.of(1, 1, 0))), TEST_EPS);
    201         Assert.assertEquals(0.0, circle.azimuth(Point2S.from(Vector3D.of(1, 0, 1))), TEST_EPS);
    202         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(1, -1, 0))), TEST_EPS);
    203         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Point2S.from(Vector3D.of(1, 0, -1))), TEST_EPS);
    204
    205         // poles
    206         Assert.assertEquals(0, circle.azimuth(Point2S.from(Vector3D.Unit.MINUS_X)), TEST_EPS);
    207         Assert.assertEquals(0, circle.azimuth(Point2S.from(Vector3D.Unit.PLUS_X)), TEST_EPS);
    208     }
    209
    210     @Test
    211     public void testAzimuth_vector() {
    212         // --- arrange
    213         final GreatCircle circle = GreatCircles.fromPoleAndU(
    214                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    215
    216         // --- act/assert
    217
    218         // on circle
    219         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Vector3D.of(0, 1, 0)), TEST_EPS);
    220         Assert.assertEquals(0.0, circle.azimuth(Vector3D.of(0, 0, 1)), TEST_EPS);
    221         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(0, -1, 0)), TEST_EPS);
    222         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(0, 0, -1)), TEST_EPS);
    223
    224         // +1/-1
    225         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Vector3D.of(-1, 1, 0)), TEST_EPS);
    226         Assert.assertEquals(0.0, circle.azimuth(Vector3D.of(-1, 0, 1)), TEST_EPS);
    227         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(-1, -1, 0)), TEST_EPS);
    228         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(-1, 0, -1)), TEST_EPS);
    229
    230         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, circle.azimuth(Vector3D.of(1, 1, 0)), TEST_EPS);
    231         Assert.assertEquals(0.0, circle.azimuth(Vector3D.of(1, 0, 1)), TEST_EPS);
    232         Assert.assertEquals(1.5 * PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(1, -1, 0)), TEST_EPS);
    233         Assert.assertEquals(PlaneAngleRadians.PI, circle.azimuth(Vector3D.of(1, 0, -1)), TEST_EPS);
    234
    235         // poles
    236         Assert.assertEquals(0, circle.azimuth(Vector3D.Unit.MINUS_X), TEST_EPS);
    237         Assert.assertEquals(0, circle.azimuth(Vector3D.Unit.PLUS_X), TEST_EPS);
    238     }
    239
    240     @Test
    241     public void testVectorAt() {
    242         // arrange
    243         final GreatCircle circle = GreatCircles.fromPoleAndU(
    244                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    245
    246         // act/assert
    247         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z, circle.vectorAt(0.0), TEST_EPS);
    248         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Y, circle.vectorAt(PlaneAngleRadians.PI_OVER_TWO), TEST_EPS);
    249         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Z, circle.vectorAt(PlaneAngleRadians.PI), TEST_EPS);
    250         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Y, circle.vectorAt(-PlaneAngleRadians.PI_OVER_TWO), TEST_EPS);
    251         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z, circle.vectorAt(PlaneAngleRadians.TWO_PI), TEST_EPS);
    252     }
    253
    254     @Test
    255     public void testProject() {
    256         // arrange
    257         final GreatCircle circle = GreatCircles.fromPoleAndU(
    258                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    259
    260         // act/assert
    261         SphericalTestUtils.assertPointsEqual(Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    262                 circle.project(Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    263         SphericalTestUtils.assertPointsEqual(Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    264                 circle.project(Point2S.of(PlaneAngleRadians.PI_OVER_TWO + 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    265         SphericalTestUtils.assertPointsEqual(Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    266                 circle.project(Point2S.of(PlaneAngleRadians.PI_OVER_TWO - 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    267
    268         SphericalTestUtils.assertPointsEqual(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    269                 circle.project(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    270         SphericalTestUtils.assertPointsEqual(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    271                 circle.project(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO + 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    272         SphericalTestUtils.assertPointsEqual(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO),
    273                 circle.project(Point2S.of(-PlaneAngleRadians.PI_OVER_TWO - 1, PlaneAngleRadians.PI_OVER_TWO)), TEST_EPS);
    274     }
    275
    276     @Test
    277     public void testProject_poles() {
    278         // arrange
    279         final GreatCircle minusXCircle = GreatCircles.fromPoleAndU(
    280                 Vector3D.Unit.MINUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    281         final GreatCircle plusZCircle = GreatCircles.fromPoleAndU(
    282                 Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_Y, TEST_PRECISION);
    283
    284         // act
    285         SphericalTestUtils.assertPointsEqual(Point2S.of(0.0, 0.0),
    286                 minusXCircle.project(Point2S.from(Vector3D.Unit.MINUS_X)), TEST_EPS);
    287         SphericalTestUtils.assertPointsEqual(Point2S.of(0.0, 0.0),
    288                 minusXCircle.project(Point2S.from(Vector3D.Unit.PLUS_X)), TEST_EPS);
    289
    290         SphericalTestUtils.assertPointsEqual(Point2S.of(1.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO),
    291                 plusZCircle.project(Point2S.from(Vector3D.Unit.PLUS_Z)), TEST_EPS);
    292         SphericalTestUtils.assertPointsEqual(Point2S.of(1.5 * PlaneAngleRadians.PI, PlaneAngleRadians.PI_OVER_TWO),
    293                 plusZCircle.project(Point2S.from(Vector3D.Unit.MINUS_Z)), TEST_EPS);
    294     }
    295
    296     @Test
    297     public void testReverse() {
    298         // arrange
    299         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    300
    301         // act
    302         final GreatCircle reverse = circle.reverse();
    303
    304         // assert
    305         checkGreatCircle(reverse, Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X);
    306     }
    307
    308     @Test
    309     public void testTransform_rotateAroundPole() {
    310         // arrange
    311         final GreatCircle circle = GreatCircles.fromPoints(
    312                 Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    313                 Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO),
    314                 TEST_PRECISION);
    315
    316         final Transform2S t = Transform2S.createRotation(circle.getPolePoint(), 0.25 * PlaneAngleRadians.PI);
    317
    318         // act
    319         final GreatCircle result = circle.transform(t);
    320
    321         // assert
    322         Assert.assertNotSame(circle, result);
    323         checkGreatCircle(result, Vector3D.Unit.PLUS_Z, Vector3D.Unit.from(1, 1, 0));
    324     }
    325
    326     @Test
    327     public void testTransform_rotateAroundNonPole() {
    328         // arrange
    329         final GreatCircle circle = GreatCircles.fromPoints(
    330                 Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    331                 Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO),
    332                 TEST_PRECISION);
    333
    334         final Transform2S t = Transform2S.createRotation(Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO), PlaneAngleRadians.PI_OVER_TWO);
    335
    336         // act
    337         final GreatCircle result = circle.transform(t);
    338
    339         // assert
    340         Assert.assertNotSame(circle, result);
    341         checkGreatCircle(result, Vector3D.Unit.MINUS_Y, Vector3D.Unit.PLUS_X);
    342     }
    343
    344     @Test
    345     public void testTransform_piMinusAzimuth() {
    346         // arrange
    347         final GreatCircle circle = GreatCircles.fromPoints(
    348                 Point2S.of(0, PlaneAngleRadians.PI_OVER_TWO),
    349                 Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO),
    350                 TEST_PRECISION);
    351
    352         final Transform2S t = Transform2S.createReflection(Point2S.PLUS_J)
    353                 .rotate(Point2S.PLUS_K, PlaneAngleRadians.PI);
    354
    355         // act
    356         final GreatCircle result = circle.transform(t);
    357
    358         // assert
    359         Assert.assertNotSame(circle, result);
    360         checkGreatCircle(result, Vector3D.Unit.MINUS_Z, Vector3D.Unit.MINUS_X);
    361     }
    362
    363     @Test
    364     public void testSimilarOrientation() {
    365         // arrange
    366         final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    367         final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION);
    368         final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.MINUS_Z, TEST_PRECISION);
    369         final GreatCircle d = GreatCircles.fromPole(Vector3D.Unit.from(1, 1, -1), TEST_PRECISION);
    370         final GreatCircle e = GreatCircles.fromPole(Vector3D.Unit.from(1, 1, 1), TEST_PRECISION);
    371
    372         // act/assert
    373         Assert.assertTrue(a.similarOrientation(a));
    374
    375         Assert.assertFalse(a.similarOrientation(b));
    376         Assert.assertFalse(a.similarOrientation(c));
    377         Assert.assertFalse(a.similarOrientation(d));
    378
    379         Assert.assertTrue(a.similarOrientation(e));
    380     }
    381
    382     @Test
    383     public void testSpan() {
    384         // arrange
    385         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    386
    387         // act
    388         final GreatArc span = circle.span();
    389
    390         // assert
    391         Assert.assertSame(circle, span.getCircle());
    392         Assert.assertTrue(span.getInterval().isFull());
    393
    394         Assert.assertNull(span.getStartPoint());
    395         Assert.assertNull(span.getEndPoint());
    396     }
    397
    398     @Test
    399     public void testArc_points_2s() {
    400         // arrange
    401         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    402
    403         // act/assert
    404         checkArc(circle.arc(Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO), Point2S.of(0, 1)),
    405                 Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO), Point2S.of(0, 0));
    406
    407         Assert.assertTrue(circle.arc(Point2S.PLUS_I, Point2S.PLUS_I).isFull());
    408     }
    409
    410     @Test
    411     public void testArc_points_1s() {
    412         // arrange
    413         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    414
    415         // act/assert
    416         checkArc(circle.arc(Point1S.of(PlaneAngleRadians.PI), Point1S.of(1.5 * PlaneAngleRadians.PI)),
    417                 Point2S.of(0, PlaneAngleRadians.PI), Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO));
    418
    419         Assert.assertTrue(circle.arc(Point1S.of(1), Point1S.of(1)).isFull());
    420     }
    421
    422     @Test
    423     public void testArc_azimuths() {
    424         // arrange
    425         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    426
    427         // act/assert
    428         checkArc(circle.arc(PlaneAngleRadians.PI, 1.5 * PlaneAngleRadians.PI),
    429                 Point2S.of(0, PlaneAngleRadians.PI), Point2S.of(PlaneAngleRadians.PI_OVER_TWO, PlaneAngleRadians.PI_OVER_TWO));
    430
    431         Assert.assertTrue(circle.arc(1, 1).isFull());
    432     }
    433
    434     @Test
    435     public void testArc_interval() {
    436         // arrange
    437         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_X, Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    438         final AngularInterval.Convex interval = AngularInterval.Convex.of(1, 2, TEST_PRECISION);
    439
    440         // act
    441         final GreatArc arc = circle.arc(interval);
    442
    443         // assert
    444         Assert.assertSame(circle, arc.getCircle());
    445         Assert.assertSame(interval, arc.getInterval());
    446     }
    447
    448     @Test
    449     public void testIntersection_parallel() {
    450         // arrange
    451         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    452
    453         final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, precision);
    454         final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, precision);
    455         final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.of(1, 1e-4, 1e-4), precision);
    456         final GreatCircle d = GreatCircles.fromPole(Vector3D.Unit.MINUS_X, precision);
    457         final GreatCircle e = GreatCircles.fromPole(Vector3D.Unit.of(-1, 1e-4, 1e-4), precision);
    458
    459         // act/assert
    460         Assert.assertNull(a.intersection(b));
    461         Assert.assertNull(a.intersection(c));
    462         Assert.assertNull(a.intersection(d));
    463         Assert.assertNull(a.intersection(e));
    464     }
    465
    466     @Test
    467     public void testIntersection() {
    468         // arrange
    469         final GreatCircle a = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION);
    470         final GreatCircle b = GreatCircles.fromPole(Vector3D.Unit.PLUS_Y, TEST_PRECISION);
    471         final GreatCircle c = GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION);
    472
    473         // act/assert
    474         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_Z,
    475                 a.intersection(b).getVector(), TEST_EPS);
    476         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_Z,
    477                 b.intersection(a).getVector(), TEST_EPS);
    478
    479         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.PLUS_X,
    480                 b.intersection(c).getVector(), TEST_EPS);
    481         SphericalTestUtils.assertVectorsEqual(Vector3D.Unit.MINUS_X,
    482                 c.intersection(b).getVector(), TEST_EPS);
    483     }
    484
    485     @Test
    486     public void testAngle_withoutReferencePoint() {
    487      // arrange
    488         final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    489         final GreatCircle b = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_I, TEST_PRECISION);
    490         final GreatCircle c = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_K, TEST_PRECISION);
    491         final GreatCircle d = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
    492         final GreatCircle e = GreatCircles.fromPoleAndU(
    493                 Vector3D.Unit.of(1, 0, 1),
    494                 Vector3D.Unit.PLUS_Y,
    495                 TEST_PRECISION);
    496
    497         final GreatCircle f = GreatCircles.fromPoleAndU(
    498                 Vector3D.Unit.of(1, 0, -1),
    499                 Vector3D.Unit.PLUS_Y,
    500                 TEST_PRECISION);
    501
    502         // act/assert
    503         Assert.assertEquals(0, a.angle(a), TEST_EPS);
    504         Assert.assertEquals(PlaneAngleRadians.PI, a.angle(b), TEST_EPS);
    505
    506         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, a.angle(c), TEST_EPS);
    507         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, c.angle(a), TEST_EPS);
    508
    509         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, a.angle(d), TEST_EPS);
    510         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, d.angle(a), TEST_EPS);
    511
    512         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, a.angle(e), TEST_EPS);
    513         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, e.angle(a), TEST_EPS);
    514
    515         Assert.assertEquals(0.75 * PlaneAngleRadians.PI, a.angle(f), TEST_EPS);
    516         Assert.assertEquals(0.75 * PlaneAngleRadians.PI, f.angle(a), TEST_EPS);
    517     }
    518
    519     @Test
    520     public void testAngle_withReferencePoint() {
    521         // arrange
    522         final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    523         final GreatCircle b = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_I, TEST_PRECISION);
    524         final GreatCircle c = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_K, TEST_PRECISION);
    525         final GreatCircle d = GreatCircles.fromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
    526         final GreatCircle e = GreatCircles.fromPoleAndU(
    527                 Vector3D.Unit.of(1, 0, 1),
    528                 Vector3D.Unit.PLUS_Y,
    529                 TEST_PRECISION);
    530
    531         final GreatCircle f = GreatCircles.fromPoleAndU(
    532                 Vector3D.Unit.of(1, 0, -1),
    533                 Vector3D.Unit.PLUS_Y,
    534                 TEST_PRECISION);
    535
    536         // act/assert
    537         Assert.assertEquals(0, a.angle(a, Point2S.PLUS_J), TEST_EPS);
    538         Assert.assertEquals(0, a.angle(a, Point2S.MINUS_J), TEST_EPS);
    539
    540         Assert.assertEquals(-PlaneAngleRadians.PI, a.angle(b, Point2S.PLUS_J), TEST_EPS);
    541         Assert.assertEquals(-PlaneAngleRadians.PI, a.angle(b, Point2S.MINUS_J), TEST_EPS);
    542
    543         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, a.angle(c, Point2S.PLUS_I), TEST_EPS);
    544         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, a.angle(c, Point2S.MINUS_I), TEST_EPS);
    545
    546         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, c.angle(a, Point2S.PLUS_I), TEST_EPS);
    547         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, c.angle(a, Point2S.MINUS_I), TEST_EPS);
    548
    549         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, a.angle(d, Point2S.PLUS_J), TEST_EPS);
    550         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, a.angle(d, Point2S.MINUS_J), TEST_EPS);
    551
    552         Assert.assertEquals(-PlaneAngleRadians.PI_OVER_TWO, d.angle(a, Point2S.PLUS_J), TEST_EPS);
    553         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, d.angle(a, Point2S.MINUS_J), TEST_EPS);
    554
    555         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, a.angle(e, Point2S.PLUS_J), TEST_EPS);
    556         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, a.angle(e, Point2S.MINUS_J), TEST_EPS);
    557
    558         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, e.angle(a, Point2S.PLUS_J), TEST_EPS);
    559         Assert.assertEquals(0.25 * PlaneAngleRadians.PI, e.angle(a, Point2S.MINUS_J), TEST_EPS);
    560
    561         Assert.assertEquals(0.75 * PlaneAngleRadians.PI, a.angle(f, Point2S.PLUS_J), TEST_EPS);
    562         Assert.assertEquals(-0.75 * PlaneAngleRadians.PI, a.angle(f, Point2S.MINUS_J), TEST_EPS);
    563
    564         Assert.assertEquals(-0.75 * PlaneAngleRadians.PI, f.angle(a, Point2S.PLUS_J), TEST_EPS);
    565         Assert.assertEquals(0.75 * PlaneAngleRadians.PI, f.angle(a, Point2S.MINUS_J), TEST_EPS);
    566     }
    567
    568     @Test
    569     public void testAngle_withReferencePoint_pointEquidistanceFromIntersections() {
    570         // arrange
    571         final GreatCircle a = GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    572         final GreatCircle b = GreatCircles.fromPoleAndU(
    573                 Vector3D.Unit.of(1, 0, 1),
    574                 Vector3D.Unit.PLUS_Y,
    575                 TEST_PRECISION);
    576
    577         // act/assert
    578         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, a.angle(b, Point2S.PLUS_I), TEST_EPS);
    579         Assert.assertEquals(-0.25 * PlaneAngleRadians.PI, a.angle(b, Point2S.MINUS_I), TEST_EPS);
    580     }
    581
    582     @Test
    583     public void testToSubspace() {
    584         // arrange
    585         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_Z, TEST_PRECISION);
    586
    587         // act/assert
    588         SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
    589                 circle.toSubspace(Point2S.from(Vector3D.Unit.MINUS_Z)), TEST_EPS);
    590
    591         SphericalTestUtils.assertPointsEqual(Point1S.of(0.25 * PlaneAngleRadians.PI),
    592                 circle.toSubspace(Point2S.from(Vector3D.of(-1, -1, -1))), TEST_EPS);
    593         SphericalTestUtils.assertPointsEqual(Point1S.of(0.75 * PlaneAngleRadians.PI),
    594                 circle.toSubspace(Point2S.from(Vector3D.of(-1, 1, 1))), TEST_EPS);
    595         SphericalTestUtils.assertPointsEqual(Point1S.of(1.25 * PlaneAngleRadians.PI),
    596                 circle.toSubspace(Point2S.from(Vector3D.of(1, -1, 1))), TEST_EPS);
    597         SphericalTestUtils.assertPointsEqual(Point1S.of(1.75 * PlaneAngleRadians.PI),
    598                 circle.toSubspace(Point2S.from(Vector3D.of(1, 1, -1))), TEST_EPS);
    599
    600         SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
    601                 circle.toSubspace(Point2S.from(Vector3D.Unit.PLUS_Y)), TEST_EPS);
    602         SphericalTestUtils.assertPointsEqual(Point1S.ZERO,
    603                 circle.toSubspace(Point2S.from(Vector3D.Unit.MINUS_Y)), TEST_EPS);
    604     }
    605
    606     @Test
    607     public void testToSpace() {
    608         // arrange
    609         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Y, Vector3D.Unit.MINUS_Z, TEST_PRECISION);
    610
    611         // act/assert
    612         SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.Unit.MINUS_Z),
    613                 circle.toSpace(Point1S.ZERO), TEST_EPS);
    614
    615         SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(-1, 0, -1)),
    616                 circle.toSpace(Point1S.of(0.25 * PlaneAngleRadians.PI)), TEST_EPS);
    617         SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(-1, 0, 1)),
    618                 circle.toSpace(Point1S.of(0.75 * PlaneAngleRadians.PI)), TEST_EPS);
    619         SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(1, 0, 1)),
    620                 circle.toSpace(Point1S.of(1.25 * PlaneAngleRadians.PI)), TEST_EPS);
    621         SphericalTestUtils.assertPointsEqual(Point2S.from(Vector3D.of(1, 0, -1)),
    622                 circle.toSpace(Point1S.of(1.75 * PlaneAngleRadians.PI)), TEST_EPS);
    623     }
    624
    625     @Test
    626     public void testEq() {
    627         // arrange
    628         final double eps = 1e-3;
    629         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(eps);
    630
    631         final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
    632
    633         final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X, precision);
    634         final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, precision);
    635         final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    636
    637         final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.of(1e-6, 0, 1), Vector3D.Unit.PLUS_X, precision);
    638         final GreatCircle f = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.of(1, 1e-6, 0), precision);
    639         final GreatCircle g = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X,
    640                 new EpsilonDoublePrecisionContext(eps));
    641
    642         // act/assert
    643         Assert.assertTrue(a.eq(a, precision));
    644
    645         Assert.assertFalse(a.eq(b, precision));
    646         Assert.assertFalse(a.eq(c, precision));
    647
    648         Assert.assertTrue(a.eq(d, precision));
    649         Assert.assertTrue(a.eq(e, precision));
    650         Assert.assertTrue(e.eq(a, precision));
    651
    652         Assert.assertTrue(a.eq(f, precision));
    653         Assert.assertTrue(f.eq(a, precision));
    654
    655         Assert.assertTrue(g.eq(e, precision));
    656         Assert.assertTrue(e.eq(g, precision));
    657     }
    658
    659     @Test
    660     public void testHashCode() {
    661         // arrange
    662         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    663
    664         final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    665
    666         final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.of(0, 1, 1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
    667         final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, TEST_PRECISION);
    668         final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
    669
    670         final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    671
    672         // act
    673         final int hash = a.hashCode();
    674
    675         // act/assert
    676         Assert.assertEquals(hash, a.hashCode());
    677
    678         Assert.assertNotEquals(hash, b.hashCode());
    679         Assert.assertNotEquals(hash, c.hashCode());
    680         Assert.assertNotEquals(hash, d.hashCode());
    681
    682         Assert.assertEquals(hash, e.hashCode());
    683     }
    684
    685     @Test
    686     public void testEquals() {
    687         // arrange
    688         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-3);
    689
    690         final GreatCircle a = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    691
    692         final GreatCircle b = GreatCircles.fromPoleAndU(Vector3D.Unit.MINUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    693         final GreatCircle c = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.MINUS_X, TEST_PRECISION);
    694         final GreatCircle d = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, precision);
    695
    696         final GreatCircle e = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    697
    698         // act/assert
    699         Assert.assertEquals(a, a);
    700
    701         Assert.assertFalse(a.equals(null));
    702         Assert.assertFalse(a.equals(new Object()));
    703
    704         Assert.assertNotEquals(a, b);
    705         Assert.assertNotEquals(a, c);
    706         Assert.assertNotEquals(a, d);
    707
    708         Assert.assertEquals(a, e);
    709         Assert.assertEquals(e, a);
    710     }
    711
    712     @Test
    713     public void testToString() {
    714         // arrange
    715         final GreatCircle circle = GreatCircles.fromPoleAndU(Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    716
    717         // act
    718         final String str = circle.toString();
    719
    720         // assert
    721         GeometryTestUtils.assertContains("GreatCircle[", str);
    722         GeometryTestUtils.assertContains("pole= (0.0, 0.0, 1.0)", str);
    723         GeometryTestUtils.assertContains("u= (1.0, 0.0, 0.0)", str);
    724         GeometryTestUtils.assertContains("v= (0.0, 1.0, 0.0)", str);
    725     }
    726
    727     private static void checkGreatCircle(final GreatCircle circle, final Vector3D pole, final Vector3D u) {
    728         SphericalTestUtils.assertVectorsEqual(pole, circle.getPole(), TEST_EPS);
    729         SphericalTestUtils.assertVectorsEqual(pole, circle.getW(), TEST_EPS);
    730         SphericalTestUtils.assertVectorsEqual(u, circle.getU(), TEST_EPS);
    731         SphericalTestUtils.assertVectorsEqual(pole.cross(u), circle.getV(), TEST_EPS);
    732
    733         final Point2S plusPolePt = Point2S.from(circle.getPole());
    734         final Point2S minusPolePt = Point2S.from(circle.getPole().negate());
    735         final Point2S origin = Point2S.from(circle.getU());
    736
    737         SphericalTestUtils.assertPointsEqual(plusPolePt, circle.getPolePoint(), TEST_EPS);
    738
    739         Assert.assertFalse(circle.contains(plusPolePt));
    740         Assert.assertFalse(circle.contains(minusPolePt));
    741         Assert.assertTrue(circle.contains(origin));
    742
    743         Assert.assertEquals(HyperplaneLocation.MINUS, circle.classify(plusPolePt));
    744         Assert.assertEquals(HyperplaneLocation.PLUS, circle.classify(minusPolePt));
    745         Assert.assertEquals(HyperplaneLocation.ON, circle.classify(origin));
    746     }
    747
    748     private static void checkArc(final GreatArc arc, final Point2S start, final Point2S end) {
    749         SphericalTestUtils.assertPointsEq(start, arc.getStartPoint(), TEST_EPS);
    750         SphericalTestUtils.assertPointsEq(end, arc.getEndPoint(), TEST_EPS);
    751     }
    752 }