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