def __init__(self, a, f): """ Construct a Geodesic object for ellipsoid with major radius a and flattening f. """ self._a = float(a) self._f = float(f) if f <= 1 else 1.0 / f self._f1 = 1 - self._f self._e2 = self._f * (2 - self._f) self._ep2 = self._e2 / Math.sq(self._f1) # e2 / (1 - e2) self._n = self._f / (2 - self._f) self._b = self._a * self._f1 # authalic radius squared self._c2 = ( Math.sq(self._a) + Math.sq(self._b) * (1 if self._e2 == 0 else (Math.atanh(math.sqrt(self._e2)) if self._e2 > 0 else math.atan( math.sqrt(-self._e2))) / math.sqrt(abs(self._e2)))) / 2 # The sig12 threshold for "really short" self._etol2 = 0.01 * Geodesic.tol2_ / max(0.1, math.sqrt(abs( self._e2))) if not (Math.isfinite(self._a) and self._a > 0): raise ValueError("Major radius is not positive") if not (Math.isfinite(self._b) and self._b > 0): raise ValueError("Minor radius is not positive") self._A3x = range(Geodesic.nA3x_) self._C3x = range(Geodesic.nC3x_) self._C4x = range(Geodesic.nC4x_) self.A3coeff() self.C3coeff() self.C4coeff()
def __init__(self, a, f): """ Construct a Geodesic object for ellipsoid with major radius a and flattening f. """ self._a = float(a) self._f = float(f) if f <= 1 else 1.0/f self._f1 = 1 - self._f self._e2 = self._f * (2 - self._f) self._ep2 = self._e2 / Math.sq(self._f1) # e2 / (1 - e2) self._n = self._f / ( 2 - self._f) self._b = self._a * self._f1 # authalic radius squared self._c2 = (Math.sq(self._a) + Math.sq(self._b) * (1 if self._e2 == 0 else (Math.atanh(math.sqrt(self._e2)) if self._e2 > 0 else math.atan(math.sqrt(-self._e2))) / math.sqrt(abs(self._e2))))/2 # The sig12 threshold for "really short" self._etol2 = 0.01 * Geodesic.tol2_ / max(0.1, math.sqrt(abs(self._e2))) if not(Math.isfinite(self._a) and self._a > 0): raise ValueError("Major radius is not positive") if not(Math.isfinite(self._b) and self._b > 0): raise ValueError("Minor radius is not positive") self._A3x = range(Geodesic.nA3x_) self._C3x = range(Geodesic.nC3x_) self._C4x = range(Geodesic.nC4x_) self.A3coeff() self.C3coeff() self.C4coeff()
def __init__(self, a, f): """Construct a Geodesic object :param a: the equatorial radius of the ellipsoid in meters :param f: the flattening of the ellipsoid An exception is thrown if *a* or the polar semi-axis *b* = *a* (1 - *f*) is not a finite positive quantity. """ self.a = float(a) """The equatorial radius in meters (readonly)""" self.f = float(f) """The flattening (readonly)""" self._f1 = 1 - self.f self._e2 = self.f * (2 - self.f) self._ep2 = self._e2 / Math.sq(self._f1) # e2 / (1 - e2) self._n = self.f / ( 2 - self.f) self._b = self.a * self._f1 # authalic radius squared self._c2 = (Math.sq(self.a) + Math.sq(self._b) * (1 if self._e2 == 0 else (Math.atanh(math.sqrt(self._e2)) if self._e2 > 0 else math.atan(math.sqrt(-self._e2))) / math.sqrt(abs(self._e2))))/2 # The sig12 threshold for "really short". Using the auxiliary sphere # solution with dnm computed at (bet1 + bet2) / 2, the relative error in # the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. # (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given # f and sig12, the max error occurs for lines near the pole. If the old # rule for computing dnm = (dn1 + dn2)/2 is used, then the error increases # by a factor of 2.) Setting this equal to epsilon gives sig12 = etol2. # Here 0.1 is a safety factor (error decreased by 100) and max(0.001, # abs(f)) stops etol2 getting too large in the nearly spherical case. self._etol2 = 0.1 * Geodesic.tol2_ / math.sqrt( max(0.001, abs(self.f)) * min(1.0, 1-self.f/2) / 2 ) if not(Math.isfinite(self.a) and self.a > 0): raise ValueError("Equatorial radius is not positive") if not(Math.isfinite(self._b) and self._b > 0): raise ValueError("Polar semi-axis is not positive") self._A3x = list(range(Geodesic.nA3x_)) self._C3x = list(range(Geodesic.nC3x_)) self._C4x = list(range(Geodesic.nC4x_)) self._A3coeff() self._C3coeff() self._C4coeff()
def __init__(self, a, f): """ Construct a Geodesic object for ellipsoid with major radius a and flattening f. """ self._a = float(a) self._f = float(f) if f <= 1 else 1.0 / f self._f1 = 1 - self._f self._e2 = self._f * (2 - self._f) self._ep2 = self._e2 / Math.sq(self._f1) # e2 / (1 - e2) self._n = self._f / (2 - self._f) self._b = self._a * self._f1 # authalic radius squared self._c2 = ( Math.sq(self._a) + Math.sq(self._b) * (1 if self._e2 == 0 else (Math.atanh(math.sqrt(self._e2)) if self._e2 > 0 else math.atan( math.sqrt(-self._e2))) / math.sqrt(abs(self._e2)))) / 2 # The sig12 threshold for "really short". Using the auxiliary sphere # solution with dnm computed at (bet1 + bet2) / 2, the relative error in # the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. # (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given # f and sig12, the max error occurs for lines near the pole. If the old # rule for computing dnm = (dn1 + dn2)/2 is used, then the error increases # by a factor of 2.) Setting this equal to epsilon gives sig12 = etol2. # Here 0.1 is a safety factor (error decreased by 100) and max(0.001, # abs(f)) stops etol2 getting too large in the nearly spherical case. self._etol2 = 0.1 * Geodesic.tol2_ / math.sqrt( max(0.001, abs(self._f)) * min(1.0, 1 - self._f / 2) / 2) if not (Math.isfinite(self._a) and self._a > 0): raise ValueError("Major radius is not positive") if not (Math.isfinite(self._b) and self._b > 0): raise ValueError("Minor radius is not positive") self._A3x = list(range(Geodesic.nA3x_)) self._C3x = list(range(Geodesic.nC3x_)) self._C4x = list(range(Geodesic.nC4x_)) self.A3coeff() self.C3coeff() self.C4coeff()
def __init__(self, a, f): """Construct a Geodesic object for ellipsoid with major radius a and flattening f. """ self._a = float(a) self._f = float(f) if f <= 1 else 1.0/f self._f1 = 1 - self._f self._e2 = self._f * (2 - self._f) self._ep2 = self._e2 / Math.sq(self._f1) # e2 / (1 - e2) self._n = self._f / ( 2 - self._f) self._b = self._a * self._f1 # authalic radius squared self._c2 = (Math.sq(self._a) + Math.sq(self._b) * (1 if self._e2 == 0 else (Math.atanh(math.sqrt(self._e2)) if self._e2 > 0 else math.atan(math.sqrt(-self._e2))) / math.sqrt(abs(self._e2))))/2 # The sig12 threshold for "really short". Using the auxiliary sphere # solution with dnm computed at (bet1 + bet2) / 2, the relative error in # the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. # (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given # f and sig12, the max error occurs for lines near the pole. If the old # rule for computing dnm = (dn1 + dn2)/2 is used, then the error increases # by a factor of 2.) Setting this equal to epsilon gives sig12 = etol2. # Here 0.1 is a safety factor (error decreased by 100) and max(0.001, # abs(f)) stops etol2 getting too large in the nearly spherical case. self._etol2 = 0.1 * Geodesic.tol2_ / math.sqrt( max(0.001, abs(self._f)) * min(1.0, 1-self._f/2) / 2 ) if not(Math.isfinite(self._a) and self._a > 0): raise ValueError("Major radius is not positive") if not(Math.isfinite(self._b) and self._b > 0): raise ValueError("Minor radius is not positive") self._A3x = list(range(Geodesic.nA3x_)) self._C3x = list(range(Geodesic.nC3x_)) self._C4x = list(range(Geodesic.nC4x_)) self.A3coeff() self.C3coeff() self.C4coeff()
def CheckDistance(s): """Check that s is a legal distance""" if not (Math.isfinite(s)): raise ValueError("distance " + str(s) + " not a finite number")
def CheckDistance(s): if not (Math.isfinite(s)): raise ValueError("distance " + str(s) + " not a finite number")
def _GenPosition(self, arcmode, s12_a12, outmask): """Private: General solution of position along geodesic""" from geographiclib.geodesic import Geodesic a12 = lat2 = lon2 = azi2 = s12 = m12 = M12 = M21 = S12 = Math.nan outmask &= self.caps & Geodesic.OUT_MASK if not (arcmode or (self.caps & (Geodesic.OUT_MASK & Geodesic.DISTANCE_IN))): # Uninitialized or impossible distance calculation requested return a12, lat2, lon2, azi2, s12, m12, M12, M21, S12 # Avoid warning about uninitialized B12. B12 = 0.0; AB1 = 0.0 if arcmode: # Interpret s12_a12 as spherical arc length sig12 = math.radians(s12_a12) ssig12, csig12 = Math.sincosd(s12_a12) else: # Interpret s12_a12 as distance tau12 = s12_a12 / (self._b * (1 + self._A1m1)) tau12 = tau12 if Math.isfinite(tau12) else Math.nan s = math.sin(tau12); c = math.cos(tau12) # tau2 = tau1 + tau12 B12 = - Geodesic._SinCosSeries(True, self._stau1 * c + self._ctau1 * s, self._ctau1 * c - self._stau1 * s, self._C1pa) sig12 = tau12 - (B12 - self._B11) ssig12 = math.sin(sig12); csig12 = math.cos(sig12) if abs(self.f) > 0.01: # Reverted distance series is inaccurate for |f| > 1/100, so correct # sig12 with 1 Newton iteration. The following table shows the # approximate maximum error for a = WGS_a() and various f relative to # GeodesicExact. # erri = the error in the inverse solution (nm) # errd = the error in the direct solution (series only) (nm) # errda = the error in the direct solution (series + 1 Newton) (nm) # # f erri errd errda # -1/5 12e6 1.2e9 69e6 # -1/10 123e3 12e6 765e3 # -1/20 1110 108e3 7155 # -1/50 18.63 200.9 27.12 # -1/100 18.63 23.78 23.37 # -1/150 18.63 21.05 20.26 # 1/150 22.35 24.73 25.83 # 1/100 22.35 25.03 25.31 # 1/50 29.80 231.9 30.44 # 1/20 5376 146e3 10e3 # 1/10 829e3 22e6 1.5e6 # 1/5 157e6 3.8e9 280e6 ssig2 = self._ssig1 * csig12 + self._csig1 * ssig12 csig2 = self._csig1 * csig12 - self._ssig1 * ssig12 B12 = Geodesic._SinCosSeries(True, ssig2, csig2, self._C1a) serr = ((1 + self._A1m1) * (sig12 + (B12 - self._B11)) - s12_a12 / self._b) sig12 = sig12 - serr / math.sqrt(1 + self._k2 * Math.sq(ssig2)) ssig12 = math.sin(sig12); csig12 = math.cos(sig12) # Update B12 below # real omg12, lam12, lon12 # real ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2 # sig2 = sig1 + sig12 ssig2 = self._ssig1 * csig12 + self._csig1 * ssig12 csig2 = self._csig1 * csig12 - self._ssig1 * ssig12 dn2 = math.sqrt(1 + self._k2 * Math.sq(ssig2)) if outmask & ( Geodesic.DISTANCE | Geodesic.REDUCEDLENGTH | Geodesic.GEODESICSCALE): if arcmode or abs(self.f) > 0.01: B12 = Geodesic._SinCosSeries(True, ssig2, csig2, self._C1a) AB1 = (1 + self._A1m1) * (B12 - self._B11) # sin(bet2) = cos(alp0) * sin(sig2) sbet2 = self._calp0 * ssig2 # Alt: cbet2 = hypot(csig2, salp0 * ssig2) cbet2 = math.hypot(self._salp0, self._calp0 * csig2) if cbet2 == 0: # I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case cbet2 = csig2 = Geodesic.tiny_ # tan(alp0) = cos(sig2)*tan(alp2) salp2 = self._salp0; calp2 = self._calp0 * csig2 # No need to normalize if outmask & Geodesic.DISTANCE: s12 = self._b * ((1 + self._A1m1) * sig12 + AB1) if arcmode else s12_a12 if outmask & Geodesic.LONGITUDE: # tan(omg2) = sin(alp0) * tan(sig2) somg2 = self._salp0 * ssig2; comg2 = csig2 # No need to normalize E = Math.copysign(1, self._salp0) # East or west going? # omg12 = omg2 - omg1 omg12 = (E * (sig12 - (math.atan2( ssig2, csig2) - math.atan2( self._ssig1, self._csig1)) + (math.atan2(E * somg2, comg2) - math.atan2(E * self._somg1, self._comg1))) if outmask & Geodesic.LONG_UNROLL else math.atan2(somg2 * self._comg1 - comg2 * self._somg1, comg2 * self._comg1 + somg2 * self._somg1)) lam12 = omg12 + self._A3c * ( sig12 + (Geodesic._SinCosSeries(True, ssig2, csig2, self._C3a) - self._B31)) lon12 = math.degrees(lam12) lon2 = (self.lon1 + lon12 if outmask & Geodesic.LONG_UNROLL else Math.AngNormalize(Math.AngNormalize(self.lon1) + Math.AngNormalize(lon12))) if outmask & Geodesic.LATITUDE: lat2 = Math.atan2d(sbet2, self._f1 * cbet2) if outmask & Geodesic.AZIMUTH: azi2 = Math.atan2d(salp2, calp2) if outmask & (Geodesic.REDUCEDLENGTH | Geodesic.GEODESICSCALE): B22 = Geodesic._SinCosSeries(True, ssig2, csig2, self._C2a) AB2 = (1 + self._A2m1) * (B22 - self._B21) J12 = (self._A1m1 - self._A2m1) * sig12 + (AB1 - AB2) if outmask & Geodesic.REDUCEDLENGTH: # Add parens around (_csig1 * ssig2) and (_ssig1 * csig2) to ensure # accurate cancellation in the case of coincident points. m12 = self._b * (( dn2 * (self._csig1 * ssig2) - self._dn1 * (self._ssig1 * csig2)) - self._csig1 * csig2 * J12) if outmask & Geodesic.GEODESICSCALE: t = (self._k2 * (ssig2 - self._ssig1) * (ssig2 + self._ssig1) / (self._dn1 + dn2)) M12 = csig12 + (t * ssig2 - csig2 * J12) * self._ssig1 / self._dn1 M21 = csig12 - (t * self._ssig1 - self._csig1 * J12) * ssig2 / dn2 if outmask & Geodesic.AREA: B42 = Geodesic._SinCosSeries(False, ssig2, csig2, self._C4a) # real salp12, calp12 if self._calp0 == 0 or self._salp0 == 0: # alp12 = alp2 - alp1, used in atan2 so no need to normalize salp12 = salp2 * self.calp1 - calp2 * self.salp1 calp12 = calp2 * self.calp1 + salp2 * self.salp1 else: # tan(alp) = tan(alp0) * sec(sig) # tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1) # = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2) # If csig12 > 0, write # csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1) # else # csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1 # No need to normalize salp12 = self._calp0 * self._salp0 * ( self._csig1 * (1 - csig12) + ssig12 * self._ssig1 if csig12 <= 0 else ssig12 * (self._csig1 * ssig12 / (1 + csig12) + self._ssig1)) calp12 = (Math.sq(self._salp0) + Math.sq(self._calp0) * self._csig1 * csig2) S12 = (self._c2 * math.atan2(salp12, calp12) + self._A4 * (B42 - self._B41)) a12 = s12_a12 if arcmode else math.degrees(sig12) return a12, lat2, lon2, azi2, s12, m12, M12, M21, S12