1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
42 final Parallelogram box = Parallelogram.unitSquare(TEST_PRECISION);
43
44
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
60 final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.of(1, 0))
61 .rotate(Math.PI * 0.25)
62 .scale(Vector2D.of(2, 1));
63
64
65 final Parallelogram p = Parallelogram.fromTransformedUnitSquare(t, TEST_PRECISION);
66
67
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
86 final AffineTransformMatrix2D t = AffineTransformMatrix2D.createTranslation(Vector2D.of(1, 0))
87 .rotate(Math.PI * 0.25)
88 .scale(Vector2D.of(-2, 1));
89
90
91 final Parallelogram p = Parallelogram.fromTransformedUnitSquare(t, TEST_PRECISION);
92
93
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
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
122 final Parallelogram box = Parallelogram.axisAligned(Vector2D.of(1, 2), Vector2D.of(3, 4), TEST_PRECISION);
123
124
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
140 final Parallelogram box = Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(-1, -2), TEST_PRECISION);
141
142
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
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
167 final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
168
169
170 final Parallelogram p = builder.build();
171
172
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
188 final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
189
190
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
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
213 final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
214
215
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
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
238 final Parallelogram.Builder builder = Parallelogram.builder(TEST_PRECISION);
239
240
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
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
265 final RegionBSPTree2D tree = Parallelogram.axisAligned(Vector2D.ZERO, Vector2D.of(1, 4), TEST_PRECISION)
266 .toTree();
267
268
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 }