pygeodesy 24.10.24__py2.py3-none-any.whl → 24.11.11__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 (54) hide show
  1. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +4 -4
  2. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/RECORD +54 -54
  3. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +2 -2
  5. pygeodesy/azimuthal.py +51 -61
  6. pygeodesy/basics.py +34 -33
  7. pygeodesy/booleans.py +36 -36
  8. pygeodesy/cartesianBase.py +5 -5
  9. pygeodesy/constants.py +4 -4
  10. pygeodesy/css.py +7 -8
  11. pygeodesy/deprecated/__init__.py +1 -1
  12. pygeodesy/deprecated/classes.py +9 -9
  13. pygeodesy/deprecated/functions.py +6 -6
  14. pygeodesy/ecef.py +11 -14
  15. pygeodesy/ellipsoidalBase.py +105 -120
  16. pygeodesy/ellipsoidalBaseDI.py +114 -118
  17. pygeodesy/ellipsoidalExact.py +35 -37
  18. pygeodesy/ellipsoids.py +3 -3
  19. pygeodesy/errors.py +24 -24
  20. pygeodesy/etm.py +80 -72
  21. pygeodesy/fmath.py +39 -37
  22. pygeodesy/formy.py +3 -2
  23. pygeodesy/fsums.py +51 -40
  24. pygeodesy/geodesicw.py +15 -14
  25. pygeodesy/geodesicx/__init__.py +2 -2
  26. pygeodesy/geodsolve.py +7 -16
  27. pygeodesy/geoids.py +5 -5
  28. pygeodesy/heights.py +2 -2
  29. pygeodesy/internals.py +63 -79
  30. pygeodesy/karney.py +2 -2
  31. pygeodesy/ktm.py +11 -13
  32. pygeodesy/latlonBase.py +6 -6
  33. pygeodesy/lazily.py +5 -5
  34. pygeodesy/lcc.py +4 -4
  35. pygeodesy/ltp.py +10 -10
  36. pygeodesy/ltpTuples.py +74 -75
  37. pygeodesy/mgrs.py +9 -10
  38. pygeodesy/named.py +4 -0
  39. pygeodesy/osgr.py +9 -12
  40. pygeodesy/props.py +2 -2
  41. pygeodesy/resections.py +9 -10
  42. pygeodesy/rhumb/__init__.py +1 -1
  43. pygeodesy/rhumb/solve.py +3 -3
  44. pygeodesy/simplify.py +5 -5
  45. pygeodesy/sphericalNvector.py +80 -123
  46. pygeodesy/sphericalTrigonometry.py +60 -66
  47. pygeodesy/units.py +2 -2
  48. pygeodesy/utm.py +6 -6
  49. pygeodesy/vector2d.py +13 -13
  50. pygeodesy/vector3d.py +19 -21
  51. pygeodesy/vector3dBase.py +18 -15
  52. pygeodesy/webmercator.py +4 -4
  53. pygeodesy/wgrs.py +4 -4
  54. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,7 @@ from pygeodesy.points import _areaError, ispolar # PYCHOK exported
24
24
  # from math import fabs # from .karney
25
25
 
26
26
  __all__ = _ALL_LAZY.ellipsoidalExact
27
- __version__ = '24.08.13'
27
+ __version__ = '24.11.06'
28
28
 
29
29
 
30
30
  class Cartesian(CartesianEllipsoidalBase):
@@ -119,30 +119,28 @@ def areaOf(points, datum=_WGS84, wrap=True):
119
119
 
120
120
 
121
121
  def intersection3(start1, end1, start2, end2, height=None, wrap=False, # was=True
122
- equidistant=None, tol=_TOL_M, LatLon=LatLon, **LatLon_kwds):
123
- '''I{Iteratively} compute the intersection point of two lines, each defined
124
- by two (ellipsoidal) points or by an (ellipsoidal) start point and an
125
- initial bearing from North.
122
+ equidistant=None, tol=_TOL_M, **LatLon_and_kwds):
123
+ '''I{Iteratively} compute the intersection point of two geodesic lines, each
124
+ given as two points or as an start point and a bearing from North.
126
125
 
127
126
  @arg start1: Start point of the first line (L{LatLon}).
128
127
  @arg end1: End point of the first line (L{LatLon}) or the initial bearing
129
- at the first point (compass C{degrees360}).
128
+ at B{C{start1}} (compass C{degrees360}).
130
129
  @arg start2: Start point of the second line (L{LatLon}).
131
130
  @arg end2: End point of the second line (L{LatLon}) or the initial bearing
132
- at the second point (compass C{degrees360}).
131
+ at B{C{start2}} (compass C{degrees360}).
133
132
  @kwarg height: Optional height at the intersection (C{meter}, conventionally)
134
133
  or C{None} for the mean height.
135
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{start2}}
136
- and B{C{end*}} points (C{bool}).
134
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{start2}} and
135
+ both B{C{end*}} points (C{bool}).
137
136
  @kwarg equidistant: An azimuthal equidistant projection (I{class} or function
138
137
  L{pygeodesy.equidistant}) or C{None} for the preferred
139
138
  C{B{start1}.Equidistant}.
140
139
  @kwarg tol: Tolerance for convergence and for skew line distance and length
141
140
  (C{meter}, conventionally).
142
- @kwarg LatLon: Optional class to return the intersection points (L{LatLon})
143
- or C{None}.
144
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword arguments,
145
- ignored if C{B{LatLon} is None}.
141
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to return the
142
+ intersection points and optionally, additional B{C{LatLon}}
143
+ keyword arguments, ignored if C{B{LatLon}=None}.
146
144
 
147
145
  @return: An L{Intersection3Tuple}C{(point, outside1, outside2)} with C{point}
148
146
  a B{C{LatLon}} or if C{B{LatLon} is None}, a L{LatLon4Tuple}C{(lat,
@@ -154,23 +152,23 @@ def intersection3(start1, end1, start2, end2, height=None, wrap=False, # was=Tr
154
152
  @raise TypeError: Invalid or non-ellipsoidal B{C{start1}}, B{C{end1}},
155
153
  B{C{start2}} or B{C{end2}} or invalid B{C{equidistant}}.
156
154
 
157
- @note: For each line specified with an initial bearing, a pseudo-end point
158
- is computed as the C{destination} along that bearing at about 1.5
159
- times the distance from the start point to an initial gu-/estimate
160
- of the intersection point (and between 1/8 and 3/8 of the authalic
161
- earth perimeter).
155
+ @note: For each line specified with an initial bearing, a pseudo-end point is
156
+ computed as the C{destination} along that bearing at about 1.5 times the
157
+ distance from the start point to an initial gu-/estimate of the intersection
158
+ point (and between 1/8 and 3/8 of the authalic earth perimeter).
162
159
 
163
160
  @see: U{The B{ellipsoidal} case<https://GIS.StackExchange.com/questions/48937/
164
161
  calculating-intersection-of-two-circles>} and U{Karney's paper
165
162
  <https://ArXiv.org/pdf/1102.1215.pdf>}, pp 20-21, section B{14. MARITIME
166
163
  BOUNDARIES} for more details about the iteration algorithm.
167
164
  '''
165
+ kwds = _xkwds(LatLon_and_kwds, LatLon=LatLon)
168
166
  return _intersection3(start1, end1, start2, end2, height=height, wrap=wrap,
169
- equidistant=equidistant, tol=tol, LatLon=LatLon, **LatLon_kwds)
167
+ equidistant=equidistant, tol=tol, **kwds)
170
168
 
171
169
 
172
170
  def intersections2(center1, radius1, center2, radius2, height=None, wrap=False, # was=True
173
- equidistant=None, tol=_TOL_M, LatLon=LatLon, **LatLon_kwds):
171
+ equidistant=None, tol=_TOL_M, **LatLon_and_kwds):
174
172
  '''I{Iteratively} compute the intersection points of two circles, each defined
175
173
  by an (ellipsoidal) center point and a radius.
176
174
 
@@ -189,10 +187,9 @@ def intersections2(center1, radius1, center2, radius2, height=None, wrap=False,
189
187
  the preferred C{B{center1}.Equidistant}.
190
188
  @kwarg tol: Convergence tolerance (C{meter}, same units as B{C{radius1}}
191
189
  and B{C{radius2}}).
192
- @kwarg LatLon: Optional class to return the intersection points (L{LatLon})
193
- or C{None}.
194
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword arguments,
195
- ignored if C{B{LatLon} is None}.
190
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to return the
191
+ intersection points and optionally, additional B{C{LatLon}}
192
+ keyword arguments, ignored if C{B{LatLon}=None}.
196
193
 
197
194
  @return: 2-Tuple of the intersection points, each a B{C{LatLon}} instance
198
195
  or L{LatLon4Tuple}C{(lat, lon, height, datum)} if C{B{LatLon} is
@@ -214,8 +211,9 @@ def intersections2(center1, radius1, center2, radius2, height=None, wrap=False,
214
211
  U{sphere-sphere<https://MathWorld.Wolfram.com/Sphere-SphereIntersection.html>}
215
212
  intersections.
216
213
  '''
214
+ kwds = _xkwds(LatLon_and_kwds, LatLon=LatLon)
217
215
  return _intersections2(center1, radius1, center2, radius2, height=height, wrap=wrap,
218
- equidistant=equidistant, tol=tol, LatLon=LatLon, **LatLon_kwds)
216
+ equidistant=equidistant, tol=tol, **kwds)
219
217
 
220
218
 
221
219
  def isclockwise(points, datum=_WGS84, wrap=True):
@@ -245,9 +243,9 @@ def isclockwise(points, datum=_WGS84, wrap=True):
245
243
 
246
244
 
247
245
  def nearestOn(point, point1, point2, within=True, height=None, wrap=False,
248
- equidistant=None, tol=_TOL_M, LatLon=LatLon, **LatLon_kwds):
249
- '''I{Iteratively} locate the closest point on the geodesic between
250
- two other (ellispoidal) points.
246
+ equidistant=None, tol=_TOL_M, **LatLon_and_kwds):
247
+ '''I{Iteratively} locate the closest point on the geodesic (line)
248
+ between two other (ellipsoidal) points.
251
249
 
252
250
  @arg point: Reference point (C{LatLon}).
253
251
  @arg point1: Start point of the geodesic (C{LatLon}).
@@ -265,16 +263,15 @@ def nearestOn(point, point1, point2, within=True, height=None, wrap=False,
265
263
  or function L{pygeodesy.equidistant}) or C{None}
266
264
  for the preferred C{B{point}.Equidistant}.
267
265
  @kwarg tol: Convergence tolerance (C{meter}).
268
- @kwarg LatLon: Optional class to return the closest point
269
- (L{LatLon}) or C{None}.
270
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
271
- arguments, ignored if C{B{LatLon} is None}.
266
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to return the
267
+ closest point and optionally, additional B{C{LatLon}} keyword
268
+ arguments, ignored if C{B{LatLon}=None}.
272
269
 
273
- @return: Closest point, a B{C{LatLon}} instance or if C{B{LatLon}
274
- is None}, a L{LatLon4Tuple}C{(lat, lon, height, datum)}.
270
+ @return: Closest point, a B{C{LatLon}} instance or if C{B{LatLon} is None},
271
+ a L{LatLon4Tuple}C{(lat, lon, height, datum)}.
275
272
 
276
- @raise TypeError: Invalid or non-ellipsoidal B{C{point}}, B{C{point1}}
277
- or B{C{point2}} or invalid B{C{equidistant}}.
273
+ @raise TypeError: Invalid or non-ellipsoidal B{C{point}}, B{C{point1}} or
274
+ B{C{point2}} or invalid B{C{equidistant}}.
278
275
 
279
276
  @raise ValueError: No convergence for the B{C{tol}}.
280
277
 
@@ -283,8 +280,9 @@ def nearestOn(point, point1, point2, within=True, height=None, wrap=False,
283
280
  <https://ArXiv.org/pdf/1102.1215.pdf>}, pp 20-21, section B{14. MARITIME
284
281
  BOUNDARIES} for more details about the iteration algorithm.
285
282
  '''
283
+ kwds = _xkwds(LatLon_and_kwds, LatLon=LatLon)
286
284
  return _nearestOn(point, point1, point2, within=within, height=height, wrap=wrap,
287
- equidistant=equidistant, tol=tol, LatLon=LatLon, **LatLon_kwds)
285
+ equidistant=equidistant, tol=tol, **kwds)
288
286
 
289
287
 
290
288
  def perimeterOf(points, closed=False, datum=_WGS84, wrap=True):
pygeodesy/ellipsoids.py CHANGED
@@ -811,9 +811,9 @@ class Ellipsoid(_NamedEnumItem):
811
811
 
812
812
  eccentricity = e # eccentricity
813
813
  # eccentricity2 = e2 # eccentricity squared
814
- eccentricity1st2 = e2 # first eccentricity squared
815
- eccentricity2nd2 = e22 # second eccentricity squared
816
- eccentricity3rd2 = e32 # third eccentricity squared
814
+ eccentricity1st2 = e2 # first eccentricity squared, signed
815
+ eccentricity2nd2 = e22 # second eccentricity squared, signed
816
+ eccentricity3rd2 = e32 # third eccentricity squared, signed
817
817
 
818
818
  def ecef(self, Ecef=None):
819
819
  '''Return U{ECEF<https://WikiPedia.org/wiki/ECEF>} converter.
pygeodesy/errors.py CHANGED
@@ -27,7 +27,7 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _PYTHON_X_DEV
27
27
  from copy import copy as _copy
28
28
 
29
29
  __all__ = _ALL_LAZY.errors # _ALL_DOCS('_InvalidError', '_IsnotError') _under
30
- __version__ = '24.10.14'
30
+ __version__ = '24.11.02'
31
31
 
32
32
  _argument_ = 'argument'
33
33
  _box_ = 'box'
@@ -777,7 +777,7 @@ except AttributeError:
777
777
  return d
778
778
 
779
779
 
780
- # def _xkwds_bool(inst, **kwds): # no longer in .frechet, .hausdorff, .heights
780
+ # def _xkwds_bool(inst, **kwds): # unused
781
781
  # '''(INTERNAL) Set applicable C{bool} properties/attributes.
782
782
  # '''
783
783
  # for n, v in kwds.items():
@@ -789,18 +789,18 @@ except AttributeError:
789
789
  # setattr(inst, NN(_UNDER_, n), v)
790
790
 
791
791
 
792
- def _xkwds_from(orig, *args, **kwds):
793
- '''(INTERNAL) Return the items from C{orig} with the keys
794
- from C{kwds} and a value not in C{args} and C{kwds}.
795
- '''
796
- def _items(orig, args, items):
797
- for n, m in items:
798
- if n in orig: # n in (orig.keys() & kwds.keys())
799
- t = orig[n]
800
- if t is not m and t not in args:
801
- yield n, t
802
-
803
- return _items(orig, args, kwds.items())
792
+ # def _xkwds_from(orig, *args, **kwds): # unused
793
+ # '''(INTERNAL) Return the items from C{orig} with the keys
794
+ # from C{kwds} and a value not in C{args} and C{kwds}.
795
+ # '''
796
+ # def _items(orig, args, items):
797
+ # for n, m in items:
798
+ # if n in orig: # n in (orig.keys() & kwds.keys())
799
+ # t = orig[n]
800
+ # if t is not m and t not in args:
801
+ # yield n, t
802
+ #
803
+ # return _items(orig, args, kwds.items())
804
804
 
805
805
 
806
806
  def _xkwds_get(kwds, **name_default):
@@ -813,14 +813,14 @@ def _xkwds_get(kwds, **name_default):
813
813
  raise _xAssertionError(_xkwds_get, kwds, **name_default)
814
814
 
815
815
 
816
- def _xkwds_get_(kwds, **names_defaults):
817
- '''(INTERNAL) Yield each C{kwds} value or its C{default}
818
- in I{case-insensitive, alphabetical} C{name} order.
819
- '''
820
- if not isinstance(kwds, dict):
821
- raise _xAssertionError(_xkwds_get_, kwds)
822
- for n, v in _MODS.basics.itemsorted(names_defaults):
823
- yield kwds.get(n, v)
816
+ # def _xkwds_get_(kwds, **names_defaults): # unused
817
+ # '''(INTERNAL) Yield each C{kwds} value or its C{default}
818
+ # in I{case-insensitive, alphabetical} C{name} order.
819
+ # '''
820
+ # if not isinstance(kwds, dict):
821
+ # raise _xAssertionError(_xkwds_get_, kwds)
822
+ # for n, v in _MODS.basics.itemsorted(names_defaults):
823
+ # yield kwds.get(n, v)
824
824
 
825
825
 
826
826
  def _xkwds_get1(kwds, **name_default):
@@ -844,11 +844,11 @@ def _xkwds_item2(kwds):
844
844
  raise _xAssertionError(_xkwds_item2, kwds)
845
845
 
846
846
 
847
- def _xkwds_kwds(kwds, **names_defaults):
847
+ def _xkwds_kwds(kwds, **names_defaults): # in .geodesici # PYCHOK no cover
848
848
  '''(INTERNAL) Return a C{dict} of C{named_defaults} items replaced with C{kwds}.
849
849
  '''
850
850
  if not isinstance(kwds, dict):
851
- raise _xAssertionError(_xkwds_get_, kwds)
851
+ raise _xAssertionError(_xkwds_kwds, kwds)
852
852
  _g = kwds.get
853
853
  return dict((n, _g(n, v)) for n, v in names_defaults.items())
854
854
 
pygeodesy/etm.py CHANGED
@@ -11,7 +11,7 @@ Class L{ExactTransverseMercator} provides C{Exact Transverse Mercator} projectio
11
11
  instances of class L{Etm} represent ETM C{(easting, northing)} locations. See also
12
12
  I{Karney}'s utility U{TransverseMercatorProj<https://GeographicLib.SourceForge.io/C++/doc/
13
13
  TransverseMercatorProj.1.html>} and use C{"python[3] -m pygeodesy.etm ..."} to compare
14
- the results.
14
+ the results, see usage C{"python[3] -m pygeodesy.etm -h"}.
15
15
 
16
16
  Following is a copy of I{Karney}'s U{TransverseMercatorExact.hpp
17
17
  <https://GeographicLib.SourceForge.io/C++/doc/TransverseMercatorExact_8hpp_source.html>}
@@ -65,23 +65,25 @@ from __future__ import division as _; del _ # PYCHOK semicolon
65
65
 
66
66
  from pygeodesy.basics import map1, neg, neg_, _xinstanceof
67
67
  from pygeodesy.constants import EPS, EPS02, PI_2, PI_4, _K0_UTM, \
68
- _1_EPS, _0_0, _0_1, _0_5, _1_0, _2_0, \
69
- _3_0, _4_0, _90_0, isnear0, isnear90
68
+ _1_EPS, _0_0, _0_1, _0_5, _1_0, _2_0, \
69
+ _3_0, _90_0, isnear0, isnear90
70
+ from pygeodesy.constants import _4_0 # PYCHOK used!
70
71
  from pygeodesy.datums import _ellipsoidal_datum, _WGS84, _EWGS84
71
72
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
72
- from pygeodesy.elliptic import _ALL_LAZY, Elliptic
73
+ # from pygeodesy.elliptic import Elliptic # _MODS
73
74
  # from pygeodesy.errors import _incompatible # from .named
74
75
  # from pygeodesy.fsums import Fsum # from .fmath
75
76
  from pygeodesy.fmath import cbrt, hypot, hypot1, hypot2, Fsum
76
77
  from pygeodesy.interns import _COMMASPACE_, _near_, _SPACE_, _spherical_
77
78
  from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, \
78
79
  _norm2, _norm180, _tand, _unsigned2
79
- # from pygeodesy.lazily import _ALL_LAZY # from .elliptic
80
- from pygeodesy.named import callername, _incompatible, _NamedBase
80
+ # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
81
+ from pygeodesy.named import callername, _incompatible, _NamedBase, \
82
+ _ALL_LAZY, _MODS
81
83
  from pygeodesy.namedTuples import Forward4Tuple, Reverse4Tuple
82
84
  from pygeodesy.props import deprecated_method, deprecated_property_RO, \
83
85
  Property_RO, property_RO, _update_all, \
84
- property_doc_
86
+ property_doc_, _allPropertiesOf_n
85
87
  from pygeodesy.streprs import Fmt, pairs, unstr
86
88
  from pygeodesy.units import Degrees, Scalar_
87
89
  from pygeodesy.utily import atan1d, atan2d, _loneg, sincos2
@@ -91,12 +93,12 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
91
93
  from math import asinh, atan2, degrees, radians, sinh, sqrt
92
94
 
93
95
  __all__ = _ALL_LAZY.etm
94
- __version__ = '24.10.21'
96
+ __version__ = '24.11.04'
95
97
 
96
- _OVERFLOW = _1_EPS**2 # about 2e+31
97
- _TAYTOL = pow(EPS, 0.6)
98
+ _OVERFLOW = _1_EPS**2 # ~2e+31
99
+ _TAYTOL = pow(EPS, 0.6)
98
100
  _TAYTOL2 = _TAYTOL * _2_0
99
- _TOL_10 = EPS * _0_1
101
+ _TOL_10 = EPS * _0_1
100
102
  _TRIPS = 21 # C++ 10
101
103
 
102
104
 
@@ -218,12 +220,12 @@ class Etm(Utm):
218
220
  class ExactTransverseMercator(_NamedBase):
219
221
  '''Pure Python version of Karney's C++ class U{TransverseMercatorExact
220
222
  <https://GeographicLib.SourceForge.io/C++/doc/TransverseMercatorExact_8cpp_source.html>},
221
- a numerically exact transverse Mercator projection, further referred to as C{TMExact}.
223
+ a numerically exact transverse Mercator projection, abbreviated as C{TMExact}.
222
224
  '''
223
225
  _datum = _WGS84 # Datum
224
226
  _E = _EWGS84 # Ellipsoid
225
227
  _extendp = False # use extended domain
226
- # _iteration = None # ._sigmaInv2 and ._zetaInv2
228
+ # _iteration = None # _NameBase, ._sigmaInv2 and ._zetaInv2
227
229
  _k0 = _K0_UTM # central scale factor
228
230
  _lat0 = _0_0 # central parallel
229
231
  _lon0 = _0_0 # central meridian
@@ -240,7 +242,7 @@ class ExactTransverseMercator(_NamedBase):
240
242
  L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
241
243
  @kwarg lon0: Central meridian, default (C{degrees180}).
242
244
  @kwarg k0: Central scale factor (C{float}).
243
- @kwarg extendp: Use the I{extended} domain (C{bool}), I{standard} otherwise.
245
+ @kwarg extendp: If C{True}, use the I{extended} domain, I{standard} otherwise (C{bool}).
244
246
  @kwarg raiser: If C{True}, throw an L{ETMError} for convergence failures (C{bool}).
245
247
  @kwarg name: Optional C{B{name}=NN} for the projection (C{str}).
246
248
 
@@ -349,7 +351,7 @@ class ExactTransverseMercator(_NamedBase):
349
351
  def _Eu(self):
350
352
  '''(INTERNAL) Get and cache C{Elliptic(_mu)}.
351
353
  '''
352
- return Elliptic(self._mu)
354
+ return _MODS.elliptic.Elliptic(self._mu)
353
355
 
354
356
  @Property_RO
355
357
  def _Eu_cE(self):
@@ -390,7 +392,7 @@ class ExactTransverseMercator(_NamedBase):
390
392
  def _Ev(self):
391
393
  '''(INTERNAL) Get and cache C{Elliptic(_mv)}.
392
394
  '''
393
- return Elliptic(self._mv)
395
+ return _MODS.elliptic.Elliptic(self._mv)
394
396
 
395
397
  @Property_RO
396
398
  def _Ev_cK(self):
@@ -416,7 +418,7 @@ class ExactTransverseMercator(_NamedBase):
416
418
  '''
417
419
  return self._Ev_cKE * 1.25 # _1_25
418
420
 
419
- @Property_RO
421
+ @property_RO
420
422
  def extendp(self):
421
423
  '''Get the domain (C{bool}), I{extended} or I{standard}.
422
424
  '''
@@ -635,7 +637,7 @@ class ExactTransverseMercator(_NamedBase):
635
637
  '''Set the central parallel and meridian.
636
638
 
637
639
  @arg lat0: Latitude of the central parallel (C{degrees90}).
638
- @arg lon0: Longitude of the central parallel (C{degrees180}).
640
+ @arg lon0: Longitude of the central meridian (C{degrees180}).
639
641
 
640
642
  @return: 2-Tuple C{(lat0, lon0)} of the previous central
641
643
  parallel and meridian.
@@ -644,7 +646,7 @@ class ExactTransverseMercator(_NamedBase):
644
646
  '''
645
647
  t = self._lat0, self.lon0
646
648
  self._lat0 = _fix90(Degrees(lat0=lat0, Error=ETMError))
647
- self. lon0 = lon0
649
+ self. lon0 = lon0 # lon0.setter
648
650
  return t
649
651
 
650
652
  def _resets(self, datum):
@@ -655,15 +657,15 @@ class ExactTransverseMercator(_NamedBase):
655
657
  @raise ETMError: Near-spherical B{C{datum}} or C{ellipsoid}.
656
658
  '''
657
659
  E = datum.ellipsoid
658
- mu = E.e2 # .eccentricity1st2
660
+ mu = E.e2 # E.eccentricity1st2
659
661
  mv = E.e21 # _1_0 - mu
660
662
  if isnear0(E.e) or isnear0(mu, eps0=EPS02) \
661
663
  or isnear0(mv, eps0=EPS02): # or sqrt(mu) != E.e
662
664
  raise ETMError(ellipsoid=E, txt=_near_(_spherical_))
663
665
 
664
666
  if self._datum or self._E:
665
- _i = ExactTransverseMercator.iteration._uname
666
- _update_all(self, _i, '_sigmaC', '_zetaC') # _under
667
+ _i = ExactTransverseMercator.iteration._uname # property_RO
668
+ _update_all(self, _i, '_sigmaC', '_zetaC', Base=Property_RO) # _under
667
669
 
668
670
  self._E = E
669
671
  self._mu = mu
@@ -757,7 +759,7 @@ class ExactTransverseMercator(_NamedBase):
757
759
  # k = sqrt(mv + mu / sec2) * sqrt(sec2) * sqrt(q2)
758
760
  # = sqrt(mv * sec2 + mu) * sqrt(q2)
759
761
  # = sqrt(mv + mv * tau**2 + mu) * sqrt(q2)
760
- k, q2 = _0_0, (mv * snv**2 + cnudnv**2)
762
+ k, q2 = _0_0, (snv**2 * mv + cnudnv**2)
761
763
  if q2 > 0:
762
764
  k2 = (tau**2 + _1_0) * mv + mu
763
765
  if k2 > 0:
@@ -809,9 +811,9 @@ class ExactTransverseMercator(_NamedBase):
809
811
  d = (cnv**2 + snuv**2 * mu)**2 * self._mv
810
812
  r = cnv * dnu * dnv
811
813
  i = cnu * snuv * mu
812
- du = (r**2 - i**2) / d # (r + i) * (r - i) / d
813
- dv = neg(r * i * _2_0 / d)
814
- return du, dv
814
+ du = (r + i) * (r - i) / d # (r**2 - i**2) / d
815
+ dv = r * i * _2_0 / d
816
+ return du, neg(dv)
815
817
 
816
818
  def _sigmaInv2(self, xi, eta):
817
819
  '''(INTERNAL) Invert C{sigma} using Newton's method.
@@ -874,7 +876,8 @@ class ExactTransverseMercator(_NamedBase):
874
876
  '''
875
877
  # snu, cnu, dnu = self._Eu.sncndn(u)
876
878
  # snv, cnv, dnv = self._Ev.sncndn(v)
877
- return self._Eu.sncndn(u, **jam) + self._Ev.sncndn(v, **jam)
879
+ return self._Eu.sncndn(u, **jam) + \
880
+ self._Ev.sncndn(v, **jam)
878
881
 
879
882
  def toStr(self, joined=_COMMASPACE_, **kwds): # PYCHOK signature
880
883
  '''Return a C{str} representation.
@@ -900,21 +903,19 @@ class ExactTransverseMercator(_NamedBase):
900
903
  real &taup, real &lam)}
901
904
  '''
902
905
  e, cnu2, mv = self._e, cnu**2, self._mv
903
- # Overflow value like atan(overflow) = pi/2
904
- t1 = t2 = _overflow(snu)
905
906
  # Lee 54.17 but write
906
907
  # atanh(snu * dnv) = asinh(snu * dnv / sqrt(cnu^2 + _mv * snu^2 * snv^2))
907
908
  # atanh(_e * snu / dnv) = asinh(_e * snu / sqrt(_mu * cnu^2 + _mv * cnv^2))
908
- d1 = cnu2 + mv * (snu * snv)**2
909
+ d1 = cnu2 + (snu * snv)**2 * mv
909
910
  if d1 > EPS02: # _EPSmin
910
911
  t1 = snu * dnv / sqrt(d1)
911
- else:
912
- d1 = 0
913
- d2 = self._mu * cnu2 + mv * cnv**2
912
+ else: # like atan(overflow) = pi/2
913
+ t1, d1 = _overflow(snu), 0
914
+ d2 = cnu2 * self._mu + cnv**2 * mv
914
915
  if d2 > EPS02: # _EPSmin
915
916
  t2 = sinh(e * asinh(e * snu / sqrt(d2)))
916
917
  else:
917
- d2 = 0
918
+ t2, d2 = _overflow(snu), 0
918
919
  # psi = asinh(t1) - asinh(t2)
919
920
  # taup = sinh(psi)
920
921
  taup = t1 * hypot1(t2) - t2 * hypot1(t1)
@@ -939,9 +940,9 @@ class ExactTransverseMercator(_NamedBase):
939
940
  snuv2 = snuv**2 * self._mu
940
941
  # Lee 54.21 but write (see A+S 16.21.4)
941
942
  # (1 - dnu^2 * snv^2) = (cnv^2 + _mu * snu^2 * snv^2)
942
- d = self._mv * (cnv2 + snuv2)**2 # max(d, EPS02)?
943
- du = cnu * dnuv * (cnv2 - snuv2) / d
944
- dv = cnv * snuv * (cnu2 + dnuv2) / d
943
+ d = (cnv2 + snuv2)**2 * self._mv # max(d, EPS02)?
944
+ du = (cnv2 - snuv2) * cnu * dnuv / d
945
+ dv = (cnu2 + dnuv2) * cnv * snuv / d
945
946
  return du, neg(dv)
946
947
 
947
948
  def _zetaInv2(self, taup, lam):
@@ -1021,6 +1022,9 @@ class ExactTransverseMercator(_NamedBase):
1021
1022
  g_k += atan1d(tau), degrees(lam)
1022
1023
  return g_k # or (g, k, lat, lon)
1023
1024
 
1025
+ _allPropertiesOf_n(22, ExactTransverseMercator, Property_RO) # PYCHOK assert
1026
+ del _0_1, _allPropertiesOf_n, EPS, _1_EPS, _EWGS84
1027
+
1024
1028
 
1025
1029
  def _overflow(x):
1026
1030
  '''(INTERNAL) Like C{copysign0(OVERFLOW, B{x})}.
@@ -1102,32 +1106,42 @@ if __name__ == '__main__': # MCCABE 16
1102
1106
  def _main():
1103
1107
 
1104
1108
  from pygeodesy import fstr, KTransverseMercator
1105
- # from pygeodesy.interns import _DASH_ # from internals
1106
- from pygeodesy.internals import printf, _usage, _DASH_
1109
+ from pygeodesy.interns import _BAR_, _COLONSPACE_, _DASH_, NN
1110
+ from pygeodesy.internals import printf, _usage
1107
1111
  from sys import argv, exit as _exit
1108
1112
 
1109
- def _help():
1110
- _exit(_usage(argv[0], '[-s | -t ]',
1111
- '[-p[recision] <ndigits>',
1112
- '[-f[orward] <lat> <lon>',
1113
- '|-r[everse] <easting> <northing>',
1114
- '|<lat> <lon>]',
1115
- '|-h[elp]'))
1113
+ def _error(why, _a=NN):
1114
+ if _a:
1115
+ why = 'option %r %s' % (_a, why)
1116
+ _exit(_COLONSPACE_(_usage(*argv), why))
1117
+
1118
+ def _help(*why):
1119
+ if why:
1120
+ printf(_COLONSPACE_(_usage(*argv), *why))
1121
+ _exit(_usage(argv[0], '[-s[eries]', _BAR_, '-t]',
1122
+ '[-p[recision] <ndigits>]',
1123
+ '[-f[orward] <lat> <lon>', _BAR_,
1124
+ '-r[everse] <easting> <northing>', _BAR_,
1125
+ '<lat> <lon>]', _BAR_,
1126
+ '-h[elp]'))
1127
+
1128
+ def _result(t4):
1129
+ printf(_COLONSPACE_(tm.classname, fstr(t4, prec=_p, sep=_SPACE_)))
1116
1130
 
1117
1131
  # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1118
1132
  _f = _r = _s = _t = False
1119
1133
  _p = -6
1120
- _as = argv[1:]
1121
- while _as and _as[0].startswith(_DASH_):
1122
- _a = _as.pop(0)
1134
+ args = argv[1:]
1135
+ while args and args[0].startswith(_DASH_):
1136
+ _a = args.pop(0)
1123
1137
  if len(_a) < 2:
1124
- _exit('%s: option %r invalid' % (_usage(*argv), _a))
1138
+ _error('invalid', _a)
1125
1139
  elif '-forward'.startswith(_a):
1126
1140
  _f, _r = True, False
1127
1141
  elif '-reverse'.startswith(_a):
1128
1142
  _f, _r = False, True
1129
- elif '-precision'.startswith(_a):
1130
- _p = int(_as.pop(0))
1143
+ elif '-precision'.startswith(_a) and args:
1144
+ _p = int(args.pop(0))
1131
1145
  elif '-series'.startswith(_a):
1132
1146
  _s, _t = True, False
1133
1147
  elif _a == '-t':
@@ -1135,52 +1149,46 @@ if __name__ == '__main__': # MCCABE 16
1135
1149
  elif '-help'.startswith(_a):
1136
1150
  _help()
1137
1151
  else:
1138
- _exit('%s: option %r not supported' % (_usage(*argv), _a))
1139
-
1140
- if len(_as) > 1:
1141
- f2 = map1(float, *_as[:2])
1142
- else:
1143
- printf('%s ...: incomplete', _usage(*argv))
1144
- _help()
1145
-
1146
- if _s: # -series
1147
- tm = KTransverseMercator()
1148
- else:
1149
- tm = ExactTransverseMercator(extendp=_t)
1152
+ _error('not supported', _a)
1153
+ if len(args) < 2:
1154
+ _help('incomplete')
1150
1155
 
1156
+ f2 = map1(float, *args[:2])
1157
+ tm = KTransverseMercator() if _s else \
1158
+ ExactTransverseMercator(extendp=_t)
1151
1159
  if _f:
1152
1160
  t = tm.forward(*f2)
1153
1161
  elif _r:
1154
1162
  t = tm.reverse(*f2)
1155
1163
  else:
1156
1164
  t = tm.forward(*f2)
1157
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1165
+ _result(t)
1158
1166
  t = tm.reverse(t.easting, t.northing)
1159
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1167
+ _result(t)
1160
1168
 
1161
1169
  _main()
1162
1170
 
1163
- # % python3.13 -m pygeodesy.etm -p 12 33.33 44.44
1171
+ # % python3.13 -m pygeodesy.etm -p 12 33.33 44.44
1164
1172
  # ExactTransverseMercator: 4276926.114803905599 4727193.767015309073 28.375536563148 1.233325101778
1165
1173
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1166
1174
 
1167
- # % python3.13 -m pygeodesy.etm -s -p 12 33.33 44.44
1175
+ # % python3.13 -m pygeodesy.etm -s -p 12 33.33 44.44
1168
1176
  # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1169
1177
  # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1170
1178
 
1171
- # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1179
+ # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1172
1180
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1173
1181
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1174
1182
 
1175
- # % python3.12 -m pygeodesy.etm -s -p 12 33.33 44.44
1183
+ # % python3.12 -m pygeodesy.etm -s -p 12 33.33 44.44
1176
1184
  # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1177
1185
  # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1178
1186
 
1179
- # % python2 -m pygeodesy.etm -p 12 33.33 44.44
1187
+ # % python2 -m pygeodesy.etm -p 12 33.33 44.44
1180
1188
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1181
1189
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1182
1190
 
1183
- # % python2 -m pygeodesy.etm -s -p 12 33.33 44.44
1191
+ # % python2 -m pygeodesy.etm -s -p 12 33.33 44.44
1184
1192
  # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1185
1193
  # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1186
1194