1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.euclidean.twod;
18
19 import java.util.regex.Pattern;
20
21 import org.apache.commons.geometry.core.GeometryTestUtils;
22 import org.apache.commons.numbers.angle.Angle;
23 import org.junit.jupiter.api.Assertions;
24 import org.junit.jupiter.api.Test;
25
26 class PolarCoordinatesTest {
27
28 private static final double EPS = 1e-10;
29
30 private static final double THREE_PI_OVER_TWO = 3 * Math.PI / 2;
31
32 @Test
33 void testOf() {
34
35 checkPolar(PolarCoordinates.of(0, 0), 0, 0);
36
37 checkPolar(PolarCoordinates.of(2, 0), 2, 0);
38 checkPolar(PolarCoordinates.of(2, Angle.PI_OVER_TWO), 2, Angle.PI_OVER_TWO);
39 checkPolar(PolarCoordinates.of(2, Math.PI), 2, Math.PI);
40 checkPolar(PolarCoordinates.of(2, -Angle.PI_OVER_TWO), 2, THREE_PI_OVER_TWO);
41 }
42
43 @Test
44 void testOf_unnormalizedAngles() {
45
46 checkPolar(PolarCoordinates.of(2, Angle.TWO_PI), 2, 0);
47 checkPolar(PolarCoordinates.of(2, Angle.PI_OVER_TWO + Angle.TWO_PI), 2, Angle.PI_OVER_TWO);
48 checkPolar(PolarCoordinates.of(2, -Math.PI), 2, Math.PI);
49 checkPolar(PolarCoordinates.of(2, -Math.PI * 1.5), 2, Angle.PI_OVER_TWO);
50 }
51
52 @Test
53 void testOf_azimuthWrapAround() {
54
55 final double delta = 1e-6;
56
57
58 checkAzimuthWrapAround(2, 0);
59 checkAzimuthWrapAround(2, delta);
60 checkAzimuthWrapAround(2, Math.PI - delta);
61 checkAzimuthWrapAround(2, Math.PI);
62
63 checkAzimuthWrapAround(2, THREE_PI_OVER_TWO);
64 checkAzimuthWrapAround(2, Angle.TWO_PI - delta);
65 }
66
67 private void checkAzimuthWrapAround(final double radius, final double azimuth) {
68 checkPolar(PolarCoordinates.of(radius, azimuth), radius, azimuth);
69
70 checkPolar(PolarCoordinates.of(radius, azimuth - Angle.TWO_PI), radius, azimuth);
71 checkPolar(PolarCoordinates.of(radius, azimuth - (2 * Angle.TWO_PI)), radius, azimuth);
72 checkPolar(PolarCoordinates.of(radius, azimuth - (3 * Angle.TWO_PI)), radius, azimuth);
73
74 checkPolar(PolarCoordinates.of(radius, azimuth + Angle.TWO_PI), radius, azimuth);
75 checkPolar(PolarCoordinates.of(radius, azimuth + (2 * Angle.TWO_PI)), radius, azimuth);
76 checkPolar(PolarCoordinates.of(radius, azimuth + (3 * Angle.TWO_PI)), radius, azimuth);
77 }
78
79 @Test
80 void testOf_negativeRadius() {
81
82 checkPolar(PolarCoordinates.of(-1, 0), 1, Math.PI);
83 checkPolar(PolarCoordinates.of(-1e-6, Angle.PI_OVER_TWO), 1e-6, THREE_PI_OVER_TWO);
84 checkPolar(PolarCoordinates.of(-2, Math.PI), 2, 0);
85 checkPolar(PolarCoordinates.of(-3, -Angle.PI_OVER_TWO), 3, Angle.PI_OVER_TWO);
86 }
87
88 @Test
89 void testOf_NaNAndInfinite() {
90
91 checkPolar(PolarCoordinates.of(Double.NaN, 0), Double.NaN, 0);
92 checkPolar(PolarCoordinates.of(Double.NEGATIVE_INFINITY, 0), Double.POSITIVE_INFINITY, Math.PI);
93 checkPolar(PolarCoordinates.of(Double.POSITIVE_INFINITY, 0), Double.POSITIVE_INFINITY, 0);
94
95 checkPolar(PolarCoordinates.of(0, Double.NaN), 0, Double.NaN);
96 checkPolar(PolarCoordinates.of(0, Double.NEGATIVE_INFINITY), 0, Double.NEGATIVE_INFINITY);
97 checkPolar(PolarCoordinates.of(0, Double.POSITIVE_INFINITY), 0, Double.POSITIVE_INFINITY);
98 }
99
100 @Test
101 void testFromCartesian_coordinates() {
102
103 final double sqrt2 = Math.sqrt(2);
104
105
106 checkPolar(PolarCoordinates.fromCartesian(0, 0), 0, 0);
107
108 checkPolar(PolarCoordinates.fromCartesian(1, 0), 1, 0);
109 checkPolar(PolarCoordinates.fromCartesian(1, 1), sqrt2, 0.25 * Math.PI);
110 checkPolar(PolarCoordinates.fromCartesian(0, 1), 1, Angle.PI_OVER_TWO);
111
112 checkPolar(PolarCoordinates.fromCartesian(-1, 1), sqrt2, 0.75 * Math.PI);
113 checkPolar(PolarCoordinates.fromCartesian(-1, 0), 1, Math.PI);
114 checkPolar(PolarCoordinates.fromCartesian(-1, -1), sqrt2, 1.25 * Math.PI);
115
116 checkPolar(PolarCoordinates.fromCartesian(0, -1), 1, 1.5 * Math.PI);
117 checkPolar(PolarCoordinates.fromCartesian(1, -1), sqrt2, 1.75 * Math.PI);
118 }
119
120 @Test
121 void testFromCartesian_vector() {
122
123 final double sqrt2 = Math.sqrt(2);
124
125
126 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(0, 0)), 0, 0);
127
128 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(1, 0)), 1, 0);
129 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(1, 1)), sqrt2, 0.25 * Math.PI);
130 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(0, 1)), 1, Angle.PI_OVER_TWO);
131
132 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(-1, 1)), sqrt2, 0.75 * Math.PI);
133 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(-1, 0)), 1, Math.PI);
134 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(-1, -1)), sqrt2, 1.25 * Math.PI);
135
136 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(0, -1)), 1, 1.5 * Math.PI);
137 checkPolar(PolarCoordinates.fromCartesian(Vector2D.of(1, -1)), sqrt2, 1.75 * Math.PI);
138 }
139
140 @Test
141 void testDimension() {
142
143 final PolarCoordinates p = PolarCoordinates.of(1, 0);
144
145
146 Assertions.assertEquals(2, p.getDimension());
147 }
148
149 @Test
150 void testIsNaN() {
151
152 Assertions.assertFalse(PolarCoordinates.of(1, 0).isNaN());
153 Assertions.assertFalse(PolarCoordinates.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY).isNaN());
154
155 Assertions.assertTrue(PolarCoordinates.of(Double.NaN, 0).isNaN());
156 Assertions.assertTrue(PolarCoordinates.of(1, Double.NaN).isNaN());
157 Assertions.assertTrue(PolarCoordinates.of(Double.NaN, Double.NaN).isNaN());
158 }
159
160 @Test
161 void testIsInfinite() {
162
163 Assertions.assertFalse(PolarCoordinates.of(1, 0).isInfinite());
164 Assertions.assertFalse(PolarCoordinates.of(Double.NaN, Double.NaN).isInfinite());
165
166 Assertions.assertTrue(PolarCoordinates.of(Double.POSITIVE_INFINITY, 0).isInfinite());
167 Assertions.assertTrue(PolarCoordinates.of(Double.NEGATIVE_INFINITY, 0).isInfinite());
168 Assertions.assertFalse(PolarCoordinates.of(Double.NEGATIVE_INFINITY, Double.NaN).isInfinite());
169
170 Assertions.assertTrue(PolarCoordinates.of(0, Double.POSITIVE_INFINITY).isInfinite());
171 Assertions.assertTrue(PolarCoordinates.of(0, Double.NEGATIVE_INFINITY).isInfinite());
172 Assertions.assertFalse(PolarCoordinates.of(Double.NaN, Double.NEGATIVE_INFINITY).isInfinite());
173
174 Assertions.assertTrue(PolarCoordinates.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY).isInfinite());
175 Assertions.assertTrue(PolarCoordinates.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY).isInfinite());
176 }
177
178 @Test
179 void testIsFinite() {
180
181 Assertions.assertTrue(PolarCoordinates.of(1, 0).isFinite());
182 Assertions.assertTrue(PolarCoordinates.of(1, Math.PI).isFinite());
183
184 Assertions.assertFalse(PolarCoordinates.of(Double.NaN, Double.NaN).isFinite());
185
186 Assertions.assertFalse(PolarCoordinates.of(Double.POSITIVE_INFINITY, 0).isFinite());
187 Assertions.assertFalse(PolarCoordinates.of(Double.NEGATIVE_INFINITY, 0).isFinite());
188 Assertions.assertFalse(PolarCoordinates.of(Double.NEGATIVE_INFINITY, Double.NaN).isFinite());
189
190 Assertions.assertFalse(PolarCoordinates.of(0, Double.POSITIVE_INFINITY).isFinite());
191 Assertions.assertFalse(PolarCoordinates.of(0, Double.NEGATIVE_INFINITY).isFinite());
192 Assertions.assertFalse(PolarCoordinates.of(Double.NaN, Double.NEGATIVE_INFINITY).isFinite());
193
194 Assertions.assertFalse(PolarCoordinates.of(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY).isFinite());
195 Assertions.assertFalse(PolarCoordinates.of(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY).isFinite());
196 }
197
198 @Test
199 void testHashCode() {
200
201 final PolarCoordinates a = PolarCoordinates.of(1, 2);
202 final PolarCoordinates b = PolarCoordinates.of(10, 2);
203 final PolarCoordinates c = PolarCoordinates.of(10, 20);
204 final PolarCoordinates d = PolarCoordinates.of(1, 20);
205
206 final PolarCoordinates e = PolarCoordinates.of(1, 2);
207
208
209 Assertions.assertEquals(a.hashCode(), a.hashCode());
210 Assertions.assertEquals(a.hashCode(), e.hashCode());
211
212 Assertions.assertNotEquals(a.hashCode(), b.hashCode());
213 Assertions.assertNotEquals(a.hashCode(), c.hashCode());
214 Assertions.assertNotEquals(a.hashCode(), d.hashCode());
215 }
216
217 @Test
218 void testHashCode_NaNInstancesHaveSameHashCode() {
219
220 final PolarCoordinates a = PolarCoordinates.of(1, Double.NaN);
221 final PolarCoordinates b = PolarCoordinates.of(Double.NaN, 1);
222
223
224 Assertions.assertEquals(a.hashCode(), b.hashCode());
225 }
226
227 @Test
228 void testEquals() {
229
230 final PolarCoordinates a = PolarCoordinates.of(1, 2);
231 final PolarCoordinates b = PolarCoordinates.of(10, 2);
232 final PolarCoordinates c = PolarCoordinates.of(10, 20);
233 final PolarCoordinates d = PolarCoordinates.of(1, 20);
234
235 final PolarCoordinates e = PolarCoordinates.of(1, 2);
236
237
238 GeometryTestUtils.assertSimpleEqualsCases(a);
239 Assertions.assertEquals(a, e);
240
241 Assertions.assertNotEquals(a, b);
242 Assertions.assertNotEquals(a, c);
243 Assertions.assertNotEquals(a, d);
244 }
245
246 @Test
247 void testEquals_NaNInstancesEqual() {
248
249 final PolarCoordinates a = PolarCoordinates.of(1, Double.NaN);
250 final PolarCoordinates b = PolarCoordinates.of(Double.NaN, 1);
251
252
253 Assertions.assertEquals(a, b);
254 }
255
256 @Test
257 void testEqualsAndHashCode_signedZeroConsistency() {
258
259 final PolarCoordinates a = PolarCoordinates.of(0.0, -0.0);
260 final PolarCoordinates b = PolarCoordinates.of(-0.0, 0.0);
261 final PolarCoordinates c = PolarCoordinates.of(0.0, -0.0);
262 final PolarCoordinates d = PolarCoordinates.of(-0.0, 0.0);
263
264
265 Assertions.assertFalse(a.equals(b));
266
267 Assertions.assertTrue(a.equals(c));
268 Assertions.assertEquals(a.hashCode(), c.hashCode());
269
270 Assertions.assertTrue(b.equals(d));
271 Assertions.assertEquals(b.hashCode(), d.hashCode());
272 }
273
274 @Test
275 void testToCartesian() {
276
277 final double sqrt2 = Math.sqrt(2);
278
279
280 checkVector(PolarCoordinates.of(0, 0).toCartesian(), 0, 0);
281
282 checkVector(PolarCoordinates.of(1, 0).toCartesian(), 1, 0);
283 checkVector(PolarCoordinates.of(sqrt2, 0.25 * Math.PI).toCartesian(), 1, 1);
284 checkVector(PolarCoordinates.of(1, Angle.PI_OVER_TWO).toCartesian(), 0, 1);
285
286 checkVector(PolarCoordinates.of(sqrt2, 0.75 * Math.PI).toCartesian(), -1, 1);
287 checkVector(PolarCoordinates.of(1, Math.PI).toCartesian(), -1, 0);
288 checkVector(PolarCoordinates.of(sqrt2, -0.75 * Math.PI).toCartesian(), -1, -1);
289
290 checkVector(PolarCoordinates.of(1, -Angle.PI_OVER_TWO).toCartesian(), 0, -1);
291 checkVector(PolarCoordinates.of(sqrt2, -0.25 * Math.PI).toCartesian(), 1, -1);
292 }
293
294 @Test
295 void testToCartesian_static() {
296
297 final double sqrt2 = Math.sqrt(2);
298
299
300 checkVector(PolarCoordinates.toCartesian(0, 0), 0, 0);
301
302 checkPoint(PolarCoordinates.toCartesian(1, 0), 1, 0);
303 checkPoint(PolarCoordinates.toCartesian(sqrt2, 0.25 * Math.PI), 1, 1);
304 checkPoint(PolarCoordinates.toCartesian(1, Angle.PI_OVER_TWO), 0, 1);
305
306 checkPoint(PolarCoordinates.toCartesian(sqrt2, 0.75 * Math.PI), -1, 1);
307 checkPoint(PolarCoordinates.toCartesian(1, Math.PI), -1, 0);
308 checkPoint(PolarCoordinates.toCartesian(sqrt2, -0.75 * Math.PI), -1, -1);
309
310 checkPoint(PolarCoordinates.toCartesian(1, -Angle.PI_OVER_TWO), 0, -1);
311 checkPoint(PolarCoordinates.toCartesian(sqrt2, -0.25 * Math.PI), 1, -1);
312 }
313
314 @Test
315 void testToCartesian_static_NaNAndInfinite() {
316
317 Assertions.assertTrue(PolarCoordinates.toCartesian(Double.NaN, 0).isNaN());
318 Assertions.assertTrue(PolarCoordinates.toCartesian(0, Double.NaN).isNaN());
319
320 Assertions.assertTrue(PolarCoordinates.toCartesian(Double.POSITIVE_INFINITY, 0).isNaN());
321 Assertions.assertTrue(PolarCoordinates.toCartesian(0, Double.POSITIVE_INFINITY).isNaN());
322 Assertions.assertTrue(PolarCoordinates.toCartesian(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY).isNaN());
323
324 Assertions.assertTrue(PolarCoordinates.toCartesian(Double.NEGATIVE_INFINITY, 0).isNaN());
325 Assertions.assertTrue(PolarCoordinates.toCartesian(0, Double.NEGATIVE_INFINITY).isNaN());
326 Assertions.assertTrue(PolarCoordinates.toCartesian(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY).isNaN());
327 }
328
329 @Test
330 void testToString() {
331
332 final PolarCoordinates polar = PolarCoordinates.of(1, 2);
333 final Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
334
335
336 final String str = polar.toString();
337
338
339 Assertions.assertTrue(pattern.matcher(str).matches(),
340 "Expected string " + str + " to match regex " + pattern);
341 }
342
343 @Test
344 void testParse() {
345
346 checkPolar(PolarCoordinates.parse("(1, 2)"), 1, 2);
347 checkPolar(PolarCoordinates.parse("( -1 , 0.5 )"), 1, 0.5 + Math.PI);
348 checkPolar(PolarCoordinates.parse("(NaN,-Infinity)"), Double.NaN, Double.NEGATIVE_INFINITY);
349 }
350
351 @Test
352 void testParse_failure() {
353
354 Assertions.assertThrows(IllegalArgumentException.class, () -> PolarCoordinates.parse("abc"));
355 }
356
357 @Test
358 void testNormalizeAzimuth() {
359
360 Assertions.assertEquals(0.0, PolarCoordinates.normalizeAzimuth(0), EPS);
361
362 Assertions.assertEquals(Angle.PI_OVER_TWO, PolarCoordinates.normalizeAzimuth(Angle.PI_OVER_TWO), EPS);
363 Assertions.assertEquals(Math.PI, PolarCoordinates.normalizeAzimuth(Math.PI), EPS);
364 Assertions.assertEquals(THREE_PI_OVER_TWO, PolarCoordinates.normalizeAzimuth(THREE_PI_OVER_TWO), EPS);
365 Assertions.assertEquals(0.0, PolarCoordinates.normalizeAzimuth(Angle.TWO_PI), EPS);
366
367 Assertions.assertEquals(THREE_PI_OVER_TWO, PolarCoordinates.normalizeAzimuth(-Angle.PI_OVER_TWO), EPS);
368 Assertions.assertEquals(Math.PI, PolarCoordinates.normalizeAzimuth(-Math.PI), EPS);
369 Assertions.assertEquals(Angle.PI_OVER_TWO, PolarCoordinates.normalizeAzimuth(-Math.PI - Angle.PI_OVER_TWO), EPS);
370 Assertions.assertEquals(0.0, PolarCoordinates.normalizeAzimuth(-Angle.TWO_PI), EPS);
371 }
372
373 @Test
374 void testNormalizeAzimuth_NaNAndInfinite() {
375
376 Assertions.assertEquals(Double.NaN, PolarCoordinates.normalizeAzimuth(Double.NaN), EPS);
377 Assertions.assertEquals(Double.NEGATIVE_INFINITY, PolarCoordinates.normalizeAzimuth(Double.NEGATIVE_INFINITY), EPS);
378 Assertions.assertEquals(Double.POSITIVE_INFINITY, PolarCoordinates.normalizeAzimuth(Double.POSITIVE_INFINITY), EPS);
379 }
380
381 private void checkPolar(final PolarCoordinates polar, final double radius, final double azimuth) {
382 Assertions.assertEquals(radius, polar.getRadius(), EPS);
383 Assertions.assertEquals(azimuth, polar.getAzimuth(), EPS);
384 }
385
386 private void checkVector(final Vector2D v, final double x, final double y) {
387 Assertions.assertEquals(x, v.getX(), EPS);
388 Assertions.assertEquals(y, v.getY(), EPS);
389 }
390
391 private void checkPoint(final Vector2D p, final double x, final double y) {
392 Assertions.assertEquals(x, p.getX(), EPS);
393 Assertions.assertEquals(y, p.getY(), EPS);
394 }
395 }