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