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.euclidean.twod;
    18
    19  import org.apache.commons.geometry.core.GeometryTestUtils;
    20  import org.apache.commons.geometry.core.RegionLocation;
    21  import org.apache.commons.geometry.core.partitioning.Split;
    22  import org.apache.commons.geometry.core.partitioning.SplitLocation;
    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.EuclideanTestUtils;
    26  import org.apache.commons.geometry.euclidean.oned.Interval;
    27  import org.junit.Assert;
    28  import org.junit.Test;
    29
    30  public class ReverseRayTest {
    31
    32      private static final double TEST_EPS = 1e-10;
    33
    34      private static final DoublePrecisionContext TEST_PRECISION =
    35              new EpsilonDoublePrecisionContext(TEST_EPS);
    36
    37      @Test
    38      public void testFromPointAndDirection() {
    39          // arrange
    40          final Vector2D p0 = Vector2D.of(1, 2);
    41          final Vector2D p1 = Vector2D.of(2, 2);
    42
    43          // act
    44          final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(p0, p0.vectorTo(p1), TEST_PRECISION);
    45
    46          // assert
    47          Assert.assertFalse(revRay.isFull());
    48          Assert.assertFalse(revRay.isEmpty());
    49          Assert.assertTrue(revRay.isInfinite());
    50          Assert.assertFalse(revRay.isFinite());
    51
    52          Assert.assertNull(revRay.getStartPoint());
    53          EuclideanTestUtils.assertCoordinatesEqual(p0, revRay.getEndPoint(), TEST_EPS);
    54
    55          GeometryTestUtils.assertNegativeInfinity(revRay.getSubspaceStart());
    56          Assert.assertEquals(1, revRay.getSubspaceEnd(), TEST_EPS);
    57
    58          GeometryTestUtils.assertPositiveInfinity(revRay.getSize());
    59          Assert.assertNull(revRay.getCentroid());
    60          Assert.assertNull(revRay.getBounds());
    61      }
    62
    63      @Test
    64      public void testFromPointAndDirection_invalidArgs() {
    65          // arrange
    66          final Vector2D p = Vector2D.of(0, 2);
    67          final Vector2D d = Vector2D.of(1e-17, -1e-12);
    68
    69          // act/assert
    70          GeometryTestUtils.assertThrows(() -> {
    71              Lines.reverseRayFromPointAndDirection(p, d, TEST_PRECISION);
    72          }, IllegalArgumentException.class, "Line direction cannot be zero");
    73      }
    74
    75      @Test
    76      public void testFromPoint() {
    77          // arrange
    78          final Vector2D p0 = Vector2D.of(1, 1);
    79          final Vector2D p1 = Vector2D.of(1, 2);
    80          final Vector2D p3 = Vector2D.of(3, 3);
    81
    82          final Line line = Lines.fromPoints(p0, p1, TEST_PRECISION);
    83
    84          // act
    85          final ReverseRay revRay = Lines.reverseRayFromPoint(line, p3);
    86
    87          // assert
    88          Assert.assertFalse(revRay.isFull());
    89          Assert.assertFalse(revRay.isEmpty());
    90          Assert.assertTrue(revRay.isInfinite());
    91          Assert.assertFalse(revRay.isFinite());
    92
    93          Assert.assertNull(revRay.getStartPoint());
    94          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 3), revRay.getEndPoint(), TEST_EPS);
    95
    96          GeometryTestUtils.assertNegativeInfinity(revRay.getSubspaceStart());
    97          Assert.assertEquals(3, revRay.getSubspaceEnd(), TEST_EPS);
    98
    99          GeometryTestUtils.assertPositiveInfinity(revRay.getSize());
    100         Assert.assertNull(revRay.getCentroid());
    101         Assert.assertNull(revRay.getBounds());
    102     }
    103
    104     @Test
    105     public void testFromPoint_invalidArgs() {
    106         // arrange
    107         final Vector2D p = Vector2D.of(0, 2);
    108         final Vector2D d = Vector2D.of(1, 1);
    109         final Line line = Lines.fromPointAndDirection(p, d, TEST_PRECISION);
    110
    111         // act/assert
    112         GeometryTestUtils.assertThrows(() -> {
    113             Lines.reverseRayFromPoint(line, Vector2D.NaN);
    114         }, IllegalArgumentException.class, "Invalid reverse ray end point: (NaN, NaN)");
    115
    116         GeometryTestUtils.assertThrows(() -> {
    117             Lines.reverseRayFromPoint(line, Vector2D.POSITIVE_INFINITY);
    118         }, IllegalArgumentException.class, "Invalid reverse ray end point: (Infinity, Infinity)");
    119
    120         GeometryTestUtils.assertThrows(() -> {
    121             Lines.reverseRayFromPoint(line, Vector2D.NEGATIVE_INFINITY);
    122         }, IllegalArgumentException.class, "Invalid reverse ray end point: (-Infinity, -Infinity)");
    123     }
    124
    125     @Test
    126     public void testFromLocation() {
    127         // arrange
    128         final Vector2D p0 = Vector2D.of(1, 1);
    129         final Vector2D p1 = Vector2D.of(1, 2);
    130
    131         final Line line = Lines.fromPoints(p0, p1, TEST_PRECISION);
    132
    133         // act
    134         final ReverseRay revRay = Lines.reverseRayFromLocation(line, -2);
    135
    136         // assert
    137         Assert.assertFalse(revRay.isFull());
    138         Assert.assertFalse(revRay.isEmpty());
    139         Assert.assertTrue(revRay.isInfinite());
    140         Assert.assertFalse(revRay.isFinite());
    141
    142         Assert.assertNull(revRay.getStartPoint());
    143         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, -2), revRay.getEndPoint(), TEST_EPS);
    144
    145         GeometryTestUtils.assertNegativeInfinity(revRay.getSubspaceStart());
    146         Assert.assertEquals(-2, revRay.getSubspaceEnd(), TEST_EPS);
    147
    148         GeometryTestUtils.assertPositiveInfinity(revRay.getSize());
    149         Assert.assertNull(revRay.getCentroid());
    150         Assert.assertNull(revRay.getBounds());
    151     }
    152
    153     @Test
    154     public void testFromLocation_invalidArgs() {
    155         // arrange
    156         final Vector2D p = Vector2D.of(0, 2);
    157         final Vector2D d = Vector2D.of(1, 1);
    158         final Line line = Lines.fromPointAndDirection(p, d, TEST_PRECISION);
    159
    160         // act/assert
    161         GeometryTestUtils.assertThrows(() -> {
    162             Lines.reverseRayFromLocation(line, Double.NaN);
    163         }, IllegalArgumentException.class, "Invalid reverse ray end location: NaN");
    164
    165         GeometryTestUtils.assertThrows(() -> {
    166             Lines.reverseRayFromLocation(line, Double.POSITIVE_INFINITY);
    167         }, IllegalArgumentException.class, "Invalid reverse ray end location: Infinity");
    168
    169         GeometryTestUtils.assertThrows(() -> {
    170             Lines.reverseRayFromLocation(line, Double.NEGATIVE_INFINITY);
    171         }, IllegalArgumentException.class, "Invalid reverse ray end location: -Infinity");
    172     }
    173
    174     @Test
    175     public void testTransform() {
    176         // arrange
    177         final AffineTransformMatrix2D t = AffineTransformMatrix2D.createRotation(-0.5 * Math.PI)
    178                 .translate(Vector2D.Unit.PLUS_X);
    179
    180         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(Vector2D.of(1, 0), Vector2D.Unit.PLUS_X, TEST_PRECISION);
    181
    182         // act
    183         final ReverseRay result = revRay.transform(t);
    184
    185         // assert
    186         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, -1), result.getEndPoint(), TEST_EPS);
    187     }
    188
    189     @Test
    190     public void testTransform_reflection() {
    191         // arrange
    192         final AffineTransformMatrix2D t = AffineTransformMatrix2D.createRotation(0.5 * Math.PI)
    193                 .translate(Vector2D.Unit.PLUS_X)
    194                 .scale(1, -1);
    195
    196         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(Vector2D.of(2, 3),
    197                 Vector2D.Unit.PLUS_X, TEST_PRECISION);
    198
    199         // act
    200         final ReverseRay result = revRay.transform(t);
    201
    202         // assert
    203         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2, -2), result.getEndPoint(), TEST_EPS);
    204     }
    205
    206     @Test
    207     public void testReverse() {
    208         // arrange
    209         final Vector2D start = Vector2D.of(1, 2);
    210
    211         EuclideanTestUtils.permuteSkipZero(-4, 4, 1, (x, y) -> {
    212             final Vector2D dir = Vector2D.of(x, y);
    213
    214             final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(start, dir, TEST_PRECISION);
    215
    216             // act
    217             final Ray rev = revRay.reverse();
    218
    219             // assert
    220             EuclideanTestUtils.assertCoordinatesEqual(revRay.getLine().getOrigin(), rev.getLine().getOrigin(), TEST_EPS);
    221             Assert.assertEquals(-1, revRay.getLine().getDirection().dot(rev.getLine().getDirection()), TEST_EPS);
    222
    223             EuclideanTestUtils.assertCoordinatesEqual(revRay.getEndPoint(), rev.getStartPoint(), TEST_EPS);
    224         });
    225     }
    226
    227     @Test
    228     public void testClosest() {
    229         // arrange
    230         final Vector2D p1 = Vector2D.of(0, -1);
    231         final Vector2D p2 = Vector2D.of(0, 1);
    232         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(p2, p1.directionTo(p2), TEST_PRECISION);
    233
    234         // act/assert
    235         EuclideanTestUtils.assertCoordinatesEqual(p1, revRay.closest(p1), TEST_EPS);
    236         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -2), revRay.closest(Vector2D.of(0, -2)), TEST_EPS);
    237         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -2), revRay.closest(Vector2D.of(2, -2)), TEST_EPS);
    238         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -1), revRay.closest(Vector2D.of(-1, -1)), TEST_EPS);
    239
    240         EuclideanTestUtils.assertCoordinatesEqual(p2, revRay.closest(p2), TEST_EPS);
    241         EuclideanTestUtils.assertCoordinatesEqual(p2, revRay.closest(Vector2D.of(0, 2)), TEST_EPS);
    242         EuclideanTestUtils.assertCoordinatesEqual(p2, revRay.closest(Vector2D.of(-2, 2)), TEST_EPS);
    243         EuclideanTestUtils.assertCoordinatesEqual(p2, revRay.closest(Vector2D.of(-1, 1)), TEST_EPS);
    244
    245         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, revRay.closest(Vector2D.ZERO), TEST_EPS);
    246         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 0.5), revRay.closest(Vector2D.of(1, 0.5)), TEST_EPS);
    247         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, -0.5), revRay.closest(Vector2D.of(-2, -0.5)), TEST_EPS);
    248     }
    249
    250     @Test
    251     public void testClassify() {
    252         // arrange
    253         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(Vector2D.of(1, 1),
    254                 Vector2D.Unit.PLUS_X, TEST_PRECISION);
    255
    256         // act/assert
    257         EuclideanTestUtils.assertRegionLocation(revRay, RegionLocation.OUTSIDE,
    258                 Vector2D.of(2, 2), Vector2D.of(2, 0),
    259                 Vector2D.of(2, 1), Vector2D.of(5, 1));
    260
    261         EuclideanTestUtils.assertRegionLocation(revRay, RegionLocation.BOUNDARY,
    262                 Vector2D.of(1, 1), Vector2D.of(1 + 1e-16, 1));
    263
    264         EuclideanTestUtils.assertRegionLocation(revRay, RegionLocation.INSIDE,
    265                 Vector2D.of(-2, 1), Vector2D.of(-5, 1 + 1e-16));
    266     }
    267
    268     @Test
    269     public void testSplit() {
    270         // --- arrange
    271         final Vector2D p0 = Vector2D.of(1, 1);
    272         final Vector2D p1 = Vector2D.of(-3, 1);
    273         final Vector2D high = Vector2D.of(2, 1);
    274
    275         final Vector2D delta = Vector2D.of(1e-11, 1e-11);
    276
    277         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(p0, Vector2D.Unit.PLUS_X, TEST_PRECISION);
    278
    279         // --- act
    280
    281         // parallel
    282         checkSplit(revRay.split(Lines.fromPointAndAngle(Vector2D.of(2, 2), 0, TEST_PRECISION)),
    283                 null, null,
    284                 null, p0);
    285         checkSplit(revRay.split(Lines.fromPointAndAngle(Vector2D.of(2, 2), Math.PI, TEST_PRECISION)),
    286                 null, p0,
    287                 null, null);
    288
    289         // coincident
    290         checkSplit(revRay.split(Lines.fromPointAndAngle(p0.add(delta), 1e-20, TEST_PRECISION)),
    291                 null, null,
    292                 null, null);
    293
    294         // through point on revRay
    295         checkSplit(revRay.split(Lines.fromPointAndAngle(p1, 1, TEST_PRECISION)),
    296                 null, p1,
    297                 p1, p0);
    298         checkSplit(revRay.split(Lines.fromPointAndAngle(p1, -1, TEST_PRECISION)),
    299                 p1, p0,
    300                 null, p1);
    301
    302         // through end point
    303         checkSplit(revRay.split(Lines.fromPointAndAngle(p0.subtract(delta), 1, TEST_PRECISION)),
    304                 null, p0,
    305                 null, null);
    306         checkSplit(revRay.split(Lines.fromPointAndAngle(p0.add(delta), -1, TEST_PRECISION)),
    307                 null, null,
    308                 null, p0);
    309
    310         // intersection above end point
    311         checkSplit(revRay.split(Lines.fromPointAndAngle(high, 1, TEST_PRECISION)),
    312                 null, p0,
    313                 null, null);
    314         checkSplit(revRay.split(Lines.fromPointAndAngle(high, -1, TEST_PRECISION)),
    315                 null, null,
    316                 null, p0);
    317     }
    318
    319     @Test
    320     public void testSplit_smallAngle_pointOnSplitter() {
    321         // arrange
    322         final DoublePrecisionContext precision = new EpsilonDoublePrecisionContext(1e-5);
    323
    324         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(
    325                 Vector2D.of(1, 1e-6), Vector2D.of(-1, 1e-2), precision);
    326
    327         final Line splitter = Lines.fromPointAndAngle(Vector2D.ZERO, 0, precision);
    328
    329         // act
    330         final Split<LineConvexSubset> split = revRay.split(splitter);
    331
    332         // assert
    333         Assert.assertEquals(SplitLocation.PLUS, split.getLocation());
    334
    335         Assert.assertNull(split.getMinus());
    336         Assert.assertSame(revRay, split.getPlus());
    337     }
    338
    339     @Test
    340     public void testGetInterval() {
    341         // arrange
    342         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(Vector2D.of(2, -1), Vector2D.Unit.PLUS_X, TEST_PRECISION);
    343
    344         // act
    345         final Interval interval = revRay.getInterval();
    346
    347         // assert
    348         GeometryTestUtils.assertNegativeInfinity(interval.getMin());
    349         Assert.assertEquals(2, interval.getMax(), TEST_EPS);
    350
    351         Assert.assertSame(revRay.getLine().getPrecision(), interval.getMaxBoundary().getPrecision());
    352     }
    353
    354     @Test
    355     public void testToString() {
    356         // arrange
    357         final ReverseRay revRay = Lines.reverseRayFromPointAndDirection(Vector2D.ZERO, Vector2D.of(1, 0), TEST_PRECISION);
    358
    359         // act
    360         final String str = revRay.toString();
    361
    362         // assert
    363         GeometryTestUtils.assertContains("ReverseRay[direction= (1", str);
    364         GeometryTestUtils.assertContains(", endPoint= (0", str);
    365     }
    366
    367     private static void checkSplit(final Split<LineConvexSubset> split, final Vector2D minusStart, final Vector2D minusEnd,
    368                                    final Vector2D plusStart, final Vector2D plusEnd) {
    369
    370         final LineConvexSubset minus = split.getMinus();
    371         if (minusStart == null && minusEnd == null) {
    372             Assert.assertNull(minus);
    373         } else {
    374             checkPoint(minusStart, minus.getStartPoint());
    375             checkPoint(minusEnd, minus.getEndPoint());
    376         }
    377
    378
    379         final LineConvexSubset plus = split.getPlus();
    380         if (plusStart == null && plusEnd == null) {
    381             Assert.assertNull(plus);
    382         } else {
    383             checkPoint(plusStart, plus.getStartPoint());
    384             checkPoint(plusEnd, plus.getEndPoint());
    385         }
    386     }
    387
    388     private static void checkPoint(final Vector2D expected, final Vector2D pt) {
    389         if (expected == null) {
    390             Assert.assertNull(pt);
    391         } else {
    392             EuclideanTestUtils.assertCoordinatesEqual(expected, pt, TEST_EPS);
    393         }
    394     }
    395 }