def thomas(lat1, lon1, lat2, lon2, datum=Datums.WGS84, wrap=False): '''Compute the distance between two (ellipsoidal) points using U{Thomas'<https://apps.DTIC.mil/dtic/tr/fulltext/u2/703541.pdf>} formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg datum: Ellipsoidal datum to use (L{Datum}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes). @raise TypeError: Invalid B{C{datum}}. @see: Functions L{thomas_}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert}, L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine}, L{vincentys} and method L{Ellipsoid.distance2}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = thomas_(Phi_(lat2, name=_lat2_), Phi_(lat1, name=_lat1_), radians(d), datum=datum) return r * datum.ellipsoid.a
def cosineForsytheAndoyerLambert(lat1, lon1, lat2, lon2, datum=Datums.WGS84, wrap=False): '''Compute the distance between two (ellipsoidal) points using the U{Forsythe-Andoyer-Lambert correction<https://www2.UNB.CA/gge/Pubs/TR77.pdf>} of the U{Law of Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg datum: Ellipsoidal datum to use (L{Datum}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes). @raise TypeError: Invalid B{C{datum}}. @see: Functions L{cosineForsytheAndoyerLambert_}, L{cosineAndoyerLambert}, L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and method L{Ellipsoid.distance2}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = cosineForsytheAndoyerLambert_(Phi_(lat2, name=_lat2_), Phi_(lat1, name=_lat1_), radians(d), datum=datum) return r * datum.ellipsoid.a
def cosineLaw(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two points using the U{spherical Law of Cosines <https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} fromula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @raise TypeError: Invalid B{C{datum}}. @see: Functions L{cosineLaw_}, L{equirectangular}, L{euclidean}, L{flatLocal}, L{flatPolar}, L{haversine}, L{vincentys} and method L{Ellipsoid.distance2}. @note: See note at function L{vincentys_}. ''' r = Radius(radius) if r: d, _ = unroll180(lon1, lon2, wrap=wrap) r *= cosineLaw_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d)) return r
def cosineAndoyerLambert(lat1, lon1, lat2, lon2, datum=Datums.WGS84, wrap=False): '''Compute the distance between two (ellipsoidal) points using the U{Andoyer-Lambert correction<https://navlib.net/wp-content/uploads/ 2013/10/admiralty-manual-of-navigation-vol-1-1964-english501c.pdf>} of the U{Law of Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} fromula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg datum: Ellipsoidal datum to use (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes). @raise TypeError: Invalid B{C{datum}}. @see: Functions L{cosineAndoyerLambert_}, L{cosineForsytheAndoyerLambert}, L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and method L{Ellipsoid.distance2}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = cosineAndoyerLambert_(Phi_(lat2=lat2), Phi_(lat1=lat1), radians(d), datum=datum) return r * datum.ellipsoid.a
def vincentys(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two (spherical) points using U{Vincenty's<https://WikiPedia.org/wiki/Great-circle_distance>} spherical formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @see: Functions L{vincentys_}, L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}, L{flatPolar}, L{haversine} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}. @note: See note at function L{vincentys_}. ''' r = Radius(radius) if r: d, _ = unroll180(lon1, lon2, wrap=wrap) r *= vincentys_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d)) return r
def flatPolar(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two (spherical) points using the U{polar coordinate flat-Earth <https://WikiPedia.org/wiki/Geographical_distance#Polar_coordinate_flat-Earth_formula>} formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @see: Functions L{flatPolar_}, L{cosineLaw}, L{flatLocal}, L{equirectangular}, L{euclidean}, L{haversine} and L{vincentys}. ''' r = Radius(radius) if r: d, _ = unroll180(lon1, lon2, wrap=wrap) r *= flatPolar_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d)) return r
def haversine(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two (spherical) points using the U{Haversine<https://www.Movable-Type.co.UK/scripts/latlong.html>} formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @see: U{Distance between two (spherical) points <https://www.EdWilliams.org/avform.htm#Dist>}, functions L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}, L{flatPolar}, L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}. @note: See note at function L{vincentys_}. ''' r = Radius(radius) if r: d, _ = unroll180(lon1, lon2, wrap=wrap) r *= haversine_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d)) return r
def euclidean(lat1, lon1, lat2, lon2, radius=R_M, adjust=True, wrap=False): '''Approximate the C{Euclidian} distance between two (spherical) points. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg adjust: Adjust the longitudinal delta by the cosine of the mean latitude (C{bool}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @see: U{Distance between two (spherical) points <https://www.EdWilliams.org/avform.htm#Dist>}, functions L{euclidean_}, L{cosineLaw}, L{equirectangular}, L{flatLocal}, L{flatPolar}, L{haversine}, L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}. ''' r = Radius(radius) if r: d, _ = unroll180(lon1, lon2, wrap=wrap) r *= euclidean_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d), adjust=adjust) return r
def flatLocal(lat1, lon1, lat2, lon2, datum=Datums.WGS84, wrap=False): '''Compute the distance between two (ellipsoidal) points using the U{ellipsoidal Earth to plane projection <https://WikiPedia.org/wiki/Geographical_distance#Ellipsoidal_Earth_projected_to_a_plane>} fromula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg datum: Optional, (ellipsoidal) datum to use (L{Datum}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes). @raise TypeError: Invalid B{C{datum}}. @note: The meridional and prime_vertical radii of curvature are taken and scaled at the mean latitude. @see: Functions L{flatLocal_}, L{cosineLaw}, L{flatPolar}, L{equirectangular}, L{euclidean}, L{haversine}, L{vincentys}, method L{Ellipsoid.distance2} and U{local, flat earth approximation <https://www.edwilliams.org/avform.htm#flat>}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) return flatLocal_(Phi_(lat2, name='lat2'), Phi_(lat1, name='lat1'), radians(d), datum=datum)
def flatLocal(lat1, lon1, lat2, lon2, datum=Datums.WGS84, wrap=False): '''Compute the distance between two (ellipsoidal) points using the U{ellipsoidal Earth to plane projection<https://WikiPedia.org/ wiki/Geographical_distance#Ellipsoidal_Earth_projected_to_a_plane>} aka U{Hubeny<https://www.OVG.AT/de/vgi/files/pdf/3781/>} formula. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg datum: Ellipsoidal datum to use (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes). @raise TypeError: Invalid B{C{datum}}. @note: The meridional and prime_vertical radii of curvature are taken and scaled at the mean of both latitude. @see: Functions L{flatLocal_}/L{hubeny_}, L{cosineLaw}, L{flatPolar}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert}, L{equirectangular}, L{euclidean}, L{haversine}, L{thomas}, L{vincentys}, method L{Ellipsoid.distance2} and U{local, flat earth approximation <https://www.EdWilliams.org/avform.htm#flat>}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) return flatLocal_(Phi_(lat2=lat2), Phi_(lat1=lat1), radians(d), datum=datum)
def __init__(self, latlon0, par1, par2=None, E0=0, N0=0, k0=1, opt3=0, name=NN, auth=NN): '''New Lambert conformal conic projection. @arg latlon0: Origin with (ellipsoidal) datum (C{LatLon}). @arg par1: First standard parallel (C{degrees90}). @kwarg par2: Optional, second standard parallel (C{degrees90}). @kwarg E0: Optional, false easting (C{meter}). @kwarg N0: Optional, false northing (C{meter}). @kwarg k0: Optional scale factor (C{scalar}). @kwarg opt3: Optional meridian (C{degrees180}). @kwarg name: Optional name of the conic (C{str}). @kwarg auth: Optional authentication authority (C{str}). @return: A Lambert projection (L{Conic}). @raise TypeError: Non-ellipsoidal B{C{latlon0}}. @raise ValueError: Invalid B{C{par1}}, B{C{par2}}, B{C{E0}}, B{C{N0}}, B{C{k0}} or B{C{opt3}}. @example: >>> from pygeodesy import Conic, Datums, ellipsoidalNvector >>> ll0 = ellipsoidalNvector.LatLon(23, -96, datum=Datums.NAD27) >>> Snyder = Conic(ll0, 33, 45, E0=0, N0=0, name='Snyder') ''' if latlon0 is not None: _xinstanceof(_LLEB, latlon0=latlon0) self._phi0, self._lam0 = latlon0.philam self._par1 = Phi_(par1, name=_par1_) self._par2 = self._par1 if par2 is None else Phi_(par2, name=_par2_) if k0 != 1: self._k0 = Scalar_(k0, name=_k0_) if E0: self._E0 = Northing(E0, name=_E0_, falsed=True) if N0: self._N0 = Easting(N0, name=_N0_, falsed=True) if opt3: self._opt3 = Lam_(opt3, name='opt3') self.toDatum(latlon0.datum)._dup2(self) self._register(Conics, name) elif name: self.name = name if auth: self._auth = str(auth)
def heightOf(angle, distance, radius=R_M): '''Determine the height above the (spherical) earth after traveling along a straight line at a given tilt. @arg angle: Tilt angle above horizontal (C{degrees}). @arg distance: Distance along the line (C{meter} or same units as B{C{radius}}). @kwarg radius: Optional mean earth radius (C{meter}). @return: Height (C{meter}, same units as B{C{distance}} and B{C{radius}}). @raise ValueError: Invalid B{C{angle}}, B{C{distance}} or B{C{radius}}. @see: U{MultiDop geog_lib.GeogBeamHt<https://GitHub.com/NASA/MultiDop>} (U{Shapiro et al. 2009, JTECH <https://Journals.AMetSoc.org/doi/abs/10.1175/2009JTECHA1256.1>} and U{Potvin et al. 2012, JTECH <https://Journals.AMetSoc.org/doi/abs/10.1175/JTECH-D-11-00019.1>}). ''' r = h = Radius(radius) d = abs(Distance(distance)) if d > h: d, h = h, d if d > EPS: d = d / h # PyChecker chokes on ... /= ... s = sin(Phi_(angle, name='angle', clip=180)) s = fsum_(1, 2 * s * d, d**2) if s > 0: return h * sqrt(s) - r raise InvalidError(angle=angle, distance=distance, radius=radius)
def philam(self): '''Get the lat- and longitude ((L{PhiLam2Tuple}C{(phi, lam)}). ''' if self._philam is None: r = self.latlon self._philam = PhiLam2Tuple(Phi_(r.lat), Lam_(r.lon)) return self._xnamed(self._philam)
def bearing(lat1, lon1, lat2, lon2, **options): '''Compute the initial or final bearing (forward or reverse azimuth) between a (spherical) start and end point. @arg lat1: Start latitude (C{degrees}). @arg lon1: Start longitude (C{degrees}). @arg lat2: End latitude (C{degrees}). @arg lon2: End longitude (C{degrees}). @kwarg options: Optional keyword arguments for function L{bearing_}. @return: Initial or final bearing (compass C{degrees360}) or zero if start and end point coincide. ''' return degrees( bearing_(Phi_(lat1, name='lat1'), Lam_(lon1, name='lon1'), Phi_(lat2, name='lat2'), Lam_(lon2, name='lon2'), **options))
def degrees2m(deg, radius=R_M, lat=0): '''Convert angle to distance along the equator or along a parallel at an other latitude. @arg deg: Angle (C{degrees}). @kwarg radius: Mean earth radius (C{meter}). @kwarg lat: Parallel latitude (C{degrees90}, C{str}). @return: Distance (C{meter}, same units as B{C{radius}}). @raise RangeError: Latitude B{C{lat}} outside valid range and L{rangerrors} set to C{True}. @raise ValueError: Invalid B{C{deg}}, B{C{radius}} or B{C{lat}}. @see: Function L{m2degrees}. ''' m = Lam_(deg, name=_deg_, clip=0) * Radius(radius) if lat: m *= cos(Phi_(lat)) return float(m)
def m2degrees(meter, radius=R_M, lat=0): '''Convert distance to angle along equator or along a parallel at an other latitude. @arg meter: Distance (C{meter}, same units as B{C{radius}}). @kwarg radius: Mean earth radius (C{meter}). @kwarg lat: Parallel latitude (C{degrees90}, C{str}). @return: Angle (C{degrees}). @raise RangeError: Latitude B{C{lat}} outside valid range and L{rangerrors} set to C{True}. @raise ValueError: Invalid B{C{meter}}, B{C{radius}} or B{C{lat}}. @see: Function L{degrees2m}. ''' r = Radius(radius) if lat: r *= cos(Phi_(lat)) return degrees(Meter(meter) / r)
from pygeodesy.lazily import _ALL_LAZY from pygeodesy.named import EasNor2Tuple, LatLonDatum3Tuple, \ _NamedBase, nameof, _xnamed from pygeodesy.streprs import enstr2 from pygeodesy.units import Easting, Lam_, Northing, Phi_, Scalar from pygeodesy.utily import degrees90, degrees180, sincos2 from math import cos, radians, sin, sqrt, tan __all__ = _ALL_LAZY.osgr __version__ = '20.09.01' _10um = 1e-5 #: (INTERNAL) 0.01 millimeter (C{meter}) _100km = 100000 #: (INTERNAL) 100 km (int meter) _A0 = Phi_(49) #: (INTERNAL) NatGrid true origin latitude, 49°N. _B0 = Lam_(-2) #: (INTERNAL) NatGrid true origin longitude, 2°W. _E0 = Easting(400e3) #: (INTERNAL) Easting of true origin (C{meter}). _N0 = Northing(-100e3) #: (INTERNAL) Northing of true origin (C{meter}). _F0 = Scalar( 0.9996012717) #: (INTERNAL) NatGrid scale of central meridian (C{float}). _Datums_OSGB36 = Datums.OSGB36 #: (INTERNAL) Airy130 ellipsoid _latlon_ = 'latlon' _no_convertDatum_ = 'no .convertDatum' _ord_A = ord('A') _TRIPS = 33 #: (INTERNAL) .toLatLon convergence def _ll2datum(ll, datum, name): '''(INTERNAL) Convert datum if needed.