pygeodesy 24.9.29__py2.py3-none-any.whl → 24.10.24__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 (56) hide show
  1. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/METADATA +15 -15
  2. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/RECORD +56 -56
  3. pygeodesy/__init__.py +20 -19
  4. pygeodesy/__main__.py +5 -5
  5. pygeodesy/albers.py +12 -17
  6. pygeodesy/basics.py +38 -41
  7. pygeodesy/booleans.py +54 -46
  8. pygeodesy/cartesianBase.py +2 -2
  9. pygeodesy/constants.py +20 -16
  10. pygeodesy/datums.py +3 -3
  11. pygeodesy/dms.py +250 -270
  12. pygeodesy/ellipsoidalBase.py +2 -2
  13. pygeodesy/ellipsoidalBaseDI.py +10 -10
  14. pygeodesy/ellipsoidalNvector.py +4 -4
  15. pygeodesy/ellipsoidalVincenty.py +2 -2
  16. pygeodesy/ellipsoids.py +7 -48
  17. pygeodesy/elliptic.py +14 -14
  18. pygeodesy/errors.py +15 -10
  19. pygeodesy/etm.py +18 -2
  20. pygeodesy/fmath.py +188 -176
  21. pygeodesy/formy.py +4 -4
  22. pygeodesy/fstats.py +54 -56
  23. pygeodesy/fsums.py +304 -266
  24. pygeodesy/geodesici.py +43 -40
  25. pygeodesy/geodesicw.py +3 -3
  26. pygeodesy/geodesicx/gxarea.py +3 -2
  27. pygeodesy/geodsolve.py +73 -24
  28. pygeodesy/geohash.py +2 -2
  29. pygeodesy/geoids.py +28 -27
  30. pygeodesy/internals.py +156 -85
  31. pygeodesy/interns.py +23 -20
  32. pygeodesy/karney.py +61 -12
  33. pygeodesy/latlonBase.py +13 -15
  34. pygeodesy/lazily.py +206 -214
  35. pygeodesy/mgrs.py +13 -13
  36. pygeodesy/named.py +11 -10
  37. pygeodesy/nvectorBase.py +1 -1
  38. pygeodesy/points.py +2 -2
  39. pygeodesy/props.py +34 -13
  40. pygeodesy/rhumb/bases.py +5 -5
  41. pygeodesy/rhumb/solve.py +7 -8
  42. pygeodesy/solveBase.py +7 -25
  43. pygeodesy/sphericalBase.py +20 -23
  44. pygeodesy/sphericalNvector.py +24 -23
  45. pygeodesy/sphericalTrigonometry.py +9 -8
  46. pygeodesy/streprs.py +11 -8
  47. pygeodesy/trf.py +6 -4
  48. pygeodesy/triaxials.py +46 -9
  49. pygeodesy/units.py +4 -3
  50. pygeodesy/ups.py +6 -6
  51. pygeodesy/utily.py +2 -2
  52. pygeodesy/utm.py +2 -2
  53. pygeodesy/vector3d.py +5 -5
  54. pygeodesy/vector3dBase.py +4 -5
  55. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/WHEEL +0 -0
  56. {PyGeodesy-24.9.29.dist-info → PyGeodesy-24.10.24.dist-info}/top_level.txt +0 -0
pygeodesy/dms.py CHANGED
@@ -10,7 +10,7 @@ compass point suffix, including parsing of C{decimal} and C{sexagecimal} degrees
10
10
  Set env variable C{PYGEODESY_FMT_FORM} to any C{F_...} form to override default C{F_DMS}
11
11
  formatting of lat- and longitudes or to an empty string to restore the default.
12
12
 
13
- After I{(C) Chris Veness 2011-2015} published under the same MIT Licence**, see
13
+ After I{(C) Chris Veness 2011-2024} published under the same MIT Licence**, see
14
14
  U{Latitude/Longitude<https://www.Movable-Type.co.UK/scripts/latlong.html>} and
15
15
  U{Vector-based geodesy<https://www.Movable-Type.co.UK/scripts/latlong-vectors.html>}.
16
16
 
@@ -61,17 +61,18 @@ U{Vector-based geodesy<https://www.Movable-Type.co.UK/scripts/latlong-vectors.ht
61
61
  non-ascii characters and if so, I{not} C{unicode}.
62
62
  '''
63
63
 
64
- from pygeodesy.basics import copysign0, isLatLon, isodd, issequence, isstr, map2, \
64
+ from pygeodesy.basics import copysign0, isLatLon, isodd, issequence, isstr, \
65
65
  neg as _neg # in .ups
66
66
  from pygeodesy.constants import _umod_360, _0_0, _0_5, _60_0, _360_0, _3600_0
67
- from pygeodesy.errors import ParseError, RangeError, _TypeError, _ValueError,\
68
- _parseX, rangerrors, _xkwds, _xkwds_get
69
- from pygeodesy.interns import NN, _arg_, _COMMA_, _d_, _DASH_, _deg_, _degrees_, \
70
- _DOT_, _0_, _e_, _E_, _EW_, _f_, _F_, _g_, _keyword_, \
71
- _MINUS_, _N_, _NE_, _NS_, _NSEW_, _NW_, _of_, \
72
- _PERCENTDOTSTAR_, _PLUS_, _PLUSMINUS_, _QUOTE1_, \
73
- _QUOTE2_, _radians_, _S_, _SE_, _SPACE_, _SW_, _W_
74
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv
67
+ from pygeodesy.errors import ParseError, RangeError, _TypeError, _ValueError, \
68
+ _parseX, rangerrors, _xError, _xkwds, _getPYGEODESY
69
+ # from pygeodesy.internals import _getPYGEODESY # from .errors
70
+ from pygeodesy.interns import NN, _COMMA_, _d_, _DASH_, _deg_, _degrees_, _DOT_, \
71
+ _0_, _e_, _E_, _EW_, _f_, _F_, _g_, _MINUS_, _N_, \
72
+ _NE_, _NS_, _NSEW_, _NW_, _PERCENTDOTSTAR_, _PLUS_, \
73
+ _PLUSMINUS_, _QUOTE1_, _QUOTE2_, _radians_, _S_, \
74
+ _SE_, _SPACE_, _SW_, _W_
75
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
75
76
  # from pygeodesy.namedTuples import LatLon2Tuple # _MODS
76
77
  # from pygeodesy.props import _throwarning # _MODS
77
78
  from pygeodesy.streprs import Fmt, fstr, fstrzs, _0wpF
@@ -85,12 +86,10 @@ except ImportError: # Python 3+
85
86
  from string import ascii_letters as _LETTERS
86
87
 
87
88
  __all__ = _ALL_LAZY.dms
88
- __version__ = '24.06.11'
89
+ __version__ = '24.10.18'
89
90
 
90
91
  _beyond_ = 'beyond'
91
- _DDDMMSS_ = 'DDDMMSS'
92
92
  _deg_min_ = 'deg+min'
93
- _SDIGITS_ = '-0123456789+'
94
93
  _sexagecimal_ = 'sexagecimal'
95
94
  _SEXAGECIMUL = 1.e4 # sexagecimal C{D.MMSSss} into decimal C{DMMSS.ss}
96
95
 
@@ -101,7 +100,7 @@ F_D_, F_DM_, F_DMS_, F_DEG_, F_MIN_, F_SEC_, F_D60_, F__E_, F__F_, F__G
101
100
  F_D__, F_DM__, F_DMS__, F_DEG__, F_MIN__, F_SEC__, F_D60__, F__E__, F__F__, F__G__, F_RAD__ = (NN(
102
101
  _PLUS_, _) for _ in _F_s)
103
102
  del _F_s
104
- _F_DMS = _getenv('PYGEODESY_FMT_FORM', NN) or F_DMS
103
+ _F_DMS = _getPYGEODESY('FMT_FORM') or F_DMS
105
104
 
106
105
  _F_case = {F_D: F_D, F_DEG: F_D, _degrees_: F_D, # unsigned _F_s
107
106
  F_DM: F_DM, F_MIN: F_DM, _deg_min_: F_DM,
@@ -150,13 +149,20 @@ def _DMS3(form, s_D=S_DEG, s_M=S_MIN, s_S=S_SEC, s_DMS=S_DMS, **unused):
150
149
  def _dms3(d, ddd, p, w):
151
150
  '''(INTERNAL) Format C{d} as (deg, min, sec) C{str}s with leading zeros.
152
151
  '''
153
- d, s = divmod(round(d * _3600_0, p), _3600_0)
152
+ d = round(d * _3600_0, p)
153
+ d, s = divmod(d, _3600_0)
154
154
  m, s = divmod(s, _60_0)
155
155
  return (_0wpF(ddd, 0, d),
156
156
  _0wpF( 2, 0, m),
157
157
  _0wpF(w+2, p, s))
158
158
 
159
159
 
160
+ def _DR2(s_D=S_NUL, s_R=S_RAD, **unused):
161
+ '''(INTERNAL) Get the overridden or default C{D} and C{RAD} symbols.
162
+ '''
163
+ return s_D, s_R
164
+
165
+
160
166
  def _fstrzs(t, **unused):
161
167
  '''(INTERNAL) Pass-thru version of C{.streprs.fstrzs}.
162
168
  '''
@@ -169,79 +175,78 @@ def _split3(strDMS, suffix=_NSEW_):
169
175
  t = strDMS.strip()
170
176
  s = t[:1] # sign or digit
171
177
  P = t[-1:] # compass point or digit or dot
172
- t = t.lstrip(_PLUSMINUS_).rstrip(suffix).strip()
173
- return s, t, P
178
+ t = t.lstrip(_PLUSMINUS_).rstrip(suffix)
179
+ return s, t.strip(), P
174
180
 
175
181
 
176
- def _toDMS(deg, form, prec, sep, ddd, suff, s_D_M_S): # MCCABE 13 in .units
182
+ def _toDMS(deg, form, prec, sep, ddd, P, s_D_M_S): # MCCABE 15 in .units
177
183
  '''(INTERNAL) Convert C{deg} to C{str}, with/-out sign, DMS symbols and/or suffix.
178
184
  '''
179
- f = form
180
185
  try:
186
+ F = None
181
187
  deg = float(deg)
182
- except (TypeError, ValueError) as x:
183
- raise _ValueError(deg=deg, form=f, prec=prec, cause=x)
184
-
185
- if f[:1] in _PLUSMINUS_: # signed
186
- sign = _MINUS_ if deg < 0 else (
187
- _PLUS_ if deg > 0 and f[:1] == _PLUS_ else NN)
188
- f = f.lstrip(_PLUSMINUS_)
189
- suff = NN # no suffix if signed
190
- else: # suffixed
191
- sign = NN # no sign if suffixed
192
- if suff and sep: # no sep if no suffix
193
- suff = NN(sep, suff)
194
- try:
195
- F = _F_case[f] # .strip()
196
- except KeyError:
197
- f = f.lower() # .strip()
198
- F = _F_case.get(f, F_DMS)
199
188
 
200
- if prec is None:
201
- z = p = _F_prec.get(F, 6)
202
- else:
203
- z = int(prec)
204
- p = abs(z)
205
- w = p + (1 if p else 0)
206
- z = fstrzs if z > 1 else _fstrzs
207
- d = fabs(deg)
189
+ f, s = form, form[:1]
190
+ if s in _PLUSMINUS_: # signed
191
+ n = _MINUS_ if deg < 0 else (
192
+ _PLUS_ if deg > 0 and s == _PLUS_ else NN)
193
+ P = NN # no suffix
194
+ f = f.lstrip(_PLUSMINUS_)
195
+ else: # suffixed
196
+ n = NN
197
+ if sep and P: # no sep if no suffix
198
+ P = NN(sep, P)
199
+ try:
200
+ F = _F_case[f] # .strip()
201
+ except KeyError:
202
+ f = f.lower() # .strip()
203
+ F = _F_case.get(f, F_DMS)
204
+
205
+ if prec is None:
206
+ z = p = _F_prec.get(F, 6)
207
+ else:
208
+ z = int(prec)
209
+ p = abs(z)
210
+ w = p + (1 if p else 0)
211
+ z = fstrzs if z > 1 else _fstrzs
212
+ d = fabs(deg)
208
213
 
209
- try:
210
214
  if F is F_DMS: # 'deg+min+sec', default
211
215
  D, M, S = _DMS3(f, **s_D_M_S)
212
216
  d, m, s = _dms3(d, ddd, p, w)
213
- t = NN(sign, d, D, sep,
214
- m, M, sep,
215
- z(s), S, suff)
217
+ t = NN(n, d, D, sep,
218
+ m, M, sep,
219
+ z(s), S, P)
216
220
 
217
221
  elif F is F_DM: # 'deg+min'
218
222
  D, M, _ = _DMS3(f, **s_D_M_S)
219
223
  d, m = divmod(round(d * _60_0, p), _60_0)
220
- t = NN(sign, _0wpF(ddd, 0, d), D, sep,
221
- z(_0wpF(w+2, p, m)), M, suff)
224
+ t = NN(n, _0wpF(ddd, 0, d), D, sep,
225
+ z(_0wpF(w+2, p, m)), M, P)
222
226
 
223
227
  elif F is F_D: # 'deg'
224
228
  D, _, _ = _DMS3(f, **s_D_M_S)
225
- t = NN(sign, z(_0wpF(w+ddd, p, d)), D, suff)
229
+ t = NN(n, z(_0wpF(w+ddd, p, d)), D, P)
226
230
 
227
231
  elif F is F_D60: # 'deg.MM|SSss|'
228
232
  D, M, S = _D603(sep, **s_D_M_S)
229
233
  d, m, s = _dms3(d, ddd, p, w)
230
- t = z(s).split(_DOT_) + [S, suff]
231
- t = NN(sign, d, D, m, M, *t)
234
+ t = z(s).split(_DOT_) + [S, P]
235
+ t = NN(n, d, D, m, M, *t)
232
236
 
233
237
  elif F is F_RAD:
234
- R = _xkwds_get(s_D_M_S, s_R=S_RAD)
235
- r = NN(_PERCENTDOTSTAR_, _F_) % (p, radians(d))
236
- t = NN(sign, z(r), R, suff)
238
+ _, R = _DR2(**s_D_M_S)
239
+ r = NN(_PERCENTDOTSTAR_, _F_) % (p, radians(d))
240
+ t = NN(n, z(r), R, P)
237
241
 
238
242
  else: # F in (F__E, F__F, F__G)
239
- D = _xkwds_get(s_D_M_S, s_D=S_NUL)
240
- d = NN(_PERCENTDOTSTAR_, F) % (p, d) # XXX f?
241
- t = NN(sign, z(d, ap1z=F is F__G), D, suff)
243
+ D, _ = _DR2(**s_D_M_S)
244
+ d = NN(_PERCENTDOTSTAR_, F) % (p, d) # XXX f?
245
+ t = NN(n, z(d, ap1z=F is F__G), D, P)
242
246
 
243
247
  except Exception as x:
244
- raise _ValueError(deg=deg, form=form, F=F, prec=prec, suff=suff, cause=x)
248
+ d = {} if F is None else dict(F_=F, P=P)
249
+ raise _xError(x, deg=deg, form=form, prec=prec, **d)
245
250
 
246
251
  return t # NOT unicode in Python 2-
247
252
 
@@ -250,26 +255,15 @@ def bearingDMS(bearing, form=F_D, prec=None, sep=S_SEP, **s_D_M_S):
250
255
  '''Convert bearing to a string (without compass point suffix).
251
256
 
252
257
  @arg bearing: Bearing from North (compass C{degrees360}).
253
- @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D},
254
- L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
255
- L{F_D60}, L{F__E}, L{F__F}, L{F__G}, L{F_RAD},
256
- L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_},
257
- L{F_SEC_}, L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_},
258
- L{F_RAD_}, L{F_D__}, L{F_DM__}, L{F_DMS__}, L{F_DEG__},
259
- L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
260
- L{F__F__}, L{F__G__} or L{F_RAD__}).
258
+ @kwarg form: Format specifier for B{C{deg}} (C{str} or C{F_...}).
261
259
  @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
262
- Trailing zero decimals are stripped for B{C{prec}}
263
- values of 1 and above, but kept for negative B{C{prec}}.
264
260
  @kwarg sep: Separator between degrees, minutes, seconds, suffix (C{str}).
265
- @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=str}, C{B{s_M}=str},
266
- C{B{s_S}=str} and C{B{s_DMS}=True} to override any or
267
- cancel all DMS symbols, defaults L{S_DEG}, L{S_MIN}
268
- respectively L{S_SEC}.
261
+ @kwarg s_D_M_S: Optional keyword arguments to override any or cancel all
262
+ DMS symbol suffixes, see function L{pygeodesy.toDMS}.
269
263
 
270
264
  @return: Compass degrees per the specified B{C{form}} (C{str}).
271
265
 
272
- @see: Function L{pygeodesy.toDMS}.
266
+ @see: Function L{pygeodesy.toDMS} and its B{Notes} for further details.
273
267
  '''
274
268
  return _toDMS(_umod_360(bearing), form, prec, sep, 1, NN, s_D_M_S)
275
269
 
@@ -317,26 +311,15 @@ def compassDMS(bearing, form=F_D, prec=None, sep=S_SEP, **s_D_M_S):
317
311
  '''Convert bearing to a string suffixed with compass point.
318
312
 
319
313
  @arg bearing: Bearing from North (compass C{degrees360}).
320
- @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D},
321
- L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
322
- L{F_D60}, L{F__E}, L{F__F}, L{F__G}, L{F_RAD},
323
- L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_},
324
- L{F_SEC_}, L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_},
325
- L{F_RAD_}, L{F_D__}, L{F_DM__}, L{F_DMS__}, L{F_DEG__},
326
- L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
327
- L{F__F__}, L{F__G__} or L{F_RAD__}).
314
+ @kwarg form: Format specifier for B{C{deg}} (C{str} or C{F_...}).
328
315
  @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
329
- Trailing zero decimals are stripped for B{C{prec}}
330
- values of 1 and above, but kept for negative B{C{prec}}.
331
316
  @kwarg sep: Separator between degrees, minutes, seconds, suffix (C{str}).
332
- @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=str}, C{B{s_M}=str}
333
- C{B{s_S}=str} and C{B{s_DMS}=True} to override any or
334
- cancel all DMS symbols, defaults L{S_DEG}, L{S_MIN}
335
- respectively L{S_SEC}.
317
+ @kwarg s_D_M_S: Optional keyword arguments to override any or cancel all
318
+ DMS symbol suffixes, see function L{pygeodesy.toDMS}.
336
319
 
337
320
  @return: Compass degrees and point in the specified form (C{str}).
338
321
 
339
- @see: Function L{pygeodesy.toDMS}.
322
+ @see: Function L{pygeodesy.toDMS} and its B{Notes} for further details.
340
323
  '''
341
324
  b = _umod_360(bearing)
342
325
  return _toDMS(b, form, prec, sep, 1, compassPoint(b), s_D_M_S)
@@ -371,7 +354,7 @@ def compassPoint(bearing, prec=3):
371
354
  w *= int(b * m / _360_0 + _0_5) % m
372
355
  return _WINDS[w]
373
356
  except Exception as x:
374
- raise _ValueError(bearing=bearing, prec=prec, cause=x)
357
+ raise _xError(x, bearing=bearing, prec=prec)
375
358
 
376
359
 
377
360
  def degDMS(deg, prec=6, s_D=S_DEG, s_M=S_MIN, s_S=S_SEC, neg=_MINUS_, pos=NN):
@@ -379,13 +362,13 @@ def degDMS(deg, prec=6, s_D=S_DEG, s_M=S_MIN, s_S=S_SEC, neg=_MINUS_, pos=NN):
379
362
 
380
363
  @arg deg: Value in degrees (C{scalar degrees}).
381
364
  @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
382
- Trailing zero decimals are stripped for B{C{prec}}
383
- values of 1 and above, but kept for negative B{C{prec}}.
365
+ Trailing zero decimals are stripped for C{B{prec}=1}
366
+ and above, but kept for negative B{C{prec}}.
384
367
  @kwarg s_D: D symbol for degrees (C{str}).
385
- @kwarg s_M: M symbol for minutes (C{str}) or C{""}.
386
- @kwarg s_S: S symbol for seconds (C{str}) or C{""}.
368
+ @kwarg s_M: M symbol for minutes (C{str}) or C{""} aka L{pygeodesy.NN}.
369
+ @kwarg s_S: S symbol for seconds (C{str}) or C{""} aka L{pygeodesy.NN}.
387
370
  @kwarg neg: Optional sign for negative (C{'-'}).
388
- @kwarg pos: Optional sign for positive (C{''}).
371
+ @kwarg pos: Optional sign for positive (C{""}) aka L{pygeodesy.NN}.
389
372
 
390
373
  @return: I{Either} degrees, minutes I{or} seconds (C{str}).
391
374
 
@@ -393,8 +376,8 @@ def degDMS(deg, prec=6, s_D=S_DEG, s_M=S_MIN, s_S=S_SEC, neg=_MINUS_, pos=NN):
393
376
  '''
394
377
  try:
395
378
  deg = float(deg)
396
- except (TypeError, ValueError) as x:
397
- raise _ValueError(deg=deg, prec=prec, cause=x)
379
+ except Exception as x:
380
+ raise _xError(x, deg=deg, prec=prec)
398
381
 
399
382
  d, s = fabs(deg), s_D
400
383
  if d < 1:
@@ -421,40 +404,28 @@ def latDMS(deg, form=_F_DMS, prec=None, sep=S_SEP, **s_D_M_S):
421
404
  '''Convert latitude to a string, optionally suffixed with N or S.
422
405
 
423
406
  @arg deg: Latitude to be formatted (C{scalar degrees}).
424
- @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D},
425
- L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
426
- L{F_D60}, L{F__E}, L{F__F}, L{F__G}, L{F_RAD},
427
- L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_},
428
- L{F_SEC_}, L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_},
429
- L{F_RAD_}, L{F_D__}, L{F_DM__}, L{F_DMS__}, L{F_DEG__},
430
- L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
431
- L{F__F__}, L{F__G__} or L{F_RAD__}).
407
+ @kwarg form: Format specifier for B{C{deg}} (C{str} or C{F_...}).
432
408
  @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
433
- Trailing zero decimals are stripped for B{C{prec}}
434
- values of 1 and above, but kept for negative B{C{prec}}.
435
409
  @kwarg sep: Separator between degrees, minutes, seconds, suffix (C{str}).
436
- @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=str}, C{B{s_M}=str}
437
- C{B{s_S}=str} and C{B{s_DMS}=True} to override any or
438
- cancel all DMS symbols, defaults L{S_DEG}, L{S_MIN}
439
- respectively L{S_SEC}.
410
+ @kwarg s_D_M_S: Optional keyword arguments to override any or cancel all
411
+ DMS symbol suffixes, see function L{pygeodesy.toDMS}.
440
412
 
441
413
  @return: Degrees in the specified form (C{str}).
442
414
 
443
- @see: Functions L{pygeodesy.toDMS} and L{pygeodesy.lonDMS}.
415
+ @see: Function L{pygeodesy.toDMS} and its B{Notes} for further details.
444
416
  '''
445
- p = _S_ if deg < 0 else _N_
446
- return _toDMS(deg, form, prec, sep, 2, p, s_D_M_S)
417
+ P = _S_ if deg < 0 else _N_
418
+ return _toDMS(deg, form, prec, sep, 2, P, s_D_M_S)
447
419
 
448
420
 
449
421
  def latlonDMS(lls, **m_form_prec_sep_s_D_M_S):
450
422
  '''Convert one or more C{LatLon} instances to strings.
451
423
 
452
- @arg lls: Single (C{LatLon}) or list, sequence, tuple, etc. (C{LatLon}s).
424
+ @arg lls: Single (C{LatLon}) or an iterable (C{LatLon}s).
453
425
  @kwarg m_form_prec_sep_s_D_M_S: Optional keyword arguments C{B{m}eter},
454
426
  C{B{form}at}, C{B{prec}ision}, B{C{s_D}}, B{C{s_M}}, B{C{s_S}},
455
- B{C{s_DMS}} and I{DEPRECATED} C{B{sep}=None}, see method
456
- C{LatLon.toStr} and functions L{pygeodesy.latDMS} and
457
- L{pygeodesy.lonDMS} for more details.
427
+ B{C{s_DMS}} and I{DEPRECATED} C{B{sep}=None}, see function
428
+ L{pygeodesy.toDMS} and method C{LatLon.toStr} for more details.
458
429
 
459
430
  @return: A C{tuple} of C{str}s if B{C{lls}} is a list, sequence, tuple, etc.
460
431
  of C{LatLon}s or a single C{str} if B{C{lls}} is a single C{LatLon}.
@@ -462,15 +433,15 @@ def latlonDMS(lls, **m_form_prec_sep_s_D_M_S):
462
433
  @see: Functions L{pygeodesy.latlonDMS_}, L{pygeodesy.latDMS}, L{pygeodesy.lonDMS}
463
434
  and L{pygeodesy.toDMS} and method C{LatLon.toStr}.
464
435
 
465
- @note: Keyword argument C{B{sep}=None} to join a C{str}ing from the returned C{tuple}
466
- has been I{DEPRECATED}, use C{B{sep}.join(B{latlonDMS_}(...))} instead.
436
+ @note: Keyword argument C{B{sep}=None} to join the resturned C{tuple} has
437
+ been I{DEPRECATED}, use C{B{sep}.join(B{latlonDMS_}(...))} instead.
467
438
  '''
468
439
  sep, kwds = _latlonDMS_sep2(latlonDMS, **m_form_prec_sep_s_D_M_S)
469
440
  if isLatLon(lls):
470
441
  t = lls.toStr(**kwds)
471
442
  elif issequence(lls):
472
443
  t = tuple(ll.toStr(**kwds) for ll in lls)
473
- if sep: # XXX TO BE REMOVED
444
+ if sep: # XXX DEPRECATED, to be removed
474
445
  t = sep.join(t)
475
446
  else:
476
447
  raise _TypeError(lls=lls, **m_form_prec_sep_s_D_M_S)
@@ -481,12 +452,10 @@ def latlonDMS_(*lls, **m_form_prec_sep_s_D_M_S):
481
452
  '''Convert one or more C{LatLon} instances to strings.
482
453
 
483
454
  @arg lls: The instances (C{LatLon}s), all positional arguments.
484
- @kwarg m_form_prec_sep_s_D_M_S: Optional keyword arguments
485
- C{B{m}eter}, C{B{form}at}, C{B{prec}ision}, B{C{s_D}},
486
- B{C{s_M}}, B{C{s_S}}, B{C{s_DMS}} and I{DEPRECATED}
487
- C{B{sep}=None}, see method C{LatLon.toStr} and
488
- functions L{pygeodesy.latDMS} and L{pygeodesy.lonDMS}
489
- for more details.
455
+ @kwarg m_form_prec_sep_s_D_M_S: Optional keyword arguments C{B{m}eter},
456
+ C{B{form}at}, C{B{prec}ision}, B{C{s_D}}, B{C{s_M}}, B{C{s_S}},
457
+ B{C{s_DMS}} and I{DEPRECATED} C{B{sep}=None}, see function
458
+ L{pygeodesy.toDMS} and method C{LatLon.toStr} for more details.
490
459
 
491
460
  @return: A C{tuple} of C{str}s if 2 or more C{LatLon} instances
492
461
  or a single C{str} if only a single C{LatLon} instance
@@ -496,9 +465,8 @@ def latlonDMS_(*lls, **m_form_prec_sep_s_D_M_S):
496
465
  L{pygeodesy.lonDMS} and L{pygeodesy.toDMS} and method
497
466
  C{LatLon.toStr}.
498
467
 
499
- @note: Keyword argument C{B{sep}=None} to join a C{str}ing
500
- from the returned C{tuple} has been I{DEPRECATED},
501
- use C{B{sep}.join(B{latlonDMS_}(...))} instead.
468
+ @note: Keyword argument C{B{sep}=None} to join the resturned C{tuple} has
469
+ been I{DEPRECATED}, use C{B{sep}.join(B{latlonDMS_}(...))} instead.
502
470
  '''
503
471
  sep, kwds = _latlonDMS_sep2(latlonDMS, **m_form_prec_sep_s_D_M_S)
504
472
  if not lls:
@@ -510,9 +478,11 @@ def latlonDMS_(*lls, **m_form_prec_sep_s_D_M_S):
510
478
 
511
479
 
512
480
  def _latlonDMS_sep2(where, sep=None, **kwds):
513
- '''DEPRECATED, instead use: %r.join(%s(...))'''
514
- if sep:
515
- k = _SPACE_(_keyword_, _arg_, Fmt.EQUAL(sep=repr(sep)), _of_)
481
+ '''DEPRECATED, use %r.join(%s(...)) instead.'''
482
+ if sep: # PYCHOK no cover
483
+ i = _MODS.inters
484
+ k = Fmt.EQUAL(sep=repr(sep))
485
+ k = _SPACE_(i._keyword_, i._arg_, k, i._of_)
516
486
  n = where.__name__
517
487
  t = _latlonDMS_sep2.__doc__ % (sep, n)
518
488
  _MODS.props._throwarning(k, n, t)
@@ -523,41 +493,29 @@ def lonDMS(deg, form=_F_DMS, prec=None, sep=S_SEP, **s_D_M_S):
523
493
  '''Convert longitude to a string, optionally suffixed with E or W.
524
494
 
525
495
  @arg deg: Longitude to be formatted (C{scalar degrees}).
526
- @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D},
527
- L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
528
- L{F_D60}, L{F__E}, L{F__F}, L{F__G}, L{F_RAD},
529
- L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_},
530
- L{F_SEC_}, L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_},
531
- L{F_RAD_}, L{F_D__}, L{F_DM__}, L{F_DMS__}, L{F_DEG__},
532
- L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
533
- L{F__F__}, L{F__G__} or L{F_RAD__}).
496
+ @kwarg form: Format specifier for B{C{deg}} (C{str} or C{F_...}).
534
497
  @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
535
- Trailing zero decimals are stripped for B{C{prec}}
536
- values of 1 and above, but kept for negative B{C{prec}}.
537
498
  @kwarg sep: Separator between degrees, minutes, seconds, suffix (C{str}).
538
- @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=str}, C{B{s_M}=str}
539
- C{B{s_S}=str} and C{B{s_DMS}=True} to override any or
540
- cancel all DMS symbols, defaults L{S_DEG}, L{S_MIN}
541
- respectively L{S_SEC}.
499
+ @kwarg s_D_M_S: Optional keyword arguments to override any or cancel all
500
+ DMS symbol suffixes.
542
501
 
543
502
  @return: Degrees in the specified form (C{str}).
544
503
 
545
- @see: Functions L{pygeodesy.toDMS} and L{pygeodesy.latDMS}.
504
+ @see: Function L{pygeodesy.toDMS} and its B{Notes} for further details.
546
505
  '''
547
- p = _W_ if deg < 0 else _E_
548
- return _toDMS(deg, form, prec, sep, 3, p, s_D_M_S)
506
+ P = _W_ if deg < 0 else _E_
507
+ return _toDMS(deg, form, prec, sep, 3, P, s_D_M_S)
549
508
 
550
509
 
551
510
  def normDMS(strDMS, norm=None, **s_D_M_S):
552
- '''Normalize all degrees, minutes and seconds (DMS) I{symbols} in
511
+ '''Normalize all degrees, minutes and seconds (DMS) I{symbol} suffixes in
553
512
  a string to the default symbols L{S_DEG}, L{S_MIN}, L{S_SEC}.
554
513
 
555
514
  @arg strDMS: Original DMS string (C{str}).
556
- @kwarg norm: Optional replacement symbol (C{str}) or C{None} for
557
- the default DMS symbols). Use C{B{norm}=""} to
558
- remove all DMS symbols.
559
- @kwarg s_D_M_S: Optional, alternate DMS symbols C{B{s_D}=str},
560
- C{B{s_M}=str}, C{B{s_S}=str} and/or C{B{s_R}=str}
515
+ @kwarg norm: Optional replacement symbol (C{str}) or C{None} for the default
516
+ DMS symbol). Use C{B{norm}=""} to remove all DMS symbols.
517
+ @kwarg s_D_M_S: Optional, alternate DMS symbol suffixes C{B{s_D}=}L{S_DEG},
518
+ C{B{s_M}=}L{S_MIN}, C{B{s_S}=}L{S_SEC} and C{B{s_R}=}L{S_RAD}
561
519
  for radians, each to be replaced by B{C{norm}}.
562
520
 
563
521
  @return: Normalized DMS (C{str}).
@@ -588,13 +546,14 @@ def normDMS(strDMS, norm=None, **s_D_M_S):
588
546
  return strDMS # NOT unicode in Python 2-
589
547
 
590
548
 
591
- def parseDDDMMSS(strDDDMMSS, suffix=_NSEW_, sep=S_SEP, clip=0, sexagecimal=False): # MCCABE 14
549
+ def parseDDDMMSS(strDDDMMSS, suffix=_NSEW_, sep=S_SEP, clip=0, sexagecimal=False):
592
550
  '''Parse a lat- or longitude represention forms as [D]DDMMSS in degrees.
593
551
 
594
552
  @arg strDDDMMSS: Degrees in any of several forms (C{str}) and types (C{float},
595
553
  C{int}, other).
596
- @kwarg suffix: Optional, valid compass points (C{str}, C{tuple}).
597
- @kwarg sep: Optional separator between "[D]DD", "MM", "SS", B{C{suffix}} (L{S_SEP}).
554
+ @kwarg suffix: Optional compass points (C{str}), valid in B{C{strDDDMMSS}}.
555
+ @kwarg sep: Optional separator between "[D]DD", "MM", "SS", B{C{suffix}}
556
+ (L{S_SEP}) in B{C{strDDDMMSS}}.
598
557
  @kwarg clip: Optionally, limit value to range C{-/+B{clip}} (C{degrees}).
599
558
  @kwarg sexagecimal: If C{True}, convert C{"D.MMSS"} or C{float(D.MMSS)} to
600
559
  C{base-60} "MM" and "SS" digits. See C{form}s L{F_D60},
@@ -603,8 +562,8 @@ def parseDDDMMSS(strDDDMMSS, suffix=_NSEW_, sep=S_SEP, clip=0, sexagecimal=False
603
562
  @return: Degrees (C{float}).
604
563
 
605
564
  @raise ParseError: Invalid B{C{strDDDMMSS}} or B{C{clip}} or the form of
606
- B{C{strDDDMMSS}} is incompatible with the suffixed or
607
- B{C{suffix}} compass point.
565
+ B{C{strDDDMMSS}} is incompatible with or invalid for the
566
+ given B{C{suffix}} compass point(s).
608
567
 
609
568
  @raise RangeError: Value of B{C{strDDDMMSS}} outside the valid C{-/+B{clip}}
610
569
  range and L{rangerrors<pygeodesy.rangerrors>} is C{True}.
@@ -629,63 +588,39 @@ def parseDDDMMSS(strDDDMMSS, suffix=_NSEW_, sep=S_SEP, clip=0, sexagecimal=False
629
588
  L{pygeodesy.parse3llh}.
630
589
  '''
631
590
  def _DDDMMSS(strDDDMMSS, suffix, sep, clip, sexagecimal):
632
- S = suffix.upper()
591
+ S = suffix.upper() or _N_ # bool('' in _NE_) is True
633
592
  if isstr(strDDDMMSS):
634
- t = strDDDMMSS.replace(sep, NN) if sep else strDDDMMSS
635
- s, t, P = _split3(t, S)
636
- f = t.split(_DOT_)
637
- n = len(f[0])
638
- f = NN.join(f)
639
- if 1 < n < 8 and f.isdigit() and ( # dddN/S/E/W or ddd or +/-ddd
640
- (P in S and s.isdigit()) or
641
- (P.isdigit() and s in _SDIGITS_ # PYCHOK indent
642
- and S in _WINDS)):
643
- # check [D]DDMMSS form and compass point
644
- X = _EW_ if isodd(n) else _NS_
645
- if not (P in X or (S in X and (P.isdigit() or P == _DOT_))):
646
- t = _DDDMMSS_[int(X is _NS_):(n | 1)], _DASH_.join(X)
647
- raise ParseError('form %s applies %s' % t)
593
+ t = strDDDMMSS.replace(sep, NN) if sep else strDDDMMSS
594
+ n, s, t, f, P, X = _DDDMMSS6(t, S)
595
+ if X:
596
+ pass
648
597
  elif not sexagecimal: # try other forms
649
598
  return _DMS2deg(strDDDMMSS, S, sep, clip, {})
650
599
 
651
600
  if sexagecimal: # move decimal dot from ...
652
601
  n += 4 # ... [D]DD.MMSSs to [D]DDMMSS.s
653
602
  if n < 6:
654
- raise ParseError('%s digits (%s)' % (_sexagecimal_, n))
603
+ t = _SPACE_(_sexagecimal_, 'digits')
604
+ raise ParseError(t, n)
655
605
  z = n - len(f) # zeros to append
656
606
  t = (f + (_0_ * z)) if z > 0 else _DOT_(f[:n], f[n:])
657
607
  f = _0_0 # fraction
658
-
659
608
  else: # float or int to [D]DDMMSS[.fff]
660
- f, m = float(strDDDMMSS), 0
661
- if sexagecimal:
662
- f *= _SEXAGECIMUL
663
- m = 6
664
- s = P = _0_ # anything except NN, _S_, _SW_, _W_
665
- if f < 0:
666
- f = -f
667
- s = _MINUS_
668
- f, i = modf(f) # returns ...
669
- t = str(int(i)) # ... float(i)
670
- n = len(t) # number of digits to ...
671
- if n < m: # ... required min or ...
672
- t = (_0_ * (m - n)) + t
673
- # ... match the given compass point
674
- elif S in (_NS_ if isodd(n) else _EW_):
675
- t = _0_ + t
676
- # P = S
677
- # elif n > 1:
678
- # P = (_EW_ if isodd(n) else _NS_)[0]
679
- n = len(t)
609
+ f = float(strDDDMMSS)
610
+ n, s, t, f, P = _DDDMMSS5(f, S, sexagecimal)
680
611
 
681
612
  if n < 4: # [D]DD[.ddd]
682
- t = (float(t) + f),
613
+ if t:
614
+ f += float(t)
615
+ t = f,
683
616
  else:
684
- f += float(t[n-2:])
685
- if n < 6: # [D]DDMM[.mmm]
686
- t = float(t[:n-2]), f
617
+ n -= 2
618
+ f += float(t[n:])
619
+ if n < 4: # [D]DDMM[.mmm]
620
+ t = float(t[:n]), f
687
621
  else: # [D]DDMMSS[.sss]
688
- t = float(t[:n-4]), float(t[n-4:n-2]), f
622
+ d = n - 2
623
+ t = float(t[:d]), float(t[d:n]), f
689
624
  d = _dms2deg(s, P, *t)
690
625
  return clipDegrees(d, float(clip)) if clip else d
691
626
 
@@ -693,13 +628,54 @@ def parseDDDMMSS(strDDDMMSS, suffix=_NSEW_, sep=S_SEP, clip=0, sexagecimal=False
693
628
  strDDDMMSS=strDDDMMSS, suffix=suffix, sexagecimal=sexagecimal)
694
629
 
695
630
 
696
- def _dms2deg(s, P, deg, min=_0_0, sec=_0_0):
697
- '''(INTERNAL) Helper for C{parseDDDMMSS} and C{_DMS2deg}.
631
+ def _DDDMMSS5(f, S, sexagecimal):
632
+ '''(INTERNAL) Partial C{parseDDDMMSS} of C{float}.
633
+ '''
634
+ if sexagecimal:
635
+ f *= _SEXAGECIMUL
636
+ m = 6
637
+ else:
638
+ m = 0
639
+ s = P = _PLUS_ # anything except NN, _S_, _SW_, _W_
640
+ if f < 0:
641
+ f = -f
642
+ s = _MINUS_
643
+ f, i = modf(f) # returns ...
644
+ t = str(int(i)) # ... float(i)
645
+ n = len(t) # number of digits to ...
646
+ if n < m: # ... required min or ...
647
+ t = (_0_ * (m - n)) + t
648
+ # ... match the given compass point
649
+ elif S in (_NS_ if isodd(n) else _EW_):
650
+ t = _0_ + t
651
+ # P = S
652
+ # elif n > 1:
653
+ # P = (_EW_ if isodd(n) else _NS_)[0]
654
+ return len(t), s, t, f, P # float(f) fraction
655
+
656
+
657
+ def _DDDMMSS6(t, S):
658
+ '''(INTERNAL) Partial C{parseDDDMMSS} of C{str}.
698
659
  '''
699
- deg += (min + (sec / _60_0)) / _60_0
700
- if s == _MINUS_ or (P and P in _SW_):
701
- deg = _neg(deg)
702
- return deg
660
+ s, t, P = _split3(t, S)
661
+ f = t.split(_DOT_)
662
+ if len(f) > 2:
663
+ raise ParseError('dots', len(f) - 1)
664
+ n = len(f[0])
665
+ f = NN.join(f)
666
+ if 1 < n < 8 and f.isdigit() and ( # dddN/S/E/W or ddd or +/-ddd
667
+ (P in S and s.isdigit()) or
668
+ (P.isdigit() and S in _WINDS # PYCHOK indent
669
+ and (s in _PLUSMINUS_ or s.isdigit()))):
670
+ # check [D]DDMMSS form and compass point
671
+ X = _EW_ if isodd(n) else _NS_
672
+ if not (P in X or (S in X and (P.isdigit() or P == _DOT_))):
673
+ t = parseDDDMMSS.__name__[5 if isodd(n) else 6:]
674
+ t = _SPACE_('form', t, 'applies', _DASH_.join(X))
675
+ raise ParseError(t)
676
+ else:
677
+ X = NN
678
+ return n, s, t, f, P, X # str(f) fraction
703
679
 
704
680
 
705
681
  def _DMS2deg(strDMS, suffix, sep, clip, s_D_M_S):
@@ -707,7 +683,6 @@ def _DMS2deg(strDMS, suffix, sep, clip, s_D_M_S):
707
683
  '''
708
684
  try:
709
685
  d = float(strDMS)
710
-
711
686
  except (TypeError, ValueError):
712
687
  s, t, P = _split3(strDMS, suffix.upper())
713
688
  if sep: # remove all DMS symbols
@@ -715,29 +690,40 @@ def _DMS2deg(strDMS, suffix, sep, clip, s_D_M_S):
715
690
  t = normDMS(t, norm=NN, **s_D_M_S)
716
691
  else: # replace all DMS symbols
717
692
  t = normDMS(t, norm=_SPACE_, **s_D_M_S)
718
- t = map2(float, t.strip().split())
719
- d = _dms2deg(s, P, *t[:3])
720
-
693
+ t = t.strip().split()
694
+ d = _dms2deg(s, P, *map(float, t))
721
695
  return clipDegrees(d, float(clip)) if clip else d
722
696
 
723
697
 
698
+ def _dms2deg(n, P, d, m=_0_0, s=_0_0):
699
+ '''(INTERNAL) Helper for C{parseDDDMMSS}, C{parseRad} and C{_DMS2deg}.
700
+ '''
701
+ m += s / _60_0
702
+ d += m / _60_0
703
+ if n == _MINUS_ or (P and P in _SW_):
704
+ d = _neg(d)
705
+ return d
706
+
707
+
724
708
  def parseDMS(strDMS, suffix=_NSEW_, sep=S_SEP, clip=0, **s_D_M_S): # MCCABE 14
725
709
  '''Parse a lat- or longitude representation in C{degrees}.
726
710
 
727
- This is very flexible on formats, allowing signed decimal
728
- degrees, degrees and minutes or degrees minutes and seconds
729
- optionally suffixed by a cardinal compass point.
711
+ This is very flexible on formats, allowing signed decimal degrees, degrees
712
+ and minutes or degrees minutes and seconds optionally suffixed by a cardinal
713
+ compass point.
730
714
 
731
- A variety of symbols, separators and suffixes are accepted,
732
- for example "3°37′09″W". Minutes and seconds may be omitted.
715
+ A variety of symbols, separators and suffixes are accepted, for example
716
+ "3°37′09″W". Minutes and seconds may be omitted.
733
717
 
734
- @arg strDMS: Degrees in any of several forms (C{str}) and
735
- types (C{float}, C{int}, other).
718
+ @arg strDMS: Degrees in any of several forms (C{str}) and types (C{float},
719
+ C{int}, other).
736
720
  @kwarg suffix: Optional, valid compass points (C{str}, C{tuple}).
737
- @kwarg sep: Optional separator between deg°, min′, sec″, B{C{suffix}} (C{''}).
721
+ @kwarg sep: Optional separator between C{deg°}, C{min′}, C{sec″},
722
+ B{C{suffix}} (C{''}).
738
723
  @kwarg clip: Optionally, limit value to range C{-/+B{clip}} (C{degrees}).
739
- @kwarg s_D_M_S: Optional, alternate symbol for degrees C{B{s_D}=str},
740
- minutes C{B{s_M}=str} and/or seconds C{B{s_S}=str}.
724
+ @kwarg s_D_M_S: Optional, alternate DMS symbol suffixes for degrees
725
+ C{B{s_D}=}L{S_DEG}, minutes C{B{s_M}=}L{S_MIN} and
726
+ seconds C{B{s_S}=}L{S_SEC}, see function L{pygeodesy.toDMS}.
741
727
 
742
728
  @return: Degrees (C{float}).
743
729
 
@@ -767,8 +753,9 @@ def parseDMS2(strLat, strLon, sep=S_SEP, clipLat=90, clipLon=180, wrap=False, **
767
753
  @kwarg clipLon: Limit longitude to range C{-/+B{clipLon}} (C{degrees}).
768
754
  @kwarg wrap: If C{True}, wrap or I{normalize} the lat- and longitude,
769
755
  overriding B{C{clipLat}} and B{C{clipLon}} (C{bool}).
770
- @kwarg s_D_M_S: Optional, alternate symbol for degrees C{B{s_D}=str},
771
- minutes C{B{s_M}=str} and/or seconds C{B{s_S}=str}.
756
+ @kwarg s_D_M_S: Optional, alternate DMS symbol suffixes for degrees
757
+ C{B{s_D}=}L{S_DEG}, minutes C{B{s_M}=}L{S_MIN} and
758
+ seconds C{B{s_S}=}L{S_SEC}, see function L{pygeodesy.toDMS}.
772
759
 
773
760
  @return: A L{LatLon2Tuple}C{(lat, lon)} in C{degrees}.
774
761
 
@@ -791,14 +778,14 @@ def _2Tuple(strLat, strLon, clipLat, clipLon, wrap, **kwds):
791
778
  '''
792
779
  if wrap:
793
780
  _W = _MODS.utily._Wrap
794
- lat, lon = _W.latlon(parseDMS(strLat, suffix=_NS_, **kwds),
795
- parseDMS(strLon, suffix=_EW_, **kwds))
781
+ ll = _W.latlon(parseDMS(strLat, suffix=_NS_, **kwds),
782
+ parseDMS(strLon, suffix=_EW_, **kwds))
796
783
  else:
797
784
  # if wrap is None:
798
785
  # clipLat = clipLon = 0
799
- lat = parseDMS(strLat, suffix=_NS_, clip=clipLat, **kwds)
800
- lon = parseDMS(strLon, suffix=_EW_, clip=clipLon, **kwds)
801
- return _MODS.namedTuples.LatLon2Tuple(lat, lon)
786
+ ll = (parseDMS(strLat, suffix=_NS_, clip=clipLat, **kwds),
787
+ parseDMS(strLon, suffix=_EW_, clip=clipLon, **kwds))
788
+ return _MODS.namedTuples.LatLon2Tuple(*ll)
802
789
 
803
790
 
804
791
  def parse3llh(strllh, height=0, sep=_COMMA_, clipLat=90, clipLon=180, wrap=False, **s_D_M_S):
@@ -819,8 +806,9 @@ def parse3llh(strllh, height=0, sep=_COMMA_, clipLat=90, clipLon=180, wrap=False
819
806
  @kwarg clipLon: Limit longitude to range C{-/+B{clipLon}} (C{degrees}).
820
807
  @kwarg wrap: If C{True}, wrap or I{normalize} the lat- and longitude,
821
808
  overriding B{C{clipLat}} and B{C{clipLon}} (C{bool}).
822
- @kwarg s_D_M_S: Optional, alternate symbol for degrees C{B{s_D}=str},
823
- minutes C{B{s_M}=str} and/or seconds C{B{s_S}=str}.
809
+ @kwarg s_D_M_S: Optional, alternate DMS symbol suffixes for degrees
810
+ C{B{s_D}=}L{S_DEG}, minutes C{B{s_M}=}L{S_MIN} and
811
+ seconds C{B{s_S}=}L{S_SEC}, see function L{pygeodesy.toDMS}.
824
812
 
825
813
  @return: A L{LatLon3Tuple}C{(lat, lon, height)} in C{degrees},
826
814
  C{degrees} and C{float}.
@@ -836,7 +824,6 @@ def parse3llh(strllh, height=0, sep=_COMMA_, clipLat=90, clipLon=180, wrap=False
836
824
  @see: Functions L{pygeodesy.parseDDDMMSS}, L{pygeodesy.parseDMS},
837
825
  L{pygeodesy.parseDMS2} and L{pygeodesy.toDMS}.
838
826
  '''
839
-
840
827
  def _3llh(strllh, height, sep, wrap):
841
828
  ll = strllh.strip().split(sep)
842
829
  if len(ll) > 2: # XXX interpret height unit
@@ -849,7 +836,8 @@ def parse3llh(strllh, height=0, sep=_COMMA_, clipLat=90, clipLon=180, wrap=False
849
836
  a, b = [_.strip() for _ in ll] # PYCHOK false
850
837
  if a[-1:] in _EW_ or b[-1:] in _NS_:
851
838
  a, b = b, a
852
- return _2Tuple(a, b, clipLat, clipLon, wrap, **s_D_M_S).to3Tuple(h)
839
+ t = _2Tuple(a, b, clipLat, clipLon, wrap, **s_D_M_S)
840
+ return t.to3Tuple(h)
853
841
 
854
842
  return _parseX(_3llh, strllh, height, sep, wrap, strllh=strllh)
855
843
 
@@ -871,11 +859,9 @@ def parseRad(strRad, suffix=_NSEW_, clip=0):
871
859
  def _Rad(strRad, suffix, clip):
872
860
  try:
873
861
  r = float(strRad)
874
-
875
862
  except (TypeError, ValueError):
876
863
  s, t, P = _split3(strRad, suffix.upper())
877
864
  r = _dms2deg(s, P, float(t))
878
-
879
865
  return clipRadians(r, float(clip)) if clip else r
880
866
 
881
867
  return _parseX(_Rad, strRad, suffix, clip, strRad=strRad, suffix=suffix)
@@ -884,13 +870,11 @@ def parseRad(strRad, suffix=_NSEW_, clip=0):
884
870
  def precision(form, prec=None):
885
871
  '''Set the default precison for a given F_ form.
886
872
 
887
- @arg form: L{F_D}, L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN},
888
- L{F_SEC}, L{F_D60}, L{F__E}, L{F__F}, L{F__G}
889
- or L{F_RAD} (C{str}).
890
- @kwarg prec: Number of decimal digits (0..9 or C{None} for
891
- default). Trailing zero decimals are stripped
892
- for B{C{prec}} values of 1 and above, but kept
893
- for negative B{C{prec}}.
873
+ @arg form: L{F_D}, L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
874
+ L{F_D60}, L{F__E}, L{F__F}, L{F__G} or L{F_RAD} (C{str}).
875
+ @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
876
+ Trailing zero decimals are stripped for C{B{prec}=1}
877
+ and above, but kept for negative B{C{prec}}.
894
878
 
895
879
  @return: Previous precision for the B{C{form}} (C{int}).
896
880
 
@@ -901,10 +885,9 @@ def precision(form, prec=None):
901
885
  p = _F_prec[form]
902
886
  except KeyError:
903
887
  raise _ValueError(form=form)
904
-
905
888
  if prec is not None: # set as default
906
- _F_prec[form] = _MODS.units.Precision_(prec, low=-9, high=9)
907
-
889
+ P_ = _MODS.units.Precision_
890
+ _F_prec[form] = P_(prec, low=-9, high=9)
908
891
  return p
909
892
 
910
893
 
@@ -912,41 +895,38 @@ def toDMS(deg, form=_F_DMS, prec=2, sep=S_SEP, ddd=2, neg=_MINUS_, pos=_PLUS_, *
912
895
  '''Convert I{signed} C{degrees} to string, without suffix.
913
896
 
914
897
  @arg deg: Degrees to be formatted (C{scalar degrees}).
915
- @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D},
916
- L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC},
917
- L{F_D60}, L{F__E}, L{F__F}, L{F__G}, L{F_RAD},
918
- L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_},
919
- L{F_SEC_}, L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_},
920
- L{F_RAD_}, L{F_D__}, L{F_DM__}, L{F_DMS__}, L{F_DEG__},
921
- L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
898
+ @kwarg form: Format specifier for B{C{deg}} (C{str} or L{F_D}, L{F_DM}, L{F_DMS},
899
+ L{F_DEG}, L{F_MIN}, L{F_SEC}, L{F_D60}, L{F__E}, L{F__F}, L{F__G},
900
+ L{F_RAD}, L{F_D_}, L{F_DM_}, L{F_DMS_}, L{F_DEG_}, L{F_MIN_}, L{F_SEC_},
901
+ L{F_D60_}, L{F__E_}, L{F__F_}, L{F__G_}, L{F_RAD_}, L{F_D__}, L{F_DM__},
902
+ L{F_DMS__}, L{F_DEG__}, L{F_MIN__}, L{F_SEC__}, L{F_D60__}, L{F__E__},
922
903
  L{F__F__}, L{F__G__} or L{F_RAD__}).
923
- @kwarg prec: Number of decimal digits (0..9 or C{None} for default).
924
- Trailing zero decimals are stripped for B{C{prec}}
925
- values of 1 and above, but kept for negative B{C{prec}}.
904
+ @kwarg prec: Number of decimal digits (0..9 or C{None} for default). Trailing zero
905
+ decimals are stripped for C{B{prec}=1} and above, but kept for negative
906
+ B{C{prec}}.
926
907
  @kwarg sep: Separator between degrees, minutes, seconds, suffix (C{str}).
927
- @kwarg ddd: Number of digits for B{C{deg}°} (2 or 3).
908
+ @kwarg ddd: Number of (integer) digits for B{C{deg}°} (2 or 3).
928
909
  @kwarg neg: Prefix for negative B{C{deg}} (C{'-'}).
929
910
  @kwarg pos: Prefix for positive B{C{deg}} and signed B{C{form}} (C{'+'}).
930
- @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=str}, C{B{s_M}=str}
931
- C{B{s_S}=str} and C{B{s_DMS}=True} to override any or
932
- cancel all DMS symbols, defaults L{S_DEG}, L{S_MIN}
933
- respectively L{S_SEC}. See B{Notes} below.
911
+ @kwarg s_D_M_S: Optional keyword arguments C{B{s_D}=}L{S_DEG}, C{B{s_M}=}L{S_MIN}
912
+ C{B{s_S}=}L{S_SEC}, C{B{s_R}=}L{S_RAD} and C{B{s_DMS}=True} to
913
+ override any or cancel all DMS symbol suffixes. See the B{Notes}
914
+ below.
934
915
 
935
916
  @return: Degrees in the specified form (C{str}).
936
917
 
937
- @note: The degrees, minutes and seconds (DMS) symbol can be overridden in
938
- this and other C{*DMS} functions by using optional keyword argments
939
- C{B{s_D}="d"}, C{B{s_M}="'"} respectively C{B{s_S}='"'}. Using
940
- keyword argument B{C{s_DMS}=None} cancels all C{DMS} symbols to
941
- C{B{S_NUL}=NN}.
918
+ @note: The degrees, minutes and seconds (DMS) symbol can be overridden in this and
919
+ other C{*DMS} functions by using optional keyword argments C{B{s_D}="d"},
920
+ C{B{s_M}="'"} respectively C{B{s_S}='"'}. Using B{C{s_DMS}=None} cancels
921
+ all C{DMS} symbols to C{""} aka L{pygeodesy.NN}.
942
922
 
943
923
  @note: Sexagecimal format B{C{F_D60}} supports overridable pseudo-DMS symbols
944
924
  positioned at C{"[D]DD<B{s_D}>MM<B{s_M}>SS<B{s_S}>"} with defaults
945
925
  C{B{s_D}="."}, C{B{s_M}=B{sep}} and C{B{s_S}=}L{pygeodesy.NN}.
946
926
 
947
- @note: Formats B{C{F__E}}, B{C{F__F}} and B{C{F__G}} can be extended with
948
- a C{D}-only symbol if defined with keyword argument C{B{s_D}=str}.
949
- Likewise for B{C{F_RAD}} formats with keyword argument C{B{s_R}=str}.
927
+ @note: Formats B{C{F__E}}, B{C{F__F}} and B{C{F__G}} is extended with a C{D}-only
928
+ symbol suffix if defined with keyword argument C{B{s_D}=}L{pygeodesy.NN}.
929
+ Likewise for B{C{F_RAD}} forms with keyword argument C{B{s_R}=}L{S_RAD}.
950
930
 
951
931
  @see: Function L{pygeodesy.degDMS}
952
932
  '''