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.
Files changed (87) hide show
  1. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.7.7.dist-info/RECORD +117 -0
  3. pygeodesy/__init__.py +39 -32
  4. pygeodesy/__main__.py +6 -1
  5. pygeodesy/albers.py +2 -2
  6. pygeodesy/auxilats/__init__.py +1 -1
  7. pygeodesy/auxilats/auxAngle.py +40 -39
  8. pygeodesy/auxilats/auxDLat.py +3 -2
  9. pygeodesy/auxilats/auxLat.py +16 -18
  10. pygeodesy/auxilats/auxily.py +1 -1
  11. pygeodesy/azimuthal.py +10 -10
  12. pygeodesy/basics.py +16 -4
  13. pygeodesy/booleans.py +4 -4
  14. pygeodesy/cartesianBase.py +11 -14
  15. pygeodesy/css.py +14 -18
  16. pygeodesy/datums.py +6 -6
  17. pygeodesy/deprecated/__init__.py +1 -1
  18. pygeodesy/deprecated/classes.py +25 -4
  19. pygeodesy/deprecated/datum.py +3 -3
  20. pygeodesy/deprecated/functions.py +6 -8
  21. pygeodesy/dms.py +23 -27
  22. pygeodesy/ecef.py +4 -4
  23. pygeodesy/elevations.py +4 -4
  24. pygeodesy/ellipsoidalBase.py +23 -28
  25. pygeodesy/ellipsoidalBaseDI.py +19 -23
  26. pygeodesy/ellipsoidalExact.py +3 -3
  27. pygeodesy/ellipsoidalGeodSolve.py +15 -23
  28. pygeodesy/ellipsoidalKarney.py +37 -60
  29. pygeodesy/ellipsoidalNvector.py +38 -44
  30. pygeodesy/ellipsoidalVincenty.py +11 -14
  31. pygeodesy/ellipsoids.py +107 -101
  32. pygeodesy/errors.py +109 -48
  33. pygeodesy/etm.py +32 -44
  34. pygeodesy/formy.py +55 -58
  35. pygeodesy/frechet.py +18 -20
  36. pygeodesy/fsums.py +3 -3
  37. pygeodesy/gars.py +3 -4
  38. pygeodesy/geodesici.py +1696 -0
  39. pygeodesy/geodesicw.py +15 -15
  40. pygeodesy/geodesicx/__init__.py +4 -4
  41. pygeodesy/geodesicx/gx.py +34 -55
  42. pygeodesy/geodesicx/gxbases.py +20 -8
  43. pygeodesy/geodesicx/gxline.py +93 -88
  44. pygeodesy/geodsolve.py +108 -59
  45. pygeodesy/geohash.py +26 -34
  46. pygeodesy/geoids.py +28 -37
  47. pygeodesy/hausdorff.py +17 -18
  48. pygeodesy/heights.py +2 -2
  49. pygeodesy/internals.py +46 -13
  50. pygeodesy/interns.py +2 -2
  51. pygeodesy/karney.py +78 -15
  52. pygeodesy/ktm.py +13 -16
  53. pygeodesy/latlonBase.py +17 -19
  54. pygeodesy/lazily.py +28 -25
  55. pygeodesy/lcc.py +28 -31
  56. pygeodesy/ltp.py +7 -8
  57. pygeodesy/ltpTuples.py +71 -73
  58. pygeodesy/mgrs.py +8 -9
  59. pygeodesy/named.py +19 -10
  60. pygeodesy/nvectorBase.py +9 -10
  61. pygeodesy/osgr.py +9 -9
  62. pygeodesy/points.py +6 -6
  63. pygeodesy/rhumb/__init__.py +1 -1
  64. pygeodesy/rhumb/aux_.py +5 -5
  65. pygeodesy/rhumb/bases.py +30 -31
  66. pygeodesy/rhumb/ekx.py +3 -4
  67. pygeodesy/rhumb/solve.py +21 -22
  68. pygeodesy/solveBase.py +177 -123
  69. pygeodesy/sphericalBase.py +10 -11
  70. pygeodesy/sphericalNvector.py +13 -13
  71. pygeodesy/sphericalTrigonometry.py +86 -97
  72. pygeodesy/streprs.py +4 -34
  73. pygeodesy/triaxials.py +48 -43
  74. pygeodesy/units.py +208 -275
  75. pygeodesy/unitsBase.py +115 -107
  76. pygeodesy/ups.py +26 -31
  77. pygeodesy/utily.py +8 -8
  78. pygeodesy/utm.py +35 -40
  79. pygeodesy/utmups.py +43 -46
  80. pygeodesy/utmupsBase.py +8 -9
  81. pygeodesy/vector3d.py +26 -27
  82. pygeodesy/vector3dBase.py +6 -7
  83. pygeodesy/webmercator.py +19 -21
  84. pygeodesy/wgrs.py +18 -20
  85. PyGeodesy-24.6.9.dist-info/RECORD +0 -116
  86. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/WHEEL +0 -0
  87. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicw.py CHANGED
@@ -23,7 +23,7 @@ from pygeodesy.fsums import Fsum, Fmt, unstr
23
23
  from pygeodesy.internals import _dunder_nameof, _under
24
24
  from pygeodesy.interns import NN, _DOT_, _SPACE_, _to_, _too_
25
25
  from pygeodesy.karney import _atan2d, Caps, Direct9Tuple, GDict, \
26
- _kWrapped, Inverse10Tuple
26
+ Inverse10Tuple, _kWrapped, _llz2line
27
27
  from pygeodesy.latlonBase import LatLonBase as _LLB, F_D, Radius_
28
28
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
29
29
  from pygeodesy.named import callername, classname, _name1__, _name2__
@@ -37,7 +37,7 @@ from contextlib import contextmanager
37
37
  # from math import fabs # from .utily
38
38
 
39
39
  __all__ = _ALL_LAZY.geodesicw
40
- __version__ = '24.05.24'
40
+ __version__ = '24.07.09'
41
41
 
42
42
  _plumb_ = 'plumb'
43
43
  _TRIPS = 65
@@ -71,8 +71,8 @@ class _gWrapped(_kWrapped):
71
71
 
72
72
  @arg a_ellipsoid: The equatorial radius I{a} (C{meter}, conventionally),
73
73
  an ellipsoid (L{Ellipsoid}) or a datum (L{Datum}).
74
- @arg f: The ellipsoid's flattening (C{scalar}), ignored if B{C{a_ellipsoid})
75
- is not C{meter}.
74
+ @arg f: The ellipsoid's flattening (C{scalar}), required if B{C{a_ellipsoid})
75
+ is C{meter}, ignored otherwise.
76
76
  @kwarg name: Optional C{B{name}=NN} (C{str}).
77
77
  '''
78
78
  _earth_datum(self, a_ellipsoid, f=f, **name) # raiser=NN
@@ -220,7 +220,9 @@ class _gWrapped(_kWrapped):
220
220
  '''
221
221
  with _wargs(self, lat1, lon1, lat2, lon2, caps, **name) as args:
222
222
  t = _Geodesic.InverseLine(self, *args)
223
- return self._Line13(t, **name)
223
+ gl = self._Line13(t, **name)
224
+ p2 = gl.Position(gl.s13, outmask=Caps.AZIMUTH)
225
+ return _llz2line(gl, lat2=lat2, lon2=lon2, azi2=p2.azi2)
224
226
 
225
227
  def Line(self, lat1, lon1, azi1, caps=Caps._STD_LINE, **name):
226
228
  '''Set up a I{wrapped} C{GeodesicLine} to compute several points
@@ -429,17 +431,16 @@ class _gWrapped(_kWrapped):
429
431
  _wrapped = _gWrapped() # PYCHOK singleton, .ellipsoids, .test/base.py
430
432
 
431
433
 
432
- def Geodesic(a_ellipsoid, f=None, **name):
434
+ def Geodesic(a_ellipsoid=_EWGS84, f=None, **name):
433
435
  '''Return a I{wrapped} C{geodesic.Geodesic} instance from I{Karney}'s
434
436
  Python U{geographiclib<https://PyPI.org/project/geographiclib>},
435
437
  provide the latter is installed, otherwise an C{ImportError}.
436
438
 
437
439
  @arg a_ellipsoid: An ellipsoid (L{Ellipsoid}) or datum (L{Datum})
438
440
  or the equatorial radius I{a} of the ellipsoid (C{meter}).
439
- @arg f: The flattening of the ellipsoid (C{scalar}), ignored if
440
- B{C{a_ellipsoid}}) is not specified as C{meter}.
441
- @kwarg name: Optional ellipsoid C{B{name}=NN} (C{str}), ignored
442
- like B{C{f}}.
441
+ @arg f: The flattening of the ellipsoid (C{scalar}), required if
442
+ B{C{a_ellipsoid}}) is C{meter}, ignored otherwise.
443
+ @kwarg name: Optional C{B{name}=NN} (C{str}), ignored like B{C{f}}.
443
444
  '''
444
445
  return _wrapped.Geodesic(a_ellipsoid, f=f, **name)
445
446
 
@@ -453,11 +454,10 @@ def GeodesicLine(geodesic, lat1, lon1, azi1, caps=Caps._STD_LINE):
453
454
  @arg lat1: Latitude of the first points (C{degrees}).
454
455
  @arg lon1: Longitude of the first points (C{degrees}).
455
456
  @arg azi1: Azimuth at the first points (compass C{degrees360}).
456
- @kwarg caps: Optional, bit-or'ed combination of L{Caps} values
457
- specifying the capabilities the C{GeodesicLine}
458
- instance should possess, i.e., which quantities can
459
- be returned by calls to C{GeodesicLine.Position}
460
- and C{GeodesicLine.ArcPosition}.
457
+ @kwarg caps: Optional, bit-or'ed combination of L{Caps} values specifying
458
+ the capabilities the C{GeodesicLine} instance should possess,
459
+ i.e., which quantities can be returned by methods
460
+ C{GeodesicLine.Position} and C{GeodesicLine.ArcPosition}.
461
461
  '''
462
462
  return _wrapped.GeodesicLine(geodesic, lat1, lon1, azi1, caps=caps)
463
463
 
@@ -2,7 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  u'''A pure Python version of I{Karney}'s C++ classes U{GeodesicExact
5
- <https://GeographicLib.SourceForge.io/C++/classGeographicLib_1_1GeodesicExact.html>}
5
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
6
6
  and U{GeodesicLineExact
7
7
  <https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1GeodesicLine.html>}.
8
8
 
@@ -13,8 +13,8 @@ and the background information at U{Geodesics on an ellipsoid of revolution
13
13
 
14
14
  Also, compare C{GeodesicExact} and C{GeodesicLineExact} to I{standard} classes C{Geodesic}
15
15
  respectively C{GeodesicLine} from I{Karney}'s Python implementation U{geographiclib
16
- <https://GeographicLib.SourceForge.io/C++/doc/other.html#python>}, see module
17
- L{pygeodesy.karney}.
16
+ <https://GeographicLib.SourceForge.io/C++/doc/other.html#python>}, see modules
17
+ L{pygeodesy.geodesicw} and L{pygeodesy.karney}.
18
18
  '''
19
19
 
20
20
  from pygeodesy.geodesicx.gx import GeodesicExact, GeodesicLineExact # PYCHOK exported
@@ -23,7 +23,7 @@ from pygeodesy.karney import Caps, GeodesicError
23
23
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
24
24
 
25
25
  __all__ = _ALL_LAZY.geodesicx + _ALL_DOCS(Caps, GeodesicError)
26
- __version__ = '24.05.31'
26
+ __version__ = '24.07.09'
27
27
 
28
28
  # **) MIT License
29
29
  #
pygeodesy/geodesicx/gx.py CHANGED
@@ -44,25 +44,26 @@ from pygeodesy.constants import EPS, EPS0, EPS02, MANT_DIG, NAN, PI, _EPSqrt, \
44
44
  from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
45
45
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
46
46
  from pygeodesy.errors import GeodesicError, _xkwds_pop2
47
- from pygeodesy.fmath import hypot as _hypot
47
+ from pygeodesy.fmath import hypot as _hypot, Fmt
48
48
  from pygeodesy.fsums import fsumf_, fsum1f_
49
49
  from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
50
- _sincos12, _sin1cos2, _xnC4
51
- from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _TINY, _update_glXs
52
- from pygeodesy.interns import NN, _COMMASPACE_, _DOT_, _UNDER_
50
+ _sincos12, _sin1cos2, _sinf1cos2d, \
51
+ _TINY, _xnC4
52
+ from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _update_glXs
53
+ from pygeodesy.interns import NN, _DOT_, _UNDER_
53
54
  from pygeodesy.karney import GDict, _around, _atan2d, Caps, _cbrt, _diff182, \
54
55
  _fix90, _K_2_0, _norm2, _norm180, _polynomial, \
55
56
  _signBit, _sincos2, _sincos2d, _sincos2de, _unsigned2
56
57
  from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
57
58
  from pygeodesy.namedTuples import Destination3Tuple, Distance3Tuple
58
59
  from pygeodesy.props import deprecated_Property, Property, Property_RO, property_RO
59
- from pygeodesy.streprs import Fmt, pairs
60
+ # from pygeodesy.streprs import Fmt # from .fmath
60
61
  from pygeodesy.utily import atan2d as _atan2d_reverse, _unrollon, _Wrap, wrap360
61
62
 
62
63
  from math import atan2, copysign, cos, degrees, fabs, radians, sqrt
63
64
 
64
65
  __all__ = ()
65
- __version__ = '24.05.31'
66
+ __version__ = '24.07.09'
66
67
 
67
68
  _MAXIT1 = 20
68
69
  _MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
@@ -211,7 +212,7 @@ class GeodesicExact(_GeodesicBase):
211
212
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
212
213
  Python U{Geodesic.ArcDirectLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
213
214
  '''
214
- return self._GenDirectLine(lat1, lon1, azi1, True, a12, caps, **name)
215
+ return GeodesicLineExact(self, lat1, lon1, azi1, caps=caps, **name)._GenSet(self._debug, a12=a12)
215
216
 
216
217
  def Area(self, polyline=False, **name):
217
218
  '''Set up a L{GeodesicAreaExact} to compute area and
@@ -389,7 +390,7 @@ class GeodesicExact(_GeodesicBase):
389
390
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
390
391
  Python U{Geodesic.DirectLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
391
392
  '''
392
- return self._GenDirectLine(lat1, lon1, azi1, False, s12, caps, **name)
393
+ return GeodesicLineExact(self, lat1, lon1, azi1, caps=caps, **name)._GenSet(self._debug, s12=s12)
393
394
 
394
395
  def _dn(self, sbet, cbet): # in gxline._GeodesicLineExact.__init__
395
396
  '''(INTERNAL) Helper.
@@ -496,7 +497,7 @@ class GeodesicExact(_GeodesicBase):
496
497
  Cs = Caps
497
498
  if self._debug: # PYCHOK no cover
498
499
  outmask |= Cs._DEBUG_INVERSE & self._debug
499
- outmask &= Cs._OUT_MASK # incl. _SALPs_CALPs and _DEBUG_
500
+ outmask &= Cs._OUT_MASK # incl. _S_CALPs_ and _DEBUG_
500
501
  # compute longitude difference carefully (with _diff182):
501
502
  # result is in [-180, +180] but -180 is only for west-going
502
503
  # geodesics, +180 is for east-going and meridional geodesics
@@ -504,8 +505,10 @@ class GeodesicExact(_GeodesicBase):
504
505
  # see C{result} from geographiclib.geodesic.Inverse
505
506
  if (outmask & Cs.LONG_UNROLL): # == (lon1 + lon12) + lon12s
506
507
  r = GDict(lon1=lon1, lon2=fsumf_(lon1, lon12, lon12s))
507
- else:
508
+ elif (outmask & Cs.LONGITUDE):
508
509
  r = GDict(lon1=_norm180(lon1), lon2=_norm180(lon2))
510
+ else:
511
+ r = GDict()
509
512
  if _K_2_0: # GeographicLib 2.0
510
513
  # make longitude difference positive
511
514
  lon12, lon_ = _unsigned2(lon12)
@@ -534,7 +537,8 @@ class GeodesicExact(_GeodesicBase):
534
537
  # If really close to the equator, treat as on equator.
535
538
  lat1 = _around(_fix90(lat1))
536
539
  lat2 = _around(_fix90(lat2))
537
- r.set_(lat1=lat1, lat2=lat2)
540
+ if (outmask & Cs.LATITUDE):
541
+ r.set_(lat1=lat1, lat2=lat2)
538
542
  # Swap points so that point with higher (abs) latitude is
539
543
  # point 1. If one latitude is a NAN, then it becomes lat1.
540
544
  swap_ = fabs(lat1) < fabs(lat2) or isnan(lat2)
@@ -553,10 +557,10 @@ class GeodesicExact(_GeodesicBase):
553
557
  # to check, e.g., on verifying quadrants in atan2. In addition,
554
558
  # this enforces some symmetries in the results returned.
555
559
 
556
- # Initialize for the meridian. No longitude calculation is
557
- # done in this case to let the parameter default to 0.
558
- sbet1, cbet1 = self._sinf1cos2d(lat1)
559
- sbet2, cbet2 = self._sinf1cos2d(lat2)
560
+ # Initialize for the meridian. No longitude calculation is done in
561
+ # this case to let the parameter default to 0.
562
+ sbet1, cbet1 = _sinf1cos2d(lat1, self.f1)
563
+ sbet2, cbet2 = _sinf1cos2d(lat2, self.f1)
560
564
  # If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure
561
565
  # of the |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1),
562
566
  # abs(sbet2) + sbet1 is a better measure. This logic is used
@@ -670,7 +674,7 @@ class GeodesicExact(_GeodesicBase):
670
674
  S12 = -S12
671
675
  r.set_(S12=unsigned0(S12))
672
676
 
673
- if (outmask & (Cs.AZIMUTH | Cs._SALPs_CALPs)):
677
+ if (outmask & (Cs.AZIMUTH | Cs._S_CALPs_)):
674
678
  if swap_:
675
679
  salp1, salp2 = salp2, salp1
676
680
  calp1, calp2 = calp2, calp1
@@ -682,7 +686,7 @@ class GeodesicExact(_GeodesicBase):
682
686
  if (outmask & Cs.AZIMUTH):
683
687
  r.set_(azi1=_atan2d(salp1, calp1),
684
688
  azi2=_atan2d_reverse(salp2, calp2, reverse=outmask & Cs.REVERSE2))
685
- if (outmask & Cs._SALPs_CALPs):
689
+ if (outmask & Cs._S_CALPs_):
686
690
  r.set_(salp1=salp1, calp1=calp1,
687
691
  salp2=salp2, calp2=calp2)
688
692
 
@@ -706,25 +710,13 @@ class GeodesicExact(_GeodesicBase):
706
710
  r = self._GDictDirect(lat1, lon1, azi1, arcmode, s12_a12, outmask)
707
711
  return r.toDirect9Tuple()
708
712
 
709
- def _GenDirectLine(self, lat1, lon1, azi1, arcmode, s12_a12, caps, **name):
710
- '''(INTERNAL) Helper for C{ArcDirectLine} and C{DirectLine}.
711
-
712
- @return: A L{GeodesicLineExact} instance.
713
- '''
714
- azi1 = _norm180(azi1)
715
- # guard against underflow in salp0. Also -0 is converted to +0.
716
- s, c = _sincos2d(_around(azi1))
717
- C = caps if arcmode else (caps | Caps.DISTANCE_IN)
718
- return _GeodesicLineExact(self, lat1, lon1, azi1, C,
719
- self._debug, s, c, **name)._GenSet(arcmode, s12_a12)
720
-
721
713
  def _GenInverse(self, lat1, lon1, lat2, lon2, outmask=Caps.STANDARD):
722
714
  '''(INTERNAL) The general I{Inverse} geodesic calculation.
723
715
 
724
716
  @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
725
717
  m12, M12, M21, S12)}.
726
718
  '''
727
- r = self._GDictInverse(lat1, lon1, lat2, lon2, outmask | Caps._SALPs_CALPs)
719
+ r = self._GDictInverse(lat1, lon1, lat2, lon2, outmask | Caps._S_CALPs_)
728
720
  return r.toInverse10Tuple()
729
721
 
730
722
  def _Inverse(self, ll1, ll2, wrap, **outmask):
@@ -814,11 +806,9 @@ class GeodesicExact(_GeodesicBase):
814
806
  Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
815
807
  '''
816
808
  Cs = Caps
817
- r = self._GDictInverse(lat1, lon1, lat2, lon2, Cs._SALPs_CALPs) # No need for AZIMUTH
818
- C = (caps | Cs.DISTANCE) if (caps & (Cs.DISTANCE_IN & Cs._OUT_MASK)) else caps
819
- azi1 = _atan2d(r.salp1, r.calp1)
820
- return _GeodesicLineExact(self, lat1, lon1, azi1, C, # ensure a12 is distance
821
- self._debug, r.salp1, r.calp1, **name)._GenSet(True, r.a12)
809
+ r = self._GDictInverse(lat1, lon1, lat2, lon2, Cs.AZIMUTH | Cs.DISTANCE | Cs._S_CALPs_)
810
+ return GeodesicLineExact(self, lat1, lon1, None, caps=caps, _s_calp1=(r.salp1, r.calp1),
811
+ **name)._GenSet(self._debug, lat2=lat2, lon2=lon2, **r)
822
812
 
823
813
  def _InverseArea(self, _meridian, salp1, calp1, # PYCHOK 9 args
824
814
  salp2, calp2,
@@ -1129,7 +1119,7 @@ class GeodesicExact(_GeodesicBase):
1129
1119
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
1130
1120
  and Python U{Geodesic.Line<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
1131
1121
  '''
1132
- return _GeodesicLineExact(self, lat1, lon1, azi1, caps, self._debug, **name)
1122
+ return GeodesicLineExact(self, lat1, lon1, azi1, caps=caps, **name)._GenSet(self._debug)
1133
1123
 
1134
1124
  @Property_RO
1135
1125
  def n(self):
@@ -1241,27 +1231,16 @@ class GeodesicExact(_GeodesicBase):
1241
1231
 
1242
1232
  Polygon = Area # for C{geographiclib} compatibility
1243
1233
 
1244
- def _sinf1cos2d(self, lat):
1245
- '''(INTERNAL) Helper, also for C{_G_GeodesicLineExact}.
1246
- '''
1247
- sbet, cbet = _sincos2d(lat)
1248
- # ensure cbet1 = +epsilon at poles; doing the fix on beta means
1249
- # that sig12 will be <= 2*tiny for two points at the same pole
1250
- sbet, cbet = _norm2(sbet * self.f1, cbet)
1251
- return sbet, (cbet if fabs(cbet) > _TINY else _TINY)
1252
-
1253
- def toStr(self, prec=6, sep=_COMMASPACE_, **unused): # PYCHOK signature
1234
+ def toStr(self, **prec_sep_name): # PYCHOK signature
1254
1235
  '''Return this C{GeodesicExact} as string.
1255
1236
 
1256
- @kwarg prec: The C{float} precision, number of decimal digits (0..9).
1257
- Trailing zero decimals are stripped for B{C{prec}} values
1258
- of 1 and above, but kept for negative B{C{prec}} values.
1259
- @kwarg sep: Separator to join (C{str}).
1237
+ @see: L{Ellipsoid.toStr<pygeodesy.ellipsoids.Ellipsoid.toStr>}
1238
+ for further details.
1260
1239
 
1261
- @return: Tuple items (C{str}).
1240
+ @return: C{GeodesicExact} (C{str}).
1262
1241
  '''
1263
- d = dict(ellipsoid=self.ellipsoid, C4order=self.C4order)
1264
- return sep.join(pairs(d, prec=prec))
1242
+ t = GeodesicExact.caps, GeodesicExact.ellipsoid
1243
+ return self._instr(props=t, C4order=self.C4order, **prec_sep_name)
1265
1244
 
1266
1245
 
1267
1246
  class GeodesicLineExact(_GeodesicLineExact):
@@ -1290,9 +1269,9 @@ class GeodesicLineExact(_GeodesicLineExact):
1290
1269
  '''
1291
1270
  _xinstanceof(GeodesicExact, geodesic=geodesic)
1292
1271
  if (caps & Caps.LINE_OFF): # copy to avoid updates
1293
- geodesic = geodesic.copy(deep=False, name=_UNDER_(NN, geodesic.name)) # NOT _under!
1272
+ geodesic = geodesic.copy(deep=False, name=_UNDER_(NN, geodesic.name))
1294
1273
  # _update_all(geodesic)
1295
- _GeodesicLineExact.__init__(self, geodesic, lat1, lon1, azi1, caps, 0, **name)
1274
+ _GeodesicLineExact.__init__(self, geodesic, lat1, lon1, azi1, caps, **name)
1296
1275
 
1297
1276
 
1298
1277
  def _Astroid(x, y):
@@ -9,19 +9,21 @@ U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
9
9
  '''
10
10
 
11
11
  from pygeodesy.basics import isodd, _MODS
12
- from pygeodesy.constants import _0_0, _100_0
12
+ from pygeodesy.constants import _EPSmin as _TINY, _0_0, _100_0
13
13
  from pygeodesy.errors import _or, _xkwds_item2
14
14
  from pygeodesy.fmath import hypot as _hypot
15
- from pygeodesy.karney import _CapsBase, GeodesicError, _2cos2x, _sum2_
15
+ from pygeodesy.karney import _CapsBase, GeodesicError, _2cos2x, \
16
+ _norm2, _sincos2d, _sum2_
16
17
  # from pygeodesy.lazily import _MODS, printf # .basics, _MODS
17
18
 
18
- from math import ldexp as _ldexp
19
+ from math import fabs, ldexp as _ldexp
19
20
 
20
21
  __all__ = ()
21
- __version__ = '24.05.19'
22
+ __version__ = '24.06.16'
22
23
 
23
24
  # valid C{nC4}s and C{C4order}s, see _xnC4 below
24
25
  _nC4s = {24: 2900, 27: 4032, 30: 5425}
26
+ # assert (_TINY * EPS) > 0 and (_TINY + EPS) == EPS # underflow guard
25
27
 
26
28
 
27
29
  class _GeodesicBase(_CapsBase): # in .geodsolve
@@ -71,15 +73,15 @@ def _cosSeries(c4s, sx, cx): # PYCHOK shared .geodesicx.gx and -.gxline
71
73
  y0 = t0 = y1 = t1 = _0_0
72
74
  c4 = list(c4s)
73
75
  _c4 = c4.pop
74
- _s2 = _sum2_
75
76
  if isodd(len(c4)):
76
77
  y0 = _c4()
78
+ _s2 = _sum2_
77
79
  while c4:
78
80
  # y1 = ar * y0 - y1 + c4.pop()
79
81
  # y0 = ar * y1 - y0 + c4.pop()
80
82
  y1, t1 = _s2(ar * y0, ar * t0, -y1, -t1, _c4())
81
83
  y0, t0 = _s2(ar * y1, ar * t1, -y0, -t0, _c4())
82
- # s = cx * (y0 - y1)
84
+ # s = (y0 - y1) * cx
83
85
  s, _ = _s2(cx * y0, _0_0, cx * t0, -cx * y1, -cx * t1)
84
86
  return s
85
87
 
@@ -93,7 +95,7 @@ def _f2(hi, lo): # in .geodesicx._C4_24, _27 and _30
93
95
  return _ldexp(_f(hi), 52) + _f(lo)
94
96
 
95
97
 
96
- def _sincos12(sin1, cos1, sin2, cos2, sineg0=False): # PYCHOK shared
98
+ def _sincos12(sin1, cos1, sin2, cos2, sineg0=False):
97
99
  '''(INTERNAL) Compute the sine and cosine of angle
98
100
  M{ang12 = atan2(sin2, cos2) - atan2(sin1, cos1)}.
99
101
 
@@ -111,7 +113,7 @@ def _sincos12(sin1, cos1, sin2, cos2, sineg0=False): # PYCHOK shared
111
113
  return s, c
112
114
 
113
115
 
114
- def _sin1cos2(sin1, cos1, sin2, cos2): # PYCHOK shared
116
+ def _sin1cos2(sin1, cos1, sin2, cos2):
115
117
  '''(INTERNAL) Compute the C{sin1 * cos2} sine and its cosine.
116
118
 
117
119
  @return: 2-Tuple C{(sin1 * cos2, hypot(sin1 * sin2, cos1)}.
@@ -121,6 +123,16 @@ def _sin1cos2(sin1, cos1, sin2, cos2): # PYCHOK shared
121
123
  return s, c # _norm2(s, c)
122
124
 
123
125
 
126
+ def _sinf1cos2d(lat, f1):
127
+ '''(INTERNAL) See C{GeodesicExact} and C{_GeodesicLineExact}.
128
+ '''
129
+ sbet, cbet = _sincos2d(lat)
130
+ # ensure cbet1 = +epsilon at poles; doing the fix on beta means
131
+ # that sig12 will be <= 2*tiny for two points at the same pole
132
+ sbet, cbet = _norm2(sbet * f1, cbet)
133
+ return sbet, (cbet if fabs(cbet) > _TINY else _TINY)
134
+
135
+
124
136
  def _xnC4(**name_nC4):
125
137
  '''(INTERNAL) Validate C{C4order}.
126
138
  '''