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.euclidean.twod.shape.Parallelogram;
    20  import org.apache.commons.numbers.core.Precision;
    21  import org.junit.jupiter.api.Test;
    22
    23  class BoundarySourceLinecaster2DTest {
    24
    25      private static final double TEST_EPS = 1e-10;
    26
    27      private static final Precision.DoubleEquivalence TEST_PRECISION =
    28              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
    29
    30      private static final BoundarySource2D UNIT_SQUARE =
    31              Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION);
    32
    33      @Test
    34      void testLinecast_line_simple() {
    35          // arrange
    36          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    37
    38          // act/assert
    39
    40          // no intersections
    41          LinecastChecker2D.with(linecaster)
    42              .expectNothing()
    43              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION));
    44
    45          // through center; two directions
    46          LinecastChecker2D.with(linecaster)
    47              .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
    48              .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    49              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION));
    50
    51          LinecastChecker2D.with(linecaster)
    52              .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    53              .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
    54              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION));
    55      }
    56
    57      @Test
    58      void testLinecast_line_alongFace() {
    59          // arrange
    60          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    61
    62          // act/assert
    63          LinecastChecker2D.with(linecaster)
    64              .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
    65              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    66              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 1), Vector2D.Unit.PLUS_X, TEST_PRECISION));
    67      }
    68
    69      @Test
    70      void testLinecast_line_corners() {
    71          // arrange
    72          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    73
    74          // act/assert
    75
    76          // through single corner vertex
    77          LinecastChecker2D.with(linecaster)
    78              .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
    79              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    80              .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 2), Vector2D.of(1, -1), TEST_PRECISION));
    81
    82          // through two corner vertices
    83          LinecastChecker2D.with(linecaster)
    84              .expect(Vector2D.ZERO, Vector2D.Unit.MINUS_X)
    85              .and(Vector2D.ZERO, Vector2D.Unit.MINUS_Y)
    86              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
    87              .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    88              .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION));
    89      }
    90
    91      @Test
    92      void testLinecast_line_removesDuplicatePoints() {
    93          // arrange
    94          final BoundarySource2D src = BoundarySource2D.of(
    95                      Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
    96                      Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
    97                  );
    98          final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
    99
    100         // act/assert
    101         LinecastChecker2D.with(linecaster)
    102             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
    103             .whenGiven(Lines.fromPointAndDirection(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
    104     }
    105
    106     @Test
    107     void testLinecast_segment_simple() {
    108         // arrange
    109         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    110
    111         // act/assert
    112
    113         // no intersections; underlying line does not intersect
    114         LinecastChecker2D.with(linecaster)
    115             .expectNothing()
    116             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0, 4), Vector2D.Unit.MINUS_X, TEST_PRECISION)
    117                     .segment(-10, 10));
    118
    119         // no intersections; underlying line does intersect
    120         LinecastChecker2D.with(linecaster)
    121             .expectNothing()
    122             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
    123                     .segment(2, 10));
    124
    125         // no boundaries excluded; two directions
    126         LinecastChecker2D.with(linecaster)
    127             .expect(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
    128             .and(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    129             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.PLUS_X, TEST_PRECISION)
    130                     .segment(-10, 10));
    131
    132         LinecastChecker2D.with(linecaster)
    133             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    134             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
    135             .whenGiven(Lines.fromPointAndDirection(Vector2D.of(0.5, 0.5), Vector2D.Unit.MINUS_X, TEST_PRECISION)
    136                     .segment(-10, 10));
    137     }
    138
    139     @Test
    140     void testLinecast_segment_boundaryExcluded() {
    141         // arrange
    142         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    143
    144         // act/assert
    145         final Vector2D center = Vector2D.of(0.5, 0.5);
    146         LinecastChecker2D.with(linecaster)
    147             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    148             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.PLUS_X, TEST_PRECISION)
    149                     .rayFrom(center));
    150
    151         LinecastChecker2D.with(linecaster)
    152             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    153             .whenGiven(Lines.fromPointAndDirection(center, Vector2D.Unit.MINUS_X, TEST_PRECISION)
    154                     .reverseRayTo(center));
    155     }
    156
    157     @Test
    158     void testLinecast_segment_startEndPointsOnBoundaries() {
    159         // arrange
    160         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    161
    162         // act/assert
    163         LinecastChecker2D.with(linecaster)
    164             .expect(Vector2D.of(1, 0.5), Vector2D.Unit.PLUS_X)
    165             .and(Vector2D.of(0, 0.5), Vector2D.Unit.MINUS_X)
    166             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 0.5), Vector2D.of(0, 0.5), TEST_PRECISION));
    167     }
    168
    169     @Test
    170     void testLinecast_segment_alongFace() {
    171         // arrange
    172         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    173
    174         // act/assert
    175
    176         // includes two intersecting boundaries
    177         LinecastChecker2D.with(linecaster)
    178             .expect(Vector2D.of(0, 1), Vector2D.Unit.MINUS_X)
    179             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    180             .whenGiven(Lines.segmentFromPoints(Vector2D.of(-1, 1), Vector2D.of(2, 1), TEST_PRECISION));
    181
    182         // one intersecting boundary
    183         LinecastChecker2D.with(linecaster)
    184             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    185             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(2, 1), TEST_PRECISION));
    186
    187         // no intersecting boundary
    188         LinecastChecker2D.with(linecaster)
    189             .expectNothing()
    190             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0.25, 1), Vector2D.of(0.75, 1), TEST_PRECISION));
    191     }
    192
    193     @Test
    194     void testLinecast_segment_corners() {
    195         // arrange
    196         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(UNIT_SQUARE);
    197
    198         // act/assert
    199
    200         // through corner
    201         LinecastChecker2D.with(linecaster)
    202             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
    203             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    204             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(2, 0), TEST_PRECISION));
    205
    206         // starts on corner
    207         LinecastChecker2D.with(linecaster)
    208             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
    209             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    210             .whenGiven(Lines.segmentFromPoints(Vector2D.of(1, 1), Vector2D.of(2, 0), TEST_PRECISION));
    211
    212         // ends on corner
    213         LinecastChecker2D.with(linecaster)
    214             .expect(Vector2D.of(1, 1), Vector2D.Unit.PLUS_Y)
    215             .and(Vector2D.of(1, 1), Vector2D.Unit.PLUS_X)
    216             .whenGiven(Lines.segmentFromPoints(Vector2D.of(0, 2), Vector2D.of(1, 1), TEST_PRECISION));
    217     }
    218
    219     @Test
    220     void testLinecast_segment_removesDuplicatePoints() {
    221         // arrange
    222         final BoundarySource2D src = BoundarySource2D.of(
    223                     Lines.segmentFromPoints(Vector2D.of(-1, -1), Vector2D.ZERO, TEST_PRECISION),
    224                     Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.of(1, 1), TEST_PRECISION)
    225                 );
    226         final BoundarySourceLinecaster2D linecaster = new BoundarySourceLinecaster2D(src);
    227
    228         // act/assert
    229         LinecastChecker2D.with(linecaster)
    230             .expect(Vector2D.ZERO, Vector2D.Unit.from(1, -1))
    231             .whenGiven(Lines.segmentFromPoints(Vector2D.ZERO, Vector2D.Unit.PLUS_X, TEST_PRECISION));
    232     }
    233 }
    234