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;
    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          // act/assert
    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          // act/assert
    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          // arrange
    55          final double delta = 1e-6;
    56
    57          // act/assert
    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          // act/assert
    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          // act/assert
    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         // arrange
    103         final double sqrt2 = Math.sqrt(2);
    104
    105         // act/assert
    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         // arrange
    123         final double sqrt2 = Math.sqrt(2);
    124
    125         // act/assert
    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         // arrange
    143         final PolarCoordinates p = PolarCoordinates.of(1, 0);
    144
    145         // act/assert
    146         Assertions.assertEquals(2, p.getDimension());
    147     }
    148
    149     @Test
    150     void testIsNaN() {
    151         // act/assert
    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         // act/assert
    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         // act/assert
    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         // arrange
    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         // act/assert
    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         // arrange
    220         final PolarCoordinates a = PolarCoordinates.of(1, Double.NaN);
    221         final PolarCoordinates b = PolarCoordinates.of(Double.NaN, 1);
    222
    223         // act/assert
    224         Assertions.assertEquals(a.hashCode(), b.hashCode());
    225     }
    226
    227     @Test
    228     void testEquals() {
    229         // arrange
    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         // act/assert
    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         // arrange
    249         final PolarCoordinates a = PolarCoordinates.of(1, Double.NaN);
    250         final PolarCoordinates b = PolarCoordinates.of(Double.NaN, 1);
    251
    252         // act/assert
    253         Assertions.assertEquals(a, b);
    254     }
    255
    256     @Test
    257     void testEqualsAndHashCode_signedZeroConsistency() {
    258         // arrange
    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         // act/assert
    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         // arrange
    277         final double sqrt2 = Math.sqrt(2);
    278
    279         // act/assert
    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         // arrange
    297         final double sqrt2 = Math.sqrt(2);
    298
    299         // act/assert
    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         // act/assert
    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         // arrange
    332         final PolarCoordinates polar = PolarCoordinates.of(1, 2);
    333         final Pattern pattern = Pattern.compile("\\(1.{0,2}, 2.{0,2}\\)");
    334
    335         // act
    336         final String str = polar.toString();
    337
    338         // assert
    339         Assertions.assertTrue(pattern.matcher(str).matches(),
    340                 "Expected string " + str + " to match regex " + pattern);
    341     }
    342
    343     @Test
    344     void testParse() {
    345         // act/assert
    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         // act/assert
    354         Assertions.assertThrows(IllegalArgumentException.class, () -> PolarCoordinates.parse("abc"));
    355     }
    356
    357     @Test
    358     void testNormalizeAzimuth() {
    359         // act/assert
    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         // act/assert
    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 }