pygeodesy 24.5.15__py2.py3-none-any.whl → 24.6.1__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 (90) hide show
  1. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/METADATA +6 -5
  2. PyGeodesy-24.6.1.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +4 -4
  4. pygeodesy/albers.py +41 -41
  5. pygeodesy/auxilats/__init__.py +1 -1
  6. pygeodesy/auxilats/__main__.py +2 -2
  7. pygeodesy/auxilats/auxAngle.py +32 -31
  8. pygeodesy/auxilats/auxLat.py +80 -51
  9. pygeodesy/azimuthal.py +123 -124
  10. pygeodesy/basics.py +46 -10
  11. pygeodesy/booleans.py +13 -14
  12. pygeodesy/cartesianBase.py +25 -23
  13. pygeodesy/clipy.py +3 -3
  14. pygeodesy/constants.py +3 -3
  15. pygeodesy/css.py +50 -42
  16. pygeodesy/datums.py +42 -41
  17. pygeodesy/deprecated/functions.py +9 -3
  18. pygeodesy/dms.py +6 -6
  19. pygeodesy/ecef.py +41 -41
  20. pygeodesy/ellipsoidalBase.py +41 -41
  21. pygeodesy/ellipsoidalBaseDI.py +3 -4
  22. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  23. pygeodesy/ellipsoidalKarney.py +3 -3
  24. pygeodesy/ellipsoidalNvector.py +11 -12
  25. pygeodesy/ellipsoids.py +45 -38
  26. pygeodesy/elliptic.py +3 -4
  27. pygeodesy/epsg.py +4 -3
  28. pygeodesy/errors.py +52 -20
  29. pygeodesy/etm.py +68 -65
  30. pygeodesy/fmath.py +44 -49
  31. pygeodesy/formy.py +129 -115
  32. pygeodesy/frechet.py +118 -103
  33. pygeodesy/fstats.py +21 -14
  34. pygeodesy/fsums.py +124 -80
  35. pygeodesy/gars.py +10 -9
  36. pygeodesy/geodesicw.py +19 -17
  37. pygeodesy/geodesicx/__init__.py +1 -1
  38. pygeodesy/geodesicx/__main__.py +2 -2
  39. pygeodesy/geodesicx/gx.py +39 -33
  40. pygeodesy/geodesicx/gxarea.py +12 -9
  41. pygeodesy/geodesicx/gxbases.py +3 -4
  42. pygeodesy/geodesicx/gxline.py +6 -8
  43. pygeodesy/geodsolve.py +29 -28
  44. pygeodesy/geohash.py +60 -57
  45. pygeodesy/geoids.py +34 -32
  46. pygeodesy/hausdorff.py +114 -101
  47. pygeodesy/heights.py +137 -130
  48. pygeodesy/internals.py +16 -11
  49. pygeodesy/interns.py +3 -6
  50. pygeodesy/iters.py +19 -17
  51. pygeodesy/karney.py +21 -17
  52. pygeodesy/ktm.py +25 -18
  53. pygeodesy/latlonBase.py +12 -11
  54. pygeodesy/lazily.py +6 -6
  55. pygeodesy/lcc.py +24 -25
  56. pygeodesy/ltp.py +143 -113
  57. pygeodesy/ltpTuples.py +207 -150
  58. pygeodesy/mgrs.py +26 -26
  59. pygeodesy/named.py +172 -90
  60. pygeodesy/namedTuples.py +33 -25
  61. pygeodesy/nvectorBase.py +8 -8
  62. pygeodesy/osgr.py +40 -48
  63. pygeodesy/points.py +18 -18
  64. pygeodesy/props.py +29 -16
  65. pygeodesy/rhumb/__init__.py +1 -1
  66. pygeodesy/rhumb/aux_.py +13 -15
  67. pygeodesy/rhumb/bases.py +12 -5
  68. pygeodesy/rhumb/ekx.py +24 -18
  69. pygeodesy/rhumb/solve.py +13 -10
  70. pygeodesy/simplify.py +16 -16
  71. pygeodesy/solveBase.py +18 -18
  72. pygeodesy/sphericalBase.py +17 -21
  73. pygeodesy/sphericalTrigonometry.py +21 -21
  74. pygeodesy/streprs.py +5 -5
  75. pygeodesy/trf.py +13 -11
  76. pygeodesy/triaxials.py +68 -64
  77. pygeodesy/units.py +35 -35
  78. pygeodesy/unitsBase.py +24 -11
  79. pygeodesy/ups.py +66 -70
  80. pygeodesy/utily.py +3 -3
  81. pygeodesy/utm.py +183 -187
  82. pygeodesy/utmups.py +38 -38
  83. pygeodesy/utmupsBase.py +104 -106
  84. pygeodesy/vector2d.py +6 -7
  85. pygeodesy/vector3d.py +16 -17
  86. pygeodesy/vector3dBase.py +4 -5
  87. pygeodesy/webmercator.py +43 -51
  88. PyGeodesy-24.5.15.dist-info/RECORD +0 -116
  89. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/WHEEL +0 -0
  90. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/top_level.txt +0 -0
pygeodesy/ltp.py CHANGED
@@ -13,23 +13,23 @@ and L{ChLVe} and L{Ltp}, L{ChLV}, L{LocalError}, L{Attitude} and L{Frustum}.
13
13
  # make sure int/int division yields float quotient, see .basics
14
14
  from __future__ import division as _; del _ # PYCHOK semicolon
15
15
 
16
- from pygeodesy.basics import _args_kwds_names, issubclassof, map1, map2 # .datums
16
+ from pygeodesy.basics import _args_kwds_names, map1, map2, _xsubclassof # .datums
17
17
  from pygeodesy.constants import EPS, INT0, _umod_360, _0_0, _0_01, _0_5, _1_0, \
18
18
  _2_0, _60_0, _90_0, _100_0, _180_0, _3600_0, \
19
19
  _N_1_0 # PYCHOK used!
20
20
  from pygeodesy.datums import _WGS84, _xinstanceof
21
21
  from pygeodesy.ecef import _EcefBase, EcefKarney, _llhn4, _xyzn4
22
22
  from pygeodesy.errors import _NotImplementedError, _TypesError, _ValueError, \
23
- _xattr, _xkwds, _xkwds_get
23
+ _xattr, _xkwds, _xkwds_get, _xkwds_pop2
24
24
  from pygeodesy.fmath import fabs, fdot, Fhorner
25
25
  from pygeodesy.fsums import _floor, _Fsumf_, fsumf_, fsum1f_
26
- from pygeodesy.interns import NN, _0_, _COMMASPACE_, _DOT_, _ecef_, _height_, \
27
- _invalid_, _lat0_, _lon0_, _ltp_, _M_, _name_, _too_
26
+ from pygeodesy.interns import _0_, _COMMASPACE_, _DOT_, _ecef_, _height_, _M_, \
27
+ _invalid_, _lat0_, _lon0_, _ltp_, _name_, _too_
28
28
  # from pygeodesy.lazily import _ALL_LAZY # from vector3d
29
29
  from pygeodesy.ltpTuples import Attitude4Tuple, ChLVEN2Tuple, ChLV9Tuple, \
30
30
  ChLVYX2Tuple, Footprint5Tuple, Local9Tuple, \
31
31
  ChLVyx2Tuple, _XyzLocals4, _XyzLocals5, Xyz4Tuple
32
- from pygeodesy.named import _NamedBase, notOverloaded
32
+ from pygeodesy.named import _name__, _name2__, _NamedBase, notOverloaded
33
33
  from pygeodesy.namedTuples import LatLon3Tuple, LatLon4Tuple, Vector3Tuple
34
34
  from pygeodesy.props import Property, Property_RO, property_doc_, property_RO, \
35
35
  _update_all
@@ -42,44 +42,34 @@ from pygeodesy.vector3d import _ALL_LAZY, Vector3d
42
42
  # from math import fabs, floor as _floor # from .fmath, .fsums
43
43
 
44
44
  __all__ = _ALL_LAZY.ltp
45
- __version__ = '24.04.14'
45
+ __version__ = '24.05.31'
46
46
 
47
47
  _height0_ = _height_ + _0_
48
48
  _narrow_ = 'narrow'
49
49
  _wide_ = 'wide'
50
- _Xyz_ = 'Xyz'
51
-
52
-
53
- def _fov_2(**fov):
54
- # Half a field-of-view angle in C{degrees}.
55
- f = Degrees(Error=LocalError, **fov) * _0_5
56
- if EPS < f < _90_0:
57
- return f
58
- t = _invalid_ if f < 0 else _too_(_wide_ if f > EPS else _narrow_)
59
- raise LocalError(txt=t, **fov)
60
50
 
61
51
 
62
52
  class Attitude(_NamedBase):
63
- '''The orientation of a plane or camera in space.
53
+ '''The pose of a plane or camera in space.
64
54
  '''
65
55
  _alt = Meter( alt =_0_0)
66
56
  _roll = Degrees(roll=_0_0)
67
57
  _tilt = Degrees(tilt=_0_0)
68
58
  _yaw = Bearing(yaw =_0_0)
69
59
 
70
- def __init__(self, alt_attitude=INT0, tilt=INT0, yaw=INT0, roll=INT0, name=NN):
60
+ def __init__(self, alt_attitude=INT0, tilt=INT0, yaw=INT0, roll=INT0, **name):
71
61
  '''New L{Attitude}.
72
62
 
73
- @kwarg alt_attitude: An altitude (C{meter}) above earth or an attitude
74
- (L{Attitude} or L{Attitude4Tuple}) with the
75
- C{B{alt}itude}, B{C{tilt}}, B{C{yaw}} and B{C{roll}}.
63
+ @kwarg alt_attitude: Altitude (C{meter}) above earth or previous attitude
64
+ (L{Attitude} or L{Attitude4Tuple}) with the C{B{alt}itude},
65
+ B{C{tilt}}, B{C{yaw}} and B{C{roll}}.
76
66
  @kwarg tilt: Pitch, elevation from horizontal (C{degrees180}), negative down
77
67
  (clockwise rotation along and around the x- or East axis).
78
68
  @kwarg yaw: Bearing, heading (compass C{degrees360}), clockwise from North
79
69
  (counter-clockwise rotation along and around the z- or Up axis).
80
70
  @kwarg roll: Roll, bank (C{degrees180}), positive to the right and down
81
71
  (clockwise rotation along and around the y- or North axis).
82
- @kwarg name: Optional name C{str}).
72
+ @kwarg name: Optional C{B{name}=NN} C{str}).
83
73
 
84
74
  @raise AttitudeError: Invalid B{C{alt_attitude}}, B{C{tilt}}, B{C{yaw}} or
85
75
  B{C{roll}}.
@@ -97,7 +87,7 @@ class Attitude(_NamedBase):
97
87
  for n, v in t.items():
98
88
  if v:
99
89
  setattr(self, n, v)
100
- n = name or t.name
90
+ n = _name__(name, _or_nameof=t)
101
91
  if n:
102
92
  self.name = n
103
93
 
@@ -149,23 +139,26 @@ class Attitude(_NamedBase):
149
139
 
150
140
  bank = roll
151
141
 
152
- def rotate(self, x_xyz, y=None, z=None, Vector=None, **Vector_kwds):
142
+ def rotate(self, x_xyz, y=None, z=None, Vector=None, **name_Vector_kwds):
153
143
  '''Transform a (local) cartesian by this attitude's matrix.
154
144
 
155
- @arg x_xyz: X component of vector (C{scalar}) or (3-D) vector
156
- (C{Cartesian}, L{Vector3d} or L{Vector3Tuple}).
145
+ @arg x_xyz: X component of vector (C{scalar}) or (3-D) vector (C{Cartesian},
146
+ L{Vector3d} or L{Vector3Tuple}).
157
147
  @kwarg y: Y component of vector (C{scalar}), same units as B{C{x}}.
158
148
  @kwarg z: Z component of vector (C{scalar}), same units as B{C{x}}.
159
- @kwarg Vector: Class to return transformed point (C{Cartesian},
160
- L{Vector3d} or C{Vector3Tuple}) or C{None}.
161
- @kwarg Vector_kwds: Optional, additional B{C{Vector}} keyword arguments,
162
- ignored if C{B{Vector} is None}.
149
+ @kwarg Vector: Class to return transformed point (C{Cartesian}, L{Vector3d}
150
+ or C{Vector3Tuple}) or C{None}.
151
+ @kwarg name_Vector_kwds: Optional C{B{name}=NN} (C{str}) and optional,
152
+ additional B{C{Vector}} keyword arguments, ignored if
153
+ C{B{Vector} is None}.
163
154
 
164
- @return: A B{C{Vector}} instance or a L{Vector3Tuple}C{(x, y, z)} if
165
- C{B{Vector}=None}.
155
+ @return: A named B{C{Vector}} instance or if B{C{Vector}} is C{None},
156
+ a named L{Vector3Tuple}C{(x, y, z)}.
166
157
 
167
158
  @raise AttitudeError: Invalid B{C{x_xyz}}, B{C{y}} or B{C{z}}.
168
159
 
160
+ @raise TypeError: Invalid B{C{Vector}} or B{C{name_Vector_kwds}}.
161
+
169
162
  @see: U{Yaw, pitch, and roll rotations<http://MSL.CS.UIUC.edu/planning/node102.html>}.
170
163
  '''
171
164
  try:
@@ -177,8 +170,9 @@ class Attitude(_NamedBase):
177
170
  raise AttitudeError(x_xyz=x_xyz, y=y, z=z, cause=x)
178
171
 
179
172
  x, y, z = (fdot(r, *xyz) for r in self.matrix)
180
- return Vector3Tuple(x, y, z, name=self.name) if Vector is None else \
181
- Vector(x, y, z, **_xkwds(Vector_kwds, name=self.name))
173
+ n, kwds = _name2__(name_Vector_kwds, _or_nameof=self)
174
+ return Vector3Tuple(x, y, z, name=n) if Vector is None else \
175
+ Vector(x, y, z, name=n, **kwds)
182
176
 
183
177
  @property_doc_(' tilt/pitch/elevation from horizontal in C{degrees180}, negative down.')
184
178
  def tilt(self):
@@ -214,7 +208,7 @@ class Attitude(_NamedBase):
214
208
  def _r2d(r):
215
209
  return fsumf_(_N_1_0, *r)
216
210
 
217
- return Vector3d(*map(_r2d, self.matrix), name=tyr3d.__name__)
211
+ return Vector3d(*map(_r2d, self.matrix), name__=tyr3d)
218
212
 
219
213
  @property_doc_(' yaw/bearing/heading in compass C{degrees360}, clockwise from North.')
220
214
  def yaw(self):
@@ -247,12 +241,13 @@ class Frustum(_NamedBase):
247
241
  _tan_h_2 = _0_0 # tan(_h_2)
248
242
  _v_2 = _0_0 # half vfov in degrees
249
243
 
250
- def __init__(self, hfov, vfov, ltp=None):
244
+ def __init__(self, hfov, vfov, ltp=None, **name):
251
245
  '''New L{Frustum}.
252
246
 
253
247
  @arg hfov: Horizontal field-of-view (C{degrees180}).
254
248
  @arg vfov: Vertical field-of-view (C{degrees180}).
255
249
  @kwarg ltp: Optional I{local tangent plane} (L{Ltp}).
250
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
256
251
 
257
252
  @raise LocalError: Invalid B{C{hfov}} or B{C{vfov}}.
258
253
  '''
@@ -263,8 +258,10 @@ class Frustum(_NamedBase):
263
258
 
264
259
  if ltp:
265
260
  self._ltp = _xLtp(ltp)
261
+ if name:
262
+ self.name # PYCHOK effect
266
263
 
267
- def footprint5(self, alt_attitude, tilt=0, yaw=0, roll=0, z=_0_0, ltp=None): # MCCABE 15
264
+ def footprint5(self, alt_attitude, tilt=0, yaw=0, roll=0, z=_0_0, ltp=None, **name): # MCCABE 15
268
265
  '''Compute the center and corners of the intersection with (or projection
269
266
  to) the I{local tangent plane} (LTP).
270
267
 
@@ -280,6 +277,7 @@ class Frustum(_NamedBase):
280
277
  @kwarg z: Optional height of the footprint (C{meter}) above I{local tangent plane}.
281
278
  @kwarg ltp: The I{local tangent plane} (L{Ltp}), overriding this
282
279
  frustum's C{ltp}.
280
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
283
281
 
284
282
  @return: A L{Footprint5Tuple}C{(center, upperleft, upperight, loweright,
285
283
  lowerleft)} with the C{center} and 4 corners, each an L{Xyz4Tuple}.
@@ -350,7 +348,7 @@ class Frustum(_NamedBase):
350
348
  + _xy2(a, e + v, -h, -t, r) # swapped
351
349
  # turn center and corners by yaw, clockwise
352
350
  p = self.ltp if ltp is None else ltp # None OK
353
- return Footprint5Tuple(_xyz5(b, xy5, z, p)) # *_xyz5
351
+ return Footprint5Tuple(_xyz5(b, xy5, z, p), **name) # *_xyz5
354
352
 
355
353
  @Property_RO
356
354
  def hfov(self):
@@ -413,7 +411,7 @@ class LocalCartesian(_NamedBase):
413
411
  _t0 = None # origin (..., lat0, lon0, height0, ...) L{Ecef9Tuple}
414
412
  _9Tuple = Local9Tuple
415
413
 
416
- def __init__(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, name=NN, **lon00):
414
+ def __init__(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, **lon00_name):
417
415
  '''New L{LocalCartesian} converter.
418
416
 
419
417
  @kwarg latlonh0: The (geodetic) origin (C{LatLon}, L{LatLon4Tuple}, L{Ltp}
@@ -426,9 +424,10 @@ class LocalCartesian(_NamedBase):
426
424
  surface and for C{scalar} B{C{latlonh0}}, ignored otherwise.
427
425
  @kwarg ecef: An ECEF converter (L{EcefKarney} I{only}) for C{scalar}
428
426
  B{C{latlonh0}}, ignored otherwise.
429
- @kwarg name: Optional name (C{str}).
430
- @kwarg lon00: An arbitrary, I{polar} longitude (C{degrees}), overriding
431
- the default C{B{lon00}=B{lon0}}, see method C{reverse}.
427
+ @kwarg lon00_name: Optional C{B{name}=NN} (C{str}) and keyword argument
428
+ C{B{lon00}=B{lon0}} for the arbitrary I{polar} longitude
429
+ (C{degrees}), see method C{reverse} and property C{lon00}
430
+ for further details.
432
431
 
433
432
  @raise LocalError: If B{C{latlonh0}} not C{LatLon}, L{LatLon4Tuple}, L{Ltp},
434
433
  L{LocalCartesian} or L{Ecef9Tuple} or B{C{latlonh0}},
@@ -439,7 +438,7 @@ class LocalCartesian(_NamedBase):
439
438
  @note: If BC{latlonh0} is an L{Ltp} or L{LocalCartesian}, only C{lat0}, C{lon0},
440
439
  C{height0} and I{polar} C{lon00} are copied, I{not} the ECEF converter.
441
440
  '''
442
- self.reset(latlonh0, lon0=lon0, height0=height0, ecef=ecef, name=name, **lon00)
441
+ self.reset(latlonh0, lon0=lon0, height0=height0, ecef=ecef, **lon00_name)
443
442
 
444
443
  def __eq__(self, other):
445
444
  '''Compare this and an other instance.
@@ -464,29 +463,33 @@ class LocalCartesian(_NamedBase):
464
463
  '''
465
464
  return self._ecef
466
465
 
467
- def _ecef2local(self, ecef, Xyz, Xyz_kwds):
466
+ def _ecef2local(self, ecef, Xyz, name_Xyz_kwds):
468
467
  '''(INTERNAL) Convert geocentric/geodetic to local, like I{forward}.
469
468
 
470
469
  @arg ecef: Geocentric (and geodetic) (L{Ecef9Tuple}).
471
470
  @arg Xyz: An L{XyzLocal}, L{Enu} or L{Ned} I{class} or C{None}.
472
- @arg Xyz_kwds: B{C{Xyz}} keyword arguments, ignored if C{B{Xyz} is None}.
471
+ @arg name_Xyz_kwds: Optional C{B{name}=NN} (C{str}) and optional,
472
+ additional B{C{Xyz}} keyword arguments, ignored if
473
+ C{B{Xyz} is None}.
473
474
 
474
- @return: An C{B{Xyz}(x, y, z, ltp, **B{Xyz_kwds}} instance or if
475
- C{B{Xyz} is None}, a L{Local9Tuple}C{(x, y, z, lat, lon,
475
+ @return: An C{B{Xyz}(x, y, z, ltp, **B{name_Xyz_kwds}} instance or
476
+ if C{B{Xyz} is None}, a L{Local9Tuple}C{(x, y, z, lat, lon,
476
477
  height, ltp, ecef, M)} with this C{ltp}, B{C{ecef}}
477
478
  (L{Ecef9Tuple}) converted to this C{datum} and C{M=None},
478
479
  always.
480
+
481
+ @raise TypeError: Invalid B{C{Xyz}} or B{C{name_Xyz_kwds}}.
479
482
  '''
480
483
  ltp = self
481
484
  if ecef.datum != ltp.datum:
482
485
  ecef = ecef.toDatum(ltp.datum)
483
- x, y, z = self.M.rotate(ecef.xyz, *ltp._t0_xyz)
486
+ n, kwds = _name2__(name_Xyz_kwds, _or_nameof=ecef)
487
+ x, y, z = self.M.rotate(ecef.xyz, *ltp._t0_xyz)
484
488
  r = Local9Tuple(x, y, z, ecef.lat, ecef.lon, ecef.height,
485
- ltp, ecef, None, name=ecef.name)
489
+ ltp, ecef, None, name=n)
486
490
  if Xyz:
487
- if not issubclassof(Xyz, *_XyzLocals4): # Vector3d
488
- raise _TypesError(_Xyz_, Xyz, *_XyzLocals4)
489
- r = r.toXyz(Xyz=Xyz, **Xyz_kwds)
491
+ _xsubclassof(*_XyzLocals4, Xyz=Xyz) # Vector3d
492
+ r = r.toXyz(Xyz=Xyz, name=n, **kwds)
490
493
  return r
491
494
 
492
495
  @Property_RO
@@ -495,7 +498,7 @@ class LocalCartesian(_NamedBase):
495
498
  '''
496
499
  return self.ecef.datum.ellipsoid
497
500
 
498
- def forward(self, latlonh, lon=None, height=0, M=False, name=NN):
501
+ def forward(self, latlonh, lon=None, height=0, M=False, **name):
499
502
  '''Convert I{geodetic} C{(lat, lon, height)} to I{local} cartesian
500
503
  C{(x, y, z)}.
501
504
 
@@ -507,7 +510,7 @@ class LocalCartesian(_NamedBase):
507
510
  to and above (or below) the ellipsoid's surface.
508
511
  @kwarg M: Optionally, return the I{concatenated} rotation L{EcefMatrix},
509
512
  iff available (C{bool}).
510
- @kwarg name: Optional name (C{str}).
513
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
511
514
 
512
515
  @return: A L{Local9Tuple}C{(x, y, z, lat, lon, height, ltp, ecef, M)}
513
516
  with I{local} C{x}, C{y}, C{z}, I{geodetic} C{(lat}, C{lon},
@@ -521,7 +524,7 @@ class LocalCartesian(_NamedBase):
521
524
  C{scalar} for C{scalar} B{C{latlonh}} or invalid
522
525
  or if B{C{height}} invalid.
523
526
  '''
524
- lat, lon, h, n = _llhn4(latlonh, lon, height, Error=LocalError, name=name)
527
+ lat, lon, h, n = _llhn4(latlonh, lon, height, Error=LocalError, **name)
525
528
  t = self.ecef._forward(lat, lon, h, n, M=M)
526
529
  x, y, z = self.M.rotate(t.xyz, *self._t0_xyz)
527
530
  m = self.M.multiply(t.M) if M else None
@@ -549,7 +552,7 @@ class LocalCartesian(_NamedBase):
549
552
  '''(INTERNAL) Convert I{local} to geocentric/geodetic, like I{.reverse}.
550
553
 
551
554
  @arg local: Local (L{XyzLocal}, L{Enu}, L{Ned}, L{Aer} or L{Local9Tuple}).
552
- @kwarg nine: Return 3- or 9-tuple (C{bool}).
555
+ @kwarg nine: If C{True}, return a 9-, otherwise a 3-tuple (C{bool}).
553
556
  @kwarg M: Include the rotation matrix (C{bool}).
554
557
 
555
558
  @return: A I{geocentric} 3-tuple C{(x, y, z)} or if C{B{nine}=True},
@@ -586,19 +589,21 @@ class LocalCartesian(_NamedBase):
586
589
  '''
587
590
  return self._t0.M
588
591
 
589
- def reset(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, name=NN, **lon00):
590
- '''Reset this converter, see L{LocalCartesian.__init__} and L{Ltp.__init__} for more details.
592
+ def reset(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, **lon00_name):
593
+ '''Reset this converter, see L{LocalCartesian.__init__} for more details.
591
594
  '''
595
+ _, name = _xkwds_pop2(lon00_name, lon00=None) # PYCHOK get **name
592
596
  if isinstance(latlonh0, LocalCartesian):
593
597
  if self._t0:
594
598
  _update_all(self)
595
- self._ecef = latlonh0.ecef
596
- self._lon00 = latlonh0.lon00
597
- self._t0 = latlonh0._t0
598
- n = name or latlonh0.name
599
+ self._ecef = latlonh0.ecef
600
+ self._lon00 = latlonh0.lon00
601
+ self._t0 = latlonh0._t0
602
+ n = _name__(name, _or_nameof=latlonh0)
599
603
  else:
604
+ n = _name__(name, _or_nameof=self)
600
605
  lat0, lon0, height0, n = _llhn4(latlonh0, lon0, height0, suffix=_0_,
601
- Error=LocalError, name=name or self.name)
606
+ Error=LocalError, name=n)
602
607
  if ecef: # PYCHOK no cover
603
608
  _xinstanceof(self._Ecef, ecef=ecef)
604
609
  _update_all(self)
@@ -606,11 +611,11 @@ class LocalCartesian(_NamedBase):
606
611
  elif self._t0:
607
612
  _update_all(self)
608
613
  self._t0 = self.ecef._forward(lat0, lon0, height0, n, M=True)
609
- self.lon00 = _xattr(latlonh0, lon00=_xkwds_get(lon00, lon00=lon0))
614
+ self.lon00 = _xattr(latlonh0, lon00=_xkwds_get(lon00_name, lon00=lon0))
610
615
  if n:
611
616
  self.rename(n)
612
617
 
613
- def reverse(self, xyz, y=None, z=None, M=False, name=NN, **lon00):
618
+ def reverse(self, xyz, y=None, z=None, M=False, **lon00_name):
614
619
  '''Convert I{local} C{(x, y, z)} to I{geodetic} C{(lat, lon, height)}.
615
620
 
616
621
  @arg xyz: A I{local} (L{XyzLocal}, L{Enu}, L{Ned}, L{Aer}, L{Local9Tuple}) or
@@ -619,10 +624,12 @@ class LocalCartesian(_NamedBase):
619
624
  @kwarg z: Local C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}).
620
625
  @kwarg M: Optionally, return the I{concatenated} rotation L{EcefMatrix}, iff
621
626
  available (C{bool}).
622
- @kwarg name: Optional name (C{str}).
623
- @kwarg lon00: An arbitrary, I{polar} longitude (C{degrees}), returned for local
624
- C{B{x}=0} and C{B{y}=0} at I{polar} latitudes C{abs(B{lat0}) == 90},
625
- overriding property C{lon00} and default C{B{lon00}=B{lon0}}.
627
+ @kwarg lon00_name: Optional C{B{name}=NN} (C{str}) and keyword argument
628
+ C{B{lon00}=B{lon0}} for the arbitrary I{polar} longitude
629
+ (C{degrees}), overriding see the property C{B{lon00}=B{lon0}}
630
+ value. The I{polar} longitude (C{degrees}) is returned with
631
+ I{polar} latitudes C{abs(B{lat0}) == 90} for local C{B{x}=0}
632
+ and C{B{y}=0} locations.
626
633
 
627
634
  @return: An L{Local9Tuple}C{(x, y, z, lat, lon, height, ltp, ecef, M)} with
628
635
  I{local} C{x}, C{y}, C{z}, I{geodetic} C{lat}, C{lon}, C{height},
@@ -633,9 +640,10 @@ class LocalCartesian(_NamedBase):
633
640
  @raise LocalError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}}
634
641
  not C{scalar} for C{scalar} B{C{xyz}}.
635
642
  '''
643
+ lon00, name =_xkwds_pop2(lon00_name, lon00=self.lon00)
636
644
  x, y, z, n = _xyzn4(xyz, y, z, _XyzLocals5, Error=LocalError, name=name)
637
645
  c = self.M.unrotate((x, y, z), *self._t0_xyz)
638
- t = self.ecef.reverse(*c, M=M, lon00=_xkwds_get(lon00, lon00=self.lon00))
646
+ t = self.ecef.reverse(*c, M=M, lon00=lon00)
639
647
  m = self.M.multiply(t.M) if M else None
640
648
  return self._9Tuple(x, y, z, t.lat, t.lon, t.height, self, t, m, name=n or self.name)
641
649
 
@@ -661,7 +669,7 @@ class Ltp(LocalCartesian):
661
669
  '''
662
670
  _Ecef = _EcefBase
663
671
 
664
- def __init__(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, name=NN, **lon00):
672
+ def __init__(self, latlonh0=INT0, lon0=INT0, height0=INT0, ecef=None, **lon00_name):
665
673
  '''New C{Ltp}, see L{LocalCartesian.__init__} for more details.
666
674
 
667
675
  @kwarg ecef: Optional ECEF converter (L{EcefKarney}, L{EcefFarrell21},
@@ -669,10 +677,12 @@ class Ltp(LocalCartesian):
669
677
  L{EcefYou} I{instance}), overriding the default
670
678
  L{EcefKarney}C{(datum=Datums.WGS84)} for C{scalar}.
671
679
 
680
+ @see: Class L{LocalCartesian<LocalCartesian.__init__>} for further details.
681
+
672
682
  @raise TypeError: Invalid B{C{ecef}}.
673
683
  '''
674
684
  LocalCartesian.reset(self, latlonh0, lon0=lon0, height0=height0,
675
- ecef=ecef, name=name, **lon00)
685
+ ecef=ecef, **lon00_name)
676
686
 
677
687
  @Property
678
688
  def ecef(self):
@@ -719,7 +729,7 @@ class _ChLV(object):
719
729
  # assert _args_kwds_names(ChLVe.reverse)[1:4] == t
720
730
  return t
721
731
 
722
- def forward(self, latlonh, lon=None, height=0, M=None, name=NN): # PYCHOK no cover
732
+ def forward(self, latlonh, lon=None, height=0, M=None, **name): # PYCHOK no cover
723
733
  '''Convert WGS84 geodetic to I{Swiss} projection coordinates. I{Must be overloaded}.
724
734
 
725
735
  @arg latlonh: Either a C{LatLon}, L{Ltp} or C{scalar} (geodetic) latitude (C{degrees}).
@@ -728,7 +738,7 @@ class _ChLV(object):
728
738
  (C{meter}) for C{scalar} B{C{latlonh}} and B{C{lon}}.
729
739
  @kwarg M: If C{True}, return the I{concatenated} rotation L{EcefMatrix} iff available
730
740
  for C{ChLV} only, C{None} otherwise (C{bool}).
731
- @kwarg name: Optional name (C{str}).
741
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
732
742
 
733
743
  @return: A L{ChLV9Tuple}C{(Y, X, h_, lat, lon, height, ltp, ecef, M)} with the unfalsed
734
744
  I{Swiss Y, X} coordinates, I{Swiss h_} height, the given I{geodetic} C{lat},
@@ -738,7 +748,7 @@ class _ChLV(object):
738
748
 
739
749
  @raise LocalError: Invalid or non-C{scalar} B{C{latlonh}}, B{C{lon}} or B{C{height}}.
740
750
  '''
741
- notOverloaded(self, latlonh, lon=lon, height=height, M=M, name=name)
751
+ notOverloaded(self, latlonh, lon=lon, height=height, M=M, **name)
742
752
 
743
753
  def reverse(self, enh_, n=None, h_=0, M=None, **name): # PYCHOK no cover
744
754
  '''Convert I{Swiss} projection to WGS84 geodetic coordinates.
@@ -750,7 +760,7 @@ class _ChLV(object):
750
760
  @kwarg h_: I{Swiss h'} height for C{scalar} B{C{enh_}} and B{C{n}} (C{meter}).
751
761
  @kwarg M: If C{True}, return the I{concatenated} rotation L{EcefMatrix} iff available
752
762
  for C{ChLV} only, C{None} otherwise (C{bool}).
753
- @kwarg name: Optional name (C{str}).
763
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
754
764
 
755
765
  @return: A L{ChLV9Tuple}C{(Y, X, h_, lat, lon, height, ltp, ecef, M)} with the unfalsed
756
766
  I{Swiss Y, X} coordinates, I{Swiss h_} height, the given I{geodetic} C{lat},
@@ -848,24 +858,24 @@ class ChLV(_ChLV, Ltp):
848
858
  '''
849
859
  Ltp.__init__(self, latlonh0, **_xkwds(other_Ltp_kwds, ecef=None, name=ChLV.Bern.name))
850
860
 
851
- def forward(self, latlonh, lon=None, height=0, M=None, name=NN): # PYCHOK unused M
861
+ def forward(self, latlonh, lon=None, height=0, M=None, **name): # PYCHOK unused M
852
862
  # overloaded for the _ChLV.forward.__doc__
853
- return Ltp.forward(self, latlonh, lon=lon, height=height, M=M, name=name)
863
+ return Ltp.forward(self, latlonh, lon=lon, height=height, M=M, **name)
854
864
 
855
865
  def reverse(self, enh_, n=None, h_=0, M=None, **name): # PYCHOK signature
856
866
  # overloaded for the _ChLV.reverse.__doc__
857
- Y, X, h_, name = self._YXh_n4(enh_, n, h_, **name)
858
- return Ltp.reverse(self, Y, X, h_, M=M, name=name)
867
+ Y, X, h_, n = self._YXh_n4(enh_, n, h_, **name)
868
+ return Ltp.reverse(self, Y, X, h_, M=M, name=n)
859
869
 
860
870
  @staticmethod
861
- def false2(Y, X, LV95=True, name=NN):
871
+ def false2(Y, X, LV95=True, **name):
862
872
  '''Add the I{Swiss LV95} or I{LV03} falsing.
863
873
 
864
874
  @arg Y: Unfalsed I{Swiss Y} easting (C{meter}).
865
875
  @arg X: Unfalsed I{Swiss X} northing (C{meter}).
866
876
  @kwarg LV95: If C{True} add C{LV95} falsing, if C{False} add
867
877
  C{LV03} falsing, otherwise leave unfalsed.
868
- @kwarg name: Optional name (C{str}).
878
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
869
879
 
870
880
  @return: A L{ChLVEN2Tuple}C{(E_LV95, N_LV95)} or a
871
881
  L{ChLVyx2Tuple}C{(y_LV03, x_LV03)} with falsed B{C{Y}}
@@ -873,7 +883,7 @@ class ChLV(_ChLV, Ltp):
873
883
  with B{C{Y}} and B{C{X}} as-is.
874
884
  '''
875
885
  e, n = t = _ChLV._falsing2(LV95)
876
- return t.classof(e + Y, n + X, name=name)
886
+ return t.classof(e + Y, n + X, **name)
877
887
 
878
888
  @staticmethod
879
889
  def isLV03(e, n):
@@ -910,7 +920,7 @@ class ChLV(_ChLV, Ltp):
910
920
  return None
911
921
 
912
922
  @staticmethod
913
- def unfalse2(e, n, LV95=None, name=NN):
923
+ def unfalse2(e, n, LV95=None, **name):
914
924
  '''Remove the I{Swiss LV95} or I{LV03} falsing.
915
925
 
916
926
  @arg e: Falsed I{Swiss E_LV95} or I{y_LV03} easting (C{meter}).
@@ -918,13 +928,13 @@ class ChLV(_ChLV, Ltp):
918
928
  @kwarg LV95: If C{True} remove I{LV95} falsing, if C{False} remove
919
929
  I{LV03} falsing, otherwise use method C{isLV95(B{e},
920
930
  B{n})}.
921
- @kwarg name: Optional name (C{str}).
931
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
922
932
 
923
933
  @return: A L{ChLVYX2Tuple}C{(Y, X)} with the unfalsed B{C{e}}
924
934
  respectively B{C{n}}.
925
935
  '''
926
936
  Y, X = _ChLV._falsing2(ChLV.isLV95(e, n) if LV95 is None else LV95)
927
- return ChLVYX2Tuple(e - Y, n - X, name=name)
937
+ return ChLVYX2Tuple(e - Y, n - X, **name)
928
938
 
929
939
 
930
940
  class ChLVa(_ChLV, LocalCartesian):
@@ -937,15 +947,15 @@ class ChLVa(_ChLV, LocalCartesian):
937
947
  def __init__(self, name=ChLV.Bern.name):
938
948
  '''New I{Approximate WGS84-Swiss} L{ChLVa} converter, centered at I{Bern, Ch}.
939
949
 
940
- @kwarg name: Optional name (C{str}), overriding C{Bern.name}.
950
+ @kwarg name: Optional C{B{name}=Bern.name} (C{str}).
941
951
  '''
942
952
  LocalCartesian.__init__(self, latlonh0=ChLV.Bern, name=name)
943
953
 
944
- def forward(self, latlonh, lon=None, height=0, M=None, name=NN):
954
+ def forward(self, latlonh, lon=None, height=0, M=None, **name):
945
955
  # overloaded for the _ChLV.forward.__doc__
946
- lat, lon, h, name = _llhn4(latlonh, lon, height, name=name)
947
- a, b, h_ = _ChLV._llh2abh_3(lat, lon, h)
948
- a2, b2 = a**2, b**2
956
+ lat, lon, h, n = _llhn4(latlonh, lon, height, **name)
957
+ a, b, h_ = _ChLV._llh2abh_3(lat, lon, h)
958
+ a2, b2 = a**2, b**2
949
959
 
950
960
  Y = fsumf_( 72.37, 211455.93 * b,
951
961
  -10938.51 * b * a,
@@ -956,13 +966,13 @@ class ChLVa(_ChLV, LocalCartesian):
956
966
  76.63 * a2,
957
967
  -194.56 * b2 * a,
958
968
  119.79 * a2 * a) # + 200_000
959
- return self._ChLV9Tuple(True, M, name, Y, X, h_, lat, lon, h)
969
+ return self._ChLV9Tuple(True, M, n, Y, X, h_, lat, lon, h)
960
970
 
961
971
  def reverse(self, enh_, n=None, h_=0, M=None, **name): # PYCHOK signature
962
972
  # overloaded for the _ChLV.reverse.__doc__
963
- Y, X, h_, name = self._YXh_n4(enh_, n, h_, **name)
964
- a, b, h = _ChLV._YXh_2abh3(Y, X, h_)
965
- ab_d, a2, b2 = ChLV._ab_d, a**2, b**2
973
+ Y, X, h_, n = self._YXh_n4(enh_, n, h_, **name)
974
+ a, b, h = _ChLV._YXh_2abh3(Y, X, h_)
975
+ ab_d, a2, b2 = ChLV._ab_d, a**2, b**2
966
976
 
967
977
  lat = _Fsumf_(16.9023892, 3.238272 * b,
968
978
  -0.270978 * a2,
@@ -973,7 +983,7 @@ class ChLVa(_ChLV, LocalCartesian):
973
983
  0.791484 * a * b,
974
984
  0.1306 * a * b2,
975
985
  -0.0436 * a * a2).fover(ab_d)
976
- return self._ChLV9Tuple(False, M, name, Y, X, h_, lat, lon, h)
986
+ return self._ChLV9Tuple(False, M, n, Y, X, h_, lat, lon, h)
977
987
 
978
988
 
979
989
  class ChLVe(_ChLV, LocalCartesian):
@@ -995,15 +1005,15 @@ class ChLVe(_ChLV, LocalCartesian):
995
1005
  def __init__(self, name=ChLV.Bern.name):
996
1006
  '''New I{Approximate WGS84-Swiss} L{ChLVe} converter, centered at I{Bern, Ch}.
997
1007
 
998
- @kwarg name: Optional name (C{str}), overriding C{Bern.name}.
1008
+ @kwarg name: Optional C{B{name}=Bern.name} (C{str}).
999
1009
  '''
1000
1010
  LocalCartesian.__init__(self, latlonh0=ChLV.Bern, name=name)
1001
1011
 
1002
- def forward(self, latlonh, lon=None, height=0, M=None, name=NN, gamma=False): # PYCHOK gamma
1012
+ def forward(self, latlonh, lon=None, height=0, M=None, gamma=False, **name): # PYCHOK gamma
1003
1013
  # overloaded for the _ChLV.forward.__doc__
1004
- lat, lon, h, name = _llhn4(latlonh, lon, height, name=name)
1005
- a, b, h_ = _ChLV._llh2abh_3(lat, lon, h)
1006
- ab_M, z, _H = ChLV._ab_M, 0, Fhorner
1014
+ lat, lon, h, n = _llhn4(latlonh, lon, height, **name)
1015
+ a, b, h_ = _ChLV._llh2abh_3(lat, lon, h)
1016
+ ab_M, z, _H = ChLV._ab_M, 0, Fhorner
1007
1017
 
1008
1018
  B1 = _H(a, 211428.533991, -10939.608605, -2.658213, -8.539078, -0.00345, -0.007992)
1009
1019
  B3 = _H(a, -44.232717, 4.291740, -0.309883, 0.013924)
@@ -1016,7 +1026,7 @@ class ChLVe(_ChLV, LocalCartesian):
1016
1026
  B6 = 0.000488
1017
1027
  X = _H(b, B0, z, B2, z, B4, z, B6).fover(ab_M) # 1,000 Km!
1018
1028
 
1019
- t = self._ChLV9Tuple(True, M, name, Y, X, h_, lat, lon, h)
1029
+ t = self._ChLV9Tuple(True, M, n, Y, X, h_, lat, lon, h)
1020
1030
  if gamma:
1021
1031
  U1 = _H(a, 2255515.207166, 2642.456961, 1.284180, 2.577486, 0.001165)
1022
1032
  U3 = _H(a, -412.991934, 64.106344, -2.679566, 0.123833)
@@ -1025,11 +1035,11 @@ class ChLVe(_ChLV, LocalCartesian):
1025
1035
  t = t, g
1026
1036
  return t
1027
1037
 
1028
- def reverse(self, enh_, n=None, h_=0, M=None, name=NN, gamma=False): # PYCHOK gamma
1038
+ def reverse(self, enh_, n=None, h_=0, M=None, gamma=False, **name): # PYCHOK gamma
1029
1039
  # overloaded for the _ChLV.reverse.__doc__
1030
- Y, X, h_, name = self._YXh_n4(enh_, n, h_, name=name)
1031
- a, b, h = _ChLV._YXh_2abh3(Y, X, h_)
1032
- s_d, _H, z = ChLV._s_d, Fhorner, 0
1040
+ Y, X, h_, n = self._YXh_n4(enh_, n, h_, **name)
1041
+ a, b, h = _ChLV._YXh_2abh3(Y, X, h_)
1042
+ s_d, _H, z = ChLV._s_d, Fhorner, 0
1033
1043
 
1034
1044
  A0 = _H(b, ChLV._sLat, 32386.4877666, -25.486822, -132.457771, 0.48747, 0.81305, -0.0069)
1035
1045
  A2 = _H(b, -2713.537919, -450.442705, -75.53194, -14.63049, -2.7604)
@@ -1043,7 +1053,7 @@ class ChLVe(_ChLV, LocalCartesian):
1043
1053
  lon = _H(a, ChLV._sLon, A1, z, A3, z, A5).fover(s_d)
1044
1054
  # == (ChLV._sLon + a * (A1 + a**2 * (A3 + a**2 * A5))) / s_d
1045
1055
 
1046
- t = self._ChLV9Tuple(False, M, name, Y, X, h_, lat, lon, h)
1056
+ t = self._ChLV9Tuple(False, M, n, Y, X, h_, lat, lon, h)
1047
1057
  if gamma:
1048
1058
  U1 = _H(b, 106679.792202, 17876.57022, 4306.5241, 794.87772, 148.1545, 27.8725)
1049
1059
  U3 = _H(b, -1435.508, -794.8777, -296.309, -92.908)
@@ -1053,8 +1063,17 @@ class ChLVe(_ChLV, LocalCartesian):
1053
1063
  return t
1054
1064
 
1055
1065
 
1056
- def tyr3d(tilt=INT0, yaw=INT0, roll=INT0, Vector=Vector3d, **Vector_kwds):
1057
- '''Convert an attitude oriention into a (3-D) direction vector.
1066
+ def _fov_2(**fov):
1067
+ # Half a field-of-view angle in C{degrees}.
1068
+ f = Degrees(Error=LocalError, **fov) * _0_5
1069
+ if EPS < f < _90_0:
1070
+ return f
1071
+ t = _invalid_ if f < 0 else _too_(_wide_ if f > EPS else _narrow_)
1072
+ raise LocalError(txt=t, **fov)
1073
+
1074
+
1075
+ def tyr3d(tilt=INT0, yaw=INT0, roll=INT0, Vector=Vector3d, **name_Vector_kwds):
1076
+ '''Convert an attitude pose into a (3-D) direction vector.
1058
1077
 
1059
1078
  @kwarg tilt: Pitch, elevation from horizontal (C{degrees}), negative down
1060
1079
  (clockwise rotation along and around the x-axis).
@@ -1062,17 +1081,28 @@ def tyr3d(tilt=INT0, yaw=INT0, roll=INT0, Vector=Vector3d, **Vector_kwds):
1062
1081
  (counter-clockwise rotation along and around the z-axis).
1063
1082
  @kwarg roll: Roll, bank (C{degrees}), positive to the right and down
1064
1083
  (clockwise rotation along and around the y-axis).
1084
+ @kwarg Vector: Class to return the direction vector (C{Cartesian},
1085
+ L{Vector3d} or C{Vector3Tuple}) or C{None}.
1086
+ @kwarg name_Vector_kwds: Optional C{B{name}=NN} (C{str}) and optional,
1087
+ additional B{C{Vector}} keyword arguments, ignored if
1088
+ C{B{Vector} is None}.
1065
1089
 
1066
1090
  @return: A named B{C{Vector}} instance or if B{C{Vector}} is C{None},
1067
1091
  a named L{Vector3Tuple}C{(x, y, z)}.
1068
1092
 
1093
+ @raise AttitudeError: Invalid B{C{tilt}}, B{C{yaw}} or B{C{roll}}.
1094
+
1095
+ @raise TypeError: Invalid B{C{Vector}} or B{C{name_Vector_kwds}}.
1096
+
1069
1097
  @see: U{Yaw, pitch, and roll rotations<http://MSL.CS.UIUC.edu/planning/node102.html>}
1070
- and function L{pygeodesy.hartzell} argument C{los}.
1098
+ and function L{pygeodesy.hartzell} argument C{los}, Line-Of-Sight.
1071
1099
  '''
1072
1100
  d = Attitude4Tuple(_0_0, tilt, yaw, roll).tyr3d
1073
- return d if Vector is type(d) else (
1074
- Vector3Tuple(d.x, d.y, d.z, name=d.name) if Vector is None else
1075
- Vector(d.x, d.y, d.z, **_xkwds(Vector_kwds, name=d.name))) # PYCHOK indent
1101
+ if Vector is not type(d):
1102
+ n, kwds = _name2__(name_Vector_kwds, name__=tyr3d)
1103
+ d = Vector3Tuple(d.x, d.y, d.z, name=n) if Vector is None else \
1104
+ Vector(d.x, d.y, d.z, name=n, **kwds)
1105
+ return d
1076
1106
 
1077
1107
 
1078
1108
  def _xLtp(ltp, *dflt):