pygeodesy 25.11.5__py2.py3-none-any.whl → 25.12.31__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 (125) hide show
  1. pygeodesy/__init__.py +46 -25
  2. pygeodesy/__main__.py +1 -1
  3. pygeodesy/albers.py +1 -1
  4. pygeodesy/angles.py +960 -0
  5. pygeodesy/auxilats/_CX_4.py +1 -1
  6. pygeodesy/auxilats/_CX_6.py +1 -1
  7. pygeodesy/auxilats/_CX_8.py +1 -1
  8. pygeodesy/auxilats/_CX_Rs.py +1 -1
  9. pygeodesy/auxilats/__init__.py +2 -2
  10. pygeodesy/auxilats/__main__.py +1 -1
  11. pygeodesy/auxilats/auxAngle.py +7 -8
  12. pygeodesy/auxilats/auxDLat.py +1 -1
  13. pygeodesy/auxilats/auxDST.py +1 -1
  14. pygeodesy/auxilats/auxLat.py +1 -1
  15. pygeodesy/auxilats/auxily.py +1 -1
  16. pygeodesy/azimuthal.py +6 -5
  17. pygeodesy/basics.py +14 -10
  18. pygeodesy/booleans.py +1 -1
  19. pygeodesy/cartesianBase.py +7 -7
  20. pygeodesy/clipy.py +1 -1
  21. pygeodesy/constants.py +29 -24
  22. pygeodesy/css.py +1 -1
  23. pygeodesy/datums.py +1 -1
  24. pygeodesy/deprecated/__init__.py +1 -1
  25. pygeodesy/deprecated/bases.py +1 -1
  26. pygeodesy/deprecated/classes.py +14 -7
  27. pygeodesy/deprecated/consterns.py +1 -1
  28. pygeodesy/deprecated/datum.py +1 -1
  29. pygeodesy/deprecated/functions.py +1 -1
  30. pygeodesy/deprecated/nvector.py +1 -1
  31. pygeodesy/deprecated/rhumbBase.py +1 -1
  32. pygeodesy/deprecated/rhumbaux.py +1 -1
  33. pygeodesy/deprecated/rhumbsolve.py +1 -1
  34. pygeodesy/deprecated/rhumbx.py +1 -1
  35. pygeodesy/dms.py +1 -1
  36. pygeodesy/ecef.py +1 -1
  37. pygeodesy/ecefLocals.py +1 -1
  38. pygeodesy/elevations.py +1 -1
  39. pygeodesy/ellipsoidalBase.py +1 -1
  40. pygeodesy/ellipsoidalBaseDI.py +1 -1
  41. pygeodesy/ellipsoidalExact.py +1 -1
  42. pygeodesy/ellipsoidalGeodSolve.py +1 -1
  43. pygeodesy/ellipsoidalKarney.py +1 -1
  44. pygeodesy/ellipsoidalNvector.py +1 -1
  45. pygeodesy/ellipsoidalVincenty.py +1 -1
  46. pygeodesy/ellipsoids.py +30 -17
  47. pygeodesy/elliptic.py +1 -1
  48. pygeodesy/epsg.py +1 -1
  49. pygeodesy/errors.py +8 -4
  50. pygeodesy/etm.py +1 -1
  51. pygeodesy/fmath.py +19 -14
  52. pygeodesy/formy.py +251 -10
  53. pygeodesy/frechet.py +1 -1
  54. pygeodesy/fstats.py +1 -1
  55. pygeodesy/fsums.py +41 -29
  56. pygeodesy/gars.py +1 -1
  57. pygeodesy/geod3solve.py +489 -0
  58. pygeodesy/geodesici.py +9 -8
  59. pygeodesy/geodesicw.py +1 -1
  60. pygeodesy/geodesicx/_C4_24.py +1 -1
  61. pygeodesy/geodesicx/_C4_27.py +1 -1
  62. pygeodesy/geodesicx/_C4_30.py +1 -1
  63. pygeodesy/geodesicx/__init__.py +2 -2
  64. pygeodesy/geodesicx/__main__.py +1 -1
  65. pygeodesy/geodesicx/gx.py +1 -1
  66. pygeodesy/geodesicx/gxarea.py +54 -24
  67. pygeodesy/geodesicx/gxbases.py +1 -1
  68. pygeodesy/geodesicx/gxline.py +1 -1
  69. pygeodesy/geodsolve.py +73 -104
  70. pygeodesy/geohash.py +1 -1
  71. pygeodesy/geoids.py +1 -1
  72. pygeodesy/hausdorff.py +1 -1
  73. pygeodesy/heights.py +1 -1
  74. pygeodesy/internals.py +1 -1
  75. pygeodesy/interns.py +3 -3
  76. pygeodesy/iters.py +1 -1
  77. pygeodesy/karney.py +152 -151
  78. pygeodesy/ktm.py +1 -1
  79. pygeodesy/latlonBase.py +1 -1
  80. pygeodesy/lazily.py +24 -13
  81. pygeodesy/lcc.py +1 -1
  82. pygeodesy/ltp.py +1 -1
  83. pygeodesy/ltpTuples.py +1 -1
  84. pygeodesy/mgrs.py +3 -3
  85. pygeodesy/named.py +15 -10
  86. pygeodesy/namedTuples.py +1 -1
  87. pygeodesy/nvectorBase.py +1 -1
  88. pygeodesy/osgr.py +1 -1
  89. pygeodesy/points.py +1 -1
  90. pygeodesy/props.py +6 -4
  91. pygeodesy/resections.py +1 -1
  92. pygeodesy/rhumb/__init__.py +8 -6
  93. pygeodesy/rhumb/aux_.py +1 -1
  94. pygeodesy/rhumb/bases.py +1 -1
  95. pygeodesy/rhumb/ekx.py +1 -1
  96. pygeodesy/rhumb/solve.py +91 -84
  97. pygeodesy/simplify.py +1 -1
  98. pygeodesy/solveBase.py +72 -49
  99. pygeodesy/sphericalBase.py +1 -1
  100. pygeodesy/sphericalNvector.py +1 -1
  101. pygeodesy/sphericalTrigonometry.py +1 -1
  102. pygeodesy/streprs.py +6 -4
  103. pygeodesy/trf.py +2 -4
  104. pygeodesy/triaxials/__init__.py +70 -0
  105. pygeodesy/triaxials/bases.py +966 -0
  106. pygeodesy/triaxials/conformal3.py +617 -0
  107. pygeodesy/triaxials/triaxial3.py +968 -0
  108. pygeodesy/{triaxials.py → triaxials/triaxial5.py} +353 -781
  109. pygeodesy/units.py +1 -1
  110. pygeodesy/unitsBase.py +1 -1
  111. pygeodesy/ups.py +2 -3
  112. pygeodesy/utily.py +17 -14
  113. pygeodesy/utm.py +1 -1
  114. pygeodesy/utmups.py +1 -1
  115. pygeodesy/utmupsBase.py +1 -1
  116. pygeodesy/vector2d.py +1 -1
  117. pygeodesy/vector3d.py +1 -1
  118. pygeodesy/vector3dBase.py +1 -1
  119. pygeodesy/webmercator.py +1 -1
  120. pygeodesy/wgrs.py +1 -1
  121. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/METADATA +28 -21
  122. pygeodesy-25.12.31.dist-info/RECORD +125 -0
  123. pygeodesy-25.11.5.dist-info/RECORD +0 -119
  124. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/WHEEL +0 -0
  125. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/top_level.txt +0 -0
pygeodesy/karney.py CHANGED
@@ -19,19 +19,25 @@ Karney-based functionality
19
19
 
20
20
  1. The following classes and functions in C{pygeodesy}
21
21
 
22
- - L{AlbersEqualArea}, L{AlbersEqualArea2}, L{AlbersEqualArea4},
23
- L{AlbersEqualAreaCylindrical}, L{AlbersEqualAreaNorth}, L{AlbersEqualAreaSouth} --
24
- U{AlbersEqualArea<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AlbersEqualArea.html>}
22
+ - L{AlbersEqualArea}, L{AlbersEqualArea2}, L{AlbersEqualArea4}, L{AlbersEqualAreaCylindrical},
23
+ L{AlbersEqualAreaNorth}, L{AlbersEqualAreaSouth} -- U{AlbersEqualArea
24
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AlbersEqualArea.html>}
25
25
 
26
- - L{AuxAngle}, L{AuxDST}, L{AuxDLat}, L{AuxLat} -- U{AuxAngle
27
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxAngle.html>},
28
- U{DST<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1DST.html>},
29
- U{DAuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1DAuxLatitude.html>},
30
- U{AuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxLatitude.html>} in I{GeographicLib 2.2+}
26
+ - L{Ang}, L{Deg}, L{Rad} -- U{AngleT<https://GeographicLib.SourceForge.io/C++/doc/
27
+ classGeographicLib_1_1AngleT.html>} in I{GeographicLib 2.7}.
28
+
29
+ - L{AuxAngle}, L{AuxDST}, L{AuxDLat}, L{AuxLat} -- U{AuxAngle<https://GeographicLib.SourceForge.io/C++/doc/
30
+ classGeographicLib_1_1AuxAngle.html>}, U{DST<https://GeographicLib.SourceForge.io/C++/doc/
31
+ classGeographicLib_1_1DST.html>}, U{DAuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/
32
+ classGeographicLib_1_1DAuxLatitude.html>}, U{AuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/
33
+ classGeographicLib_1_1AuxLatitude.html>} in I{GeographicLib 2.2+}
31
34
 
32
35
  - L{CassiniSoldner} -- U{CassiniSoldner<https://GeographicLib.SourceForge.io/C++/doc/
33
36
  classGeographicLib_1_1CassiniSoldner.html>}
34
37
 
38
+ - L{Conformal3}, L{Conformal3B}, L{Conformal3Sphere} -- U{Conformal3<https://GeographicLib.SourceForge.io/C++/doc/
39
+ classGeographicLib_1_1Triaxial_1_1Conformal3.html>} in I{GeographicLib 2.7}
40
+
35
41
  - L{EcefKarney} -- U{Geocentric<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Geocentric.html>}
36
42
 
37
43
  - L{Elliptic} -- U{EllipticFunction<https://GeographicLib.SourceForge.io/C++/doc/
@@ -40,8 +46,8 @@ Karney-based functionality
40
46
  - L{EquidistantExact}, L{EquidistantGeodSolve}, L{EquidistantKarney} -- U{AzimuthalEquidistant
41
47
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AzimuthalEquidistant.html>}
42
48
 
43
- - L{Etm}, L{ExactTransverseMercator} -- U{TransverseMercatorExact
44
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercatorExact.html>}
49
+ - L{Etm}, L{ExactTransverseMercator} -- U{TransverseMercatorExact<https://GeographicLib.SourceForge.io/C++/doc/
50
+ classGeographicLib_1_1TransverseMercatorExact.html>}
45
51
 
46
52
  - L{Geodesic}, L{GeodesicLine} -- I{wrapped} U{geodesic.Geodesic<https://PyPI.org/project/geographiclib>},
47
53
  I{wrapped} U{geodesicline.GeodesicLine<https://PyPI.org/project/geographiclib>}
@@ -60,29 +66,32 @@ Karney-based functionality
60
66
  - L{GnomonicExact}, L{GnomonicGeodSolve}, L{GnomonicKarney} -- U{Gnomonic
61
67
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Gnomonic.html>}
62
68
 
63
- - L{Intersector} -- U{Intersect
64
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Intersect.html>} from I{GeographicLib 2.3+}
69
+ - L{Intersector} -- U{Intersect<https://GeographicLib.SourceForge.io/C++/doc/
70
+ classGeographicLib_1_1Intersect.html>} from I{GeographicLib 2.3+}
65
71
 
66
72
  - L{JacobiConformal} -- U{JacobiConformal
67
73
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1experimental_1_1JacobiConformal.html>}
68
74
 
69
- - L{KTransverseMercator} - U{TransverseMercator
70
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
75
+ - L{KTransverseMercator} - U{TransverseMercator<https://GeographicLib.SourceForge.io/C++/doc/
76
+ classGeographicLib_1_1TransverseMercator.html>}
71
77
 
72
78
  - L{LocalCartesian}, L{Ltp} -- U{LocalCartesian<https://GeographicLib.SourceForge.io/C++/doc/
73
79
  classGeographicLib_1_1LocalCartesian.html>}
74
80
 
75
81
  - L{Osgr} -- U{OSGB<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1OSGB.html>}
76
82
 
77
- - L{rhumb.aux_}, L{RhumbAux}, L{RhumbLineAux} -- U{Rhumb
78
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Rhumb.html>} and U{RhumbLine
79
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1RhumbLine.html>} from I{GeographicLib 2.2+}
83
+ - L{rhumb.aux_}, L{RhumbAux}, L{RhumbLineAux} -- U{Rhumb<https://GeographicLib.SourceForge.io/C++/doc/
84
+ classGeographicLib_1_1Rhumb.html>} and U{RhumbLine<https://GeographicLib.SourceForge.io/C++/doc/
85
+ classGeographicLib_1_1RhumbLine.html>} from I{GeographicLib 2.2+}
86
+
87
+ - L{rhumb.ekx}, L{Rhumb}, L{RhumbLine} -- U{Rhumb<https://GeographicLib.SourceForge.io/C++/doc/
88
+ classGeographicLib_1_1Rhumb.html>}, U{RhumbLine<https://GeographicLib.SourceForge.io/C++/doc/
89
+ classGeographicLib_1_1RhumbLine.html>}, U{TransverseMercator<https://GeographicLib.SourceForge.io/C++/doc/
90
+ classGeographicLib_1_1TransverseMercator.html>} from I{GeographicLib 2.0}
80
91
 
81
- - L{rhumb.ekx}, L{Rhumb}, L{RhumbLine} -- U{Rhumb
82
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Rhumb.html>},
83
- U{RhumbLine<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1RhumbLine.html>},
84
- U{TransverseMercator<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
85
- from I{GeographicLib 2.0}
92
+ - L{Triaxial3}, L{Triaxial3B} -- U{Cartesian3<https://GeographicLib.SourceForge.io/C++/doc/
93
+ classGeographicLib_1_1Triaxial_1_1Cartesian3.html>}, U{Ellipsoidal3<https://GeographicLib.SourceForge.io/C++/doc/
94
+ classGeographicLib_1_1Triaxial_1_1Ellipsoidal3.html>} in I{GeographicLib 2.7}
86
95
 
87
96
  - L{Ups} -- U{PolarStereographic<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1PolarStereographic.html>}
88
97
 
@@ -90,21 +99,22 @@ Karney-based functionality
90
99
 
91
100
  - L{UtmUps}, L{Epsg} -- U{UTMUPS<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1UTMUPS.html>}
92
101
 
93
- - L{atan1d}, L{atan2d}, L{sincos2}, L{sincos2d}, L{tand} -- U{geomath.Math
94
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Math.html>}
102
+ - L{atan1d}, L{atan2d}, L{sincos2}, L{sincos2d}, L{tand} -- U{geomath.Math<https://GeographicLib.SourceForge.io/C++/doc/
103
+ classGeographicLib_1_1Math.html>}
95
104
 
96
105
  are I{transcoded} from C++ classes in I{Karney}'s U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>}.
97
106
 
98
107
  2. These C{pygeodesy} modules and classes
99
108
 
100
109
  - L{ellipsoidalGeodSolve}, L{ellipsoidalKarney}, L{geodesici}, L{geodsolve}, L{karney}, L{rhumb.solve}
101
- - L{EquidistantKarney}, L{FrechetKarney}, L{GeodesicSolve}, L{GeodesicLineSolve}, L{GnomonicGeodSolve},
102
- L{GnomonicKarney}, L{HeightIDWkarney}, L{Intersectool}
110
+ - L{EquidistantKarney}, L{FrechetKarney}, L{GeodesicSolve}, L{GeodesicLineSolve}, L{Geodesic3Solve},
111
+ L{GeodesicLine3Solve}, L{GnomonicGeodSolve}, L{GnomonicKarney}, L{HeightIDWkarney}, L{Intersectool}
103
112
 
104
113
  are or use I{wrappers} around I{Karney}'s Python U{geographiclib<https://PyPI.org/project/geographiclib>} or
105
- C++ utility U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>},
106
- U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} or
107
- U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>}.
114
+ C++ utility U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}, U{Geod3Solve
115
+ <https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}, U{IntersectTool
116
+ <https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} or U{RhumbSolve
117
+ <https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>}.
108
118
 
109
119
  3. All C{pygeodesy} functions and methods to compute I{ellipsoidal} intersections, nearest points and trilaterations
110
120
 
@@ -143,18 +153,20 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
143
153
  # make sure int/int division yields float quotient, see .basics
144
154
  from __future__ import division as _; del _ # noqa: E702 ;
145
155
 
146
- from pygeodesy.basics import _copysign, _isin, isint, neg, unsigned0, \
147
- _xgeographiclib, _zip
156
+ from pygeodesy.basics import _copysign, _isin, isint, neg, _xgeographiclib, _zip
148
157
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, \
149
158
  _0_0, _1_0, _2_0, _180_0, _N_180_0, _360_0
159
+ # from pygeodesy.deprecated.classes import Rhumb7Tuple # _MODS
150
160
  from pygeodesy.errors import GeodesicError, _ValueError, _xkwds
151
- from pygeodesy.fmath import cbrt, fremainder, norm2 # Fhorner, Fsum
161
+ # from pygeodesy.geod3Solve import Geod3Solve8Tuple # _MODS
162
+ from pygeodesy.fmath import cbrt, fhorner, fremainder, norm2
163
+ from pygeodesy.fsums import _Ksum
152
164
  from pygeodesy.internals import _getenv, _popen2, _PYGEODESY_ENV, typename, \
153
165
  _version_info
154
- from pygeodesy.interns import NN, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
155
- _composite_, _lat1_, _lat2_, _lon1_, _lon2_, \
156
- _m12_, _M12_, _M21_, _number_, _s12_, _S12_, \
157
- _SPACE_, _UNDER_, _X_, _1_, _2_, _BAR_ # PYCHOK used!
166
+ from pygeodesy.interns import NN, _a12_, _area_, _azi2_, _azi12_, _composite_, \
167
+ _lat1_, _lat2_, _lon1_, _lon2_, _m12_, _M12_, \
168
+ _M21_, _number_, _s12_, _S12_, _SPACE_, \
169
+ _UNDER_, _X_, _1_, _2_, _BAR_ # PYCHOK used!
158
170
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
159
171
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
160
172
  from pygeodesy.props import deprecated_method, property_RO, property_ROnce
@@ -165,7 +177,7 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
165
177
  # from math import fabs # from .utily
166
178
 
167
179
  __all__ = _ALL_LAZY.karney
168
- __version__ = '25.09.13'
180
+ __version__ = '25.12.23'
169
181
 
170
182
  _1_16th = _1_0 / 16
171
183
  _2_4_ = '2.4'
@@ -178,6 +190,11 @@ _perimeter_ = 'perimeter'
178
190
  class _GTuple(_NamedTuple): # in .testNamedTuples
179
191
  '''(INTERNAL) Helper.
180
192
  '''
193
+ def _dup_iteration(self, r):
194
+ if self._iteration is not None:
195
+ r._iteration = self._iteration
196
+ return r
197
+
181
198
  def toGDict(self, **updates): # NO name=NN
182
199
  '''Convert this C{*Tuple} to a L{GDict}.
183
200
 
@@ -186,9 +203,15 @@ class _GTuple(_NamedTuple): # in .testNamedTuples
186
203
  r = GDict(_zip(self._Names_, self)) # strict=True
187
204
  if updates:
188
205
  r.update(updates)
189
- if self._iteration is not None:
190
- r._iteration = self._iteration
191
- return r
206
+ return self._dup_iteration(r)
207
+
208
+ def _toTuple(self, nTuple, dflt, updates={}):
209
+ '''(INTERNAL) Convert this C{_GTuple} to an B{C{nTuple}}.
210
+ '''
211
+ _g = self.toGDict(**updates).get
212
+ t = tuple(_g(n, dflt) for n in nTuple._Names_)
213
+ t = nTuple(t, name=self.name)
214
+ return self._dup_iteration(t)
192
215
 
193
216
 
194
217
  class _Lat(Lat):
@@ -444,14 +467,25 @@ class GDict(ADict): # XXX _NamedDict
444
467
  '''
445
468
  return self._toTuple(_MODS.geodsolve.GeodSolve12Tuple, dflt)
446
469
 
470
+ def toGeod3Solve8Tuple(self, dflt=NAN): # PYCHOK 12 args
471
+ '''Convert this L{GDict} result to an 8-Tuple, compatible with I{Karney}'s
472
+ U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}
473
+ result.
474
+
475
+ @kwarg dflt: Default value for missing items (C{any}).
476
+
477
+ @return: L{Geod3Solve8Tuple}C{(bet1, omg1, alp1, bet2, omg2, alp2, s12, a12)}.
478
+ '''
479
+ return self._toTuple(_MODS.geod3solve.Geod3Solve8Tuple, dflt)
480
+
447
481
  def toInverse10Tuple(self, dflt=NAN):
448
482
  '''Convert this L{GDict} result to a 10-tuple, like I{Karney}'s
449
483
  method C{geographiclib.geodesic.Geodesic._GenInverse}.
450
484
 
451
485
  @kwarg dflt: Default value for missing items (C{any}).
452
486
 
453
- @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1,
454
- salp2, calp2, m12, M12, M21, S12)}.
487
+ @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
488
+ m12, M12, M21, S12)}.
455
489
  '''
456
490
  return self._toTuple(Inverse10Tuple, dflt)
457
491
 
@@ -480,8 +514,8 @@ class GDict(ADict): # XXX _NamedDict
480
514
 
481
515
  @kwarg dflt: Default value for missing items (C{any}).
482
516
 
483
- @return: L{Rhumb8Tuple}C{(lat1, lon1, lat2, lon2,
484
- azi12, s12, S12, a12)}.
517
+ @return: L{Rhumb8Tuple}C{(lat1, lon1, lat2, lon2, azi12,
518
+ s12, S12, a12)}.
485
519
  '''
486
520
  return self._toTuple(Rhumb8Tuple, dflt)
487
521
 
@@ -498,9 +532,8 @@ class GDict(ADict): # XXX _NamedDict
498
532
  def _toTuple(self, nTuple, dflt):
499
533
  '''(INTERNAL) Convert this C{GDict} to an B{C{nTuple}}.
500
534
  '''
501
- _g = getattr
502
- t = tuple(_g(self, n, dflt) for n in nTuple._Names_)
503
- return nTuple(t, iteration=self._iteration)
535
+ t = tuple(self.get(n, dflt) for n in nTuple._Names_)
536
+ return nTuple(t, iteration=self._iteration, name=self.name) # PYCHOK name
504
537
 
505
538
  def _2X(self, gl, _2X=_X_): # .Intersectool, .Intersector
506
539
  '''(INTERNAL) Rename C{-2} attr to C{-X} or C{-M}.
@@ -523,19 +556,6 @@ class GDict(ADict): # XXX _NamedDict
523
556
  return self
524
557
 
525
558
 
526
- class GeodSolve12Tuple(_GTuple):
527
- '''12-Tuple C{(lat1, lon1, azi1, lat2, lon2, azi2, s12, a12, m12, M12, M21, S12)} with
528
- angles C{lat1}, C{lon1}, C{azi1}, C{lat2}, C{lon2} and C{azi2} and arc C{a12} all in
529
- C{degrees}, initial C{azi1} and final C{azi2} forward azimuths, distance C{s12} and
530
- reduced length C{m12} in C{meter}, area C{S12} in C{meter} I{squared} and geodesic
531
- scale factors C{M12} and C{M21}, both C{scalar}, see U{GeodSolve
532
- <https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}.
533
- '''
534
- # from GeodSolve --help option -f ... lat1 lon1 azi1 lat2 lon2 azi2 s12 a12 m12 M12 M21 S12
535
- _Names_ = (_lat1_, _lon1_, _azi1_, _lat2_, _lon2_, _azi2_, _s12_, _a12_, _m12_, _M12_, _M21_, _S12_)
536
- _Units_ = (_Lat, _Lon, _Azi, _Lat, _Lon, _Azi, _M, _Deg, _Pass, _Pass, _Pass, _M2)
537
-
538
-
539
559
  class Inverse10Tuple(_GTuple):
540
560
  '''10-Tuple C{(a12, s12, salp1, calp1, salp2, calp2, m12, M12, M21, S12)} with arc length
541
561
  C{a12} in C{degrees}, distance C{s12} and reduced length C{m12} in C{meter}, area
@@ -555,6 +575,56 @@ class Inverse10Tuple(_GTuple):
555
575
  **updates) # PYCHOK indent
556
576
 
557
577
 
578
+ class Rhumb8Tuple(_GTuple):
579
+ '''8-Tuple C{(lat1, lon1, lat2, lon2, azi12, s12, S12, a12)} with lat- C{lat1},
580
+ C{lat2} and longitudes C{lon1}, C{lon2} of both points, the azimuth of the
581
+ rhumb line C{azi12}, the distance C{s12}, the area C{S12} under the rhumb
582
+ line and the angular distance C{a12} between both points.
583
+ '''
584
+ _Names_ = (_lat1_, _lon1_, _lat2_, _lon2_, _azi12_, _s12_, _S12_, _a12_)
585
+ _Units_ = ( Lat, Lon, Lat, Lon, _Azi, _M, _M2, _Deg)
586
+
587
+ def toDirect9Tuple(self, dflt=NAN, **a12_azi1_azi2_m12_M12_M21):
588
+ '''Convert this L{Rhumb8Tuple} result to a 9-tuple, like I{Karney}'s
589
+ method C{geographiclib.geodesic.Geodesic._GenDirect}.
590
+
591
+ @kwarg dflt: Default value for missing items (C{any}).
592
+ @kwarg a12_azi1_azi2_m12_M12_M21: Optional keyword arguments
593
+ to specify or override L{Inverse10Tuple} items.
594
+
595
+ @return: L{Direct9Tuple}C{(a12, lat2, lon2, azi2, s12,
596
+ m12, M12, M21, S12)}
597
+ '''
598
+ d = dict(azi1=self.azi12, M12=_1_0, m12=self.s12, # PYCHOK attr
599
+ azi2=self.azi12, M21=_1_0) # PYCHOK attr
600
+ if a12_azi1_azi2_m12_M12_M21:
601
+ d.update(a12_azi1_azi2_m12_M12_M21)
602
+ return self._toTuple(Direct9Tuple, dflt, d)
603
+
604
+ def toInverse10Tuple(self, dflt=NAN, **a12_m12_M12_M21_salp1_calp1_salp2_calp2):
605
+ '''Convert this L{Rhumb8Tuple} to a 10-tuple, like I{Karney}'s
606
+ method C{geographiclib.geodesic.Geodesic._GenInverse}.
607
+
608
+ @kwarg dflt: Default value for missing items (C{any}).
609
+ @kwarg a12_m12_M12_M21_salp1_calp1_salp2_calp2: Optional keyword
610
+ arguments to specify or override L{Inverse10Tuple} items.
611
+
612
+ @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
613
+ m12, M12, M21, S12)}.
614
+ '''
615
+ s, c = _sincos2d(self.azi12) # PYCHOK attr
616
+ d = dict(salp1=s, calp1=c, M12=_1_0, m12=self.s12, # PYCHOK attr
617
+ salp2=s, calp2=c, M21=_1_0)
618
+ if a12_m12_M12_M21_salp1_calp1_salp2_calp2:
619
+ d.update(a12_m12_M12_M21_salp1_calp1_salp2_calp2)
620
+ return self._toTuple(Inverse10Tuple, dflt, d)
621
+
622
+ @deprecated_method
623
+ def _to7Tuple(self): # in DEPRECATED Rhumb7Tuple
624
+ '''DEPRECATED, I{do not use!}'''
625
+ return _MODS.deprecated.classes.Rhumb7Tuple(self[:-1])
626
+
627
+
558
628
  class _kWrapped(_CapsBase): # in .geodesicw
559
629
  '''(INTERNAL) Wrapper for some of I{Karney}'s U{geographiclib
560
630
  <https://PyPI.org/project/geographiclib>} classes.
@@ -608,67 +678,10 @@ class _kWrapped(_CapsBase): # in .geodesicw
608
678
  _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
609
679
 
610
680
 
611
- class Rhumb8Tuple(_GTuple):
612
- '''8-Tuple C{(lat1, lon1, lat2, lon2, azi12, s12, S12, a12)} with lat- C{lat1},
613
- C{lat2} and longitudes C{lon1}, C{lon2} of both points, the azimuth of the
614
- rhumb line C{azi12}, the distance C{s12}, the area C{S12} under the rhumb
615
- line and the angular distance C{a12} between both points.
616
- '''
617
- _Names_ = (_lat1_, _lon1_, _lat2_, _lon2_, _azi12_, _s12_, _S12_, _a12_)
618
- _Units_ = ( Lat, Lon, Lat, Lon, _Azi, _M, _M2, _Deg)
619
-
620
- def toDirect9Tuple(self, dflt=NAN, **a12_azi1_azi2_m12_M12_M21):
621
- '''Convert this L{Rhumb8Tuple} result to a 9-tuple, like I{Karney}'s
622
- method C{geographiclib.geodesic.Geodesic._GenDirect}.
623
-
624
- @kwarg dflt: Default value for missing items (C{any}).
625
- @kwarg a12_azi1_azi2_m12_M12_M21: Optional keyword arguments
626
- to specify or override L{Inverse10Tuple} items.
627
-
628
- @return: L{Direct9Tuple}C{(a12, lat2, lon2, azi2, s12,
629
- m12, M12, M21, S12)}
630
- '''
631
- d = dict(azi1=self.azi12, M12=_1_0, m12=self.s12, # PYCHOK attr
632
- azi2=self.azi12, M21=_1_0) # PYCHOK attr
633
- if a12_azi1_azi2_m12_M12_M21:
634
- d.update(a12_azi1_azi2_m12_M12_M21)
635
- return self._toTuple(Direct9Tuple, dflt, d)
636
-
637
- def toInverse10Tuple(self, dflt=NAN, **a12_m12_M12_M21_salp1_calp1_salp2_calp2):
638
- '''Convert this L{Rhumb8Tuple} to a 10-tuple, like I{Karney}'s
639
- method C{geographiclib.geodesic.Geodesic._GenInverse}.
640
-
641
- @kwarg dflt: Default value for missing items (C{any}).
642
- @kwarg a12_m12_M12_M21_salp1_calp1_salp2_calp2: Optional keyword
643
- arguments to specify or override L{Inverse10Tuple} items.
644
-
645
- @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
646
- m12, M12, M21, S12)}.
647
- '''
648
- s, c = sincos2d(self.azi12) # PYCHOK attr
649
- d = dict(salp1=s, calp1=c, M12=_1_0, m12=self.s12, # PYCHOK attr
650
- salp2=s, calp2=c, M21=_1_0)
651
- if a12_m12_M12_M21_salp1_calp1_salp2_calp2:
652
- d.update(a12_m12_M12_M21_salp1_calp1_salp2_calp2)
653
- return self._toTuple(Inverse10Tuple, dflt, d)
654
-
655
- def _toTuple(self, nTuple, dflt, updates={}):
656
- '''(INTERNAL) Convert this C{Rhumb8Tuple} to an B{C{nTuple}}.
657
- '''
658
- _g = self.toGDict(**updates).get
659
- t = tuple(_g(n, dflt) for n in nTuple._Names_)
660
- return nTuple(t, name=self.name)
661
-
662
- @deprecated_method
663
- def _to7Tuple(self):
664
- '''DEPRECATED, do not use!'''
665
- return _MODS.deprecated.classes.Rhumb7Tuple(self[:-1])
666
-
667
-
668
681
  class _Xables(object):
669
682
  '''(INTERNAL) Get I{Karney}'s executable paths from/and env vars.
670
683
  '''
671
- bin_ = '/opt/local/bin/' # '/opt/local/Cellar/geographiclib/2.3/bin/' # HomeBrew on macOS
684
+ bin_ = '/opt/local/bin/' # '/opt/local/Cellar/geographiclib/2.X/bin/' # HomeBrew on macOS
672
685
  ENV = NN
673
686
 
674
687
  def GeoConvert(self, *dir_):
@@ -677,6 +690,9 @@ class _Xables(object):
677
690
  def GeodSolve(self, *dir_):
678
691
  return self._path(self.GeodSolve, *dir_)
679
692
 
693
+ def Geod3Solve(self, *dir_):
694
+ return self._path(self.Geod3Solve, *dir_)
695
+
680
696
  def IntersectTool(self, *dir_):
681
697
  return self._path(self.IntersectTool, *dir_)
682
698
 
@@ -897,20 +913,18 @@ try:
897
913
 
898
914
  except ImportError: # Python 3.12-
899
915
 
900
- def _poly_fma(x, s, *cs): # PYCHOK redef
901
- t = _0_0
902
- for c in cs:
903
- s, t, _ = _sum3(s * x, t * x, c)
904
- return s + t
916
+ def _poly_fma(x, *cs): # PYCHOK redef
917
+ return fhorner(x, *cs, incx=False)
905
918
 
906
919
  # def _poly_fma(x, s, *cs):
907
- # S = Fhorner(x, *cs, incx=False)
908
- # S += s
909
- # return float(S)
920
+ # t = _0_0
921
+ # for c in cs:
922
+ # s, t, _ = _sum3(s * x, t * x, c)
923
+ # return s + t
910
924
 
911
925
  def _polynomial(x, cs, i, j): # PYCHOK shared
912
- '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but with a
913
- signature and cascaded summation different from C{karney._sum3}.
926
+ '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but
927
+ with a different signature and cascaded summation.
914
928
 
915
929
  @return: M{sum(x**(j - k - 1) * cs[k] for k in range(i, j)}
916
930
  '''
@@ -991,18 +1005,18 @@ def _sum2(a, b): # mimick geomath.Math.sum, actually sum2
991
1005
  r = s - b
992
1006
  t = s - r
993
1007
  # elif C_CPP: # Math::sum C/C++
994
- # r -= a; t -= b; t += r; t = -t
995
- # else:
996
- t = (a - r) + (b - t)
1008
+ # r -= a; t -= b; t += r; t = (-t) if s else s
1009
+ # else: # if s == 0: t = _copysign_0_0(s)
1010
+ t = ((a - r) + (b - t)) if s else s
997
1011
  # assert fabs(s) >= fabs(t)
998
1012
  return s, t
999
1013
 
1000
1014
 
1001
1015
  def _sum3(s, t, *xs):
1002
- '''Accumulate any B{C{xs}} into a previous C{_sum2(s, t)}.
1016
+ '''Accumulate all B{C{xs}} scalars into a previous C{_sum2(s, t)}.
1003
1017
 
1004
1018
  @return: 3-Tuple C{(s, t, n)} where C{s} is the sum of B{s}, B{t} and all
1005
- B{xs}, C{t} the residual and C{n} the number of zero C{xs}.
1019
+ B{xs}, C{t} the residual and C{n} the number of non-zero C{xs}.
1006
1020
 
1007
1021
  @see: I{Karney's} C++ U{Accumulator<https://GeographicLib.SourceForge.io/
1008
1022
  C++/doc/Accumulator_8hpp_source.html>} comments for more details and
@@ -1010,23 +1024,10 @@ def _sum3(s, t, *xs):
1010
1024
 
1011
1025
  @note: Not "error-free", see C{pygeodesy.test/testKarney.py}.
1012
1026
  '''
1013
- z = 0
1014
- for x in xs:
1015
- if x:
1016
- t, r = _sum2(t, x) # start at the least-
1017
- if s:
1018
- s, t = _sum2(s, t) # -significant end
1019
- if s:
1020
- t += r # accumulate r into t
1021
- else:
1022
- # assert t == 0 # s == 0 implies t == 0
1023
- s = unsigned0(r) # result is r, t = 0
1024
- else:
1025
- s, t = unsigned0(t), r
1026
- else:
1027
- z += 1
1028
- # assert fabs(s) >= fabs(t)
1029
- return s, t, z
1027
+ return _Ksum(s, t, *xs)._s_t_n3 if xs else (s, t, 0)
1028
+ # previous _sum3 in .geodesicx.gxarea._Accumulator.Add
1029
+ # which fails .fmath.frandoms tests, but does pass
1030
+ # _sum3(1e20, 1, 2, 100, 5000, -1e20) ... 5103.0, 0.0, 4
1030
1031
 
1031
1032
 
1032
1033
  def _tand(x):
@@ -1063,7 +1064,7 @@ __all__ += _ALL_DOCS(Caps, _CapsBase)
1063
1064
 
1064
1065
  # **) MIT License
1065
1066
  #
1066
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1067
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1067
1068
  #
1068
1069
  # Permission is hereby granted, free of charge, to any person obtaining a
1069
1070
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/ktm.py CHANGED
@@ -612,7 +612,7 @@ if __name__ == _DMAIN_:
612
612
 
613
613
  # **) MIT License
614
614
  #
615
- # Copyright (C) 2022-2025 -- mrJean1 at Gmail -- All Rights Reserved.
615
+ # Copyright (C) 2022-2026 -- mrJean1 at Gmail -- All Rights Reserved.
616
616
  #
617
617
  # Permission is hereby granted, free of charge, to any person obtaining a
618
618
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/latlonBase.py CHANGED
@@ -1672,7 +1672,7 @@ __all__ += _ALL_DOCS(LatLonBase)
1672
1672
 
1673
1673
  # **) MIT License
1674
1674
  #
1675
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1675
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1676
1676
  #
1677
1677
  # Permission is hereby granted, free of charge, to any person obtaining a
1678
1678
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/lazily.py CHANGED
@@ -179,6 +179,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
179
179
  albers=_a('AlbersEqualArea', 'AlbersEqualArea2', 'AlbersEqualArea4',
180
180
  'AlbersEqualAreaCylindrical', 'AlbersEqualAreaNorth', 'AlbersEqualAreaSouth',
181
181
  'AlbersError', 'Albers7Tuple'),
182
+ angles=_a('Ang', 'Deg', 'Lambertian', 'Rad', 'isAng'),
182
183
  auxilats=_a(), # module only
183
184
  azimuthal=_a('AzimuthalError', 'Azimuthal7Tuple',
184
185
  'Equidistant', 'EquidistantExact', 'EquidistantGeodSolve', 'EquidistantKarney',
@@ -199,9 +200,9 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
199
200
  'clipCS4', 'clipFHP4', 'clipGH4', 'clipLB6', 'clipSH', 'clipSH3'),
200
201
  css=_a('CassiniSoldner', 'Css', 'CSSError', 'toCss',
201
202
  'EasNorAziRk4Tuple', 'EasNorAziRkEqu6Tuple', 'LatLonAziRk4Tuple'),
202
- constants=_a('DIG', 'EPS', 'EPS0', 'EPS02', 'EPS1', 'EPS2', 'EPS4', 'EPS_2',
203
+ constants=_a('DIG', 'EPS', 'EPS0', 'EPS02', 'EPS1', 'EPS2', 'EPS4', 'EPS8', 'EPS_2',
203
204
  'INF', 'INT0', 'MANT_DIG', 'MAX', 'MAX_EXP', 'MIN', 'MIN_EXP', 'NAN', 'NEG0', 'NINF',
204
- 'PI', 'PI2', 'PI_2', 'PI3', 'PI_3', 'PI3_2', 'PI4', 'PI_4', 'PI_6',
205
+ 'OVERFLOW', 'PI', 'PI2', 'PI_2', 'PI3', 'PI_3', 'PI3_2', 'PI4', 'PI_4', 'PI_6',
205
206
  'R_FM', 'R_GM', 'R_KM', 'R_M', 'R_MA', 'R_MB', 'R_NM', 'R_QM', 'R_SM', 'R_VM',
206
207
  'float_', 'float0_', 'floats_', 'isclose', 'isfinite', 'isinf', 'isint0',
207
208
  'isnan', 'isnear0', 'isnear1', 'isnear90', 'isneg', 'isneg0', 'isninf', 'isnon0',
@@ -249,10 +250,10 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
249
250
  'fpolynomial', 'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
250
251
  'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
251
252
  'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
252
- formy=_a('Radical2Tuple',
253
+ formy=_a('Elliperim', 'Radical2Tuple',
253
254
  'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_',
254
255
  'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_',
255
- 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',
256
+ 'elliperim', 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',
256
257
  'excessAbc_', 'excessCagnoli_', 'excessGirard_', 'excessLHuilier_',
257
258
  'excessKarney', 'excessKarney_', 'excessQuad', 'excessQuad_',
258
259
  'flatLocal', 'flatLocal_', 'flatPolar', 'flatPolar_',
@@ -275,6 +276,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
275
276
  geodesicx=_a('gx', 'gxarea', 'gxbases', 'gxline', # modules
276
277
  'GeodesicAreaExact', 'GeodesicExact', 'GeodesicLineExact', 'PolygonArea'),
277
278
  geodsolve=_a('GeodesicSolve', 'GeodesicLineSolve', 'GeodSolve12Tuple'),
279
+ geod3solve=_a('Geodesic3Solve', 'GeodesicLine3Solve', 'Geod3Solve8Tuple', 'Geodesic3Error'),
278
280
  geohash=_a('Geohash', 'Geohashed', 'GeohashError', 'Neighbors8Dict', 'Resolutions2Tuple', 'Sizes3Tuple'),
279
281
  geoids=_a('GeoidError', 'GeoidEGM96', 'GeoidG2012B', 'GeoidKarney', 'GeoidPGM', 'egmGeoidHeights',
280
282
  'PGMError', 'GeoidHeight5Tuple'),
@@ -291,7 +293,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
291
293
  interns=_interns.__all__,
292
294
  iters=_a('LatLon2PsxyIter', 'PointsIter', 'points2',
293
295
  'isNumpy2', 'isPoints2', 'isTuple2', 'iterNumpy2', 'iterNumpy2over'),
294
- karney=_a('Area3Tuple', 'Caps', 'Direct9Tuple', 'GDict', 'Inverse10Tuple', 'Rhumb8Tuple'),
296
+ karney=_a('Area3Tuple', 'Caps', 'Direct9Tuple', 'GDict', 'Inverse10Tuple'),
295
297
  ktm=_a('KTMError', 'KTransverseMercator'),
296
298
  latlonBase=_a('latlon2n_xyz', 'philam2n_xyz'),
297
299
  lazily=_a('LazyAttributeError', 'LazyImportError', 'isLazy'),
@@ -336,7 +338,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
336
338
  rhumb=_a(), # module only
337
339
  rhumb_aux_=_a('RhumbAux', 'RhumbLineAux'),
338
340
  rhumb_ekx=_a('Rhumb', 'RhumbLine'),
339
- rhumb_solve=_a('RhumbSolve', 'RhumbLineSolve', 'RhumbSolve7Tuple'),
341
+ rhumb_solve=_a('RhumbSolve', 'RhumbLineSolve', 'RhumbSolve7Tuple', 'Rhumb8Tuple'), # in .karney
340
342
  sphericalBase=_a(), # module only
341
343
  sphericalNvector=_a(), # module only
342
344
  sphericalTrigonometry=_a(), # module only
@@ -346,9 +348,15 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
346
348
  'lrstrip', 'pairs', 'reprs', 'strs', 'unstr'),
347
349
  trf=_a('RefFrame', 'RefFrames', 'TransformXform', 'TRFXform', 'TRFXform7Tuple',
348
350
  'date2epoch', 'epoch2date', 'trfTransform0', 'trfTransforms', 'trfXform'),
349
- triaxials=_a('BetaOmega2Tuple', 'BetaOmega3Tuple',
350
- 'ConformalSphere', 'ConformalTriaxial', 'Conformal2Tuple',
351
- 'Triaxial', 'Triaxial_', 'TriaxialError', 'Triaxials', 'hartzell4'), # 'height4'
351
+ triaxials=_a(), # module only
352
+ triaxials_bases=_a('LLK', 'TriaxialError'),
353
+ triaxials_conformal3=_a('BetOmgGam5Tuple',
354
+ 'Conformal3', 'Conformal3B', 'Conformal3Sphere', 'Conformal5Tuple'),
355
+ triaxials_triaxial3=_a('BetOmgAlp5Tuple', 'Cartesian5Tuple', 'PhiLamZet5Tuple',
356
+ 'Triaxial3', 'Triaxial3B', 'Triaxial3s'),
357
+ triaxials_triaxial5=_a('BetaOmega2Tuple', 'BetaOmega3Tuple',
358
+ 'Conformal', 'ConformalSphere', 'Conformal2Tuple',
359
+ 'Triaxial', 'Triaxial_', 'Triaxials', 'hartzell4', 'height4'),
352
360
  units=_a('Azimuth', 'Band', 'Bearing', 'Bearing_', 'Bool',
353
361
  'Degrees', 'Degrees_', 'Degrees2', 'Distance', 'Distance_', 'Easting', 'Epoch',
354
362
  'Feet', 'FIx', 'Float_', 'Height', 'Height_', 'HeightX', 'Int_',
@@ -512,7 +520,7 @@ class _ALL_MODS(_internals._MODS_Base):
512
520
  _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
513
521
 
514
522
  __all__ = _ALL_LAZY.lazily
515
- __version__ = '25.10.30'
523
+ __version__ = '25.12.23'
516
524
 
517
525
 
518
526
  def _ALL_OTHER(*objs):
@@ -617,7 +625,7 @@ def _getmodinto(mod_DNAME, *Intos):
617
625
  assert isinstance(i, Intos)
618
626
  m = _MODS.getmodule(mod)
619
627
  setattr(d, _mod, m) # overwrite C{d._mod}
620
- if isLazy > 1:
628
+ if isLazy and isLazy > 1:
621
629
  t = _SPACE_(_HASH_, _imported_, m.__name__) # typename(m)
622
630
  _hash_imported(t, _MODS.into.__name__)
623
631
  assert getattr(d, _mod, None) is m
@@ -637,7 +645,7 @@ def _getmodule(name, *parent):
637
645
  def _hash_imported(t, by_into, up=3):
638
646
  '''(INTERNAL) Helper for C{_lazy_import2} and C{_ALL_MODS.into}.
639
647
  '''
640
- if isLazy > 2:
648
+ if isLazy and isLazy > 2:
641
649
  try: # see C{internals._caller3}
642
650
  _, f, s = _caller3(up)
643
651
  t = _SPACE_(t, by_into, f, _line_, s)
@@ -907,6 +915,9 @@ if __name__ == _DMAIN_:
907
915
 
908
916
  _main()
909
917
 
918
+ # % python3.14 -W ignore -m pygeodesy.lazily
919
+ # 0.061219 import vs 0.047896 _ALL_MODS: 1.28X, pygeodesy 25.12.6 Python 3.14.0 64bit arm64 macOS 26.1
920
+
910
921
  # % python3.13 -W ignore -m pygeodesy.lazily
911
922
  # 0.054235 import vs 0.052469 _ALL_MODS: 1.03X, pygeodesy 25.4.24 Python 3.13.3 64bit arm64 macOS 15.4
912
923
 
@@ -933,7 +944,7 @@ if __name__ == _DMAIN_:
933
944
 
934
945
  # **) MIT License
935
946
  #
936
- # Copyright (C) 2018-2025 -- mrJean1 at Gmail -- All Rights Reserved.
947
+ # Copyright (C) 2018-2026 -- mrJean1 at Gmail -- All Rights Reserved.
937
948
  #
938
949
  # Permission is hereby granted, free of charge, to any person obtaining a
939
950
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/lcc.py CHANGED
@@ -661,7 +661,7 @@ if __name__ == _DMAIN_:
661
661
 
662
662
  # **) MIT License
663
663
  #
664
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
664
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
665
665
  #
666
666
  # Permission is hereby granted, free of charge, to any person obtaining a
667
667
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/ltp.py CHANGED
@@ -1128,7 +1128,7 @@ def _xLtp(ltp, *dflt):
1128
1128
 
1129
1129
  # **) MIT License
1130
1130
  #
1131
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1131
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1132
1132
  #
1133
1133
  # Permission is hereby granted, free of charge, to any person obtaining a
1134
1134
  # copy of this software and associated documentation files (the "Software"),