Coverage for pygeodesy/geodsolve.py : 95%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
<https://GeographicLib.SourceForge.io/html/GeodSolve.1.html>} utility as an (exact) geodesic, but intended I{for testing purposes only}.
Set env variable C{PYGEODESY_GEODSOLVE} to the (fully qualified) path of the C{GeodSolve} executable. '''
_SLASH_, _SPACE_ GeodesicError, GeodSolve12Tuple _getenv, printf, _sys_version_info2 # from pygeodesy.named import callername # from .karney
def _cmd_stdin_(cmd, stdin): # PYCHOK no cover '''(INTERNAL) Cmd line, stdin and caller as sC{str}. ''' c = Fmt.PAREN(callername(up=3)) t = (c,) if stdin is None else (_SLASH_, str(stdin), c) return _SPACE_.join(cmd + t)
'''(NTERNAL) Base class for L{GeodesicSolve} and L{GeodesicLineSolve}. '''
'''Get the I{equatorial} radius, semi-axis (C{meter}). ''' return self.ellipsoid.a
'''(INTERNAL) Get the C{GeodSolve} basic cmd (C{tuple}). ''' + self._e_option \ + self._E_option \ + self._p_option \ + self._u_option + ('-f',)
'''Get the ellipsoid (C{Ellipsoid}). '''
'''Get the C{GeodesicExact} usage (C{bool}). '''
'''Set the C{GeodesicExact} usage (C{bool}).
@arg Exact: If C{True} use C{GeodesicExact}, otherwise use C{Geodesic} (C{bool}). '''
'''Get the ellipsoid's I{flattening} (C{float}), M{(a - b) / a}, C{0} for spherical, negative for prolate. ''' return self.ellipsoid.f
'''(INTERNAL) Invoke C{GeodSolve}, return results as C{GDict}. ''' if len(t) > _len_N: # PYCHOK no cover # unzip instrumented name=value pairs to names and values n, v = zip(*(p.split(_EQUAL_) for p in t[:-_len_N])) v += tuple(t[-_len_N:]) n += GeodSolve12Tuple._Names_ else: if self.verbose: # PYCHOK no cover self._print(_COMMASPACE_.join(map(Fmt.EQUAL, n, map(fstrzs, v))))
'''Get the U{GeodSolve<https://GeographicLib.SourceForge.io/html/GeodSolve.1.html>} executable (C{filename}). '''
'''Set the U{GeodSolve<https://GeographicLib.SourceForge.io/html/GeodSolve.1.html>} executable (C{filename}).
@arg path: The (fully qualified) path to the C{GeodSolve} executable (C{str}).
@raise GeodesicError: Invalid B{C{path}}, B{C{path}} doesn't exist or isn't the C{GeodSolve} executable. ''' raise GeodesicError(GeodSolve=path, status=self.status, txt=_not_(_0_)) finally: # restore in case of error
'''Get the most recent C{GeodSolve} invokation number (C{int}). '''
'''Invoke the C{GeodSolve} executable and return the result.
@arg options: No, one or several C{GeodSolve} command line options (C{str}s). @kwarg stdin: Optional input to pass to C{GeodSolve.stdin} (C{str}).
@return: The C{GeodSolve.stdout} and C{.stderr} output (C{str}).
@raise GeodesicError: On any error, including a non-zero return code from C{GeodSolve}.
@note: The C{GeodSolve} return code is in property L{status}. ''' raise GeodesicError(cmd=_cmd_stdin_(c, i), status=s, txt=_not_(_0_)) if self.verbose: # PYCHOK no cover self._print(r)
'''(INTERNAL) Invoke the C{GeodSolve} executable, with the given B{C{cmd}} line and optional input to B{C{stdin}}. ''' if self.verbose: # PYCHOK no cover t = _cmd_stdin_(cmd, stdin) self._print(t) # executable =sys.executable, # shell =True, stdin =_PIPE, stdout =_PIPE, # PYCHOK kwArgs stderr =_STDOUT, **self._text_True) # invoke and write to stdin raise ValueError(r)
except (IOError, OSError, TypeError, ValueError) as x: raise GeodesicError(cmd=t or _cmd_stdin_(cmd, stdin), txt=str(x))
'''Get the precision, number of (decimal) digits (C{int}). '''
'''Set the precision for C{angles} in C{degrees}, like C{lat}, C{lon}, C{azimuth} and C{arc}.
@arg prec: Number of decimal digits (C{int}, C{0}..L{DIG}).
@note: The precision for C{distance = B{prec} - 5} or up to 10 decimal digits for C{nanometer} and for C{area = B{prec} - 12} or at most C{millimeter} I{squared}. '''
def _print(self, line): # PYCHOK no cover '''(INTERNAL) Print a status line. ''' if self.status is not None: line = _SPACE_(line, Fmt.PAREN(self.status)) printf('%s %d: %s', self.named2, self.invokation, line)
'''Get the C{azi2} direction (C{bool}). '''
'''Set the direction for C{azi2} (C{bool}).
@arg reverse2: If C{True} reverse C{azi2} (C{bool}). '''
'''Get the most recent C{GeodSolve} return code (C{int}, C{str}) or C{None}. '''
'''Return this C{GeodesicSolve} as string.
@kwarg prec: The C{float} precision, number of decimal digits (0..9). Trailing zero decimals are stripped for B{C{prec}} values of 1 and above, but kept for negative B{C{prec}} values. @kwarg sep: Separator to join (C{str}).
@return: GeodesicSolve items (C{str}). ''' invokation=self.invokation, status=self.status)
'''Get the C{lon2} unroll'ing (C{bool}). '''
'''Set unroll'ing for C{lon2} (C{bool}).
@arg unroll: If C{True} unroll C{lon2}, otherwise don't (C{bool}). '''
'''Get the C{verbose} option (C{bool}). '''
'''Set the C{verbose} option.
@arg verbose: Print a message around each C{GeodSolve} invokation (C{bool}). '''
'''Get the result of C{"GeodSolve --version"}. '''
'''Wrapper to invoke I{Karney}'s U{GeodSolve<https://GeographicLib.SourceForge.io/html/GeodSolve.1.html>} as an C{Exact} version of I{Karney}'s Python class U{Geodesic<https://GeographicLib.SourceForge.io/html/ python/code.html#geographiclib.geodesic.Geodesic>}.
@note: Use property C{GeodSolve} or env variable C{PYGEODESY_GEODSOLVE} to specify the (fully qualified) path to the C{GeodSolve} executable.
@note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve} executable for I{every} method call. ''' '''New L{GeodesicSolve} instance.
@arg a_ellipsoid: An ellipsoid (L{Ellipsoid}) or datum (L{Datum}) or the equatorial radius of the ellipsoid (C{scalar}, conventionally in C{meter}), see B{C{f}}. @arg f: The flattening of the ellipsoid (C{scalar}) if B{C{a_ellipsoid}} is specified as C{scalar}. @kwarg name: Optional name (C{str}). '''
'''Set up an L{GeodesicAreaExact} to compute area and perimeter of a polygon.
@kwarg polyline: If C{True} perimeter only, otherwise area and perimeter (C{bool}). @kwarg name: Optional name (C{str}).
@return: A L{GeodesicAreaExact} instance.
@note: The B{C{debug}} setting is passed as C{verbose} to the returned L{GeodesicAreaExact} instance. ''' name=name or self.name) if self.verbose or self.debug: # PYCHOK no cover gaX.verbose = True
'''(INTERNAL) Get the C{GeodSolve} I{Direct} cmd (C{tuple}). '''
'''(INTERNAL) Get the C{GeodSolve} I{Inverse} cmd (C{tuple}). '''
'''Return the C{Direct} result. '''
'''Return the destination lat, lon and reverse azimuth (final bearing) in C{degrees}.
@return: L{Destination3Tuple}C{(lat, lon, final)}. '''
'''(INTERNAL) Get C{_GenDirect}-like result as C{GDict}. ''' raise GeodesicError(arcmode=arcmode, txt=str(NotImplemented))
'''(INTERNAL) Get C{_GenInverse}-like result as C{GDict}, but I{without} C{_SALPs_CALPs_}. '''
'''Return the C{Inverse} result. '''
'''Return the non-negative, I{angular} distance in C{degrees}. ''' # see .FrechetKarney.distance, .HausdorffKarney._distance # and .HeightIDWkarney._distances _, lon2 = unroll180(lon1, lon2, wrap=wrap) # self.LONG_UNROLL d = self._GDictInvoke(self._cmdInverse, False, lat1, lon1, lat2, lon2) # XXX self.DISTANCE needed for 'a12'? return abs(float(d.a12))
'''Return the distance in C{meter} and the forward and reverse azimuths (initial and final bearing) in C{degrees}.
@return: L{Distance3Tuple}C{(distance, initial, final)}. '''
'''Set up an L{GeodesicLineSolve} to compute several points on a single geodesic.
@arg lat1: Latitude of the first point (C{degrees}). @arg lon1: Longitude of the first point (C{degrees}). @arg azi1: Azimuth at the first point (compass C{degrees}). @kwarg caps: Bit-or'ed combination of L{Caps} values specifying the capabilities the L{GeodesicLineSolve} instance should possess, always C{Caps.ALL}.
@return: A L{GeodesicLineSolve} instance.
@note: If the point is at a pole, the azimuth is defined by keeping B{C{lon1}} fixed, writing C{B{lat1} = ±(90 − ε)}, and taking the limit C{ε → 0+}.
@see: C++ U{GeodesicExact.Line <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1GeodesicExact.html>} and Python U{Geodesic.Line<https://GeographicLib.SourceForge.io/html/python/code.html>}. '''
'''Wrapper to invoke I{Karney}'s U{GeodSolve<https://GeographicLib.SourceForge.io/html/GeodSolve.1.html>} as an C{Exact} version of I{Karney}'s Python class U{GeodesicLine<https://GeographicLib.SourceForge.io/html/ python/code.html#geographiclib.geodesicline.GeodesicLine>}.
@note: Use property C{GeodSolve} or env variable C{PYGEODESY_GEODSOLVE} to specify the (fully qualified) path to the C{GeodSolve} executable.
@note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve} executable for I{every} method call. '''
'''New L{GeodesicLineSolve} instance, allowing points to be found along a geodesic starting at C{(B{lat1}, B{lon1})} with azimuth B{C{azi1}}.
@arg geodesic: The geodesic to use (L{GeodesicSolve}). @arg lat1: Latitude of the first point (C{degrees}). @arg lon1: Longitude of the first point (C{degrees}). @arg azi1: Azimuth at the first points (compass C{degrees}). @kwarg caps: Bit-or'ed combination of L{Caps} values specifying the capabilities the L{GeodesicLineSolve} instance should possess, always C{Caps.ALL}. @kwarg name: Optional name (C{str}).
@raise TypeError: Invalid B{C{geodesic}}. '''
except GeodesicError: pass
'''Find the position on the line given B{C{a12}}.
@arg a12: Spherical arc length from the first point to the second point (C{degrees}).
@return: A C{dict} with 12 items C{lat1, lon1, azi1, lat2, lon2, azi2, m12, a12, s12, M12, M21, S12}. ''' return self._GDictInvoke(self._cmdArc, True, a12)
'''Get the azimuth at the first point (compass C{degrees}). ''' return self._lla1[2]
'''Get the sine and cosine of the first point's azimuth (2-tuple C{(sin, cos)}). ''' return sincos2d(self.azi1)
'''Get the capabilities (bit-or'ed C{Caps}). ''' return self._caps
'''Check the available capabilities.
@arg caps: Bit-or'ed combination of L{Caps} values for all capabilities to be checked.
@return: C{True} if I{all} B{C{caps}} are available, C{False} otherwise (C{bool}). ''' return _all_caps(self.caps, caps)
'''(INTERNAL) Get the C{GeodSolve} I{-a -L} cmd (C{tuple}). ''' return self._cmdDistance + ('-a',)
'''(INTERNAL) Get the C{GeodSolve} I{-L} cmd (C{tuple}). '''
'''Get the ellipsoid (C{Ellipsoid}). '''
'''Get the latitude of the first point (C{degrees}). ''' return self._lla1[0]
'''Get the longitude of the first point (C{degrees}). ''' return self._lla1[1]
'''Find the position on the line given B{C{s12}}.
@arg s12: Distance from the first point to the second (C{meter}).
@return: A C{dict} with 12 items C{lat1, lon1, azi1, lat2, lon2, azi2, m12, a12, s12, M12, M21, S12}, possibly C{a12=NAN}. '''
if __name__ == '__main__':
gS = GeodesicSolve(name='Test') if gS.GeodSolve in (_PYGEODESY_GEODSOLVE_, None): # not set gS.GeodSolve = '/opt/local/Cellar/geographiclib/1.51/bin/GeodSolve' # HomeBrew # gS.verbose = True printf('version: %s', gS.version)
r = gS.Direct(40.6, -73.8, 51, 5.5e6) printf('Direct: %r', r, nl=1) # GDict(M12=0.650911, M21=0.651229, S12=39735075134877.09375, a12=49.475527, azi1=51.0, azi2=107.189397, lat1=40.6, lat2=51.884565, lon1=-73.8, lon2=-1.141173, m12=4844148.703101, s12=5500000.0) printf('Direct3: %r', gS.Direct3(40.6, -73.8, 51, 5.5e6)) # Destination3Tuple(lat=51.884565, lon=-1.141173, final=107.189397)
printf('Inverse: %r', gS.Inverse( 40.6, -73.8, 51.6, -0.5), nl=1) # GDict(M12=0.64473, M21=0.645046, S12=40041368848742.53125, a12=49.94131, azi1=51.198883, azi2=107.821777, lat1=40.6, lat2=51.6, lon1=-73.8, lon2=-0.5, m12=4877684.602706, s12=5551759.400319) printf('Inverse1: %r', gS.Inverse1(40.6, -73.8, 51.6, -0.5)) # 49.94131021789904 printf('Inverse3: %r', gS.Inverse3(40.6, -73.8, 51.6, -0.5)) # Distance3Tuple(distance=5551759.400319, initial=51.198883, final=107.821777)
glS = GeodesicLineSolve(gS, 40.6, -73.8, 51) p = glS.Position(5.5e6) printf('Position: %s %r', p == r, p, nl=1) p = glS.ArcPosition(49.475527) printf('ArcPosition: %s %r', p == r, p)
# % python3 -m pygeodesy.geodsolve
# version: /opt/local/Cellar/geographiclib/1.51/bin/GeodSolve: GeographicLib version 1.51
# Direct: GDict(M12=0.650911, M21=0.651229, S12=39735075134877.09375, a12=49.475527, azi1=51.0, azi2=107.189397, lat1=40.6, lat2=51.884565, lon1=-73.8, lon2=-1.141173, m12=4844148.703101, s12=5500000.0) # Direct3: Destination3Tuple(lat=51.884565, lon=-1.141173, final=107.189397)
# Inverse: GDict(M12=0.64473, M21=0.645046, S12=40041368848742.53125, a12=49.94131, azi1=51.198883, azi2=107.821777, lat1=40.6, lat2=51.6, lon1=-73.8, lon2=-0.5, m12=4877684.602706, s12=5551759.400319) # Inverse1: 49.94131021789904 # Inverse3: Distance3Tuple(distance=5551759.400319, initial=51.198883, final=107.821777)
# Position: True GDict(M12=0.650911, M21=0.651229, S12=39735075134877.09375, a12=49.475527, azi1=51.0, azi2=107.189397, lat1=40.6, lat2=51.884565, lon1=-73.8, lon2=-1.141173, m12=4844148.703101, s12=5500000.0) # ArcPosition: False GDict(M12=0.650911, M21=0.651229, S12=39735074737272.734375, a12=49.475527, azi1=51.0, azi2=107.189397, lat1=40.6, lat2=51.884565, lon1=-73.8, lon2=-1.141174, m12=4844148.669561, s12=5499999.948497)
# **) MIT License # # Copyright (C) 2016-2022 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |