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