pygeodesy 24.5.24__py2.py3-none-any.whl → 24.6.9__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 (71) hide show
  1. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/METADATA +6 -5
  2. PyGeodesy-24.6.9.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +4 -4
  4. pygeodesy/auxilats/__init__.py +1 -1
  5. pygeodesy/auxilats/__main__.py +2 -2
  6. pygeodesy/auxilats/auxAngle.py +4 -4
  7. pygeodesy/basics.py +39 -5
  8. pygeodesy/booleans.py +54 -67
  9. pygeodesy/cartesianBase.py +138 -147
  10. pygeodesy/constants.py +3 -3
  11. pygeodesy/deprecated/functions.py +9 -3
  12. pygeodesy/ecef.py +67 -72
  13. pygeodesy/ellipsoidalBase.py +18 -56
  14. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  15. pygeodesy/ellipsoidalKarney.py +3 -3
  16. pygeodesy/ellipsoidalNvector.py +7 -7
  17. pygeodesy/ellipsoids.py +6 -5
  18. pygeodesy/errors.py +20 -10
  19. pygeodesy/etm.py +16 -21
  20. pygeodesy/fmath.py +9 -20
  21. pygeodesy/formy.py +60 -74
  22. pygeodesy/frechet.py +13 -14
  23. pygeodesy/fsums.py +60 -26
  24. pygeodesy/geodesicx/__init__.py +1 -1
  25. pygeodesy/geodesicx/__main__.py +2 -2
  26. pygeodesy/geodesicx/gx.py +3 -5
  27. pygeodesy/geodsolve.py +24 -26
  28. pygeodesy/geohash.py +27 -40
  29. pygeodesy/geoids.py +1 -1
  30. pygeodesy/hausdorff.py +17 -18
  31. pygeodesy/heights.py +17 -30
  32. pygeodesy/internals.py +15 -14
  33. pygeodesy/interns.py +3 -9
  34. pygeodesy/iters.py +2 -2
  35. pygeodesy/karney.py +8 -7
  36. pygeodesy/latlonBase.py +189 -176
  37. pygeodesy/lazily.py +92 -56
  38. pygeodesy/lcc.py +2 -2
  39. pygeodesy/ltp.py +93 -55
  40. pygeodesy/ltpTuples.py +304 -240
  41. pygeodesy/mgrs.py +51 -24
  42. pygeodesy/named.py +159 -136
  43. pygeodesy/namedTuples.py +43 -14
  44. pygeodesy/nvectorBase.py +20 -23
  45. pygeodesy/osgr.py +40 -48
  46. pygeodesy/points.py +11 -11
  47. pygeodesy/props.py +29 -16
  48. pygeodesy/rhumb/aux_.py +13 -15
  49. pygeodesy/rhumb/bases.py +12 -5
  50. pygeodesy/rhumb/ekx.py +24 -18
  51. pygeodesy/rhumb/solve.py +20 -70
  52. pygeodesy/simplify.py +16 -16
  53. pygeodesy/solveBase.py +35 -32
  54. pygeodesy/sphericalBase.py +33 -31
  55. pygeodesy/sphericalTrigonometry.py +17 -17
  56. pygeodesy/streprs.py +6 -4
  57. pygeodesy/trf.py +11 -9
  58. pygeodesy/triaxials.py +71 -50
  59. pygeodesy/units.py +40 -65
  60. pygeodesy/unitsBase.py +2 -2
  61. pygeodesy/ups.py +66 -70
  62. pygeodesy/utily.py +7 -6
  63. pygeodesy/utm.py +152 -156
  64. pygeodesy/utmups.py +38 -38
  65. pygeodesy/utmupsBase.py +102 -106
  66. pygeodesy/vector3d.py +34 -36
  67. pygeodesy/vector3dBase.py +12 -9
  68. pygeodesy/webmercator.py +43 -51
  69. PyGeodesy-24.5.24.dist-info/RECORD +0 -116
  70. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/WHEEL +0 -0
  71. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/top_level.txt +0 -0
pygeodesy/units.py CHANGED
@@ -1,18 +1,17 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- u'''Various units, all sub-classes of C{Float}, C{Int} and
5
- C{Str} from basic C{float}, C{int} respectively C{str} to
6
- named units as L{Degrees}, L{Feet}, L{Meter}, L{Radians}, etc.
4
+ u'''Various named units, all sub-classes of C{Float}, C{Int} or C{Str} from
5
+ basic C{float}, C{int} respectively C{str} to named units as L{Degrees},
6
+ L{Feet}, L{Meter}, L{Radians}, etc.
7
7
  '''
8
8
 
9
- from pygeodesy.basics import isinstanceof, isscalar, isstr, issubclassof, signOf
9
+ from pygeodesy.basics import isscalar, isstr, issubclassof, signOf, _xsubclassof
10
10
  from pygeodesy.constants import EPS, EPS1, PI, PI2, PI_2, _umod_360, _0_0, \
11
11
  _0_001, _0_5, INT0 # PYCHOK for .mgrs, .namedTuples
12
- from pygeodesy.dms import F__F, F__F_, S_NUL, S_SEP, parseDMS, parseRad, \
13
- _toDMS, toDMS
12
+ from pygeodesy.dms import F__F, F__F_, S_NUL, S_SEP, parseDMS, parseRad, _toDMS
14
13
  from pygeodesy.errors import _AssertionError, _IsnotError, TRFError, UnitError, \
15
- _xkwds
14
+ _xattr
16
15
  from pygeodesy.interns import NN, _band_, _bearing_, _degrees_, _degrees2_, \
17
16
  _distance_, _E_, _easting_, _epoch_, _EW_, _feet_, \
18
17
  _height_, _lam_, _lat_, _LatLon_, _lon_, _meter_, \
@@ -29,7 +28,7 @@ from pygeodesy.unitsBase import _Error, Float, Fmt, fstr, Int, _arg_name_arg2, \
29
28
  from math import degrees, radians
30
29
 
31
30
  __all__ = _ALL_LAZY.units
32
- __version__ = '24.05.20'
31
+ __version__ = '24.06.10'
33
32
 
34
33
  _negative_falsed_ = 'negative, falsed'
35
34
 
@@ -108,10 +107,9 @@ class Bool(Int, _NamedUnit):
108
107
  @kwarg cls: This class (C{Bool} or sub-class).
109
108
  @kwarg arg: The value (any C{type} convertable to C{bool}).
110
109
  @kwarg name: Optional instance name (C{str}).
111
- @kwarg Error: Optional error to raise, overriding the default
112
- L{UnitError}.
113
- @kwarg name_arg: Optional C{name=arg} keyword argument, inlieu
114
- of B{C{name}} and B{C{arg}}.
110
+ @kwarg Error: Optional error to raise, overriding the default L{UnitError}.
111
+ @kwarg name_arg: Optional C{name=arg} keyword argument, inlieu of separate
112
+ B{C{name}} and B{C{arg}}.
115
113
 
116
114
  @returns: A L{Bool}, a C{bool}-like instance.
117
115
 
@@ -137,13 +135,11 @@ class Bool(Int, _NamedUnit):
137
135
  def toRepr(self, std=False, **unused): # PYCHOK **unused
138
136
  '''Return a representation of this C{Bool}.
139
137
 
140
- @kwarg std: Use the standard C{repr} or the named
141
- representation (C{bool}).
138
+ @kwarg std: Use the standard C{repr} or the named representation (C{bool}).
142
139
 
143
- @note: Use C{env} variable C{PYGEODESY_BOOL_STD_REPR=std}
144
- prior to C{import pygeodesy} to get the standard
145
- C{repr} or set property C{std_repr=False} to always
146
- get the named C{toRepr} representation.
140
+ @note: Use C{env} variable C{PYGEODESY_BOOL_STD_REPR=std} prior to C{import
141
+ pygeodesy} to get the standard C{repr} or set property C{std_repr=False}
142
+ to always get the named C{toRepr} representation.
147
143
  '''
148
144
  r = repr(self._bool_True_or_False)
149
145
  return r if std else self._toRepr(r)
@@ -174,17 +170,16 @@ class Degrees(Float):
174
170
  '''New C{Degrees} instance, see L{Float}.
175
171
 
176
172
  @arg cls: This class (C{Degrees} or sub-class).
177
- @kwarg arg: The value (any scalar C{type} convertable to C{float} or
178
- parsable by L{pygeodesy.parseDMS}).
173
+ @kwarg arg: The value (any scalar C{type} convertable to C{float} or parsable
174
+ by L{pygeodesy.parseDMS}).
179
175
  @kwarg name: Optional instance name (C{str}).
180
- @kwarg Error: Optional error to raise, overriding the default
181
- L{UnitError}.
176
+ @kwarg Error: Optional error to raise, overriding the default L{UnitError}.
182
177
  @kwarg suffix: Optional, valid compass direction suffixes (C{NSEW}).
183
- @kwarg clip: Optional B{C{arg}} range B{C{-clip..+clip}}
184
- (C{degrees} or C{0} or C{None} for unclipped).
178
+ @kwarg clip: Optional B{C{arg}} range B{C{-clip..+clip}} (C{degrees} or C{0}
179
+ or C{None} for unclipped).
185
180
  @kwarg wrap: Optionally adjust the B{C{arg}} value (L{pygeodesy.wrap90},
186
181
  L{pygeodesy.wrap180} or L{pygeodesy.wrap360}).
187
- @kwarg name_arg: Optional C{name=arg} keyword argument, inlieu of
182
+ @kwarg name_arg: Optional C{name=arg} keyword argument, inlieu of separate
188
183
  B{C{name}} and B{C{arg}}.
189
184
 
190
185
  @returns: A C{Degrees} instance.
@@ -218,18 +213,18 @@ class Degrees(Float):
218
213
  def toRepr(self, std=False, **prec_fmt_ints): # PYCHOK prec=8, ...
219
214
  '''Return a representation of this C{Degrees}.
220
215
 
221
- @kwarg std: If C{True} return the standard C{repr},
222
- otherwise the named representation (C{bool}).
216
+ @kwarg std: If C{True} return the standard C{repr}, otherwise
217
+ the named representation (C{bool}).
223
218
 
224
219
  @see: Methods L{Degrees.toStr}, L{Float.toRepr} and function
225
- L{pygeodesy.toDMS} for more documentation.
220
+ L{pygeodesy.toDMS} for futher C{prec_fmt_ints} details.
226
221
  '''
227
222
  return Float.toRepr(self, std=std, **prec_fmt_ints)
228
223
 
229
224
  def toStr(self, prec=None, fmt=F__F_, ints=False, **s_D_M_S): # PYCHOK prec=8, ...
230
225
  '''Return this C{Degrees} as standard C{str}.
231
226
 
232
- @see: Function L{pygeodesy.toDMS} for keyword argument details.
227
+ @see: Function L{pygeodesy.toDMS} for futher details.
233
228
  '''
234
229
  if fmt.startswith(_PERCENT_): # use regular formatting
235
230
  p = 8 if prec is None else prec
@@ -288,8 +283,8 @@ class Radians(Float):
288
283
  '''New C{Radians} instance, see L{Float}.
289
284
 
290
285
  @arg cls: This class (C{Radians} or sub-class).
291
- @kwarg arg: The value (any C{type} convertable to C{float} or parsable
292
- by L{pygeodesy.parseRad}).
286
+ @kwarg arg: The value (any C{type} convertable to C{float} or parsable by
287
+ L{pygeodesy.parseRad}).
293
288
  @kwarg name: Optional instance name (C{str}).
294
289
  @kwarg Error: Optional error to raise, overriding the default L{UnitError}.
295
290
  @kwarg suffix: Optional, valid compass direction suffixes (C{NSEW}).
@@ -547,7 +542,7 @@ class FIx(Float_):
547
542
  @arg points: The points (C{LatLon}[], L{Numpy2LatLon}[],
548
543
  L{Tuple2LatLon}[] or C{other}[]).
549
544
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
550
- B{C{points}} (C{bool}) C{None} for backward
545
+ B{C{points}} (C{bool}) or C{None} for backward
551
546
  compatible L{LatLon2Tuple} or B{C{LatLon}} with
552
547
  I{averaged} lat- and longitudes.
553
548
  @kwarg LatLon: Optional class to return the I{intermediate},
@@ -695,10 +690,9 @@ class Meter(Float):
695
690
 
696
691
  @see: Method C{Str.toRepr} and property C{Str.std_repr}.
697
692
 
698
- @note: Use C{env} variable C{PYGEODESY_METER_STD_REPR=std}
699
- prior to C{import pygeodesy} to get the standard
700
- C{repr} or set property C{std_repr=False} to always
701
- get the named C{toRepr} representation.
693
+ @note: Use C{env} variable C{PYGEODESY_METER_STD_REPR=std} prior to C{import
694
+ pygeodesy} to get the standard C{repr} or set property C{std_repr=False}
695
+ to always get the named C{toRepr} representation.
702
696
  '''
703
697
  return self.toRepr(std=self._std_repr)
704
698
 
@@ -875,29 +869,13 @@ def _isScalar(obj):
875
869
  return isscalar(obj) and not isinstance(obj, _NamedUnit)
876
870
 
877
871
 
878
- def _toDegrees(s, *xs, **toDMS_kwds):
879
- '''(INTERNAL) Convert C{xs} from C{Radians} to C{Degrees} or C{toDMS}.
880
- '''
881
- if toDMS_kwds:
882
- toDMS_kwds = _xkwds(toDMS_kwds, ddd=1, pos=NN)
883
-
884
- for x in xs:
885
- if not isinstanceof(x, Degrees, Degrees_):
886
- s = None
887
- x = x.toDegrees()
888
- yield toDMS(x, **toDMS_kwds) if toDMS_kwds else x
889
- yield None if toDMS_kwds else s
890
-
891
-
892
- def _toRadians(s, *xs):
893
- '''(INTERNAL) Convert C{xs} from C{Degrees} to C{Radians}.
872
+ def _toUnit(Unit, arg, name=NN, **Error):
873
+ '''(INTERNAL) Wrap C{arg} in a C{name}d C{Unit}.
894
874
  '''
895
- for x in xs:
896
- if not isinstanceof(x, Radians, Radians_):
897
- s = None
898
- x = x.toRadians()
899
- yield x
900
- yield s
875
+ if not (issubclassof(Unit, _NamedUnit) and isinstance(arg, Unit) and
876
+ _xattr(arg, name=NN) == name):
877
+ arg = Unit(arg, name=name, **Error)
878
+ return arg
901
879
 
902
880
 
903
881
  def _xStrError(*Refs, **name_value_Error):
@@ -910,8 +888,7 @@ def _xStrError(*Refs, **name_value_Error):
910
888
  def _xUnit(units, Base): # in .frechet, .hausdorff
911
889
  '''(INTERNAL) Get C{Unit} from C{Unit} or C{name}, ortherwise C{Base}.
912
890
  '''
913
- if not issubclassof(Base, _NamedUnit):
914
- raise _IsnotError(_NamedUnit.__name__, Base=Base)
891
+ _xsubclassof(_NamedUnit, Base=Base)
915
892
  U = globals().get(units.capitalize(), Base) if isstr(units) else (
916
893
  units if issubclassof(units, Base) else Base)
917
894
  return U if issubclassof(U, Base) else Base
@@ -920,14 +897,12 @@ def _xUnit(units, Base): # in .frechet, .hausdorff
920
897
  def _xUnits(units, Base=_NamedUnit): # in .frechet, .hausdorff
921
898
  '''(INTERNAL) Set property C{units} as C{Unit} or C{Str}.
922
899
  '''
923
- if not issubclassof(Base, _NamedUnit):
924
- raise _IsnotError(_NamedUnit.__name__, Base=Base)
925
- elif issubclassof(units, Base):
900
+ _xsubclassof(_NamedUnit, Base=Base)
901
+ if issubclassof(units, Base):
926
902
  return units
927
903
  elif isstr(units):
928
904
  return Str(units, name=_units_) # XXX Str to _Pass and for backward compatibility
929
- else:
930
- raise _IsnotError(Base.__name__, Str.__name__, str.__name__, units=units)
905
+ raise _IsnotError(*(_.__name__ for _ in (Base, Str, str)), units=units)
931
906
 
932
907
 
933
908
  def _std_repr(*Classes):
pygeodesy/unitsBase.py CHANGED
@@ -14,7 +14,7 @@ from pygeodesy.named import modulename, _Named, property_doc_
14
14
  from pygeodesy.streprs import Fmt, fstr
15
15
 
16
16
  __all__ = _ALL_LAZY.unitsBase
17
- __version__ = '24.05.20'
17
+ __version__ = '24.06.05'
18
18
 
19
19
 
20
20
  class _NamedUnit(_Named):
@@ -107,7 +107,7 @@ class Float(float, _NamedUnit):
107
107
  # XXX the default number of decimals is 10-12 when using
108
108
  # float.__str__(self) with both python 3.8+ and 2.7-, but
109
109
  # float.__repr__(self) shows DIG decimals in python2.7!
110
- # return super(Float, self).__repr__() # see .test.testCss.py
110
+ # return super(Float, self).__repr__() # see .testCss.py
111
111
  return float.__str__(self) # always _std_str_
112
112
 
113
113
  def toRepr(self, std=False, **prec_fmt_ints): # PYCHOK prec=8, ...
pygeodesy/ups.py CHANGED
@@ -26,14 +26,14 @@ from pygeodesy.constants import EPS, EPS0, _EPSmin as _Tol90, \
26
26
  isnear90, _0_0, _0_5, _1_0, _2_0
27
27
  from pygeodesy.datums import _ellipsoidal_datum, _WGS84
28
28
  from pygeodesy.dms import degDMS, _neg, parseDMS2
29
- from pygeodesy.errors import RangeError, _ValueError
29
+ from pygeodesy.errors import RangeError, _ValueError, _xkwds_pop2
30
30
  from pygeodesy.fmath import hypot, hypot1, sqrt0
31
31
  # from pygeodesy.internals import _under # from .named
32
32
  from pygeodesy.interns import NN, _COMMASPACE_, _inside_, _N_, \
33
33
  _pole_, _range_, _S_, _scale0_, \
34
34
  _SPACE_, _std_, _to_, _UTM_
35
35
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv
36
- from pygeodesy.named import nameof, _xnamed, _under
36
+ from pygeodesy.named import nameof, _under
37
37
  from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple, \
38
38
  UtmUps8Tuple, UtmUpsLatLon5Tuple
39
39
  from pygeodesy.props import deprecated_method, property_doc_, \
@@ -49,7 +49,7 @@ from pygeodesy.utmupsBase import Fmt, _LLEB, _hemi, _parseUTMUPS5, _to4lldn, \
49
49
  from math import atan2, fabs, radians, tan
50
50
 
51
51
  __all__ = _ALL_LAZY.ups
52
- __version__ = '25.05.13'
52
+ __version__ = '25.05.31'
53
53
 
54
54
  _BZ_UPS = _getenv('PYGEODESY_UPS_POLES', _std_) == _std_
55
55
  _Falsing = Meter(2000e3) # false easting and northing (C{meter})
@@ -57,18 +57,6 @@ _K0_UPS = Float(_K0_UPS= 0.994) # scale factor at central meridian
57
57
  _K1_UPS = Float(_K1_UPS=_1_0) # rescale point scale factor
58
58
 
59
59
 
60
- def _scale(E, rho, tau):
61
- # compute the point scale factor, ala Karney
62
- t = hypot1(tau)
63
- return Float(scale=(rho / E.a) * t * sqrt0(E.e21 + E.e2 / t**2))
64
-
65
-
66
- def _toBand(lat, lon): # see utm._toBand
67
- '''(INTERNAL) Get the I{polar} Band letter for a (lat, lon).
68
- '''
69
- return _Bands[(0 if lat < 0 else 2) + (0 if -180 < lon < 0 else 1)]
70
-
71
-
72
60
  class UPSError(_ValueError):
73
61
  '''Universal Polar Stereographic (UPS) parse or other L{Ups} issue.
74
62
  '''
@@ -88,7 +76,7 @@ class Ups(UtmUpsBase):
88
76
  def __init__(self, zone=0, pole=_N_, easting=_Falsing, # PYCHOK expected
89
77
  northing=_Falsing, band=NN, datum=_WGS84,
90
78
  falsed=True, gamma=None, scale=None,
91
- name=NN, **convergence):
79
+ **name_convergence):
92
80
  '''New L{Ups} UPS coordinate.
93
81
 
94
82
  @kwarg zone: UPS zone (C{int}, zero) or zone with/-out I{polar} Band
@@ -100,13 +88,13 @@ class Ups(UtmUpsBase):
100
88
  @kwarg band: Optional, I{polar} Band (C{str}, 'A'|'B'|'Y'|'Z').
101
89
  @kwarg datum: Optional, this coordinate's datum (L{Datum},
102
90
  L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
103
- @kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}}
104
- are falsed (C{bool}).
105
- @kwarg gamma: Optional, meridian convergence to save (C{degrees}).
106
- @kwarg scale: Optional, computed scale factor k to save
107
- (C{scalar}).
108
- @kwarg name: Optional name (C{str}).
109
- @kwarg convergence: DEPRECATED, use keyword argument C{B{gamma}=None}.
91
+ @kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are
92
+ falsed (C{bool}).
93
+ @kwarg gamma: Optional meridian convergence, bearing off grid North,
94
+ clockwise from true North to save (C{degrees}) or C{None}.
95
+ @kwarg scale: Optional grid scale factor to save (C{scalar}) or C{None}.
96
+ @kwarg name_convergence: Optional C{B{name}=NN} (C{str}) and DEPRECATED
97
+ keyword argument C{B{convergence}=None}, use B{C{gamma}}.
110
98
 
111
99
  @raise TypeError: Invalid B{C{datum}}.
112
100
 
@@ -114,18 +102,19 @@ class Ups(UtmUpsBase):
114
102
  B{C{northing}}, B{C{band}}, B{C{convergence}}
115
103
  or B{C{scale}}.
116
104
  '''
117
- if name:
118
- self.name = name
119
-
105
+ if name_convergence:
106
+ gamma, name = _xkwds_pop2(name_convergence, convergence=gamma)
107
+ if name:
108
+ self.name = name
120
109
  try:
121
- z, B, p = _to3zBhp(zone, band, hemipole=pole)
110
+ z, B, self._pole = _to3zBhp(zone, band, hemipole=pole)
122
111
  if z != _UPS_ZONE or (B and (B not in _Bands)):
123
112
  raise ValueError
124
113
  except (TypeError, ValueError) as x:
125
114
  raise UPSError(zone=zone, pole=pole, band=band, cause=x)
126
- self._pole = p
115
+
127
116
  UtmUpsBase.__init__(self, easting, northing, band=B, datum=datum, falsed=falsed,
128
- gamma=gamma, scale=scale, **convergence)
117
+ gamma=gamma, scale=scale)
129
118
 
130
119
  def __eq__(self, other):
131
120
  return isinstance(other, Ups) and other.zone == self.zone \
@@ -161,13 +150,11 @@ class Ups(UtmUpsBase):
161
150
  f = _Falsing if self.falsed else 0
162
151
  return EasNor2Tuple(f, f)
163
152
 
164
- def parse(self, strUPS, name=NN):
153
+ def parse(self, strUPS, **name):
165
154
  '''Parse a string to a similar L{Ups} instance.
166
155
 
167
- @arg strUPS: The UPS coordinate (C{str}),
168
- see function L{parseUPS5}.
169
- @kwarg name: Optional instance name (C{str}),
170
- overriding this name.
156
+ @arg strUPS: The UPS coordinate (C{str}), see function L{parseUPS5}.
157
+ @kwarg name: Optional C{B{name}=NN} (C{str}), overriding this name.
171
158
 
172
159
  @return: The similar instance (L{Ups}).
173
160
 
@@ -176,7 +163,7 @@ class Ups(UtmUpsBase):
176
163
  @see: Functions L{parseUTM5} and L{pygeodesy.parseUTMUPS5}.
177
164
  '''
178
165
  return parseUPS5(strUPS, datum=self.datum, Ups=self.classof,
179
- name=name or self.name)
166
+ name=self._name__(name))
180
167
 
181
168
  @deprecated_method
182
169
  def parseUPS(self, strUPS): # PYCHOK no cover
@@ -250,9 +237,8 @@ class Ups(UtmUpsBase):
250
237
  b, g, a = atan2(x, y), -1, _neg(a)
251
238
  ll = _LLEB(a, degrees180(b), datum=self._datum, name=self.name)
252
239
 
253
- ll._gamma = b * g
254
- ll._scale = _scale(E, r, t) if r > 0 else self.scale0
255
- self._latlon5args(ll, _toBand, unfalse)
240
+ k = _scale(E, r, t) if r > 0 else self.scale0
241
+ self._latlon5args(ll, g * b, k, _toBand, unfalse)
256
242
 
257
243
  def toRepr(self, prec=0, fmt=Fmt.SQUARE, sep=_COMMASPACE_, B=False, cs=False, **unused): # PYCHOK expected
258
244
  '''Return a string representation of this UPS coordinate.
@@ -353,7 +339,7 @@ class _Ups_K1(Ups):
353
339
  _scale0 = _K1_UPS
354
340
 
355
341
 
356
- def parseUPS5(strUPS, datum=_WGS84, Ups=Ups, falsed=True, name=NN):
342
+ def parseUPS5(strUPS, datum=_WGS84, Ups=Ups, falsed=True, **name):
357
343
  '''Parse a string representing a UPS coordinate, consisting of
358
344
  C{"[zone][band] pole easting northing"} where B{C{zone}} is
359
345
  pseudo zone C{"00"|"0"|""} and C{band} is C{'A'|'B'|'Y'|'Z'|''}.
@@ -362,8 +348,9 @@ def parseUPS5(strUPS, datum=_WGS84, Ups=Ups, falsed=True, name=NN):
362
348
  @kwarg datum: Optional datum to use (L{Datum}).
363
349
  @kwarg Ups: Optional class to return the UPS coordinate (L{Ups})
364
350
  or C{None}.
365
- @kwarg falsed: Both B{C{easting}} and B{C{northing}} are falsed (C{bool}).
366
- @kwarg name: Optional B{C{Ups}} name (C{str}).
351
+ @kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}}
352
+ are falsed (C{bool}).
353
+ @kwarg name: Optional B{C{Ups}} C{B{name}=NN} (C{str}).
367
354
 
368
355
  @return: The UPS coordinate (B{C{Ups}}) or a
369
356
  L{UtmUps5Tuple}C{(zone, hemipole, easting, northing,
@@ -376,43 +363,54 @@ def parseUPS5(strUPS, datum=_WGS84, Ups=Ups, falsed=True, name=NN):
376
363
  if z != _UPS_ZONE or (B and B not in _Bands):
377
364
  raise UPSError(strUPS=strUPS, zone=z, band=B)
378
365
 
379
- r = UtmUps5Tuple(z, p, e, n, B, Error=UPSError) if Ups is None \
380
- else Ups(z, p, e, n, band=B, falsed=falsed, datum=datum)
381
- return _xnamed(r, name)
366
+ r = UtmUps5Tuple(z, p, e, n, B, Error=UPSError, **name) if Ups is None \
367
+ else Ups(z, p, e, n, band=B, falsed=falsed, datum=datum, **name)
368
+ return r
369
+
370
+
371
+ def _scale(E, rho, tau):
372
+ # compute the point scale factor, ala Karney
373
+ t = hypot1(tau)
374
+ return Float(scale=(rho / E.a) * t * sqrt0(E.e21 + E.e2 / t**2))
375
+
376
+
377
+ def _toBand(lat, lon): # see utm._toBand
378
+ '''(INTERNAL) Get the I{polar} Band letter for a (lat, lon).
379
+ '''
380
+ return _Bands[(0 if lat < 0 else 2) + (0 if -180 < lon < 0 else 1)]
382
381
 
383
382
 
384
383
  def toUps8(latlon, lon=None, datum=None, Ups=Ups, pole=NN,
385
- falsed=True, strict=True, name=NN):
384
+ falsed=True, strict=True, **name):
386
385
  '''Convert a lat-/longitude point to a UPS coordinate.
387
386
 
388
- @arg latlon: Latitude (C{degrees}) or an (ellipsoidal)
389
- geodetic C{LatLon} point.
387
+ @arg latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic
388
+ C{LatLon} point.
390
389
  @kwarg lon: Optional longitude (C{degrees}) or C{None} if
391
390
  B{C{latlon}} is a C{LatLon}.
392
- @kwarg datum: Optional datum for this UPS coordinate,
393
- overriding B{C{latlon}}'s datum (C{Datum},
394
- L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
395
- @kwarg Ups: Optional class to return the UPS coordinate
396
- (L{Ups}) or C{None}.
391
+ @kwarg datum: Optional datum for this UPS coordinate, overriding
392
+ B{C{latlon}}'s datum (C{Datum}, L{Ellipsoid},
393
+ L{Ellipsoid2} or L{a_f2Tuple}).
394
+ @kwarg Ups: Optional class to return the UPS coordinate (L{Ups})
395
+ or C{None}.
397
396
  @kwarg pole: Optional top/center of (stereographic) projection
398
397
  (C{str}, C{'N[orth]'} or C{'S[outh]'}).
399
- @kwarg falsed: False both easting and northing (C{bool}).
398
+ @kwarg falsed: If C{True}, false both easting and northing (C{bool}).
400
399
  @kwarg strict: Restrict B{C{lat}} to UPS ranges (C{bool}).
401
- @kwarg name: Optional B{C{Ups}} name (C{str}).
400
+ @kwarg name: Optional B{C{Ups}} C{B{name}=NN} (C{str}).
402
401
 
403
- @return: The UPS coordinate (B{C{Ups}}) or a
404
- L{UtmUps8Tuple}C{(zone, hemipole, easting, northing,
405
- band, datum, gamma, scale)} if B{C{Ups}} is C{None}.
406
- The C{hemipole} is the C{'N'|'S'} pole, the UPS
407
- projection top/center.
402
+ @return: The UPS coordinate (B{C{Ups}}) or a L{UtmUps8Tuple}C{(zone,
403
+ hemipole, easting, northing, band, datum, gamma, scale)} if
404
+ B{C{Ups}} is C{None}. The C{hemipole} is the C{'N'|'S'}
405
+ pole, the UPS projection top/center.
408
406
 
409
407
  @raise RangeError: If B{C{strict}} and B{C{lat}} outside the valid
410
408
  UPS bands or if B{C{lat}} or B{C{lon}} outside
411
409
  the valid range and L{pygeodesy.rangerrors} set
412
410
  to C{True}.
413
411
 
414
- @raise TypeError: If B{C{latlon}} is not ellipsoidal or
415
- B{C{datum}} invalid.
412
+ @raise TypeError: If B{C{latlon}} is not ellipsoidal or if B{C{datum}}
413
+ is invalid.
416
414
 
417
415
  @raise ValueError: If B{C{lon}} value is missing or if B{C{latlon}}
418
416
  is invalid.
@@ -463,9 +461,7 @@ def toUps8(latlon, lon=None, datum=None, Ups=Ups, pole=NN,
463
461
  r = Ups(z, p, x, y, band=B, datum=d, falsed=falsed,
464
462
  gamma=g, scale=k, name=n)
465
463
  if isinstance(latlon, _LLEB) and d is latlon.datum: # see utm._toXtm8
466
- r._latlon5args(latlon, _toBand, falsed) # XXX weakref(latlon)?
467
- latlon._gamma = g
468
- latlon._scale = k
464
+ r._latlon5args(latlon, g, k, _toBand, falsed) # XXX weakref(latlon)?
469
465
  else:
470
466
  r._hemisphere = _hemi(lat)
471
467
  if not r._band:
@@ -473,18 +469,18 @@ def toUps8(latlon, lon=None, datum=None, Ups=Ups, pole=NN,
473
469
  return r
474
470
 
475
471
 
476
- def upsZoneBand5(lat, lon, strict=True, name=NN):
472
+ def upsZoneBand5(lat, lon, strict=True, **name):
477
473
  '''Return the UTM/UPS zone number, I{polar} Band letter, pole and
478
474
  clipped lat- and longitude for a given location.
479
475
 
480
476
  @arg lat: Latitude in degrees (C{scalar} or C{str}).
481
477
  @arg lon: Longitude in degrees (C{scalar} or C{str}).
482
478
  @kwarg strict: Restrict B{C{lat}} to UPS ranges (C{bool}).
483
- @kwarg name: Optional name (C{str}).
479
+ @kwarg name: Optional B{C{Ups}} C{B{name}=NN} (C{str}).
484
480
 
485
- @return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole,
486
- lat, lon)} where C{hemipole} is the C{'N'|'S'} pole,
487
- the UPS projection top/center and C{lon} [-180..180).
481
+ @return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat,
482
+ lon)} where C{hemipole} is the C{'N'|'S'} pole, the
483
+ UPS projection top/center and C{lon} [-180..180).
488
484
 
489
485
  @note: The C{lon} is set to C{0} if B{C{lat}} is C{-90} or
490
486
  C{90}, see env variable C{PYGEODESY_UPS_POLES} in
@@ -514,7 +510,7 @@ def upsZoneBand5(lat, lon, strict=True, name=NN):
514
510
 
515
511
  else:
516
512
  B, p = NN, _hemi(lat)
517
- return UtmUpsLatLon5Tuple(z, B, p, lat, lon, Error=UPSError, name=name)
513
+ return UtmUpsLatLon5Tuple(z, B, p, lat, lon, Error=UPSError, **name)
518
514
 
519
515
  # **) MIT License
520
516
  #
pygeodesy/utily.py CHANGED
@@ -17,7 +17,7 @@ from pygeodesy.constants import EPS, EPS0, INF, NAN, PI, PI2, PI_2, R_M, \
17
17
  _N_180_0, _360_0, _400_0, _copysign_0_0, \
18
18
  _float as _F, _isfinite, isnan, isnear0, \
19
19
  _over, _umod_360, _umod_PI2
20
- from pygeodesy.errors import _ValueError, _xkwds, _xkwds_get, _ALL_LAZY, _MODS
20
+ from pygeodesy.errors import _ValueError, _xkwds, _xkwds_get1, _ALL_LAZY, _MODS
21
21
  from pygeodesy.internals import _passargs # , _MODS?
22
22
  from pygeodesy.interns import _edge_, _radians_, _semi_circular_, _SPACE_
23
23
  # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .errors
@@ -27,7 +27,7 @@ from pygeodesy.units import Degrees, Degrees_, Feet, Float, Lam, Lam_, \
27
27
  from math import acos, asin, atan2, cos, degrees, fabs, radians, sin, tan # pow
28
28
 
29
29
  __all__ = _ALL_LAZY.utily
30
- __version__ = '24.05.14'
30
+ __version__ = '24.06.03'
31
31
 
32
32
  # read constant name "_M_Unit" as "meter per Unit"
33
33
  _M_CHAIN = _F( 20.1168) # yard2m(1) * 22
@@ -763,7 +763,7 @@ def sincos2d(deg, **adeg):
763
763
  q -= 1
764
764
  d = deg - q * _90_0
765
765
  if adeg:
766
- t = _xkwds_get(adeg, adeg=_0_0)
766
+ t = _xkwds_get1(adeg, adeg=_0_0)
767
767
  d = _MODS.karney._around(d + t)
768
768
  t = _sin0cos2(q & 3, radians(d), deg)
769
769
  else:
@@ -1002,9 +1002,10 @@ class _Wrap(object):
1002
1002
  def normal(self, setting):
1003
1003
  '''Set L{normal} to C{True}, C{False} or C{None}.
1004
1004
  '''
1005
- t = {True: (_MODS.formy.normal, _MODS.formy.normal_),
1006
- False: (self.wraplatlon, self.wraphilam),
1007
- None: (_passargs, _passargs)}.get(setting, ())
1005
+ m = _MODS.formy
1006
+ t = {True: (m.normal, m.normal_),
1007
+ False: (self.wraplatlon, self.wraphilam),
1008
+ None: (_passargs, _passargs)}.get(setting, ())
1008
1009
  if t:
1009
1010
  self.latlon, self.philam = t
1010
1011
  self._normal = setting