pygeodesy 24.6.9__py2.py3-none-any.whl → 24.7.7__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/METADATA +2 -2
- PyGeodesy-24.7.7.dist-info/RECORD +117 -0
- pygeodesy/__init__.py +39 -32
- pygeodesy/__main__.py +6 -1
- pygeodesy/albers.py +2 -2
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/auxAngle.py +40 -39
- pygeodesy/auxilats/auxDLat.py +3 -2
- pygeodesy/auxilats/auxLat.py +16 -18
- pygeodesy/auxilats/auxily.py +1 -1
- pygeodesy/azimuthal.py +10 -10
- pygeodesy/basics.py +16 -4
- pygeodesy/booleans.py +4 -4
- pygeodesy/cartesianBase.py +11 -14
- pygeodesy/css.py +14 -18
- pygeodesy/datums.py +6 -6
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/classes.py +25 -4
- pygeodesy/deprecated/datum.py +3 -3
- pygeodesy/deprecated/functions.py +6 -8
- pygeodesy/dms.py +23 -27
- pygeodesy/ecef.py +4 -4
- pygeodesy/elevations.py +4 -4
- pygeodesy/ellipsoidalBase.py +23 -28
- pygeodesy/ellipsoidalBaseDI.py +19 -23
- pygeodesy/ellipsoidalExact.py +3 -3
- pygeodesy/ellipsoidalGeodSolve.py +15 -23
- pygeodesy/ellipsoidalKarney.py +37 -60
- pygeodesy/ellipsoidalNvector.py +38 -44
- pygeodesy/ellipsoidalVincenty.py +11 -14
- pygeodesy/ellipsoids.py +107 -101
- pygeodesy/errors.py +109 -48
- pygeodesy/etm.py +32 -44
- pygeodesy/formy.py +55 -58
- pygeodesy/frechet.py +18 -20
- pygeodesy/fsums.py +3 -3
- pygeodesy/gars.py +3 -4
- pygeodesy/geodesici.py +1696 -0
- pygeodesy/geodesicw.py +15 -15
- pygeodesy/geodesicx/__init__.py +4 -4
- pygeodesy/geodesicx/gx.py +34 -55
- pygeodesy/geodesicx/gxbases.py +20 -8
- pygeodesy/geodesicx/gxline.py +93 -88
- pygeodesy/geodsolve.py +108 -59
- pygeodesy/geohash.py +26 -34
- pygeodesy/geoids.py +28 -37
- pygeodesy/hausdorff.py +17 -18
- pygeodesy/heights.py +2 -2
- pygeodesy/internals.py +46 -13
- pygeodesy/interns.py +2 -2
- pygeodesy/karney.py +78 -15
- pygeodesy/ktm.py +13 -16
- pygeodesy/latlonBase.py +17 -19
- pygeodesy/lazily.py +28 -25
- pygeodesy/lcc.py +28 -31
- pygeodesy/ltp.py +7 -8
- pygeodesy/ltpTuples.py +71 -73
- pygeodesy/mgrs.py +8 -9
- pygeodesy/named.py +19 -10
- pygeodesy/nvectorBase.py +9 -10
- pygeodesy/osgr.py +9 -9
- pygeodesy/points.py +6 -6
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/aux_.py +5 -5
- pygeodesy/rhumb/bases.py +30 -31
- pygeodesy/rhumb/ekx.py +3 -4
- pygeodesy/rhumb/solve.py +21 -22
- pygeodesy/solveBase.py +177 -123
- pygeodesy/sphericalBase.py +10 -11
- pygeodesy/sphericalNvector.py +13 -13
- pygeodesy/sphericalTrigonometry.py +86 -97
- pygeodesy/streprs.py +4 -34
- pygeodesy/triaxials.py +48 -43
- pygeodesy/units.py +208 -275
- pygeodesy/unitsBase.py +115 -107
- pygeodesy/ups.py +26 -31
- pygeodesy/utily.py +8 -8
- pygeodesy/utm.py +35 -40
- pygeodesy/utmups.py +43 -46
- pygeodesy/utmupsBase.py +8 -9
- pygeodesy/vector3d.py +26 -27
- pygeodesy/vector3dBase.py +6 -7
- pygeodesy/webmercator.py +19 -21
- pygeodesy/wgrs.py +18 -20
- PyGeodesy-24.6.9.dist-info/RECORD +0 -116
- {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/top_level.txt +0 -0
pygeodesy/errors.py
CHANGED
|
@@ -14,19 +14,20 @@ C{PYGEODESY_EXCEPTION_CHAINING=std} or to any non-empty string.
|
|
|
14
14
|
# from pygeodesy.basics import isint, isodd, issubclassof, itemsorted, _xinstanceof, _zip # _MODS
|
|
15
15
|
# from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase, LatLonEllipsoidalBase # _MODS
|
|
16
16
|
# from pygeodesy import errors # _MODS, _MODS.getattr
|
|
17
|
-
from pygeodesy.internals import _plural, _tailof
|
|
17
|
+
from pygeodesy.internals import _dunder_nameof_, _plural, _tailof
|
|
18
18
|
from pygeodesy.interns import MISSING, NN, _a_, _an_, _and_, _clip_, _COLON_, _COLONSPACE_, \
|
|
19
19
|
_COMMASPACE_, _datum_, _ellipsoidal_, _incompatible_, _invalid_, \
|
|
20
|
-
_keyword_, _len_, _not_, _or_, _SPACE_, _specified_,
|
|
21
|
-
_vs_, _with_
|
|
20
|
+
_keyword_, _LatLon_, _len_, _not_, _or_, _SPACE_, _specified_, \
|
|
21
|
+
_UNDER_, _vs_, _with_
|
|
22
22
|
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv, _PYTHON_X_DEV
|
|
23
|
-
# from pygeodesy
|
|
23
|
+
# from pygeodesy import streprs as _streprs # _MODS
|
|
24
|
+
# from pygeodesy.unitsBase import Str # _MODS
|
|
24
25
|
# from pygeodesy.vector3dBase import Vector3dBase # _MODS
|
|
25
26
|
|
|
26
27
|
from copy import copy as _copy
|
|
27
28
|
|
|
28
29
|
__all__ = _ALL_LAZY.errors # _ALL_DOCS('_InvalidError', '_IsnotError') _under
|
|
29
|
-
__version__ = '24.
|
|
30
|
+
__version__ = '24.07.07'
|
|
30
31
|
|
|
31
32
|
_argument_ = 'argument'
|
|
32
33
|
_box_ = 'box'
|
|
@@ -35,6 +36,7 @@ _limiterrors = True # in .formy
|
|
|
35
36
|
_name_value_ = repr('name=value')
|
|
36
37
|
_rangerrors = True # in .dms
|
|
37
38
|
_region_ = 'region'
|
|
39
|
+
_streprs = _MODS.into(streprs=__name__)
|
|
38
40
|
_vs__ = _SPACE_(NN, _vs_, NN)
|
|
39
41
|
|
|
40
42
|
try:
|
|
@@ -155,7 +157,7 @@ class _UnexpectedError(TypeError): # note, a TypeError!
|
|
|
155
157
|
n = _and(a, _plural(_keyword_, n)) if n else a
|
|
156
158
|
else:
|
|
157
159
|
n = _plural(_SPACE_(_keyword_, _argument_), n)
|
|
158
|
-
u =
|
|
160
|
+
u = _streprs.unstr(_SPACE_(n, NN), *args, **kwds)
|
|
159
161
|
# _error_init(TypeError, self, (u,), txt_not_=_expected_)
|
|
160
162
|
TypeError.__init__(self, _SPACE_(u, _not_, _expected_))
|
|
161
163
|
|
|
@@ -208,8 +210,8 @@ class CrossError(_ValueError):
|
|
|
208
210
|
|
|
209
211
|
|
|
210
212
|
class GeodesicError(_ValueError):
|
|
211
|
-
'''Error raised for
|
|
212
|
-
L{pygeodesy.geodesicw} or L{pygeodesy.karney}.
|
|
213
|
+
'''Error raised for convergence or other issues in L{geodesicx<pygeodesy.geodesicx>},
|
|
214
|
+
L{geodesicw<pygeodesy.geodesicw>} or L{karney<pygeodesy.karney>}.
|
|
213
215
|
'''
|
|
214
216
|
pass
|
|
215
217
|
|
|
@@ -243,17 +245,17 @@ class LenError(_ValueError): # in .ecef, .fmath, .heights, .iters, .named
|
|
|
243
245
|
|
|
244
246
|
ns, vs, txt, x = _ns_vs_txt_x(**lens_txt)
|
|
245
247
|
ns = _COMMASPACE_.join(ns)
|
|
246
|
-
t =
|
|
248
|
+
t = _streprs.Fmt.PAREN(where.__name__, ns)
|
|
247
249
|
vs = _vs__.join(map(str, vs))
|
|
248
250
|
t = _SPACE_(t, _len_, vs)
|
|
249
251
|
_ValueError.__init__(self, t, txt=txt, cause=x)
|
|
250
252
|
|
|
251
253
|
|
|
252
254
|
class LimitError(_ValueError):
|
|
253
|
-
'''Error raised for lat- or longitudinal values or deltas exceeding
|
|
254
|
-
|
|
255
|
-
L{pygeodesy.equirectangular4}, C{nearestOn*} and
|
|
256
|
-
or methods with C{limit} or C{options} keyword arguments.
|
|
255
|
+
'''Error raised for lat- or longitudinal values or deltas exceeding the given
|
|
256
|
+
B{C{limit}} in functions L{equirectangular<pygeodesy.equirectangular>},
|
|
257
|
+
L{equirectangular4<pygeodesy.equirectangular4>}, C{nearestOn*} and
|
|
258
|
+
C{simplify*} or methods with C{limit} or C{options} keyword arguments.
|
|
257
259
|
|
|
258
260
|
@see: Subclass L{UnitError}.
|
|
259
261
|
'''
|
|
@@ -285,26 +287,25 @@ class PointsError(_ValueError): # in .clipy, .frechet, ...
|
|
|
285
287
|
|
|
286
288
|
|
|
287
289
|
class RangeError(_ValueError):
|
|
288
|
-
'''Error raised for lat- or longitude values outside the B{C{clip}},
|
|
289
|
-
B{C{
|
|
290
|
-
L{pygeodesy.
|
|
291
|
-
|
|
292
|
-
L{pygeodesy.clipRadians}.
|
|
290
|
+
'''Error raised for lat- or longitude values outside the B{C{clip}}, B{C{clipLat}},
|
|
291
|
+
B{C{clipLon}} in functions L{parse3llh<pygeodesy.dms.parse3llh>}, L{parseDMS<pygeodesy.dms.parseDMS>},
|
|
292
|
+
L{parseDMS2<pygeodesy.dms.parseDMS2>} and L{parseRad<pygeodesy.dms.parseRad>} or the B{C{limit}} set
|
|
293
|
+
with functions L{clipDegrees<pygeodesy.dms.clipDegrees>} and L{clipRadians<pygeodesy.dms.clipRadians>}.
|
|
293
294
|
|
|
294
|
-
@see: Function L{pygeodesy.rangerrors}.
|
|
295
|
+
@see: Function L{rangerrors<pygeodesy.errors.rangerrors>}.
|
|
295
296
|
'''
|
|
296
297
|
pass
|
|
297
298
|
|
|
298
299
|
|
|
299
300
|
class RhumbError(_ValueError):
|
|
300
|
-
'''Error raised for a L{pygeodesy.rhumb.aux_}, L{pygeodesy.rhumb.ekx}
|
|
301
|
-
|
|
301
|
+
'''Error raised for a rhumb L{aux_<pygeodesy.rhumb.aux_>}, L{ekx<pygeodesy.rhumb.ekx>} or
|
|
302
|
+
L{solve<pygeodesy.rhumb.solve>} issue.
|
|
302
303
|
'''
|
|
303
304
|
pass
|
|
304
305
|
|
|
305
306
|
|
|
306
307
|
class TriangleError(_ValueError): # in .resections, .vector2d
|
|
307
|
-
'''Error raised for triangle,
|
|
308
|
+
'''Error raised for triangle, intersection or resection issues.
|
|
308
309
|
'''
|
|
309
310
|
pass
|
|
310
311
|
|
|
@@ -330,15 +331,15 @@ class SciPyWarning(PointsError):
|
|
|
330
331
|
|
|
331
332
|
|
|
332
333
|
class TRFError(_ValueError): # in .ellipsoidalBase, .trf, .units
|
|
333
|
-
'''Terrestrial Reference Frame (TRF), L{Epoch}, L{RefFrame}
|
|
334
|
-
|
|
334
|
+
'''Terrestrial Reference Frame (TRF), L{Epoch}, L{RefFrame} or L{RefFrame}
|
|
335
|
+
conversion issue.
|
|
335
336
|
'''
|
|
336
337
|
pass
|
|
337
338
|
|
|
338
339
|
|
|
339
340
|
class UnitError(LimitError): # in .named, .units
|
|
340
|
-
'''Default exception for L{units} issues for a value exceeding the
|
|
341
|
-
|
|
341
|
+
'''Default exception for L{units} issues for a value exceeding the C{low}
|
|
342
|
+
or C{high} limit.
|
|
342
343
|
'''
|
|
343
344
|
pass
|
|
344
345
|
|
|
@@ -460,8 +461,8 @@ def exception_chaining(exc=None):
|
|
|
460
461
|
@return: If C{B{exc} is None}, return C{True} if exception
|
|
461
462
|
chaining is enabled for PyGeodesy errors, C{False}
|
|
462
463
|
if turned off and C{None} if not available. If
|
|
463
|
-
B{
|
|
464
|
-
or C{None}.
|
|
464
|
+
C{B{exc} is not None}, return it's error I{cause}
|
|
465
|
+
or C{None} if there is none.
|
|
465
466
|
|
|
466
467
|
@note: To enable exception chaining for C{pygeodesy} errors,
|
|
467
468
|
set env var C{PYGEODESY_EXCEPTION_CHAINING} to any
|
|
@@ -511,23 +512,22 @@ def isError(exc):
|
|
|
511
512
|
_X(exc) if isinstance(exc, Exception) else None)
|
|
512
513
|
|
|
513
514
|
|
|
514
|
-
def _IsnotError(*
|
|
515
|
+
def _IsnotError(*types__, **name_value_Error_cause): # name=value [, Error=TypeError, cause=None]
|
|
515
516
|
'''Create a C{TypeError} for an invalid C{name=value} type.
|
|
516
517
|
|
|
517
|
-
@arg
|
|
518
|
+
@arg types__: One or more types or type names.
|
|
518
519
|
@kwarg name_value_Error_cause: One C{B{name}=value} pair and optionally,
|
|
519
|
-
keyword
|
|
520
|
-
|
|
520
|
+
keyword arguments C{B{Error}=TypeError} and C{B{cause}=None}
|
|
521
|
+
for exception chaining.
|
|
521
522
|
|
|
522
523
|
@return: A C{TypeError} or an B{C{Error}} instance.
|
|
523
524
|
'''
|
|
524
|
-
|
|
525
|
-
|
|
525
|
+
x, kwds = _xkwds_pop2(name_value_Error_cause, cause=None)
|
|
526
|
+
E, kwds = _xkwds_pop2(kwds, Error=TypeError)
|
|
527
|
+
n, v = _xkwds_item2(kwds)
|
|
526
528
|
|
|
527
|
-
n
|
|
528
|
-
|
|
529
|
-
n = _MODS.streprs.Fmt.PARENSPACED(n, repr(v))
|
|
530
|
-
t = _not_(_an(_or(*nouns)) if nouns else _specified_)
|
|
529
|
+
n = _streprs.Fmt.PARENSPACED(n, repr(v))
|
|
530
|
+
t = _not_(_an(_or(*_dunder_nameof_(*types__))) if types__ else _specified_)
|
|
531
531
|
return _XError(E, n, txt=t, cause=x)
|
|
532
532
|
|
|
533
533
|
|
|
@@ -553,14 +553,13 @@ def _or(*words):
|
|
|
553
553
|
return _and_or(_or_, *words)
|
|
554
554
|
|
|
555
555
|
|
|
556
|
-
def _parseX(parser, *args, **
|
|
556
|
+
def _parseX(parser, *args, **Error_name_values): # name=value[, ..., Error=ParseError]
|
|
557
557
|
'''(INTERNAL) Invoke a parser and handle exceptions.
|
|
558
558
|
|
|
559
|
-
@arg parser: The parser (C{callable}).
|
|
559
|
+
@arg parser: The parser (C{callable(*B{args}}).
|
|
560
560
|
@arg args: Any B{C{parser}} arguments (any C{type}s).
|
|
561
|
-
@kwarg
|
|
562
|
-
|
|
563
|
-
argument to override the default.
|
|
561
|
+
@kwarg Error_name_values: Optional C{B{Error}=ParseError}
|
|
562
|
+
and number of C{B{name}=value} pairs.
|
|
564
563
|
|
|
565
564
|
@return: Parser result.
|
|
566
565
|
|
|
@@ -570,7 +569,7 @@ def _parseX(parser, *args, **name_values_Error): # name=value[, ..., Error=Pars
|
|
|
570
569
|
return parser(*args)
|
|
571
570
|
except Exception as x:
|
|
572
571
|
E = type(x) if isError(x) else ParseError
|
|
573
|
-
E, kwds = _xkwds_pop2(
|
|
572
|
+
E, kwds = _xkwds_pop2(Error_name_values, Error=E)
|
|
574
573
|
raise _XError(E, **_xkwds(kwds, cause=x))
|
|
575
574
|
|
|
576
575
|
|
|
@@ -603,11 +602,11 @@ def _xAssertionError(where, *args, **kwds):
|
|
|
603
602
|
'''(INTERNAL) Embellish an C{AssertionError} with/-out exception chaining.
|
|
604
603
|
'''
|
|
605
604
|
x, kwds = _xkwds_pop2(kwds, cause=None)
|
|
606
|
-
w =
|
|
605
|
+
w = _streprs.unstr(where, *args, **kwds)
|
|
607
606
|
return _AssertionError(w, txt=None, cause=x)
|
|
608
607
|
|
|
609
608
|
|
|
610
|
-
def _xattr(obj, **name_default):
|
|
609
|
+
def _xattr(obj, **name_default):
|
|
611
610
|
'''(INTERNAL) Get an C{obj}'s attribute by C{name}.
|
|
612
611
|
'''
|
|
613
612
|
if len(name_default) == 1:
|
|
@@ -616,6 +615,34 @@ def _xattr(obj, **name_default): # see .strerprs._xattrs
|
|
|
616
615
|
raise _xAssertionError(_xattr, obj, **name_default)
|
|
617
616
|
|
|
618
617
|
|
|
618
|
+
def _xattrs(inst, other, *attrs): # see .errors._xattr
|
|
619
|
+
'''(INTERNAL) Copy attribute values from B{C{other}} to B{C{inst}}.
|
|
620
|
+
|
|
621
|
+
@arg inst: Object to copy attribute values to (any C{type}).
|
|
622
|
+
@arg other: Object to copy attribute values from (any C{type}).
|
|
623
|
+
@arg attrs: One or more attribute names (C{str}s).
|
|
624
|
+
|
|
625
|
+
@return: Object B{C{inst}}, updated.
|
|
626
|
+
|
|
627
|
+
@raise AttributeError: An B{C{attrs}} doesn't exist or isn't settable.
|
|
628
|
+
'''
|
|
629
|
+
def _getattr(o, a):
|
|
630
|
+
if hasattr(o, a):
|
|
631
|
+
return getattr(o, a)
|
|
632
|
+
try:
|
|
633
|
+
n = o._DOT_(a)
|
|
634
|
+
except AttributeError:
|
|
635
|
+
n = _streprs.Fmt.DOT(a)
|
|
636
|
+
raise _AttributeError(o, name=n)
|
|
637
|
+
|
|
638
|
+
for a in attrs:
|
|
639
|
+
s = _getattr(other, a)
|
|
640
|
+
g = _getattr(inst, a)
|
|
641
|
+
if (g is None and s is not None) or g != s:
|
|
642
|
+
setattr(inst, a, s) # not settable?
|
|
643
|
+
return inst
|
|
644
|
+
|
|
645
|
+
|
|
619
646
|
def _xcallable(**names_callables):
|
|
620
647
|
'''(INTERNAL) Check one or more C{callable}s.
|
|
621
648
|
'''
|
|
@@ -651,9 +678,9 @@ def _xellipsoidal(**name_value): # see _xellipsoidall elel
|
|
|
651
678
|
raise _xAssertionError(_xellipsoidal, name_value)
|
|
652
679
|
|
|
653
680
|
|
|
654
|
-
def _xellipsoidall(point): # see _xellipsoidal
|
|
681
|
+
def _xellipsoidall(point): # ... elel, see _xellipsoidal
|
|
655
682
|
'''(INTERNAL) Check an ellipsoidal C{point}, return C{True}
|
|
656
|
-
if geodetic latlon
|
|
683
|
+
if geodetic latlon, C{False} if cartesian or TypeError.
|
|
657
684
|
'''
|
|
658
685
|
m = _MODS.ellipsoidalBase
|
|
659
686
|
ll = isinstance(point, m.LatLonEllipsoidalBase)
|
|
@@ -664,6 +691,14 @@ def _xellipsoidall(point): # see _xellipsoidal
|
|
|
664
691
|
return ll
|
|
665
692
|
|
|
666
693
|
|
|
694
|
+
def _xellipsoids(E1, E2, Error=_ValueError): # see .ellipsoidalBase
|
|
695
|
+
'''(INTERNAL) Check ellipsoid mis-match, E2 vs E1.
|
|
696
|
+
'''
|
|
697
|
+
if E2 != E1:
|
|
698
|
+
raise Error(E2.named2, txt=_incompatible(E1.named2))
|
|
699
|
+
return E1
|
|
700
|
+
|
|
701
|
+
|
|
667
702
|
def _XError(Error, *args, **kwds):
|
|
668
703
|
'''(INTERNAL) Format an C{Error} or C{_Error}.
|
|
669
704
|
'''
|
|
@@ -711,6 +746,15 @@ _XErrors = (_AssertionError, _AttributeError, # some isError's
|
|
|
711
746
|
# _X2Error = {AssertionError: _AssertionError, ...
|
|
712
747
|
# ZeroDivisionError: _ZeroDivisionError}
|
|
713
748
|
|
|
749
|
+
|
|
750
|
+
def _xgeodesics(G1, G2, Error=_ValueError): # see .geodesici
|
|
751
|
+
'''(INTERNAL) Check geodesics mis-match.
|
|
752
|
+
'''
|
|
753
|
+
if G1.ellipsoid != G2.ellipsoid:
|
|
754
|
+
raise Error(G1.named2, txt=_incompatible(G2.named2))
|
|
755
|
+
return G1
|
|
756
|
+
|
|
757
|
+
|
|
714
758
|
try:
|
|
715
759
|
_ = {}.__or__ # {} | {} # Python 3.9+
|
|
716
760
|
|
|
@@ -783,6 +827,15 @@ def _xkwds_item2(kwds):
|
|
|
783
827
|
raise _xAssertionError(_xkwds_item2, kwds)
|
|
784
828
|
|
|
785
829
|
|
|
830
|
+
def _xkwds_kwds(kwds, **names_defaults):
|
|
831
|
+
'''(INTERNAL) Return a C{dict} of C{named_defaults} items replaced with C{kwds}.
|
|
832
|
+
'''
|
|
833
|
+
if not isinstance(kwds, dict):
|
|
834
|
+
raise _xAssertionError(_xkwds_get_, kwds)
|
|
835
|
+
_g = kwds.get
|
|
836
|
+
return dict((n, _g(n, v)) for n, v in names_defaults.items())
|
|
837
|
+
|
|
838
|
+
|
|
786
839
|
def _xkwds_not(*args, **kwds):
|
|
787
840
|
'''(INTERNAL) Return C{kwds} with a value not in C{args}.
|
|
788
841
|
'''
|
|
@@ -811,6 +864,14 @@ def _Xorder(_Coeffs, Error, **Xorder): # in .auxLat, .ktm, .rhumb.bases, .rhumb
|
|
|
811
864
|
t = sorted(map(str, _Coeffs.keys()))
|
|
812
865
|
raise Error(X, m, txt_not_=_or(*t))
|
|
813
866
|
|
|
867
|
+
|
|
868
|
+
def _xStrError(*Refs, **name_value_Error): # in .gars, .geohash, .wgrs
|
|
869
|
+
'''(INTERNAL) Create a C{TypeError} for C{Garef}, C{Geohash}, C{Wgrs}.
|
|
870
|
+
'''
|
|
871
|
+
S = _MODS.unitsBase.Str
|
|
872
|
+
r = tuple(r.__name__ for r in Refs) + (S.__name__, _LatLon_, 'LatLon*Tuple')
|
|
873
|
+
return _IsnotError(*r, **name_value_Error)
|
|
874
|
+
|
|
814
875
|
# **) MIT License
|
|
815
876
|
#
|
|
816
877
|
# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
|
pygeodesy/etm.py
CHANGED
|
@@ -92,7 +92,7 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
|
|
|
92
92
|
from math import asinh, atan2, degrees, radians, sinh, sqrt
|
|
93
93
|
|
|
94
94
|
__all__ = _ALL_LAZY.etm
|
|
95
|
-
__version__ = '24.
|
|
95
|
+
__version__ = '24.06.11'
|
|
96
96
|
|
|
97
97
|
_OVERFLOW = _1_EPS**2 # about 2e+31
|
|
98
98
|
_TAYTOL = pow(EPS, 0.6)
|
|
@@ -176,18 +176,15 @@ class Etm(Utm):
|
|
|
176
176
|
def toLatLon(self, LatLon=None, unfalse=True, **unused): # PYCHOK expected
|
|
177
177
|
'''Convert this ETM coordinate to an (ellipsoidal) geodetic point.
|
|
178
178
|
|
|
179
|
-
@kwarg LatLon: Optional, ellipsoidal class to return the geodetic
|
|
180
|
-
|
|
181
|
-
@kwarg unfalse: Unfalse B{C{easting}} and B{C{northing}} if
|
|
182
|
-
C{falsed} (C{bool}).
|
|
179
|
+
@kwarg LatLon: Optional, ellipsoidal class to return the geodetic point
|
|
180
|
+
(C{LatLon}) or C{None}.
|
|
181
|
+
@kwarg unfalse: Unfalse B{C{easting}} and B{C{northing}} if C{falsed} (C{bool}).
|
|
183
182
|
|
|
184
|
-
@return: This ETM coordinate as (B{C{LatLon}}) or
|
|
185
|
-
L{LatLonDatum5Tuple}C{(lat, lon, datum, gamma,
|
|
186
|
-
scale)} if B{C{LatLon}} is C{None}.
|
|
183
|
+
@return: This ETM coordinate as (B{C{LatLon}}) or if C{B{LatLon} is None},
|
|
184
|
+
a L{LatLonDatum5Tuple}C{(lat, lon, datum, gamma, scale)}.
|
|
187
185
|
|
|
188
|
-
@raise ETMError: This ETM coordinate's C{exacTM} and this C{datum}
|
|
189
|
-
|
|
190
|
-
lat- and longitude.
|
|
186
|
+
@raise ETMError: This ETM coordinate's C{exacTM} and this C{datum} are not
|
|
187
|
+
compatible or no convergence transforming to lat-/longitude.
|
|
191
188
|
|
|
192
189
|
@raise TypeError: Invalid or non-ellipsoidal B{C{LatLon}}.
|
|
193
190
|
'''
|
|
@@ -1040,10 +1037,9 @@ def parseETM5(strUTM, datum=_WGS84, Etm=Etm, falsed=True, **name):
|
|
|
1040
1037
|
@kwarg falsed: Both easting and northing are C{falsed} (C{bool}).
|
|
1041
1038
|
@kwarg name: Optional B{C{Etm}} C{B{name}=NN} (C{str}).
|
|
1042
1039
|
|
|
1043
|
-
@return: The UTM coordinate (B{C{Etm}}) or if B{
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
C{'N'|'S'}.
|
|
1040
|
+
@return: The UTM coordinate (B{C{Etm}}) or if C{B{Etm} is None}, a
|
|
1041
|
+
L{UtmUps5Tuple}C{(zone, hemipole, easting, northing, band)}
|
|
1042
|
+
with C{hemipole} is the hemisphere C{'N'|'S'}.
|
|
1047
1043
|
|
|
1048
1044
|
@raise ETMError: Invalid B{C{strUTM}}.
|
|
1049
1045
|
|
|
@@ -1057,44 +1053,36 @@ def toEtm8(latlon, lon=None, datum=None, Etm=Etm, falsed=True,
|
|
|
1057
1053
|
strict=True, zone=None, **name_cmoff):
|
|
1058
1054
|
'''Convert a geodetic lat-/longitude to an ETM coordinate.
|
|
1059
1055
|
|
|
1060
|
-
@arg latlon: Latitude (C{degrees}) or an (ellipsoidal)
|
|
1061
|
-
|
|
1062
|
-
@kwarg lon: Optional longitude (C{degrees}), required
|
|
1063
|
-
|
|
1064
|
-
@kwarg datum: Optional datum for the ETM coordinate,
|
|
1065
|
-
|
|
1066
|
-
L{
|
|
1067
|
-
@kwarg Etm: Optional class to return the ETM coordinate
|
|
1068
|
-
(L{Etm}) or C{None}.
|
|
1056
|
+
@arg latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic
|
|
1057
|
+
C{LatLon} instance.
|
|
1058
|
+
@kwarg lon: Optional longitude (C{degrees}), required if B{C{latlon}}
|
|
1059
|
+
is C{degrees}, ignored otherwise.
|
|
1060
|
+
@kwarg datum: Optional datum for the ETM coordinate, overriding
|
|
1061
|
+
B{C{latlon}}'s datum (L{Datum}, L{Ellipsoid},
|
|
1062
|
+
L{Ellipsoid2} or L{a_f2Tuple}).
|
|
1063
|
+
@kwarg Etm: Optional class to return the ETM coordinate (L{Etm}) or C{None}.
|
|
1069
1064
|
@kwarg falsed: False both easting and northing (C{bool}).
|
|
1070
1065
|
@kwarg strict: Restrict B{C{lat}} to UTM ranges (C{bool}).
|
|
1071
1066
|
@kwarg zone: Optional UTM zone to enforce (C{int} or C{str}).
|
|
1072
|
-
@kwarg name_cmoff: Optional B{C{Etm}} C{B{name}=NN} (C{str})
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
meridian (C{bool}), use B{C{falsed}} instead.
|
|
1067
|
+
@kwarg name_cmoff: Optional B{C{Etm}} C{B{name}=NN} (C{str}) and DEPRECATED
|
|
1068
|
+
keyword argument C{B{cmoff}=True} to offset the longitude from
|
|
1069
|
+
the zone's central meridian (C{bool}), use B{C{falsed}} instead.
|
|
1076
1070
|
|
|
1077
|
-
@return: The ETM coordinate as
|
|
1078
|
-
L{UtmUps8Tuple}C{(zone, hemipole, easting, northing,
|
|
1079
|
-
|
|
1080
|
-
or not B{C{falsed}}. The C{hemipole} is the C{'N'|'S'}
|
|
1081
|
-
hemisphere.
|
|
1071
|
+
@return: The ETM coordinate as B{C{Etm}} or if C{B{Etm} is None} or not B{C{falsed}},
|
|
1072
|
+
a L{UtmUps8Tuple}C{(zone, hemipole, easting, northing, band, datum, gamma,
|
|
1073
|
+
scale)}. The C{hemipole} is the C{'N'|'S'} hemisphere.
|
|
1082
1074
|
|
|
1083
|
-
@raise ETMError: No convergence transforming to ETM easting
|
|
1084
|
-
and northing.
|
|
1075
|
+
@raise ETMError: No convergence transforming to ETM easting and northing.
|
|
1085
1076
|
|
|
1086
|
-
@raise ETMError: Invalid B{C{zone}} or near-spherical or
|
|
1087
|
-
|
|
1077
|
+
@raise ETMError: Invalid B{C{zone}} or near-spherical or incompatible B{C{datum}}
|
|
1078
|
+
or C{ellipsoid}.
|
|
1088
1079
|
|
|
1089
|
-
@raise RangeError: If B{C{lat}} outside the valid UTM bands or
|
|
1090
|
-
|
|
1091
|
-
range and L{pygeodesy.rangerrors} set to C{True}.
|
|
1080
|
+
@raise RangeError: If B{C{lat}} outside the valid UTM bands or if B{C{lat}} or B{C{lon}}
|
|
1081
|
+
outside the valid range and L{rangerrors<pygeodesy.rangerrors>} is C{True}.
|
|
1092
1082
|
|
|
1093
|
-
@raise TypeError: Invalid or near-spherical B{C{datum}} or
|
|
1094
|
-
B{C{latlon}} not ellipsoidal.
|
|
1083
|
+
@raise TypeError: Invalid or near-spherical B{C{datum}} or B{C{latlon}} not ellipsoidal.
|
|
1095
1084
|
|
|
1096
|
-
@raise ValueError: The B{C{lon}} value is missing or B{C{latlon}}
|
|
1097
|
-
is invalid.
|
|
1085
|
+
@raise ValueError: The B{C{lon}} value is missing or B{C{latlon}} is invalid.
|
|
1098
1086
|
'''
|
|
1099
1087
|
z, B, lat, lon, d, f, n = _to7zBlldfn(latlon, lon, datum,
|
|
1100
1088
|
falsed, zone, strict,
|
pygeodesy/formy.py
CHANGED
|
@@ -29,7 +29,7 @@ from pygeodesy.namedTuples import Bearing2Tuple, Distance4Tuple, LatLon2Tuple, \
|
|
|
29
29
|
# from pygeodesy.streprs import Fmt, unstr # from .fsums
|
|
30
30
|
# from pygeodesy.triaxials import _hartzell3 # _MODS
|
|
31
31
|
from pygeodesy.units import _isHeight, _isRadius, Bearing, Degrees_, Distance, \
|
|
32
|
-
Distance_, Height,
|
|
32
|
+
Distance_, Height, Lamd, Lat, Lon, Meter_, Phid, \
|
|
33
33
|
Radians, Radians_, Radius, Radius_, Scalar, _100km
|
|
34
34
|
from pygeodesy.utily import acos1, atan2b, atan2d, degrees2m, _loneg, m2degrees, \
|
|
35
35
|
tan_2, sincos2, sincos2_, sincos2d_, _Wrap
|
|
@@ -42,7 +42,7 @@ from contextlib import contextmanager
|
|
|
42
42
|
from math import asin, atan, atan2, cos, degrees, fabs, radians, sin, sqrt # pow
|
|
43
43
|
|
|
44
44
|
__all__ = _ALL_LAZY.formy
|
|
45
|
-
__version__ = '24.
|
|
45
|
+
__version__ = '24.06.15'
|
|
46
46
|
|
|
47
47
|
_RADIANS2 = (PI / _180_0)**2 # degrees- to radians-squared
|
|
48
48
|
_ratio_ = 'ratio'
|
|
@@ -62,8 +62,8 @@ def _anti2(a, b, n_2, n, n2):
|
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
def antipode(lat, lon, **name):
|
|
65
|
-
'''Return the antipode, the point diametrically opposite
|
|
66
|
-
|
|
65
|
+
'''Return the antipode, the point diametrically opposite to a given
|
|
66
|
+
point in C{degrees}.
|
|
67
67
|
|
|
68
68
|
@arg lat: Latitude (C{degrees}).
|
|
69
69
|
@arg lon: Longitude (C{degrees}).
|
|
@@ -78,8 +78,8 @@ def antipode(lat, lon, **name):
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def antipode_(phi, lam, **name):
|
|
81
|
-
'''Return the antipode, the point diametrically opposite
|
|
82
|
-
|
|
81
|
+
'''Return the antipode, the point diametrically opposite to a given
|
|
82
|
+
point in C{radians}.
|
|
83
83
|
|
|
84
84
|
@arg phi: Latitude (C{radians}).
|
|
85
85
|
@arg lam: Longitude (C{radians}).
|
|
@@ -94,8 +94,8 @@ def antipode_(phi, lam, **name):
|
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
def bearing(lat1, lon1, lat2, lon2, **final_wrap):
|
|
97
|
-
'''Compute the initial or final bearing (forward or reverse
|
|
98
|
-
|
|
97
|
+
'''Compute the initial or final bearing (forward or reverse azimuth)
|
|
98
|
+
between two (spherical) points.
|
|
99
99
|
|
|
100
100
|
@arg lat1: Start latitude (C{degrees}).
|
|
101
101
|
@arg lon1: Start longitude (C{degrees}).
|
|
@@ -104,33 +104,33 @@ def bearing(lat1, lon1, lat2, lon2, **final_wrap):
|
|
|
104
104
|
@kwarg final_wrap: Optional keyword arguments for function
|
|
105
105
|
L{pygeodesy.bearing_}.
|
|
106
106
|
|
|
107
|
-
@return: Initial or final bearing (compass C{degrees360}) or
|
|
108
|
-
|
|
107
|
+
@return: Initial or final bearing (compass C{degrees360}) or zero if
|
|
108
|
+
both points coincide.
|
|
109
109
|
'''
|
|
110
|
-
r = bearing_(
|
|
111
|
-
|
|
110
|
+
r = bearing_(Phid(lat1=lat1), Lamd(lon1=lon1),
|
|
111
|
+
Phid(lat2=lat2), Lamd(lon2=lon2), **final_wrap)
|
|
112
112
|
return degrees(r)
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def bearing_(phi1, lam1, phi2, lam2, final=False, wrap=False):
|
|
116
|
-
'''Compute the initial or final bearing (forward or reverse azimuth)
|
|
117
|
-
|
|
116
|
+
'''Compute the initial or final bearing (forward or reverse azimuth) between
|
|
117
|
+
two (spherical) points.
|
|
118
118
|
|
|
119
119
|
@arg phi1: Start latitude (C{radians}).
|
|
120
120
|
@arg lam1: Start longitude (C{radians}).
|
|
121
121
|
@arg phi2: End latitude (C{radians}).
|
|
122
122
|
@arg lam2: End longitude (C{radians}).
|
|
123
|
-
@kwarg final: If C{True}, return the final, otherwise the initial
|
|
124
|
-
|
|
125
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{phi2}}
|
|
126
|
-
|
|
123
|
+
@kwarg final: If C{True}, return the final, otherwise the initial bearing
|
|
124
|
+
(C{bool}).
|
|
125
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{phi2}} and
|
|
126
|
+
B{C{lam2}} (C{bool}).
|
|
127
127
|
|
|
128
|
-
@return: Initial or final bearing (compass C{radiansPI2}) or zero if
|
|
129
|
-
|
|
128
|
+
@return: Initial or final bearing (compass C{radiansPI2}) or zero if both
|
|
129
|
+
are coincident.
|
|
130
130
|
|
|
131
|
-
@see: U{Bearing<https://www.Movable-Type.co.UK/scripts/latlong.html>},
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
@see: U{Bearing<https://www.Movable-Type.co.UK/scripts/latlong.html>}, U{Course
|
|
132
|
+
between two points<https://www.EdWilliams.org/avform147.htm#Crs>} and
|
|
133
|
+
U{Bearing Between Two Points<https://web.Archive.org/web/20020630205931/
|
|
134
134
|
https://MathForum.org/library/drmath/view/55417.html>}.
|
|
135
135
|
'''
|
|
136
136
|
db, phi2, lam2 = _Wrap.philam3(lam1, phi2, lam2, wrap)
|
|
@@ -198,13 +198,13 @@ def cosineAndoyerLambert(lat1, lon1, lat2, lon2, datum=_WGS84, wrap=False):
|
|
|
198
198
|
@arg lon1: Start longitude (C{degrees}).
|
|
199
199
|
@arg lat2: End latitude (C{degrees}).
|
|
200
200
|
@arg lon2: End longitude (C{degrees}).
|
|
201
|
-
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
|
|
202
|
-
L{
|
|
203
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll
|
|
204
|
-
B{C{
|
|
201
|
+
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
|
|
202
|
+
L{a_f2Tuple}) to use.
|
|
203
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
|
|
204
|
+
B{C{lon2}} (C{bool}).
|
|
205
205
|
|
|
206
|
-
@return: Distance (C{meter}, same units as the B{C{datum}}'s
|
|
207
|
-
|
|
206
|
+
@return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes or
|
|
207
|
+
C{radians} if C{B{datum} is None}).
|
|
208
208
|
|
|
209
209
|
@raise TypeError: Invalid B{C{datum}}.
|
|
210
210
|
|
|
@@ -224,8 +224,8 @@ def cosineAndoyerLambert_(phi2, phi1, lam21, datum=_WGS84):
|
|
|
224
224
|
@arg phi2: End latitude (C{radians}).
|
|
225
225
|
@arg phi1: Start latitude (C{radians}).
|
|
226
226
|
@arg lam21: Longitudinal delta, M{end-start} (C{radians}).
|
|
227
|
-
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
|
|
228
|
-
L{
|
|
227
|
+
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
|
|
228
|
+
L{a_f2Tuple}) to use.
|
|
229
229
|
|
|
230
230
|
@return: Angular distance (C{radians}).
|
|
231
231
|
|
|
@@ -263,13 +263,13 @@ def cosineForsytheAndoyerLambert(lat1, lon1, lat2, lon2, datum=_WGS84, wrap=Fals
|
|
|
263
263
|
@arg lon1: Start longitude (C{degrees}).
|
|
264
264
|
@arg lat2: End latitude (C{degrees}).
|
|
265
265
|
@arg lon2: End longitude (C{degrees}).
|
|
266
|
-
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
|
|
267
|
-
L{
|
|
268
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll
|
|
269
|
-
B{C{
|
|
266
|
+
@kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
|
|
267
|
+
L{a_f2Tuple}) to use.
|
|
268
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
|
|
269
|
+
B{C{lon2}} (C{bool}).
|
|
270
270
|
|
|
271
|
-
@return: Distance (C{meter}, same units as the B{C{datum}}'s
|
|
272
|
-
|
|
271
|
+
@return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes or
|
|
272
|
+
C{radians} if C{B{datum} is None}).
|
|
273
273
|
|
|
274
274
|
@raise TypeError: Invalid B{C{datum}}.
|
|
275
275
|
|
|
@@ -380,9 +380,9 @@ def _d3(wrap, lat1, lon1, lat2, lon2):
|
|
|
380
380
|
'''
|
|
381
381
|
if wrap:
|
|
382
382
|
d_lon, lat2, _ = _Wrap.latlon3(lon1, lat2, lon2, wrap)
|
|
383
|
-
return radians(lat2),
|
|
383
|
+
return radians(lat2), Phid(lat1=lat1), radians(d_lon)
|
|
384
384
|
else: # for backward compaibility
|
|
385
|
-
return
|
|
385
|
+
return Phid(lat2=lat2), Phid(lat1=lat1), Phid(d_lon=lon2 - lon1)
|
|
386
386
|
|
|
387
387
|
|
|
388
388
|
def _dE(func_, earth, *wrap_lls):
|
|
@@ -458,34 +458,31 @@ def equirectangular4(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False):
|
|
|
458
458
|
'''Compute the distance between two points using the U{Equirectangular Approximation
|
|
459
459
|
/ Projection<https://www.Movable-Type.co.UK/scripts/latlong.html#equirectangular>}.
|
|
460
460
|
|
|
461
|
-
This approximation is valid for short distance of several hundred Km
|
|
462
|
-
|
|
461
|
+
This approximation is valid for short distance of several hundred Km or Miles, see
|
|
462
|
+
the B{C{limit}} keyword argument and L{LimitError}.
|
|
463
463
|
|
|
464
464
|
@arg lat1: Start latitude (C{degrees}).
|
|
465
465
|
@arg lon1: Start longitude (C{degrees}).
|
|
466
466
|
@arg lat2: End latitude (C{degrees}).
|
|
467
467
|
@arg lon2: End longitude (C{degrees}).
|
|
468
|
-
@kwarg adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine
|
|
469
|
-
|
|
470
|
-
@kwarg limit: Optional limit for lat- and longitudinal deltas (C{degrees}) or
|
|
471
|
-
|
|
472
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
|
|
473
|
-
|
|
468
|
+
@kwarg adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the mean
|
|
469
|
+
latitude (C{bool}).
|
|
470
|
+
@kwarg limit: Optional limit for lat- and longitudinal deltas (C{degrees}) or C{None}
|
|
471
|
+
or C{0} for unlimited.
|
|
472
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and B{C{lon2}}
|
|
473
|
+
(C{bool}).
|
|
474
474
|
|
|
475
475
|
@return: A L{Distance4Tuple}C{(distance2, delta_lat, delta_lon, unroll_lon2)}
|
|
476
476
|
in C{degrees squared}.
|
|
477
477
|
|
|
478
|
-
@raise LimitError: If the lat- and/or longitudinal delta exceeds the
|
|
479
|
-
|
|
480
|
-
set to C{True}.
|
|
478
|
+
@raise LimitError: If the lat- and/or longitudinal delta exceeds the B{C{-limit..limit}}
|
|
479
|
+
range and L{limiterrors<pygeodesy.limiterrors>} is C{True}.
|
|
481
480
|
|
|
482
|
-
@see: U{Local, flat earth approximation
|
|
483
|
-
|
|
484
|
-
L{
|
|
485
|
-
L{
|
|
486
|
-
|
|
487
|
-
and L{vincentys} and methods L{Ellipsoid.distance2},
|
|
488
|
-
C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}.
|
|
481
|
+
@see: U{Local, flat earth approximation<https://www.EdWilliams.org/avform.htm#flat>},
|
|
482
|
+
functions L{equirectangular}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
|
|
483
|
+
L{cosineLaw}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine},
|
|
484
|
+
L{thomas} and L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*}
|
|
485
|
+
and C{LatLon.equirectangularTo}.
|
|
489
486
|
'''
|
|
490
487
|
d_lon, lat2, ulon2 = _Wrap.latlon3(lon1, lat2, lon2, wrap)
|
|
491
488
|
d_lat = lat2 - lat1
|
|
@@ -1078,7 +1075,7 @@ def heightOf(angle, distance, radius=R_M):
|
|
|
1078
1075
|
|
|
1079
1076
|
if d > EPS0: # and h > EPS0
|
|
1080
1077
|
d = d / h # /= h chokes PyChecker
|
|
1081
|
-
s = sin(
|
|
1078
|
+
s = sin(Phid(angle=angle, clip=_180_0))
|
|
1082
1079
|
s = fsumf_(_1_0, s * d * _2_0, d**2)
|
|
1083
1080
|
if s > 0:
|
|
1084
1081
|
return h * sqrt(s) - r
|