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.Collection;
    21  import java.util.Collections;
    22  import java.util.Iterator;
    23  import java.util.List;
    24  import java.util.regex.Pattern;
    25  import java.util.stream.Collectors;
    26
    27  import org.apache.commons.geometry.core.GeometryTestUtils;
    28  import org.apache.commons.geometry.core.RegionLocation;
    29  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    30  import org.apache.commons.geometry.core.precision.EpsilonDoublePrecisionContext;
    31  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    32  import org.apache.commons.geometry.spherical.SphericalTestUtils;
    33  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    34  import org.junit.Assert;
    35  import org.junit.Test;
    36
    37  public class GreatArcPathTest {
    38
    39      private static final double TEST_EPS = 1e-10;
    40
    41      private static final DoublePrecisionContext TEST_PRECISION =
    42              new EpsilonDoublePrecisionContext(TEST_EPS);
    43
    44      @Test
    45      public void testEmpty() {
    46          // act
    47          final GreatArcPath path = GreatArcPath.empty();
    48
    49          // assert
    50          Assert.assertTrue(path.isEmpty());
    51          Assert.assertFalse(path.isClosed());
    52
    53          Assert.assertNull(path.getStartVertex());
    54          Assert.assertNull(path.getEndVertex());
    55
    56          Assert.assertNull(path.getStartArc());
    57          Assert.assertNull(path.getEndArc());
    58
    59          Assert.assertEquals(0, path.getArcs().size());
    60          Assert.assertEquals(0, path.getVertices().size());
    61      }
    62
    63      @Test
    64      public void testFromVertices_boolean_empty() {
    65          // act
    66          final GreatArcPath path = GreatArcPath.fromVertices(Collections.emptyList(), true, TEST_PRECISION);
    67
    68          // assert
    69          Assert.assertTrue(path.isEmpty());
    70
    71          Assert.assertNull(path.getStartVertex());
    72          Assert.assertNull(path.getEndVertex());
    73
    74          Assert.assertNull(path.getStartArc());
    75          Assert.assertNull(path.getEndArc());
    76
    77          Assert.assertEquals(0, path.getArcs().size());
    78          Assert.assertEquals(0, path.getVertices().size());
    79      }
    80
    81      @Test
    82      public void testFromVertices_boolean_notClosed() {
    83          // arrange
    84          final List<Point2S> points = Arrays.asList(
    85                  Point2S.PLUS_I,
    86                  Point2S.PLUS_K,
    87                  Point2S.PLUS_J);
    88
    89          // act
    90          final GreatArcPath path = GreatArcPath.fromVertices(points, false, TEST_PRECISION);
    91
    92          // assert
    93          Assert.assertFalse(path.isEmpty());
    94          Assert.assertFalse(path.isClosed());
    95
    96          SphericalTestUtils.assertPointsEq(Point2S.PLUS_I, path.getStartVertex(), TEST_EPS);
    97          SphericalTestUtils.assertPointsEq(Point2S.PLUS_J, path.getEndVertex(), TEST_EPS);
    98
    99          final List<GreatArc> arcs = path.getArcs();
    100         Assert.assertEquals(2, arcs.size());
    101         assertArc(arcs.get(0), Point2S.PLUS_I, Point2S.PLUS_K);
    102         assertArc(arcs.get(1), Point2S.PLUS_K, Point2S.PLUS_J);
    103
    104         assertPoints(points, path.getVertices());
    105     }
    106
    107     @Test
    108     public void testFromVertices_boolean_closed() {
    109         // arrange
    110         final List<Point2S> points = Arrays.asList(
    111                 Point2S.PLUS_I,
    112                 Point2S.PLUS_K,
    113                 Point2S.PLUS_J);
    114
    115         // act
    116         final GreatArcPath path = GreatArcPath.fromVertices(points, true, TEST_PRECISION);
    117
    118         // assert
    119         Assert.assertFalse(path.isEmpty());
    120         Assert.assertTrue(path.isClosed());
    121
    122         SphericalTestUtils.assertPointsEq(Point2S.PLUS_I, path.getStartVertex(), TEST_EPS);
    123         SphericalTestUtils.assertPointsEq(Point2S.PLUS_I, path.getEndVertex(), TEST_EPS);
    124
    125         final List<GreatArc> arcs = path.getArcs();
    126         Assert.assertEquals(3, arcs.size());
    127         assertArc(arcs.get(0), Point2S.PLUS_I, Point2S.PLUS_K);
    128         assertArc(arcs.get(1), Point2S.PLUS_K, Point2S.PLUS_J);
    129         assertArc(arcs.get(2), Point2S.PLUS_J, Point2S.PLUS_I);
    130
    131         assertPoints(Arrays.asList(
    132                 Point2S.PLUS_I,
    133                 Point2S.PLUS_K,
    134                 Point2S.PLUS_J,
    135                 Point2S.PLUS_I), path.getVertices());
    136     }
    137
    138     @Test
    139     public void testFromVertices_boolean_closed_pointsConsideredEqual() {
    140         // arrange
    141         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-2);
    142
    143         final Point2S almostPlusI = Point2S.of(1e-4, PlaneAngleRadians.PI_OVER_TWO);
    144
    145         final List<Point2S> points = Arrays.asList(
    146                 Point2S.PLUS_I,
    147                 Point2S.PLUS_K,
    148                 Point2S.PLUS_J,
    149                 almostPlusI);
    150
    151         // act
    152         final GreatArcPath path = GreatArcPath.fromVertices(points, true, precision);
    153
    154         // assert
    155         Assert.assertFalse(path.isEmpty());
    156         Assert.assertTrue(path.isClosed());
    157
    158         SphericalTestUtils.assertPointsEq(Point2S.PLUS_I, path.getStartVertex(), TEST_EPS);
    159         SphericalTestUtils.assertPointsEq(almostPlusI, path.getEndVertex(), TEST_EPS);
    160
    161         final List<GreatArc> arcs = path.getArcs();
    162         Assert.assertEquals(3, arcs.size());
    163         assertArc(arcs.get(0), Point2S.PLUS_I, Point2S.PLUS_K);
    164         assertArc(arcs.get(1), Point2S.PLUS_K, Point2S.PLUS_J);
    165         assertArc(arcs.get(2), Point2S.PLUS_J, almostPlusI);
    166
    167         assertPoints(Arrays.asList(
    168                 Point2S.PLUS_I,
    169                 Point2S.PLUS_K,
    170                 Point2S.PLUS_J,
    171                 almostPlusI), path.getVertices());
    172     }
    173
    174     @Test
    175     public void testFromVertices() {
    176         // arrange
    177         final List<Point2S> points = Arrays.asList(
    178                 Point2S.MINUS_I,
    179                 Point2S.MINUS_J,
    180                 Point2S.PLUS_I);
    181
    182         // act
    183         final GreatArcPath path = GreatArcPath.fromVertices(points, TEST_PRECISION);
    184
    185         // assert
    186         Assert.assertFalse(path.isEmpty());
    187         Assert.assertFalse(path.isClosed());
    188
    189         SphericalTestUtils.assertPointsEq(Point2S.MINUS_I, path.getStartVertex(), TEST_EPS);
    190         SphericalTestUtils.assertPointsEq(Point2S.PLUS_I, path.getEndVertex(), TEST_EPS);
    191
    192         final List<GreatArc> arcs = path.getArcs();
    193         Assert.assertEquals(2, arcs.size());
    194         assertArc(arcs.get(0), Point2S.MINUS_I, Point2S.MINUS_J);
    195         assertArc(arcs.get(1), Point2S.MINUS_J, Point2S.PLUS_I);
    196
    197         assertPoints(points, path.getVertices());
    198     }
    199
    200     @Test
    201     public void testFromVertexLoop() {
    202         // arrange
    203         final List<Point2S> points = Arrays.asList(
    204                 Point2S.MINUS_I,
    205                 Point2S.MINUS_J,
    206                 Point2S.MINUS_K);
    207
    208         // act
    209         final GreatArcPath path = GreatArcPath.fromVertexLoop(points, TEST_PRECISION);
    210
    211         // assert
    212         Assert.assertFalse(path.isEmpty());
    213         Assert.assertTrue(path.isClosed());
    214
    215         SphericalTestUtils.assertPointsEq(Point2S.MINUS_I, path.getStartVertex(), TEST_EPS);
    216         SphericalTestUtils.assertPointsEq(Point2S.MINUS_I, path.getEndVertex(), TEST_EPS);
    217
    218         final List<GreatArc> arcs = path.getArcs();
    219         Assert.assertEquals(3, arcs.size());
    220         assertArc(arcs.get(0), Point2S.MINUS_I, Point2S.MINUS_J);
    221         assertArc(arcs.get(1), Point2S.MINUS_J, Point2S.MINUS_K);
    222         assertArc(arcs.get(2), Point2S.MINUS_K, Point2S.MINUS_I);
    223
    224         assertPoints(Arrays.asList(
    225                 Point2S.MINUS_I,
    226                 Point2S.MINUS_J,
    227                 Point2S.MINUS_K,
    228                 Point2S.MINUS_I), path.getVertices());
    229     }
    230
    231     @Test
    232     public void testFromArcs() {
    233         // arrange
    234         final Point2S ptA = Point2S.PLUS_I;
    235         final Point2S ptB = Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO);
    236         final Point2S ptC = Point2S.of(1, PlaneAngleRadians.PI_OVER_TWO - 1);
    237         final Point2S ptD = Point2S.of(2, PlaneAngleRadians.PI_OVER_TWO - 1);
    238
    239         final GreatArc a = GreatCircles.arcFromPoints(ptA, ptB, TEST_PRECISION);
    240         final GreatArc b = GreatCircles.arcFromPoints(ptB, ptC, TEST_PRECISION);
    241         final GreatArc c = GreatCircles.arcFromPoints(ptC, ptD, TEST_PRECISION);
    242
    243         // act
    244         final GreatArcPath path = GreatArcPath.fromArcs(a, b, c);
    245
    246         // assert
    247         Assert.assertFalse(path.isEmpty());
    248         Assert.assertFalse(path.isClosed());
    249
    250         SphericalTestUtils.assertPointsEq(ptA, path.getStartVertex(), TEST_EPS);
    251         SphericalTestUtils.assertPointsEq(ptD, path.getEndVertex(), TEST_EPS);
    252
    253         final List<GreatArc> arcs = path.getArcs();
    254         Assert.assertEquals(3, arcs.size());
    255         assertArc(arcs.get(0), ptA, ptB);
    256         assertArc(arcs.get(1), ptB, ptC);
    257         assertArc(arcs.get(2), ptC, ptD);
    258
    259         assertPoints(Arrays.asList(ptA, ptB, ptC, ptD), path.getVertices());
    260     }
    261
    262     @Test
    263     public void testFromArcs_full() {
    264         // arrange
    265         final GreatArc fullArc = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION).span();
    266
    267         // act
    268         final GreatArcPath path = GreatArcPath.fromArcs(fullArc);
    269
    270         // assert
    271         Assert.assertFalse(path.isEmpty());
    272         Assert.assertFalse(path.isClosed());
    273
    274         Assert.assertSame(fullArc, path.getStartArc());
    275         Assert.assertSame(fullArc, path.getEndArc());
    276
    277         Assert.assertNull(path.getStartVertex());
    278         Assert.assertNull(path.getEndVertex());
    279
    280         final List<GreatArc> arcs = path.getArcs();
    281         Assert.assertEquals(1, arcs.size());
    282
    283         Assert.assertSame(fullArc, arcs.get(0));
    284     }
    285
    286     @Test
    287     public void testBoundaryStream() {
    288         // arrange
    289         final GreatArc fullArc = GreatCircles.fromPole(Vector3D.Unit.PLUS_X, TEST_PRECISION).span();
    290         final GreatArcPath path = GreatArcPath.fromArcs(fullArc);
    291
    292         // act
    293         final List<GreatArc> arcs = path.boundaryStream().collect(Collectors.toList());
    294
    295         // assert
    296         Assert.assertEquals(1, arcs.size());
    297         Assert.assertSame(fullArc, arcs.get(0));
    298     }
    299
    300     @Test
    301     public void testBoundaryStream_noBoundaries() {
    302         // arrange
    303         final GreatArcPath path = GreatArcPath.empty();
    304
    305         // act
    306         final List<GreatArc> arcs = path.boundaryStream().collect(Collectors.toList());
    307
    308         // assert
    309         Assert.assertEquals(0, arcs.size());
    310     }
    311
    312     @Test
    313     public void testToTree_empty() {
    314         // act
    315         final RegionBSPTree2S tree = GreatArcPath.empty().toTree();
    316
    317         // assert
    318         Assert.assertFalse(tree.isFull());
    319         Assert.assertTrue(tree.isEmpty());
    320     }
    321
    322     @Test
    323     public void testToTree_halfSpace() {
    324         // arrange
    325         final GreatArcPath path = GreatArcPath.builder(TEST_PRECISION)
    326                 .append(Point2S.PLUS_I)
    327                 .append(Point2S.PLUS_J)
    328                 .build();
    329
    330         // act
    331         final RegionBSPTree2S tree = path.toTree();
    332
    333         // assert
    334         Assert.assertFalse(tree.isFull());
    335         Assert.assertFalse(tree.isEmpty());
    336
    337         Assert.assertEquals(PlaneAngleRadians.TWO_PI, tree.getSize(), TEST_EPS);
    338         SphericalTestUtils.assertPointsEq(Point2S.PLUS_K, tree.getCentroid(), TEST_EPS);
    339
    340         SphericalTestUtils.checkClassify(tree, RegionLocation.INSIDE, Point2S.PLUS_K);
    341         SphericalTestUtils.checkClassify(tree, RegionLocation.OUTSIDE, Point2S.MINUS_K);
    342     }
    343
    344     @Test
    345     public void testToTree_triangle() {
    346         // arrange
    347         final GreatArcPath path = GreatArcPath.builder(TEST_PRECISION)
    348                 .append(Point2S.PLUS_I)
    349                 .append(Point2S.PLUS_J)
    350                 .append(Point2S.PLUS_K)
    351                 .close();
    352
    353         // act
    354         final RegionBSPTree2S tree = path.toTree();
    355
    356         // assert
    357         Assert.assertFalse(tree.isFull());
    358         Assert.assertFalse(tree.isEmpty());
    359
    360         Assert.assertEquals(PlaneAngleRadians.PI_OVER_TWO, tree.getSize(), TEST_EPS);
    361
    362         final Point2S bc = Point2S.from(Point2S.PLUS_I.getVector()
    363                 .add(Point2S.PLUS_J.getVector())
    364                 .add(Point2S.PLUS_K.getVector()));
    365
    366         SphericalTestUtils.assertPointsEq(bc, tree.getCentroid(), TEST_EPS);
    367
    368         SphericalTestUtils.checkClassify(tree, RegionLocation.INSIDE, Point2S.of(0.5, 0.5));
    369         SphericalTestUtils.checkClassify(tree, RegionLocation.OUTSIDE,
    370                 Point2S.MINUS_K, Point2S.MINUS_I, Point2S.MINUS_J);
    371     }
    372
    373     @Test
    374     public void testBuilder_append() {
    375         // arrange
    376         final Point2S a = Point2S.PLUS_I;
    377         final Point2S b = Point2S.PLUS_J;
    378         final Point2S c = Point2S.PLUS_K;
    379         final Point2S d = Point2S.of(-1, PlaneAngleRadians.PI_OVER_TWO);
    380         final Point2S e = Point2S.of(0, 0.6 * PlaneAngleRadians.PI);
    381
    382         final GreatArcPath.Builder builder = GreatArcPath.builder(TEST_PRECISION);
    383
    384         // act
    385         final GreatArcPath path = builder.append(GreatCircles.arcFromPoints(a, b, TEST_PRECISION))
    386             .appendVertices(c, d)
    387             .append(e)
    388             .append(GreatCircles.arcFromPoints(e, a, TEST_PRECISION))
    389             .build();
    390
    391         // assert
    392         Assert.assertFalse(path.isEmpty());
    393         Assert.assertTrue(path.isClosed());
    394
    395         SphericalTestUtils.assertPointsEq(a, path.getStartVertex(), TEST_EPS);
    396         SphericalTestUtils.assertPointsEq(a, path.getEndVertex(), TEST_EPS);
    397
    398         final List<GreatArc> arcs = path.getArcs();
    399         Assert.assertEquals(5, arcs.size());
    400         assertArc(arcs.get(0), a, b);
    401         assertArc(arcs.get(1), b, c);
    402         assertArc(arcs.get(2), c, d);
    403         assertArc(arcs.get(3), d, e);
    404         assertArc(arcs.get(4), e, a);
    405
    406         assertPoints(Arrays.asList(a, b, c, d, e, a), path.getVertices());
    407     }
    408
    409     @Test
    410     public void testBuilder_prepend() {
    411         // arrange
    412         final Point2S a = Point2S.PLUS_I;
    413         final Point2S b = Point2S.PLUS_J;
    414         final Point2S c = Point2S.PLUS_K;
    415         final Point2S d = Point2S.of(-1, PlaneAngleRadians.PI_OVER_TWO);
    416         final Point2S e = Point2S.of(0, 0.6 * PlaneAngleRadians.PI);
    417
    418         final GreatArcPath.Builder builder = GreatArcPath.builder(TEST_PRECISION);
    419
    420         // act
    421         final GreatArcPath path = builder.prepend(GreatCircles.arcFromPoints(e, a, TEST_PRECISION))
    422             .prependPoints(Arrays.asList(c, d))
    423             .prepend(b)
    424             .prepend(GreatCircles.arcFromPoints(a, b, TEST_PRECISION))
    425             .build();
    426
    427         // assert
    428         Assert.assertFalse(path.isEmpty());
    429         Assert.assertTrue(path.isClosed());
    430
    431         SphericalTestUtils.assertPointsEq(a, path.getStartVertex(), TEST_EPS);
    432         SphericalTestUtils.assertPointsEq(a, path.getEndVertex(), TEST_EPS);
    433
    434         final List<GreatArc> arcs = path.getArcs();
    435         Assert.assertEquals(5, arcs.size());
    436         assertArc(arcs.get(0), a, b);
    437         assertArc(arcs.get(1), b, c);
    438         assertArc(arcs.get(2), c, d);
    439         assertArc(arcs.get(3), d, e);
    440         assertArc(arcs.get(4), e, a);
    441
    442         assertPoints(Arrays.asList(a, b, c, d, e, a), path.getVertices());
    443     }
    444
    445     @Test
    446     public void testBuilder_appendAndPrepend_points() {
    447         // arrange
    448         final Point2S a = Point2S.PLUS_I;
    449         final Point2S b = Point2S.PLUS_J;
    450         final Point2S c = Point2S.PLUS_K;
    451         final Point2S d = Point2S.of(-1, PlaneAngleRadians.PI_OVER_TWO);
    452         final Point2S e = Point2S.of(0, 0.6 * PlaneAngleRadians.PI);
    453
    454         final GreatArcPath.Builder builder = GreatArcPath.builder(TEST_PRECISION);
    455
    456         // act
    457         final GreatArcPath path = builder.prepend(a)
    458                 .append(b)
    459                 .prepend(e)
    460                 .append(c)
    461                 .prepend(d)
    462                 .build();
    463
    464         // assert
    465         Assert.assertFalse(path.isEmpty());
    466         Assert.assertFalse(path.isClosed());
    467
    468         SphericalTestUtils.assertPointsEq(d, path.getStartVertex(), TEST_EPS);
    469         SphericalTestUtils.assertPointsEq(c, path.getEndVertex(), TEST_EPS);
    470
    471         final List<GreatArc> arcs = path.getArcs();
    472         Assert.assertEquals(4, arcs.size());
    473         assertArc(arcs.get(0), d, e);
    474         assertArc(arcs.get(1), e, a);
    475         assertArc(arcs.get(2), a, b);
    476         assertArc(arcs.get(3), b, c);
    477
    478         assertPoints(Arrays.asList(d, e, a, b, c), path.getVertices());
    479     }
    480
    481     @Test
    482     public void testBuilder_appendAndPrepend_mixedArguments() {
    483         // arrange
    484         final Point2S a = Point2S.PLUS_I;
    485         final Point2S b = Point2S.PLUS_J;
    486         final Point2S c = Point2S.PLUS_K;
    487         final Point2S d = Point2S.of(-1, PlaneAngleRadians.PI_OVER_TWO);
    488         final Point2S e = Point2S.of(0, 0.6 * PlaneAngleRadians.PI);
    489
    490         final GreatArcPath.Builder builder = GreatArcPath.builder(TEST_PRECISION);
    491
    492         // act
    493         final GreatArcPath path = builder.append(GreatCircles.arcFromPoints(a, b, TEST_PRECISION))
    494                 .prepend(GreatCircles.arcFromPoints(e, a, TEST_PRECISION))
    495                 .append(c)
    496                 .prepend(d)
    497                 .append(GreatCircles.arcFromPoints(c, d, TEST_PRECISION))
    498                 .build();
    499
    500         // assert
    501         Assert.assertFalse(path.isEmpty());
    502         Assert.assertTrue(path.isClosed());
    503
    504         SphericalTestUtils.assertPointsEq(d, path.getStartVertex(), TEST_EPS);
    505         SphericalTestUtils.assertPointsEq(d, path.getEndVertex(), TEST_EPS);
    506
    507         final List<GreatArc> arcs = path.getArcs();
    508         Assert.assertEquals(5, arcs.size());
    509         assertArc(arcs.get(0), d, e);
    510         assertArc(arcs.get(1), e, a);
    511         assertArc(arcs.get(2), a, b);
    512         assertArc(arcs.get(3), b, c);
    513         assertArc(arcs.get(4), c, d);
    514
    515         assertPoints(Arrays.asList(d, e, a, b, c, d), path.getVertices());
    516     }
    517
    518     @Test
    519     public void testBuilder_points_noPrecisionGiven() {
    520         // act/assert
    521         GeometryTestUtils.assertThrows(() -> {
    522             GreatArcPath.builder(null)
    523                 .append(Point2S.PLUS_I)
    524                 .append(Point2S.PLUS_J);
    525         }, IllegalStateException.class, "Unable to create arc: no point precision specified");
    526
    527         GeometryTestUtils.assertThrows(() -> {
    528             GreatArcPath.builder(null)
    529                 .prepend(Point2S.PLUS_I)
    530                 .prepend(Point2S.PLUS_J);
    531         }, IllegalStateException.class, "Unable to create arc: no point precision specified");
    532     }
    533
    534     @Test
    535     public void testBuilder_arcsNotConnected() {
    536         // act/assert
    537         GeometryTestUtils.assertThrows(() -> {
    538             GreatArcPath.builder(TEST_PRECISION)
    539                 .append(Point2S.PLUS_I)
    540                 .append(Point2S.PLUS_J)
    541                 .append(GreatCircles.arcFromPoints(Point2S.PLUS_K, Point2S.MINUS_J, TEST_PRECISION));
    542         }, IllegalStateException.class, Pattern.compile("^Path arcs are not connected.*"));
    543
    544         GeometryTestUtils.assertThrows(() -> {
    545             GreatArcPath.builder(TEST_PRECISION)
    546                 .prepend(Point2S.PLUS_I)
    547                 .prepend(Point2S.PLUS_J)
    548                 .prepend(GreatCircles.arcFromPoints(Point2S.PLUS_K, Point2S.MINUS_J, TEST_PRECISION));
    549         }, IllegalStateException.class, Pattern.compile("^Path arcs are not connected.*"));
    550     }
    551
    552     @Test
    553     public void testBuilder_addToFullArc() {
    554         // act/assert
    555         GeometryTestUtils.assertThrows(() -> {
    556             GreatArcPath.builder(TEST_PRECISION)
    557                 .append(GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span())
    558                 .append(Point2S.PLUS_J);
    559         }, IllegalStateException.class, Pattern.compile("^Cannot add point .* after full arc.*"));
    560
    561         GeometryTestUtils.assertThrows(() -> {
    562             GreatArcPath.builder(TEST_PRECISION)
    563                 .prepend(GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span())
    564                 .prepend(Point2S.PLUS_J);
    565         }, IllegalStateException.class, Pattern.compile("^Cannot add point .* before full arc.*"));
    566     }
    567
    568     @Test
    569     public void testBuilder_onlySinglePointGiven() {
    570         // act/assert
    571         GeometryTestUtils.assertThrows(() -> {
    572             GreatArcPath.builder(TEST_PRECISION)
    573                 .append(Point2S.PLUS_J)
    574                 .build();
    575         }, IllegalStateException.class, Pattern.compile("^Unable to create path; only a single point provided.*"));
    576
    577         GeometryTestUtils.assertThrows(() -> {
    578             GreatArcPath.builder(TEST_PRECISION)
    579                 .prepend(Point2S.PLUS_J)
    580                 .build();
    581         }, IllegalStateException.class,  Pattern.compile("^Unable to create path; only a single point provided.*"));
    582     }
    583
    584     @Test
    585     public void testBuilder_cannotClose() {
    586         // act/assert
    587         GeometryTestUtils.assertThrows(() -> {
    588             GreatArcPath.builder(TEST_PRECISION)
    589                 .append(GreatCircles.fromPoints(Point2S.PLUS_I, Point2S.PLUS_J, TEST_PRECISION).span())
    590                 .close();
    591         }, IllegalStateException.class, "Unable to close path: path is full");
    592     }
    593
    594     @Test
    595     public void testToString_empty() {
    596         // arrange
    597         final GreatArcPath path = GreatArcPath.empty();
    598
    599         // act
    600         final String str = path.toString();
    601
    602         // assert
    603         Assert.assertEquals("GreatArcPath[empty= true]", str);
    604     }
    605
    606     @Test
    607     public void testToString_singleFullArc() {
    608         // arrange
    609         final GreatArcPath path = GreatArcPath.fromArcs(GreatCircles.fromPole(Vector3D.Unit.PLUS_Z, TEST_PRECISION).span());
    610
    611         // act
    612         final String str = path.toString();
    613
    614         // assert
    615         GeometryTestUtils.assertContains("GreatArcPath[full= true, circle= GreatCircle[", str);
    616     }
    617
    618     @Test
    619     public void testToString_nonFullArcs() {
    620         // arrange
    621         final GreatArcPath path = GreatArcPath.builder(TEST_PRECISION)
    622                 .append(Point2S.PLUS_I)
    623                 .append(Point2S.PLUS_J)
    624                 .build();
    625
    626         // act
    627         final String str = path.toString();
    628
    629         // assert
    630         GeometryTestUtils.assertContains("ArcPath[vertices= [", str);
    631     }
    632
    633     private static void assertArc(final GreatArc arc, final Point2S start, final Point2S end) {
    634         SphericalTestUtils.assertPointsEq(start, arc.getStartPoint(), TEST_EPS);
    635         SphericalTestUtils.assertPointsEq(end, arc.getEndPoint(), TEST_EPS);
    636     }
    637
    638     private static void assertPoints(final Collection<Point2S> expected, final Collection<Point2S> actual) {
    639         Assert.assertEquals(expected.size(), actual.size());
    640
    641         final Iterator<Point2S> expIt = expected.iterator();
    642         final Iterator<Point2S> actIt = actual.iterator();
    643
    644         while (expIt.hasNext() && actIt.hasNext()) {
    645             SphericalTestUtils.assertPointsEq(expIt.next(), actIt.next(), TEST_EPS);
    646         }
    647     }
    648 }