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.shape;
    18
    19  import java.util.List;
    20
    21  import org.apache.commons.geometry.euclidean.EuclideanTestUtils;
    22  import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
    23  import org.apache.commons.geometry.euclidean.twod.LineConvexSubset;
    24  import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
    25  import org.apache.commons.geometry.euclidean.twod.Vector2D;
    26  import org.apache.commons.geometry.euclidean.twod.path.LinePath;
    27  import org.apache.commons.geometry.euclidean.twod.rotation.Rotation2D;
    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 ParallelogramTest {
    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 testUnitSquare() {
    41          // act
    42          final Parallelogram box = Parallelogram.unitSquare(TEST_PRECISION);
    43
    44          // assert
    45          Assertions.assertEquals(1, box.getSize(), TEST_EPS);
    46          Assertions.assertEquals(4, box.getBoundarySize(), TEST_EPS);
    47          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, box.getCentroid(), TEST_EPS);
    48
    49          final List<Vector2D> vertices = box.getVertices();
    50          Assertions.assertEquals(4, vertices.size());
    51          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-0.5, -0.5), vertices.get(0), TEST_EPS);
    52          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, -0.5), vertices.get(1), TEST_EPS);
    53          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), vertices.get(2), TEST_EPS);
    54          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-0.5, 0.5), vertices.get(3), TEST_EPS);
    55      }
    56
    57      @Test
    58      void testFromTransformedUnitSquare() {
    59          // arrange
    60          final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.of(1, 0))
    61                  .rotate(Math.PI * 0.25)
    62                  .scale(Vector2D.of(2, 1));
    63
    64          // act
    65          final Parallelogram p = Parallelogram.fromTransformedUnitSquare(t, TEST_PRECISION);
    66
    67          // assert
    68          final double sqrt2 = Math.sqrt(2);
    69          final double invSqrt2 = 1 / sqrt2;
    70
    71          Assertions.assertEquals(2, p.getSize(), TEST_EPS);
    72          Assertions.assertEquals(4 * Math.sqrt(2.5), p.getBoundarySize(), TEST_EPS);
    73          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2 * invSqrt2, invSqrt2), p.getCentroid(), TEST_EPS);
    74
    75          final List<Vector2D> vertices = p.getVertices();
    76          Assertions.assertEquals(4, vertices.size());
    77          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, invSqrt2), vertices.get(0), TEST_EPS);
    78          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2 * invSqrt2, 0), vertices.get(1), TEST_EPS);
    79          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2 * sqrt2, invSqrt2), vertices.get(2), TEST_EPS);
    80          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2 * invSqrt2, sqrt2), vertices.get(3), TEST_EPS);
    81      }
    82
    83      @Test
    84      void testFromTransformedUnitSquare_transformDoesNotPreserveOrientation() {
    85          // arrange
    86          final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.of(1, 0))
    87                  .rotate(Math.PI * 0.25)
    88                  .scale(Vector2D.of(-2, 1));
    89
    90          // act
    91          final Parallelogram p = Parallelogram.fromTransformedUnitSquare(t, TEST_PRECISION);
    92
    93          // assert
    94          final double sqrt2 = Math.sqrt(2);
    95          final double invSqrt2 = 1 / sqrt2;
    96
    97          Assertions.assertEquals(2, p.getSize(), TEST_EPS);
    98          Assertions.assertEquals(4 * Math.sqrt(2.5), p.getBoundarySize(), TEST_EPS);
    99          EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2 * invSqrt2, invSqrt2), p.getCentroid(), TEST_EPS);
    100
    101         final List<Vector2D> vertices = p.getVertices();
    102         Assertions.assertEquals(4, vertices.size());
    103         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2 * sqrt2, invSqrt2), vertices.get(0), TEST_EPS);
    104         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2 * invSqrt2, 0), vertices.get(1), TEST_EPS);
    105         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, invSqrt2), vertices.get(2), TEST_EPS);
    106         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-2 * invSqrt2, sqrt2), vertices.get(3), TEST_EPS);
    107     }
    108
    109     @Test
    110     void testFromTransformedUnitSquare_zeroSizeRegion() {
    111         // act/assert
    112         Assertions.assertThrows(IllegalArgumentException.class, () ->  Parallelogram.fromTransformedUnitSquare(AffineTransformMatrix2D.createScale(Vector2D.of(1e-16, 1)),
    113                 TEST_PRECISION));
    114
    115         Assertions.assertThrows(IllegalArgumentException.class, () ->  Parallelogram.fromTransformedUnitSquare(AffineTransformMatrix2D.createScale(Vector2D.of(1, 1e-16)),
    116                 TEST_PRECISION));
    117     }
    118
    119     @Test
    120     void testAxisAligned_minFirst() {
    121         // act
    122         final Parallelogram box = Parallelogram.axisAligned(Vector2D.of(1, 2), Vector2D.of(3, 4), TEST_PRECISION);
    123
    124         // assert
    125         Assertions.assertEquals(1, box.getBoundaryPaths().size());
    126         final LinePath path = box.getBoundaryPaths().get(0);
    127
    128         final List<LineConvexSubset> segments = path.getElements();
    129         Assertions.assertEquals(4, segments.size());
    130
    131         assertSegment(segments.get(0), Vector2D.of(1, 2), Vector2D.of(3, 2));
    132         assertSegment(segments.get(1), Vector2D.of(3, 2), Vector2D.of(3, 4));
    133         assertSegment(segments.get(2), Vector2D.of(3, 4), Vector2D.of(1, 4));
    134         assertSegment(segments.get(3), Vector2D.of(1, 4), Vector2D.of(1, 2));
    135     }
    136
    137     @Test
    138     void testAxisAligned_maxFirst() {
    139         // act
    140         final Parallelogram box = Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(-1, -2), TEST_PRECISION);
    141
    142         // assert
    143         Assertions.assertEquals(1, box.getBoundaryPaths().size());
    144         final LinePath path = box.getBoundaryPaths().get(0);
    145
    146         final List<LineConvexSubset> segments = path.getElements();
    147         Assertions.assertEquals(4, segments.size());
    148
    149         assertSegment(segments.get(0), Vector2D.of(-1, -2), Vector2D.of(0, -2));
    150         assertSegment(segments.get(1), Vector2D.of(0, -2), Vector2D.ZERO);
    151         assertSegment(segments.get(2), Vector2D.ZERO, Vector2D.of(-1, 0));
    152         assertSegment(segments.get(3), Vector2D.of(-1, 0), Vector2D.of(-1, -2));
    153     }
    154
    155     @Test
    156     void testAxisAligned_illegalArgs() {
    157         // act/assert
    158
    159         Assertions.assertThrows(IllegalArgumentException.class, () ->  Parallelogram.axisAligned(Vector2D.of(1, 1), Vector2D.of(1, 3), TEST_PRECISION));
    160         Assertions.assertThrows(IllegalArgumentException.class, () ->  Parallelogram.axisAligned(Vector2D.of(1, 1), Vector2D.of(3, 1), TEST_PRECISION));
    161         Assertions.assertThrows(IllegalArgumentException.class, () ->  Parallelogram.axisAligned(Vector2D.of(2, 3), Vector2D.of(2, 3), TEST_PRECISION));
    162     }
    163
    164     @Test
    165     void testBuilder_defaultValues() {
    166         // arrange
    167         final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
    168
    169         // act
    170         final Parallelogram p = builder.build();
    171
    172         // assert
    173         Assertions.assertEquals(1, p.getSize(), TEST_EPS);
    174         Assertions.assertEquals(4, p.getBoundarySize(), TEST_EPS);
    175         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.ZERO, p.getCentroid(), TEST_EPS);
    176
    177         final List<Vector2D> vertices = p.getVertices();
    178         Assertions.assertEquals(4, vertices.size());
    179         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-0.5, -0.5), vertices.get(0), TEST_EPS);
    180         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, -0.5), vertices.get(1), TEST_EPS);
    181         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 0.5), vertices.get(2), TEST_EPS);
    182         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(-0.5, 0.5), vertices.get(3), TEST_EPS);
    183     }
    184
    185     @Test
    186     void testBuilder_rotatedRect_withXDirection() {
    187         // arrange
    188         final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
    189
    190         // act
    191         final Parallelogram p = builder
    192                 .setScale(1, 2)
    193                 .setXDirection(Vector2D.Unit.PLUS_Y)
    194                 .setPosition(Vector2D.of(1, 2))
    195                 .build();
    196
    197         // assert
    198         Assertions.assertEquals(2, p.getSize(), TEST_EPS);
    199         Assertions.assertEquals(6, p.getBoundarySize(), TEST_EPS);
    200         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2), p.getCentroid(), TEST_EPS);
    201
    202         final List<Vector2D> vertices = p.getVertices();
    203         Assertions.assertEquals(4, vertices.size());
    204         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 1.5), vertices.get(0), TEST_EPS);
    205         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2, 1.5), vertices.get(1), TEST_EPS);
    206         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(2, 2.5), vertices.get(2), TEST_EPS);
    207         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0, 2.5), vertices.get(3), TEST_EPS);
    208     }
    209
    210     @Test
    211     void testBuilder_rotatedRect_withYDirection() {
    212         // arrange
    213         final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
    214
    215         // act
    216         final Parallelogram p = builder
    217                 .setScale(Vector2D.of(2, 1))
    218                 .setYDirection(Vector2D.Unit.MINUS_X)
    219                 .setPosition(Vector2D.of(1, 2))
    220                 .build();
    221
    222         // assert
    223         Assertions.assertEquals(2, p.getSize(), TEST_EPS);
    224         Assertions.assertEquals(6, p.getBoundarySize(), TEST_EPS);
    225         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2), p.getCentroid(), TEST_EPS);
    226
    227         final List<Vector2D> vertices = p.getVertices();
    228         Assertions.assertEquals(4, vertices.size());
    229         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 1), vertices.get(0), TEST_EPS);
    230         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1.5, 1), vertices.get(1), TEST_EPS);
    231         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1.5, 3), vertices.get(2), TEST_EPS);
    232         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 3), vertices.get(3), TEST_EPS);
    233     }
    234
    235     @Test
    236     void testBuilder_rotatedRect_withRotation() {
    237         // arrange
    238         final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
    239
    240         // act
    241         final Parallelogram p = builder
    242                 .setScale(2)
    243                 .setRotation(Rotation2D.of(0.25 * Math.PI))
    244                 .setPosition(Vector2D.of(1, 2))
    245                 .build();
    246
    247         // assert
    248         Assertions.assertEquals(4, p.getSize(), TEST_EPS);
    249         Assertions.assertEquals(8, p.getBoundarySize(), TEST_EPS);
    250         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2), p.getCentroid(), TEST_EPS);
    251
    252         final List<Vector2D> vertices = p.getVertices();
    253         Assertions.assertEquals(4, vertices.size());
    254
    255         final double sqrt2 = Math.sqrt(2);
    256         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1 - sqrt2, 2), vertices.get(0), TEST_EPS);
    257         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2 - sqrt2), vertices.get(1), TEST_EPS);
    258         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1 + sqrt2, 2), vertices.get(2), TEST_EPS);
    259         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(1, 2 + sqrt2), vertices.get(3), TEST_EPS);
    260     }
    261
    262     @Test
    263     void testToTree() {
    264         // act
    265         final RegionBSPTree2D tree = Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(1, 4), TEST_PRECISION)
    266                 .toTree();
    267
    268         // assert
    269         Assertions.assertFalse(tree.isFull());
    270         Assertions.assertFalse(tree.isEmpty());
    271
    272         Assertions.assertEquals(4, tree.getSize(), TEST_EPS);
    273         EuclideanTestUtils.assertCoordinatesEqual(Vector2D.of(0.5, 2), tree.getCentroid(), TEST_EPS);
    274     }
    275
    276     private static void assertSegment(final LineConvexSubset segment, final Vector2D start, final Vector2D end) {
    277         EuclideanTestUtils.assertCoordinatesEqual(start, segment.getStartPoint(), TEST_EPS);
    278         EuclideanTestUtils.assertCoordinatesEqual(end, segment.getEndPoint(), TEST_EPS);
    279     }
    280 }