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