Esempio n. 1
0
 def test_Planimeter19(self):
     # Coverage tests, includes Planimeter19 - Planimeter20 (degenerate
     # polygons) + extra cases.
     PlanimeterTest.polygon.Clear()
     num, perimeter, area = PlanimeterTest.polygon.Compute(False, True)
     self.assertTrue(area == 0)
     self.assertTrue(perimeter == 0)
     num, perimeter, area = PlanimeterTest.polygon.TestPoint(
         1, 1, False, True)
     self.assertTrue(area == 0)
     self.assertTrue(perimeter == 0)
     num, perimeter, area = PlanimeterTest.polygon.TestEdge(
         90, 1000, False, True)
     self.assertTrue(Math.isnan(area))
     self.assertTrue(Math.isnan(perimeter))
     PlanimeterTest.polygon.AddPoint(1, 1)
     num, perimeter, area = PlanimeterTest.polygon.Compute(False, True)
     self.assertTrue(area == 0)
     self.assertTrue(perimeter == 0)
     PlanimeterTest.polyline.Clear()
     num, perimeter, area = PlanimeterTest.polyline.Compute(False, True)
     self.assertTrue(perimeter == 0)
     num, perimeter, area = PlanimeterTest.polyline.TestPoint(
         1, 1, False, True)
     self.assertTrue(perimeter == 0)
     num, perimeter, area = PlanimeterTest.polyline.TestEdge(
         90, 1000, False, True)
     self.assertTrue(Math.isnan(perimeter))
     PlanimeterTest.polyline.AddPoint(1, 1)
     num, perimeter, area = PlanimeterTest.polyline.Compute(False, True)
     self.assertTrue(perimeter == 0)
     PlanimeterTest.polygon.AddPoint(1, 1)
     num, perimeter, area = PlanimeterTest.polyline.TestEdge(
         90, 1000, False, True)
     self.assertAlmostEqual(perimeter, 1000, delta=1e-10)
     num, perimeter, area = PlanimeterTest.polyline.TestPoint(
         2, 2, False, True)
     self.assertAlmostEqual(perimeter, 156876.149, delta=0.5e-3)
Esempio n. 2
0
 def test_GeodSolve55(self):
     # Check fix for nan + point on equator or pole not returning all nans in
     # Geodesic::Inverse, found 2015-09-23.
     inv = Geodesic.WGS84.Inverse(Math.nan, 0, 0, 90)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))
     inv = Geodesic.WGS84.Inverse(Math.nan, 0, 90, 9)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))
Esempio n. 3
0
 def test_GeodSolve55(self):
     # Check fix for nan + point on equator or pole not returning all nans in
     # Geodesic::Inverse, found 2015-09-23.
     inv = Geodesic.WGS84.Inverse(Math.nan, 0, 0, 90)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))
     inv = Geodesic.WGS84.Inverse(Math.nan, 0, 90, 9)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))
Esempio n. 4
0
    def test_GeodSolve80(self):
        # Some tests to add code coverage: computing scale in special cases + zero
        # length geodesic (includes GeodSolve80 - GeodSolve83) + using an incapable
        # line.
        inv = Geodesic.WGS84.Inverse(0, 0, 0, 90, Geodesic.GEODESICSCALE)
        self.assertAlmostEqual(inv["M12"], -0.00528427534, delta=0.5e-10)
        self.assertAlmostEqual(inv["M21"], -0.00528427534, delta=0.5e-10)

        inv = Geodesic.WGS84.Inverse(0, 0, 1e-6, 1e-6, Geodesic.GEODESICSCALE)
        self.assertAlmostEqual(inv["M12"], 1, delta=0.5e-10)
        self.assertAlmostEqual(inv["M21"], 1, delta=0.5e-10)

        inv = Geodesic.WGS84.Inverse(20.001, 0, 20.001, 0, Geodesic.ALL)
        self.assertAlmostEqual(inv["a12"], 0, delta=1e-13)
        self.assertAlmostEqual(inv["s12"], 0, delta=1e-8)
        self.assertAlmostEqual(inv["azi1"], 180, delta=1e-13)
        self.assertAlmostEqual(inv["azi2"], 180, delta=1e-13)
        self.assertAlmostEqual(inv["m12"], 0, delta=1e-8)
        self.assertAlmostEqual(inv["M12"], 1, delta=1e-15)
        self.assertAlmostEqual(inv["M21"], 1, delta=1e-15)
        self.assertAlmostEqual(inv["S12"], 0, delta=1e-10)
        self.assertTrue(Math.copysign(1, inv["a12"]) > 0)
        self.assertTrue(Math.copysign(1, inv["s12"]) > 0)
        self.assertTrue(Math.copysign(1, inv["m12"]) > 0)

        inv = Geodesic.WGS84.Inverse(90, 0, 90, 180, Geodesic.ALL)
        self.assertAlmostEqual(inv["a12"], 0, delta=1e-13)
        self.assertAlmostEqual(inv["s12"], 0, delta=1e-8)
        self.assertAlmostEqual(inv["azi1"], 0, delta=1e-13)
        self.assertAlmostEqual(inv["azi2"], 180, delta=1e-13)
        self.assertAlmostEqual(inv["m12"], 0, delta=1e-8)
        self.assertAlmostEqual(inv["M12"], 1, delta=1e-15)
        self.assertAlmostEqual(inv["M21"], 1, delta=1e-15)
        self.assertAlmostEqual(inv["S12"], 127516405431022.0, delta=0.5)

        # An incapable line which can't take distance as input
        line = Geodesic.WGS84.Line(1, 2, 90, Geodesic.LATITUDE)
        dir = line.Position(1000, Geodesic.EMPTY)
        self.assertTrue(Math.isnan(dir["a12"]))
Esempio n. 5
0
    def test_Planimeter0(self):
        # Check fix for pole-encircling bug found 2011-03-16
        points = [[89, 0], [89, 90], [89, 180], [89, 270]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 631819.8745, delta=1e-4)
        self.assertAlmostEqual(area, 24952305678.0, delta=1)
        points = [[-89, 0], [-89, 90], [-89, 180], [-89, 270]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 631819.8745, delta=1e-4)
        self.assertAlmostEqual(area, -24952305678.0, delta=1)

        points = [[0, -1], [-1, 0], [0, 1], [1, 0]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 627598.2731, delta=1e-4)
        self.assertAlmostEqual(area, 24619419146.0, delta=1)

        points = [[90, 0], [0, 0], [0, 90]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 30022685, delta=1)
        self.assertAlmostEqual(area, 63758202715511.0, delta=1)
        num, perimeter, area = PlanimeterTest.PolyLength(points)
        self.assertAlmostEqual(perimeter, 20020719, delta=1)
        self.assertTrue(Math.isnan(area))
Esempio n. 6
0
    def test_Planimeter0(self):
        # Check fix for pole-encircling bug found 2011-03-16
        points = [[89, 0], [89, 90], [89, 180], [89, 270]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 631819.8745, delta = 1e-4)
        self.assertAlmostEqual(area, 24952305678.0, delta = 1)
        points = [[-89, 0], [-89, 90], [-89, 180], [-89, 270]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 631819.8745, delta = 1e-4)
        self.assertAlmostEqual(area, -24952305678.0, delta = 1)

        points = [[0, -1], [-1, 0], [0, 1], [1, 0]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 627598.2731, delta = 1e-4)
        self.assertAlmostEqual(area, 24619419146.0, delta = 1)

        points = [[90, 0], [0, 0], [0, 90]]
        num, perimeter, area = PlanimeterTest.Planimeter(points)
        self.assertAlmostEqual(perimeter, 30022685, delta = 1)
        self.assertAlmostEqual(area, 63758202715511.0, delta = 1)
        num, perimeter, area = PlanimeterTest.PolyLength(points)
        self.assertAlmostEqual(perimeter, 20020719, delta = 1)
        self.assertTrue(Math.isnan(area))
Esempio n. 7
0
  def __init__(self, geod, lat1, lon1, azi1,
               caps = GeodesicCapability.STANDARD |
               GeodesicCapability.DISTANCE_IN,
               salp1 = Math.nan, calp1 = Math.nan):
    """Construct a GeodesicLine object

    :param geod: a :class:`~geographiclib.geodesic.Geodesic` object
    :param lat1: latitude of the first point in degrees
    :param lon1: longitude of the first point in degrees
    :param azi1: azimuth at the first point in degrees
    :param caps: the :ref:`capabilities <outmask>`

    This creates an object allowing points along a geodesic starting at
    (*lat1*, *lon1*), with azimuth *azi1* to be found.  The default
    value of *caps* is STANDARD | DISTANCE_IN.  The optional parameters
    *salp1* and *calp1* should not be supplied; they are part of the
    private interface.

    """

    from geographiclib.geodesic import Geodesic
    self.a = geod.a
    """The equatorial radius in meters (readonly)"""
    self.f = geod.f
    """The flattening (readonly)"""
    self._b = geod._b
    self._c2 = geod._c2
    self._f1 = geod._f1
    self.caps = (caps | Geodesic.LATITUDE | Geodesic.AZIMUTH |
                  Geodesic.LONG_UNROLL)
    """the capabilities (readonly)"""

    # Guard against underflow in salp0
    self.lat1 = Math.LatFix(lat1)
    """the latitude of the first point in degrees (readonly)"""
    self.lon1 = lon1
    """the longitude of the first point in degrees (readonly)"""
    if Math.isnan(salp1) or Math.isnan(calp1):
      self.azi1 = Math.AngNormalize(azi1)
      self.salp1, self.calp1 = Math.sincosd(Math.AngRound(azi1))
    else:
      self.azi1 = azi1
      """the azimuth at the first point in degrees (readonly)"""
      self.salp1 = salp1
      """the sine of the azimuth at the first point (readonly)"""
      self.calp1 = calp1
      """the cosine of the azimuth at the first point (readonly)"""

    # real cbet1, sbet1
    sbet1, cbet1 = Math.sincosd(Math.AngRound(lat1)); sbet1 *= self._f1
    # Ensure cbet1 = +epsilon at poles
    sbet1, cbet1 = Math.norm(sbet1, cbet1); cbet1 = max(Geodesic.tiny_, cbet1)
    self._dn1 = math.sqrt(1 + geod._ep2 * Math.sq(sbet1))

    # Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0),
    self._salp0 = self.salp1 * cbet1 # alp0 in [0, pi/2 - |bet1|]
    # Alt: calp0 = hypot(sbet1, calp1 * cbet1).  The following
    # is slightly better (consider the case salp1 = 0).
    self._calp0 = math.hypot(self.calp1, self.salp1 * sbet1)
    # Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1).
    # sig = 0 is nearest northward crossing of equator.
    # With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line).
    # With bet1 =  pi/2, alp1 = -pi, sig1 =  pi/2
    # With bet1 = -pi/2, alp1 =  0 , sig1 = -pi/2
    # Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1).
    # With alp0 in (0, pi/2], quadrants for sig and omg coincide.
    # No atan2(0,0) ambiguity at poles since cbet1 = +epsilon.
    # With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi.
    self._ssig1 = sbet1; self._somg1 = self._salp0 * sbet1
    self._csig1 = self._comg1 = (cbet1 * self.calp1
                                 if sbet1 != 0 or self.calp1 != 0 else 1)
    # sig1 in (-pi, pi]
    self._ssig1, self._csig1 = Math.norm(self._ssig1, self._csig1)
    # No need to normalize
    # self._somg1, self._comg1 = Math.norm(self._somg1, self._comg1)

    self._k2 = Math.sq(self._calp0) * geod._ep2
    eps = self._k2 / (2 * (1 + math.sqrt(1 + self._k2)) + self._k2)

    if self.caps & Geodesic.CAP_C1:
      self._A1m1 = Geodesic._A1m1f(eps)
      self._C1a = list(range(Geodesic.nC1_ + 1))
      Geodesic._C1f(eps, self._C1a)
      self._B11 = Geodesic._SinCosSeries(
        True, self._ssig1, self._csig1, self._C1a)
      s = math.sin(self._B11); c = math.cos(self._B11)
      # tau1 = sig1 + B11
      self._stau1 = self._ssig1 * c + self._csig1 * s
      self._ctau1 = self._csig1 * c - self._ssig1 * s
      # Not necessary because C1pa reverts C1a
      #    _B11 = -_SinCosSeries(true, _stau1, _ctau1, _C1pa)

    if self.caps & Geodesic.CAP_C1p:
      self._C1pa = list(range(Geodesic.nC1p_ + 1))
      Geodesic._C1pf(eps, self._C1pa)

    if self.caps & Geodesic.CAP_C2:
      self._A2m1 = Geodesic._A2m1f(eps)
      self._C2a = list(range(Geodesic.nC2_ + 1))
      Geodesic._C2f(eps, self._C2a)
      self._B21 = Geodesic._SinCosSeries(
        True, self._ssig1, self._csig1, self._C2a)

    if self.caps & Geodesic.CAP_C3:
      self._C3a = list(range(Geodesic.nC3_))
      geod._C3f(eps, self._C3a)
      self._A3c = -self.f * self._salp0 * geod._A3f(eps)
      self._B31 = Geodesic._SinCosSeries(
        True, self._ssig1, self._csig1, self._C3a)

    if self.caps & Geodesic.CAP_C4:
      self._C4a = list(range(Geodesic.nC4_))
      geod._C4f(eps, self._C4a)
      # Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0)
      self._A4 = Math.sq(self.a) * self._calp0 * self._salp0 * geod._e2
      self._B41 = Geodesic._SinCosSeries(
        False, self._ssig1, self._csig1, self._C4a)
    self.s13 = Math.nan
    """the distance between point 1 and point 3 in meters (readonly)"""
    self.a13 = Math.nan
    """the arc length between point 1 and point 3 in degrees (readonly)"""
Esempio n. 8
0
 def test_GeodSolve84(self):
     # Tests for python implementation to check fix for range errors with
     # {fmod,sin,cos}(inf) (includes GeodSolve84 - GeodSolve91).
     dir = Geodesic.WGS84.Direct(0, 0, 90, Math.inf)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
     dir = Geodesic.WGS84.Direct(0, 0, 90, Math.nan)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
     dir = Geodesic.WGS84.Direct(0, 0, Math.inf, 1000)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
     dir = Geodesic.WGS84.Direct(0, 0, Math.nan, 1000)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
     dir = Geodesic.WGS84.Direct(0, Math.inf, 90, 1000)
     self.assertTrue(dir["lat1"] == 0)
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(dir["azi2"] == 90)
     dir = Geodesic.WGS84.Direct(0, Math.nan, 90, 1000)
     self.assertTrue(dir["lat1"] == 0)
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(dir["azi2"] == 90)
     dir = Geodesic.WGS84.Direct(Math.inf, 0, 90, 1000)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
     dir = Geodesic.WGS84.Direct(Math.nan, 0, 90, 1000)
     self.assertTrue(Math.isnan(dir["lat2"]))
     self.assertTrue(Math.isnan(dir["lon2"]))
     self.assertTrue(Math.isnan(dir["azi2"]))
Esempio n. 9
0
 def test_GeodSolve14(self):
     # Check fix for inverse ignoring lon12 = nan
     inv = Geodesic.WGS84.Inverse(0, 0, 1, Math.nan)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))
Esempio n. 10
0
    def __init__(self,
                 geod,
                 lat1,
                 lon1,
                 azi1,
                 caps=GeodesicCapability.STANDARD
                 | GeodesicCapability.DISTANCE_IN,
                 salp1=Math.nan,
                 calp1=Math.nan):
        """Construct a GeodesicLine object

    :param geod: a :class:`~geographiclib.geodesic.Geodesic` object
    :param lat1: latitude of the first point in degrees
    :param lon1: longitude of the first point in degrees
    :param azi1: azimuth at the first point in degrees
    :param caps: the :ref:`capabilities <outmask>`

    This creates an object allowing points along a geodesic starting at
    (*lat1*, *lon1*), with azimuth *azi1* to be found.  The default
    value of *caps* is STANDARD | DISTANCE_IN.  The optional parameters
    *salp1* and *calp1* should not be supplied; they are part of the
    private interface.

    """

        from geographiclib.geodesic import Geodesic
        self.a = geod.a
        """The equatorial radius in meters (readonly)"""
        self.f = geod.f
        """The flattening (readonly)"""
        self._b = geod._b
        self._c2 = geod._c2
        self._f1 = geod._f1
        self.caps = (caps | Geodesic.LATITUDE | Geodesic.AZIMUTH
                     | Geodesic.LONG_UNROLL)
        """the capabilities (readonly)"""

        # Guard against underflow in salp0
        self.lat1 = Math.LatFix(lat1)
        """the latitude of the first point in degrees (readonly)"""
        self.lon1 = lon1
        """the longitude of the first point in degrees (readonly)"""
        if Math.isnan(salp1) or Math.isnan(calp1):
            self.azi1 = Math.AngNormalize(azi1)
            self.salp1, self.calp1 = Math.sincosd(Math.AngRound(azi1))
        else:
            self.azi1 = azi1
            """the azimuth at the first point in degrees (readonly)"""
            self.salp1 = salp1
            """the sine of the azimuth at the first point (readonly)"""
            self.calp1 = calp1
            """the cosine of the azimuth at the first point (readonly)"""

        # real cbet1, sbet1
        sbet1, cbet1 = Math.sincosd(Math.AngRound(lat1))
        sbet1 *= self._f1
        # Ensure cbet1 = +epsilon at poles
        sbet1, cbet1 = Math.norm(sbet1, cbet1)
        cbet1 = max(Geodesic.tiny_, cbet1)
        self._dn1 = math.sqrt(1 + geod._ep2 * Math.sq(sbet1))

        # Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0),
        self._salp0 = self.salp1 * cbet1  # alp0 in [0, pi/2 - |bet1|]
        # Alt: calp0 = hypot(sbet1, calp1 * cbet1).  The following
        # is slightly better (consider the case salp1 = 0).
        self._calp0 = math.hypot(self.calp1, self.salp1 * sbet1)
        # Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1).
        # sig = 0 is nearest northward crossing of equator.
        # With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line).
        # With bet1 =  pi/2, alp1 = -pi, sig1 =  pi/2
        # With bet1 = -pi/2, alp1 =  0 , sig1 = -pi/2
        # Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1).
        # With alp0 in (0, pi/2], quadrants for sig and omg coincide.
        # No atan2(0,0) ambiguity at poles since cbet1 = +epsilon.
        # With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi.
        self._ssig1 = sbet1
        self._somg1 = self._salp0 * sbet1
        self._csig1 = self._comg1 = (cbet1 * self.calp1
                                     if sbet1 != 0 or self.calp1 != 0 else 1)
        # sig1 in (-pi, pi]
        self._ssig1, self._csig1 = Math.norm(self._ssig1, self._csig1)
        # No need to normalize
        # self._somg1, self._comg1 = Math.norm(self._somg1, self._comg1)

        self._k2 = Math.sq(self._calp0) * geod._ep2
        eps = self._k2 / (2 * (1 + math.sqrt(1 + self._k2)) + self._k2)

        if self.caps & Geodesic.CAP_C1:
            self._A1m1 = Geodesic._A1m1f(eps)
            self._C1a = list(range(Geodesic.nC1_ + 1))
            Geodesic._C1f(eps, self._C1a)
            self._B11 = Geodesic._SinCosSeries(True, self._ssig1, self._csig1,
                                               self._C1a)
            s = math.sin(self._B11)
            c = math.cos(self._B11)
            # tau1 = sig1 + B11
            self._stau1 = self._ssig1 * c + self._csig1 * s
            self._ctau1 = self._csig1 * c - self._ssig1 * s
            # Not necessary because C1pa reverts C1a
            #    _B11 = -_SinCosSeries(true, _stau1, _ctau1, _C1pa)

        if self.caps & Geodesic.CAP_C1p:
            self._C1pa = list(range(Geodesic.nC1p_ + 1))
            Geodesic._C1pf(eps, self._C1pa)

        if self.caps & Geodesic.CAP_C2:
            self._A2m1 = Geodesic._A2m1f(eps)
            self._C2a = list(range(Geodesic.nC2_ + 1))
            Geodesic._C2f(eps, self._C2a)
            self._B21 = Geodesic._SinCosSeries(True, self._ssig1, self._csig1,
                                               self._C2a)

        if self.caps & Geodesic.CAP_C3:
            self._C3a = list(range(Geodesic.nC3_))
            geod._C3f(eps, self._C3a)
            self._A3c = -self.f * self._salp0 * geod._A3f(eps)
            self._B31 = Geodesic._SinCosSeries(True, self._ssig1, self._csig1,
                                               self._C3a)

        if self.caps & Geodesic.CAP_C4:
            self._C4a = list(range(Geodesic.nC4_))
            geod._C4f(eps, self._C4a)
            # Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0)
            self._A4 = Math.sq(self.a) * self._calp0 * self._salp0 * geod._e2
            self._B41 = Geodesic._SinCosSeries(False, self._ssig1, self._csig1,
                                               self._C4a)
        self.s13 = Math.nan
        """the distance between point 1 and point 3 in meters (readonly)"""
        self.a13 = Math.nan
        """the arc length between point 1 and point 3 in degrees (readonly)"""
Esempio n. 11
0
 def test_GeodSolve14(self):
     # Check fix for inverse ignoring lon12 = nan
     inv = Geodesic.WGS84.Inverse(0, 0, 1, Math.nan)
     self.assertTrue(Math.isnan(inv["azi1"]))
     self.assertTrue(Math.isnan(inv["azi2"]))
     self.assertTrue(Math.isnan(inv["s12"]))