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.line;
    18
    19  import org.apache.commons.geometry.core.GeometryTestUtils;
    20  import org.apache.commons.geometry.core.Transform;
    21  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
    22  import org.apache.commons.geometry.euclidean.oned.Interval;
    23  import org.apache.commons.geometry.euclidean.oned.Vector1D;
    24  import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
    25  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    26  import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
    27  import org.apache.commons.numbers.angle.Angle;
    28  import org.apache.commons.numbers.core.Precision;
    29  import org.junit.jupiter.api.Assertions;
    30  import org.junit.jupiter.api.Test;
    31
    32  class LineConvexSubset3DTest {
    33
    34      private static final double TEST_EPS = 1e-10;
    35
    36      private static final Precision.DoubleEquivalence TEST_PRECISION =
    37              Precision.doubleEquivalenceOfEpsilon(TEST_EPS);
    38
    39      @Test
    40      void testFromInterval_intervalArg_finite() {
    41          // arrange
    42          final Precision.DoubleEquivalence intervalPrecision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    43          final Interval interval = Interval.of(-1, 2, intervalPrecision);
    44
    45          final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    46
    47          // act
    48          final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, interval);
    49
    50          // assert
    51          final double side = 1.0 / Math.sqrt(3);
    52          checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
    53      }
    54
    55      @Test
    56      void testFromInterval_intervalArg_full() {
    57          // arrange
    58          final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    59
    60          // act
    61          final LineConvexSubset3D span = Lines3D.subsetFromInterval(line, Interval.full());
    62
    63          // assert
    64          Assertions.assertTrue(span.isInfinite());
    65          Assertions.assertFalse(span.isFinite());
    66
    67          GeometryTestUtils.assertNegativeInfinity(span.getSubspaceStart());
    68          GeometryTestUtils.assertPositiveInfinity(span.getSubspaceEnd());
    69
    70          Assertions.assertNull(span.getStartPoint());
    71          Assertions.assertNull(span.getEndPoint());
    72
    73          Assertions.assertSame(Interval.full(), span.getInterval());
    74      }
    75
    76      @Test
    77      void testFromInterval_intervalArg_positiveHalfSpace() {
    78          // arrange
    79          final Precision.DoubleEquivalence intervalPrecision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    80          final Interval interval = Interval.min(-1, intervalPrecision);
    81
    82          final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    83
    84          // act
    85          final Ray3D ray = (Ray3D) Lines3D.subsetFromInterval(line, interval);
    86
    87          // assert
    88          Assertions.assertTrue(ray.isInfinite());
    89          Assertions.assertFalse(ray.isFinite());
    90
    91          Assertions.assertEquals(-1.0, ray.getSubspaceStart(), TEST_EPS);
    92          GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
    93
    94          final double side = 1.0 / Math.sqrt(3);
    95
    96          EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-side, -side, -side), ray.getStartPoint(), TEST_EPS);
    97          Assertions.assertNull(ray.getEndPoint());
    98
    99          checkInterval(interval, ray.getInterval());
    100     }
    101
    102     @Test
    103     void testFromInterval_intervalArg_negativeHalfSpace() {
    104         // arrange
    105         final Precision.DoubleEquivalence intervalPrecision = Precision.doubleEquivalenceOfEpsilon(1e-2);
    106         final Interval interval = Interval.max(2, intervalPrecision);
    107
    108         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    109
    110         // act
    111         final ReverseRay3D halfLine = (ReverseRay3D) Lines3D.subsetFromInterval(line, interval);
    112
    113         // assert
    114         GeometryTestUtils.assertNegativeInfinity(halfLine.getSubspaceStart());
    115         Assertions.assertEquals(2, halfLine.getSubspaceEnd(), TEST_EPS);
    116
    117         final double side = 1.0 / Math.sqrt(3);
    118
    119         Assertions.assertNull(halfLine.getStartPoint());
    120         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2 * side, 2 * side, 2 * side), halfLine.getEndPoint(), TEST_EPS);
    121
    122         checkInterval(interval, halfLine.getInterval());
    123     }
    124
    125     @Test
    126     void testFromInterval_doubleArgs_finite() {
    127         // arrange
    128         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    129
    130         // act
    131         final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, -1, 2);
    132
    133         // assert
    134         final double side = 1.0 / Math.sqrt(3);
    135         checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
    136     }
    137
    138     @Test
    139     void testFromInterval_doubleArgs_full() {
    140         // arrange
    141         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    142
    143         // act
    144         final LineConvexSubset3D span = Lines3D.subsetFromInterval(line, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    145
    146         // assert
    147         GeometryTestUtils.assertNegativeInfinity(span.getSubspaceStart());
    148         GeometryTestUtils.assertPositiveInfinity(span.getSubspaceEnd());
    149
    150         Assertions.assertNull(span.getStartPoint());
    151         Assertions.assertNull(span.getEndPoint());
    152     }
    153
    154     @Test
    155     void testFromInterval_doubleArgs_positiveHalfSpace() {
    156         // arrange
    157         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    158
    159         // act
    160         final Ray3D ray = (Ray3D) Lines3D.subsetFromInterval(line, -1, Double.POSITIVE_INFINITY);
    161
    162         // assert
    163         Assertions.assertEquals(-1.0, ray.getSubspaceStart(), TEST_EPS);
    164         GeometryTestUtils.assertPositiveInfinity(ray.getSubspaceEnd());
    165
    166         final double side = 1.0 / Math.sqrt(3);
    167
    168         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-side, -side, -side), ray.getStartPoint(), TEST_EPS);
    169         Assertions.assertNull(ray.getEndPoint());
    170     }
    171
    172     @Test
    173     void testFromInterval_doubleArgs_negativeHalfSpace() {
    174         // arrange
    175         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    176
    177         // act
    178         final ReverseRay3D halfLine = (ReverseRay3D) Lines3D.subsetFromInterval(line, 2, Double.NEGATIVE_INFINITY);
    179
    180         // assert
    181         GeometryTestUtils.assertNegativeInfinity(halfLine.getSubspaceStart());
    182         Assertions.assertEquals(2, halfLine.getSubspaceEnd(), TEST_EPS);
    183
    184         final double side = 1.0 / Math.sqrt(3);
    185
    186         Assertions.assertNull(halfLine.getStartPoint());
    187         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(2 * side, 2 * side, 2 * side), halfLine.getEndPoint(), TEST_EPS);
    188     }
    189
    190     @Test
    191     void testFromInterval_doubleArgs_invalidArgs() {
    192         // arrange
    193         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    194
    195         // act/assert
    196         GeometryTestUtils.assertThrowsWithMessage(() -> {
    197             Lines3D.subsetFromInterval(line, Double.NaN, 0);
    198         }, IllegalArgumentException.class, "Invalid line convex subset interval: NaN, 0.0");
    199
    200         GeometryTestUtils.assertThrowsWithMessage(() -> {
    201             Lines3D.subsetFromInterval(line, 0, Double.NaN);
    202         }, IllegalArgumentException.class, "Invalid line convex subset interval: 0.0, NaN");
    203
    204         GeometryTestUtils.assertThrowsWithMessage(() -> {
    205             Lines3D.subsetFromInterval(line, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    206         }, IllegalArgumentException.class, "Invalid line convex subset interval: Infinity, Infinity");
    207
    208         GeometryTestUtils.assertThrowsWithMessage(() -> {
    209             Lines3D.subsetFromInterval(line, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
    210         }, IllegalArgumentException.class, "Invalid line convex subset interval: -Infinity, -Infinity");
    211     }
    212
    213     @Test
    214     void testFromInterval_vectorArgs() {
    215         // arrange
    216         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    217
    218         // act
    219         final Segment3D segment = (Segment3D) Lines3D.subsetFromInterval(line, Vector1D.of(-1), Vector1D.of(2));
    220
    221         // assert
    222         final double side = 1.0 / Math.sqrt(3);
    223         checkFiniteSegment(segment, Vector3D.of(-side, -side, -side), Vector3D.of(2 * side, 2 * side, 2 * side));
    224     }
    225
    226     @Test
    227     void testSpaceSubspaceConversion() {
    228         // arrange
    229         final Segment3D segment = Lines3D.segmentFromPoints(Vector3D.ZERO, Vector3D.Unit.PLUS_Y, TEST_PRECISION);
    230
    231         // act/assert
    232         EuclideanTestUtils.assertCoordinatesEqual(Vector1D.of(3), segment.toSubspace(Vector3D.of(1, 3, 5)), TEST_EPS);
    233         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 3, 0), segment.toSpace(Vector1D.of(3)), TEST_EPS);
    234     }
    235
    236     @Test
    237     void testGetSubspaceRegion() {
    238         // arrange
    239         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.ZERO, Vector3D.of(1, 1, 1), TEST_PRECISION);
    240         final Interval interval = Interval.full();
    241
    242         final LineConvexSubset3D subset = Lines3D.subsetFromInterval(line, interval);
    243
    244         // act/assert
    245         Assertions.assertSame(interval, subset.getInterval());
    246         Assertions.assertSame(interval, subset.getSubspaceRegion());
    247     }
    248
    249     @Test
    250     void testTransform_infinite() {
    251         // arrange
    252         final Line3D line = Lines3D.fromPointAndDirection(Vector3D.of(1, 0, 0), Vector3D.of(0, 1, -1), TEST_PRECISION);
    253         final LineConvexSubset3D subset = Lines3D.subsetFromInterval(line,
    254                 Interval.min(line.toSubspace(Vector3D.of(1, 0, 0)).getX(), TEST_PRECISION));
    255
    256         final Transform<Vector3D> transform = AffineTransformMatrix3D.identity()
    257                 .scale(2, 1, 1)
    258                 .rotate(QuaternionRotation.fromAxisAngle(Vector3D.Unit.PLUS_Y, Angle.PI_OVER_TWO));
    259
    260         // act
    261         final LineConvexSubset3D transformed = subset.transform(transform);
    262
    263         // assert
    264         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(0, 0, -2), transformed.getStartPoint(), TEST_EPS);
    265         Assertions.assertNull(transformed.getEndPoint());
    266         EuclideanTestUtils.assertCoordinatesEqual(Vector3D.of(-1, 1, 0).normalize(), transformed.getLine().getDirection(), TEST_EPS);
    267     }
    268
    269     private static void checkInterval(final Interval expected, final Interval actual) {
    270         Assertions.assertEquals(expected.getMin(), actual.getMin(), TEST_EPS);
    271         Assertions.assertEquals(expected.getMax(), actual.getMax(), TEST_EPS);
    272     }
    273
    274     private static void checkFiniteSegment(final LineConvexSubset3D subset, final Vector3D start, final Vector3D end) {
    275         checkFiniteSegment(subset, start, end, TEST_PRECISION);
    276     }
    277
    278     private static void checkFiniteSegment(final LineConvexSubset3D subset, final Vector3D start, final Vector3D end, final Precision.DoubleEquivalence precision) {
    279         Assertions.assertFalse(subset.isInfinite());
    280         Assertions.assertTrue(subset.isFinite());
    281
    282         EuclideanTestUtils.assertCoordinatesEqual(start, subset.getStartPoint(), TEST_EPS);
    283         EuclideanTestUtils.assertCoordinatesEqual(end, subset.getEndPoint(), TEST_EPS);
    284
    285         final Line3D line = subset.getLine();
    286
    287         Assertions.assertEquals(line.toSubspace(subset.getStartPoint()).getX(), subset.getSubspaceStart(), TEST_EPS);
    288         Assertions.assertEquals(line.toSubspace(subset.getEndPoint()).getX(), subset.getSubspaceEnd(), TEST_EPS);
    289
    290         Assertions.assertSame(precision, line.getPrecision());
    291     }
    292 }