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.Arrays;
    20  import java.util.Collections;
    21  import java.util.List;
    22
    23  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    24  import org.apache.commons.geometry.spherical.SphericalTestUtils;
    25  import org.apache.commons.geometry.spherical.twod.AbstractGreatArcConnector.ConnectableGreatArc;
    26  import org.apache.commons.numbers.angle.Angle;
    27  import org.apache.commons.numbers.core.Precision;
    28  import org.junit.jupiter.api.Assertions;
    29  import org.junit.jupiter.api.Test;
    30
    31  class AbstractGreatArcPathConnectorTest {
    32
    33      private static final double TEST_EPS = 1e-10;
    34
    35      private static final Precision.DoubleEquivalence TEST_PRECISION =
    36              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
    37
    38      private static final GreatCircle XY_PLANE = GreatCircles.fromPoleAndU(
    39              Vector3D.Unit.PLUS_Z, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    40
    41      private static final GreatCircle XZ_PLANE = GreatCircles.fromPoleAndU(
    42              Vector3D.Unit.PLUS_Y, Vector3D.Unit.PLUS_X, TEST_PRECISION);
    43
    44      private final TestConnector connector = new TestConnector();
    45
    46      @Test
    47      void testConnectAll_emptyCollection() {
    48          // act
    49          final List<GreatArcPath> paths = connector.connectAll(Collections.emptyList());
    50
    51          // assert
    52          Assertions.assertEquals(0, paths.size());
    53      }
    54
    55      @Test
    56      void testConnectAll_singleFullArc() {
    57          // act
    58          connector.add(Collections.singletonList(XY_PLANE.span()));
    59          final List<GreatArcPath> paths = connector.connectAll();
    60
    61          // assert
    62          Assertions.assertEquals(1, paths.size());
    63
    64          final GreatArcPath a = paths.get(0);
    65          Assertions.assertEquals(1, a.getArcs().size());
    66          Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
    67      }
    68
    69      @Test
    70      void testConnectAll_twoFullArcs() {
    71          // act
    72          connector.add(XZ_PLANE.span());
    73          final List<GreatArcPath> paths = connector.connectAll(Collections.singletonList(XY_PLANE.span()));
    74
    75          // assert
    76          Assertions.assertEquals(2, paths.size());
    77
    78          final GreatArcPath a = paths.get(0);
    79          Assertions.assertEquals(1, a.getArcs().size());
    80          Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
    81
    82          final GreatArcPath b = paths.get(1);
    83          Assertions.assertEquals(1, b.getArcs().size());
    84          Assertions.assertSame(XZ_PLANE, b.getStartArc().getCircle());
    85      }
    86
    87      @Test
    88      void testConnectAll_singleLune() {
    89          // arrange
    90          final GreatCircle upperBound = GreatCircles.fromPoleAndU(
    91                  Vector3D.of(0, 1, -1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
    92
    93          connector.add(XY_PLANE.arc(0, Math.PI));
    94          connector.add(upperBound.arc(Math.PI, 0));
    95
    96          // act
    97          final List<GreatArcPath> paths = connector.connectAll();
    98
    99          // assert
    100         Assertions.assertEquals(1, paths.size());
    101
    102         final GreatArcPath a = paths.get(0);
    103         Assertions.assertEquals(2, a.getArcs().size());
    104         Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
    105         Assertions.assertSame(upperBound, a.getEndArc().getCircle());
    106     }
    107
    108     @Test
    109     void testConnectAll_singleLune_pathsNotOrientedCorrectly() {
    110         // arrange
    111         final GreatCircle upperBound = GreatCircles.fromPoleAndU(
    112                 Vector3D.of(0, 1, -1), Vector3D.Unit.PLUS_X, TEST_PRECISION);
    113
    114         connector.add(XY_PLANE.arc(0, Math.PI));
    115         connector.add(upperBound.arc(0, Math.PI));
    116
    117         // act
    118         final List<GreatArcPath> paths = connector.connectAll();
    119
    120         // assert
    121         Assertions.assertEquals(2, paths.size());
    122
    123         final GreatArcPath a = paths.get(0);
    124         Assertions.assertEquals(1, a.getArcs().size());
    125         Assertions.assertSame(XY_PLANE, a.getStartArc().getCircle());
    126
    127         final GreatArcPath b = paths.get(1);
    128         Assertions.assertEquals(1, b.getArcs().size());
    129         Assertions.assertSame(upperBound, b.getStartArc().getCircle());
    130     }
    131
    132     @Test
    133     void testConnectAll_largeTriangle() {
    134         // arrange
    135         final Point2S p1 = Point2S.PLUS_I;
    136         final Point2S p2 = Point2S.PLUS_J;
    137         final Point2S p3 = Point2S.PLUS_K;
    138
    139         // act
    140         final List<GreatArcPath> paths = connector.connectAll(Arrays.asList(
    141                     GreatCircles.arcFromPoints(p1, p2, TEST_PRECISION),
    142                     GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION),
    143                     GreatCircles.arcFromPoints(p3, p1, TEST_PRECISION)
    144                 ));
    145
    146         // assert
    147         Assertions.assertEquals(1, paths.size());
    148
    149         final GreatArcPath a = paths.get(0);
    150         Assertions.assertEquals(3, a.getArcs().size());
    151
    152         assertPathPoints(a, p3, p1, p2, p3);
    153     }
    154
    155     @Test
    156     void testConnectAll_smallTriangleWithDisconnectedLuneAndArc() {
    157         // arrange
    158         final Point2S p1 = Point2S.of(0, 0);
    159         final Point2S p2 = Point2S.of(0, 0.1 * Math.PI);
    160         final Point2S p3 = Point2S.of(0.1, 0.1 * Math.PI);
    161
    162         final GreatArc luneEdge1 = GreatCircles.fromPoints(
    163                     Point2S.PLUS_J,
    164                     Point2S.MINUS_I,
    165                     TEST_PRECISION)
    166                 .arc(0, Math.PI);
    167         final GreatArc luneEdge2 = GreatCircles.fromPoints(
    168                     Point2S.MINUS_J,
    169                     Point2S.of(Angle.PI_OVER_TWO, 0.4 * Math.PI),
    170                     TEST_PRECISION)
    171                 .arc(0, Math.PI);
    172
    173         final GreatArc separateArc = GreatCircles.arcFromPoints(
    174                 Point2S.of(-Angle.PI_OVER_TWO, 0.7 * Math.PI),
    175                 Point2S.of(-Angle.PI_OVER_TWO, 0.8 * Math.PI),
    176                 TEST_PRECISION);
    177
    178         // act
    179         final List<GreatArcPath> paths = connector.connectAll(Arrays.asList(
    180                     luneEdge1,
    181                     GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION),
    182                     separateArc,
    183                     GreatCircles.arcFromPoints(p1, p2, TEST_PRECISION),
    184                     GreatCircles.arcFromPoints(p3, p1, TEST_PRECISION),
    185                     luneEdge2
    186                 ));
    187
    188         // assert
    189         Assertions.assertEquals(3, paths.size());
    190
    191         final GreatArcPath triangle = paths.get(0);
    192         Assertions.assertEquals(3, triangle.getArcs().size());
    193         assertPathPoints(triangle, p1, p2, p3, p1);
    194
    195         final GreatArcPath lune = paths.get(1);
    196         Assertions.assertEquals(2, lune.getArcs().size());
    197         Assertions.assertSame(luneEdge1, lune.getStartArc());
    198         Assertions.assertSame(luneEdge2, lune.getEndArc());
    199
    200         final GreatArcPath separate = paths.get(2);
    201         Assertions.assertEquals(1, separate.getArcs().size());
    202         Assertions.assertSame(separateArc, separate.getStartArc());
    203     }
    204
    205     @Test
    206     void testConnectAll_choosesBestPointLikeConnection() {
    207         // arrange
    208         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-1);
    209
    210         final Point2S p1 = Point2S.PLUS_I;
    211         final Point2S p2 = Point2S.of(1, Angle.PI_OVER_TWO);
    212         final Point2S p3 = Point2S.of(1.001, 0.491 * Math.PI);
    213         final Point2S p4 = Point2S.of(1.001, 0.502 * Math.PI);
    214
    215         connector.add(GreatCircles.arcFromPoints(p2, p3, TEST_PRECISION));
    216         connector.add(GreatCircles.arcFromPoints(p2, p4, TEST_PRECISION));
    217         connector.add(GreatCircles.arcFromPoints(p1, p2, precision));
    218
    219         // act
    220         final List<GreatArcPath> paths = connector.connectAll();
    221
    222         // assert
    223         Assertions.assertEquals(2, paths.size());
    224
    225         final GreatArcPath a = paths.get(0);
    226         Assertions.assertEquals(2, a.getArcs().size());
    227         assertPathPoints(a, p1, p2, p4);
    228
    229         final GreatArcPath b = paths.get(1);
    230         Assertions.assertEquals(1, b.getArcs().size());
    231         assertPathPoints(b, p2, p3);
    232     }
    233
    234     @Test
    235     void testConnect() {
    236         // arrange
    237         final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    238         final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
    239         final GreatArc arcC = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.PLUS_K, TEST_PRECISION);
    240
    241         // act
    242         connector.connect(Arrays.asList(
    243                     arcB,
    244                     arcA
    245                 ));
    246
    247         connector.connect(Collections.singletonList(arcC));
    248
    249         final List<GreatArcPath> paths = connector.connectAll();
    250
    251         // assert
    252         Assertions.assertEquals(2, paths.size());
    253
    254         final GreatArcPath a = paths.get(0);
    255         Assertions.assertEquals(2, a.getArcs().size());
    256         assertPathPoints(a, Point2S.PLUS_I, Point2S.PLUS_J, Point2S.MINUS_I);
    257
    258         final GreatArcPath b = paths.get(1);
    259         Assertions.assertEquals(1, b.getArcs().size());
    260         assertPathPoints(b, Point2S.PLUS_J, Point2S.PLUS_K);
    261     }
    262
    263     @Test
    264     void testConnectableSegment_hashCode() {
    265         // arrange
    266         final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    267         final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
    268
    269         final ConnectableGreatArc a = new ConnectableGreatArc(arcA);
    270
    271         // act
    272         final int hash = a.hashCode();
    273
    274         // assert
    275         Assertions.assertEquals(hash, a.hashCode());
    276
    277         Assertions.assertNotEquals(hash, new ConnectableGreatArc(arcB).hashCode());
    278         Assertions.assertNotEquals(hash, new ConnectableGreatArc(Point2S.MINUS_I).hashCode());
    279
    280         Assertions.assertEquals(hash, new ConnectableGreatArc(arcA).hashCode());
    281     }
    282
    283     @Test
    284     void testConnectableSegment_equals() {
    285         // arrange
    286         final GreatArc arcA = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    287         final GreatArc arcB = GreatCircles.arcFromPoints(Point2S.PLUS_J, Point2S.MINUS_I, TEST_PRECISION);
    288
    289         final ConnectableGreatArc a = new ConnectableGreatArc(arcA);
    290
    291         // act/assert
    292         Assertions.assertEquals(a, a);
    293
    294         Assertions.assertFalse(a.equals(null));
    295         Assertions.assertFalse(a.equals(new Object()));
    296
    297         Assertions.assertNotEquals(a, new ConnectableGreatArc(arcB));
    298         Assertions.assertNotEquals(a, new ConnectableGreatArc(Point2S.MINUS_I));
    299
    300         Assertions.assertEquals(a, new ConnectableGreatArc(arcA));
    301     }
    302
    303     @Test
    304     void testConnectorCanBeReused() {
    305         // arrange
    306         final GreatArc a = GreatCircles.arcFromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION);
    307         final GreatArc b = GreatCircles.arcFromPoints(Point2S.MINUS_I, Point2S.MINUS_J, TEST_PRECISION);
    308
    309         // act
    310         final List<GreatArcPath> path1 = connector.connectAll(Collections.singletonList(a));
    311         final List<GreatArcPath> path2 = connector.connectAll(Collections.singletonList(b));
    312
    313         // assert
    314         Assertions.assertEquals(1, path1.size());
    315         assertPathPoints(path1.get(0), Point2S.PLUS_I, Point2S.PLUS_J);
    316
    317         Assertions.assertEquals(1, path2.size());
    318         assertPathPoints(path2.get(0), Point2S.MINUS_I, Point2S.MINUS_J);
    319     }
    320
    321     private static void assertPathPoints(final GreatArcPath path, final Point2S... points) {
    322         final List<Point2S> expectedPoints = Arrays.asList(points);
    323         final List<Point2S> actualPoints = path.getVertices();
    324
    325         final String msg = "Expected path points to equal " + expectedPoints + " but was " + actualPoints;
    326         Assertions.assertEquals(expectedPoints.size(), actualPoints.size(), msg);
    327
    328         for (int i = 0; i < expectedPoints.size(); ++i) {
    329             SphericalTestUtils.assertPointsEq(expectedPoints.get(i), actualPoints.get(i), TEST_EPS);
    330         }
    331     }
    332
    333     private static class TestConnector extends AbstractGreatArcConnector {
    334
    335         @Override
    336         protected ConnectableGreatArc selectConnection(final ConnectableGreatArc incoming,
    337                                                        final List<ConnectableGreatArc> outgoing) {
    338
    339             // just choose the first element
    340             return outgoing.get(0);
    341         }
    342     }
    343 }