pygeodesy 25.9.9__py2.py3-none-any.whl → 25.11.5__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.
- pygeodesy/__init__.py +19 -19
- pygeodesy/azimuthal.py +10 -12
- pygeodesy/booleans.py +7 -32
- pygeodesy/clipy.py +16 -22
- pygeodesy/constants.py +82 -66
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/classes.py +24 -1
- pygeodesy/elliptic.py +2 -2
- pygeodesy/errors.py +1 -1
- pygeodesy/etm.py +3 -3
- pygeodesy/fmath.py +5 -3
- pygeodesy/geodesicx/gx.py +11 -10
- pygeodesy/geodesicx/gxarea.py +4 -4
- pygeodesy/geohash.py +6 -6
- pygeodesy/geoids.py +2 -2
- pygeodesy/heights.py +2 -2
- pygeodesy/internals.py +7 -8
- pygeodesy/karney.py +14 -14
- pygeodesy/lazily.py +6 -5
- pygeodesy/named.py +1 -1
- pygeodesy/streprs.py +9 -9
- pygeodesy/trf.py +4 -4
- pygeodesy/triaxials.py +233 -151
- pygeodesy/units.py +5 -0
- pygeodesy/utily.py +5 -4
- pygeodesy/vector2d.py +1 -1
- pygeodesy/vector3dBase.py +194 -50
- {pygeodesy-25.9.9.dist-info → pygeodesy-25.11.5.dist-info}/METADATA +20 -20
- {pygeodesy-25.9.9.dist-info → pygeodesy-25.11.5.dist-info}/RECORD +31 -31
- {pygeodesy-25.9.9.dist-info → pygeodesy-25.11.5.dist-info}/WHEEL +0 -0
- {pygeodesy-25.9.9.dist-info → pygeodesy-25.11.5.dist-info}/top_level.txt +0 -0
pygeodesy/triaxials.py
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
4
|
u'''Triaxal ellipsoid classes I{ordered} L{Triaxial} and I{unordered} L{Triaxial_} and Jacobi
|
|
5
|
-
conformal projections L{
|
|
6
|
-
I{Charles Karney}'s C++ class U{JacobiConformal
|
|
7
|
-
classGeographicLib_1_1JacobiConformal.html#details>}
|
|
8
|
-
L{BetaOmega2Tuple}, L{BetaOmega3Tuple}, L{
|
|
5
|
+
conformal projections L{ConformalTriaxial} and L{ConformalSphere}, transcoded from
|
|
6
|
+
I{Charles Karney}'s GeographicLib 2.5.2 C++ class U{JacobiConformal
|
|
7
|
+
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1JacobiConformal.html#details>}
|
|
8
|
+
to pure Python and miscellaneous classes L{BetaOmega2Tuple}, L{BetaOmega3Tuple}, L{Conformal2Tuple}
|
|
9
|
+
and L{TriaxialError}.
|
|
9
10
|
|
|
10
11
|
Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2008-2024). For more information,
|
|
11
|
-
see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
|
|
12
|
+
see the U{GeographicLib<https://GeographicLib.SourceForge.io>} 2.5.2 documentation.
|
|
12
13
|
|
|
13
14
|
@see: U{Geodesics on a triaxial ellipsoid<https://WikiPedia.org/wiki/Geodesics_on_an_ellipsoid#
|
|
14
15
|
Geodesics_on_a_triaxial_ellipsoid>} and U{Triaxial coordinate systems and their geometrical
|
|
@@ -32,7 +33,7 @@ from __future__ import division as _; del _ # noqa: E702 ;
|
|
|
32
33
|
|
|
33
34
|
from pygeodesy.basics import _isin, isLatLon, isscalar
|
|
34
35
|
from pygeodesy.constants import EPS, EPS0, EPS02, EPS4, INT0, PI2, PI_3, PI4, \
|
|
35
|
-
_EPS2e4,
|
|
36
|
+
_EPS2e4, float0_, _isfinite, isnear1, _over, _SQRT2_2, \
|
|
36
37
|
_0_0, _0_5, _1_0, _N_1_0, _64_0, _4_0 # PYCHOK used!
|
|
37
38
|
from pygeodesy.datums import Datum, _spherical_datum, _WGS84, Ellipsoid, _EWGS84, Fmt
|
|
38
39
|
# from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
|
|
@@ -44,6 +45,7 @@ from pygeodesy.interns import NN, _a_, _b_, _beta_, _c_, _distant_, _DMAIN_, \
|
|
|
44
45
|
_finite_, _height_, _inside_, _near_, _negative_, \
|
|
45
46
|
_not_, _NOTEQUAL_, _null_, _opposite_, _outside_, \
|
|
46
47
|
_SPACE_, _spherical_, _too_, _x_, _y_
|
|
48
|
+
# from pygeodesy.karney import _norm2 # _MODS
|
|
47
49
|
# from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .vector3d
|
|
48
50
|
from pygeodesy.named import _lazyNamedEnumItem as _lazy, _name__, _NamedEnum, \
|
|
49
51
|
_NamedEnumItem, _Pass
|
|
@@ -52,14 +54,14 @@ from pygeodesy.namedTuples import LatLon3Tuple, _NamedTupleTo, Vector3Tuple, \
|
|
|
52
54
|
from pygeodesy.props import Property_RO, property_ROver
|
|
53
55
|
# from pygeodesy.streprs import Fmt # from .datums
|
|
54
56
|
from pygeodesy.units import Degrees, Float, Height_, Meter, Meter2, Meter3, \
|
|
55
|
-
Radians,
|
|
57
|
+
Radians, Radius_, Scalar_
|
|
56
58
|
from pygeodesy.utily import asin1, atan2, atan2d, km2m, m2km, SinCos2, sincos2d_
|
|
57
59
|
from pygeodesy.vector3d import _otherV3d, Vector3d, _ALL_LAZY, _MODS
|
|
58
60
|
|
|
59
61
|
from math import fabs, sqrt
|
|
60
62
|
|
|
61
63
|
__all__ = _ALL_LAZY.triaxials
|
|
62
|
-
__version__ = '25.
|
|
64
|
+
__version__ = '25.10.30'
|
|
63
65
|
|
|
64
66
|
_not_ordered_ = _not_('ordered')
|
|
65
67
|
_omega_ = 'omega'
|
|
@@ -68,7 +70,7 @@ _TRIPS = 359 # Eberly 1074?
|
|
|
68
70
|
|
|
69
71
|
class _NamedTupleToX(_NamedTupleTo): # in .testNamedTuples
|
|
70
72
|
'''(INTERNAL) Base class for L{BetaOmega2Tuple},
|
|
71
|
-
L{BetaOmega3Tuple} and L{
|
|
73
|
+
L{BetaOmega3Tuple} and L{Conformal2Tuple}.
|
|
72
74
|
'''
|
|
73
75
|
def _toDegrees(self, name, **toDMS_kwds):
|
|
74
76
|
'''(INTERNAL) Convert C{self[0:2]} to L{Degrees} or C{toDMS}.
|
|
@@ -159,30 +161,30 @@ class BetaOmega3Tuple(_NamedTupleToX):
|
|
|
159
161
|
return BetaOmega2Tuple(*self[:2], name=self._name__(name))
|
|
160
162
|
|
|
161
163
|
|
|
162
|
-
class
|
|
163
|
-
'''2-Tuple C{(x, y)} with a Jacobi Conformal C{x} and C{y}
|
|
164
|
+
class Conformal2Tuple(_NamedTupleToX):
|
|
165
|
+
'''2-Tuple C{(x, y)} with a I{Jacobi Conformal} C{x} and C{y}
|
|
164
166
|
projection, both in L{Radians} (or L{Degrees}).
|
|
165
167
|
'''
|
|
166
168
|
_Names_ = (_x_, _y_)
|
|
167
169
|
_Units_ = (_Pass, _Pass)
|
|
168
170
|
|
|
169
171
|
def toDegrees(self, name=NN, **toDMS_kwds):
|
|
170
|
-
'''Convert this L{
|
|
172
|
+
'''Convert this L{Conformal2Tuple} to L{Degrees} or C{toDMS}.
|
|
171
173
|
|
|
172
174
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
173
175
|
|
|
174
|
-
@return: L{
|
|
176
|
+
@return: L{Conformal2Tuple}C{(x, y)} with C{x} and C{y} both
|
|
175
177
|
in L{Degrees} or as L{toDMS} strings provided some
|
|
176
178
|
B{C{toDMS_kwds}} keyword arguments are specified.
|
|
177
179
|
'''
|
|
178
180
|
return self._toDegrees(name, **toDMS_kwds)
|
|
179
181
|
|
|
180
182
|
def toRadians(self, **name):
|
|
181
|
-
'''Convert this L{
|
|
183
|
+
'''Convert this L{Conformal2Tuple} to L{Radians}.
|
|
182
184
|
|
|
183
185
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
184
186
|
|
|
185
|
-
@return: L{
|
|
187
|
+
@return: L{Conformal2Tuple}C{(x, y)} with C{x} and C{y} both in L{Radians}.
|
|
186
188
|
'''
|
|
187
189
|
return self._toRadians(name)
|
|
188
190
|
|
|
@@ -223,7 +225,7 @@ class Triaxial_(_NamedEnumItem):
|
|
|
223
225
|
a = a_triaxial
|
|
224
226
|
t = a._abc3
|
|
225
227
|
except AttributeError:
|
|
226
|
-
t =
|
|
228
|
+
t = Radius_(a=a), Radius_(b=b), Radius_(c=c)
|
|
227
229
|
except (TypeError, ValueError) as x:
|
|
228
230
|
raise TriaxialError(a=a, b=b, c=c, cause=x)
|
|
229
231
|
if name:
|
|
@@ -232,9 +234,9 @@ class Triaxial_(_NamedEnumItem):
|
|
|
232
234
|
a, b, c = self._abc3 = t
|
|
233
235
|
if self._unordered: # == not isinstance(self, Triaxial)
|
|
234
236
|
s, _, t = sorted(t)
|
|
235
|
-
if not (
|
|
237
|
+
if not (_isfinite(t) and s > 0):
|
|
236
238
|
raise TriaxialError(a=a, b=b, c=c) # txt=_invalid_
|
|
237
|
-
elif not (
|
|
239
|
+
elif not (_isfinite(a) and a >= b >= c > 0): # see Triaxial2
|
|
238
240
|
raise TriaxialError(a=a, b=b, c=c, txt=_not_ordered_)
|
|
239
241
|
elif not (a > c and self._a2c2 > 0 and self.e2ac > 0):
|
|
240
242
|
raise TriaxialError(a=a, c=c, e2ac=self.e2ac, txt=_spherical_)
|
|
@@ -249,6 +251,12 @@ class Triaxial_(_NamedEnumItem):
|
|
|
249
251
|
a, _, _ = self._abc3
|
|
250
252
|
return a
|
|
251
253
|
|
|
254
|
+
@Property_RO
|
|
255
|
+
def a2(self):
|
|
256
|
+
'''Get C{a**2}.
|
|
257
|
+
'''
|
|
258
|
+
return self.a**2
|
|
259
|
+
|
|
252
260
|
@Property_RO
|
|
253
261
|
def _a2b2(self):
|
|
254
262
|
'''(INTERNAL) Get C{a**2 - b**2} == E_sub_e**2.
|
|
@@ -263,6 +271,13 @@ class Triaxial_(_NamedEnumItem):
|
|
|
263
271
|
a, b, _ = self._abc3
|
|
264
272
|
return (a / b)**2 if a != b else _1_0
|
|
265
273
|
|
|
274
|
+
@Property_RO
|
|
275
|
+
def _a2b2c23(self):
|
|
276
|
+
'''(INTERNAL) Get 3-tuple C{(a**2, b**2, c**2)}.
|
|
277
|
+
'''
|
|
278
|
+
a, b, c = self._abc3
|
|
279
|
+
return self.a2, self.b2, self.c2
|
|
280
|
+
|
|
266
281
|
@Property_RO
|
|
267
282
|
def _a2c2(self):
|
|
268
283
|
'''(INTERNAL) Get C{a**2 - c**2} == E_sub_x**2.
|
|
@@ -275,12 +290,8 @@ class Triaxial_(_NamedEnumItem):
|
|
|
275
290
|
'''Get the surface area (C{meter} I{squared}).
|
|
276
291
|
'''
|
|
277
292
|
c, b, a = sorted(self._abc3)
|
|
278
|
-
if a > c
|
|
279
|
-
|
|
280
|
-
Ellipsoid(a, b=c).areax # a == b
|
|
281
|
-
else: # a == c == b
|
|
282
|
-
a = Meter2(area=a**2 * PI4)
|
|
283
|
-
return a
|
|
293
|
+
return Triaxial(a, b, c).area if a > c else \
|
|
294
|
+
Meter2(area=self.a2 * PI4) # a == c == b
|
|
284
295
|
|
|
285
296
|
def area_p(self, p=1.6075):
|
|
286
297
|
'''I{Approximate} the surface area (C{meter} I{squared}).
|
|
@@ -305,6 +316,19 @@ class Triaxial_(_NamedEnumItem):
|
|
|
305
316
|
_, b, _ = self._abc3
|
|
306
317
|
return b
|
|
307
318
|
|
|
319
|
+
@Property_RO
|
|
320
|
+
def b2(self):
|
|
321
|
+
'''Get C{b**2}.
|
|
322
|
+
'''
|
|
323
|
+
return self.b**2
|
|
324
|
+
|
|
325
|
+
@Property_RO
|
|
326
|
+
def _b2_a2(self):
|
|
327
|
+
'''(INTERNAL) Get C{(b / a)**2}.
|
|
328
|
+
'''
|
|
329
|
+
a, b, _ = self._abc3
|
|
330
|
+
return (b / a)**2 if a != b else _1_0
|
|
331
|
+
|
|
308
332
|
@Property_RO
|
|
309
333
|
def _b2c2(self):
|
|
310
334
|
'''(INTERNAL) Get C{b**2 - c**2} == E_sub_y**2.
|
|
@@ -319,6 +343,19 @@ class Triaxial_(_NamedEnumItem):
|
|
|
319
343
|
_, _, c = self._abc3
|
|
320
344
|
return c
|
|
321
345
|
|
|
346
|
+
@Property_RO
|
|
347
|
+
def c2(self):
|
|
348
|
+
'''Get C{c**2}.
|
|
349
|
+
'''
|
|
350
|
+
return self.c**2
|
|
351
|
+
|
|
352
|
+
@Property_RO
|
|
353
|
+
def _c2_a2(self):
|
|
354
|
+
'''(INTERNAL) Get C{(c / a)**2}.
|
|
355
|
+
'''
|
|
356
|
+
a, _, c = self._abc3
|
|
357
|
+
return (c / a)**2 if a != c else _1_0
|
|
358
|
+
|
|
322
359
|
@Property_RO
|
|
323
360
|
def _c2_b2(self):
|
|
324
361
|
'''(INTERNAL) Get C{(c / b)**2}.
|
|
@@ -330,35 +367,25 @@ class Triaxial_(_NamedEnumItem):
|
|
|
330
367
|
def e2ab(self):
|
|
331
368
|
'''Get the C{ab} ellipse' I{(1st) eccentricity squared} (C{scalar}), M{1 - (b/a)**2}.
|
|
332
369
|
'''
|
|
333
|
-
return Float(e2ab=(_1_0 - self.
|
|
370
|
+
return Float(e2ab=(_1_0 - self._b2_a2) or _0_0)
|
|
334
371
|
|
|
335
|
-
|
|
336
|
-
def _1e2ab(self):
|
|
337
|
-
'''(INTERNAL) Get C{1 - e2ab} == C{(b/a)**2}.
|
|
338
|
-
'''
|
|
339
|
-
a, b, _ = self._abc3
|
|
340
|
-
return (b / a)**2 if a != b else _1_0
|
|
372
|
+
# _1e2ab = _b2_a2 # C{1 - e2ab} == C{(b / a)**2}
|
|
341
373
|
|
|
342
374
|
@Property_RO
|
|
343
375
|
def e2ac(self):
|
|
344
376
|
'''Get the C{ac} ellipse' I{(1st) eccentricity squared} (C{scalar}), M{1 - (c/a)**2}.
|
|
345
377
|
'''
|
|
346
|
-
return Float(e2ac=(_1_0 - self.
|
|
378
|
+
return Float(e2ac=(_1_0 - self._c2_a2) or _0_0)
|
|
347
379
|
|
|
348
|
-
|
|
349
|
-
def _1e2ac(self):
|
|
350
|
-
'''(INTERNAL) Get C{1 - e2ac} == C{(c/a)**2}.
|
|
351
|
-
'''
|
|
352
|
-
a, _, c = self._abc3
|
|
353
|
-
return (c / a)**2 if a != c else _1_0
|
|
380
|
+
# _1e2ac = _c2_a2 # C{1 - e2ac} == C{(c / a)**2}
|
|
354
381
|
|
|
355
382
|
@Property_RO
|
|
356
383
|
def e2bc(self):
|
|
357
384
|
'''Get the C{bc} ellipse' I{(1st) eccentricity squared} (C{scalar}), M{1 - (c/b)**2}.
|
|
358
385
|
'''
|
|
359
|
-
return Float(e2bc=(_1_0 - self.
|
|
386
|
+
return Float(e2bc=(_1_0 - self._c2_b2) or _0_0)
|
|
360
387
|
|
|
361
|
-
|
|
388
|
+
# _1e2bc = _c2_b2 # C{1 - e2bc} == C{(c / b)**2}
|
|
362
389
|
|
|
363
390
|
@property_ROver
|
|
364
391
|
def _Elliptic(self):
|
|
@@ -387,7 +414,7 @@ class Triaxial_(_NamedEnumItem):
|
|
|
387
414
|
this triaxial (C{bool}).
|
|
388
415
|
@kwarg eps: Tolerance for root finding and validation (C{scalar}), use a negative
|
|
389
416
|
value to skip validation.
|
|
390
|
-
@kwarg name: Optional C{B{name}="
|
|
417
|
+
@kwarg name: Optional C{B{name}="height4"} (C{str}).
|
|
391
418
|
|
|
392
419
|
@return: L{Vector4Tuple}C{(x, y, z, h)} with the cartesian coordinates C{x}, C{y}
|
|
393
420
|
and C{z} of the projection on or the intersection with and with the height
|
|
@@ -449,37 +476,78 @@ class Triaxial_(_NamedEnumItem):
|
|
|
449
476
|
return float0_(s, c)
|
|
450
477
|
|
|
451
478
|
def normal3d(self, x_xyz, y=None, z=None, length=_1_0):
|
|
452
|
-
'''Get a 3-D vector
|
|
479
|
+
'''Get a 3-D vector I{on and perpendicular to} this triaxial's surface.
|
|
453
480
|
|
|
454
481
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
455
482
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
456
483
|
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} if C{scalar}, ignored
|
|
457
484
|
otherwise.
|
|
458
485
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
459
|
-
@kwarg length: Optional, signed length
|
|
486
|
+
@kwarg length: Optional, signed length in out-/inward direction (C{scalar}).
|
|
460
487
|
|
|
461
|
-
@return: A C{Vector3d(x_, y_, z_)} normalized to B{C{length}}, pointing
|
|
462
|
-
|
|
488
|
+
@return: A C{Vector3d(x_, y_, z_)} normalized to B{C{length}}, pointing out-
|
|
489
|
+
or inward for postive respectively negative B{C{length}}.
|
|
463
490
|
|
|
464
491
|
@raise TriaxialError: Zero length cartesian or vector.
|
|
465
492
|
|
|
466
|
-
@note: Cartesian C{(B{x}, B{y}, B{z})} I{must be on} this triaxial's surface,
|
|
467
|
-
method L{Triaxial.sideOf} to validate.
|
|
493
|
+
@note: Cartesian C{(B{x}, B{y}, B{z})} I{must be on} this triaxial's surface,
|
|
494
|
+
use method L{Triaxial.sideOf} to validate.
|
|
468
495
|
|
|
469
496
|
@see: Methods L{Triaxial.height4} and L{Triaxial.sideOf}.
|
|
470
497
|
'''
|
|
471
498
|
# n = 2 * (x / a2, y / b2, z / c2)
|
|
472
499
|
# == 2 * (x, y * a2 / b2, z * a2 / c2) / a2 # iff ordered
|
|
473
|
-
# == 2 * (x, y /
|
|
474
|
-
# == unit(x, y /
|
|
500
|
+
# == 2 * (x, y / _b2_a2, z / _c2_a2) / a2
|
|
501
|
+
# == unit(x, y / _b2_a2, z / _c2_a2).times(length)
|
|
475
502
|
x, y, z = _otherV3d_(x_xyz, y, z).xyz3
|
|
476
|
-
n = Vector3d(x, y / self.
|
|
477
|
-
z / self.
|
|
503
|
+
n = Vector3d(x, y / self._b2_a2,
|
|
504
|
+
z / self._c2_a2, name__=self.normal3d)
|
|
478
505
|
u = n.length
|
|
479
506
|
if u < EPS0:
|
|
480
507
|
raise TriaxialError(x=x_xyz, y=y, z=z, txt=_null_)
|
|
481
508
|
return n.times(length / u)
|
|
482
509
|
|
|
510
|
+
def normal4(self, x_xyz, y=None, z=None, height=0, normal=True):
|
|
511
|
+
'''Compute a cartesian above or below this triaxial's surface.
|
|
512
|
+
|
|
513
|
+
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian}, L{Ecef9Tuple},
|
|
514
|
+
L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
515
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} if C{scalar}, ignored
|
|
516
|
+
otherwise.
|
|
517
|
+
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
518
|
+
@kwarg height: The signed height (C{scalar}, same units as the triaxial axes).
|
|
519
|
+
@kwarg normal: If C{True}, the B{C{height}} is I{perpendicular, plumb} to the
|
|
520
|
+
triaxial's surface, otherwise C{radially} to the center of this
|
|
521
|
+
triaxial (C{bool}).
|
|
522
|
+
@kwarg name: Optional C{B{name}="normal4"} (C{str}).
|
|
523
|
+
|
|
524
|
+
@return: L{Vector4Tuple}C{(x, y, z, h)} with the cartesian coordinates C{x},
|
|
525
|
+
C{y} and C{z} and C{h} the I{signed, normal distance} to the triaxial's
|
|
526
|
+
surface in C{meter}, conventionally. Positive C{h} indicates, the
|
|
527
|
+
cartesian is outside the triaxial, negative C{h} means inside.
|
|
528
|
+
|
|
529
|
+
@raise TriaxialError: Zero length cartesian or vector.
|
|
530
|
+
|
|
531
|
+
@note: Cartesian C{(B{x}, B{y}, B{z})} I{must be on} this triaxial's surface,
|
|
532
|
+
use method L{Triaxial.sideOf} to validate.
|
|
533
|
+
|
|
534
|
+
@see: Methods L{Triaxial.normal3d} and L{Triaxial.height4}.
|
|
535
|
+
'''
|
|
536
|
+
v, h = _otherV3d(x_xyz, y, z), Height_(height, low=None)
|
|
537
|
+
if h:
|
|
538
|
+
if v.length < EPS0:
|
|
539
|
+
raise TriaxialError(x=x_xyz, y=y, z=z, txt=_null_)
|
|
540
|
+
if normal:
|
|
541
|
+
n = self.normal3d(v, length=h)
|
|
542
|
+
h = n.length
|
|
543
|
+
n += v
|
|
544
|
+
else:
|
|
545
|
+
h = h / v.length
|
|
546
|
+
n = v.times(h + _1_0)
|
|
547
|
+
else:
|
|
548
|
+
n = v
|
|
549
|
+
return Vector4Tuple(n.x, n.y, n.z, h, name__=self.normal4)
|
|
550
|
+
|
|
483
551
|
def _order3(self, *abc, **reverse): # reverse=False
|
|
484
552
|
'''(INTERNAL) Un-/Order C{a}, C{b} and C{c}.
|
|
485
553
|
|
|
@@ -557,7 +625,7 @@ class Triaxial_(_NamedEnumItem):
|
|
|
557
625
|
|
|
558
626
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
559
627
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
560
|
-
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}}
|
|
628
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} is C{scalar},
|
|
561
629
|
ignored otherwise.
|
|
562
630
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
563
631
|
@kwarg eps: On-surface tolerance (C{scalar}, distance I{squared}).
|
|
@@ -574,7 +642,7 @@ class Triaxial_(_NamedEnumItem):
|
|
|
574
642
|
return INT0 if fabs(s) < eps else s
|
|
575
643
|
|
|
576
644
|
def toEllipsoid(self, **name):
|
|
577
|
-
'''Convert this triaxial to
|
|
645
|
+
'''Convert this triaxial to a I{biaxial} L{Ellipsoid}, provided 2 axes match.
|
|
578
646
|
|
|
579
647
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
580
648
|
|
|
@@ -595,6 +663,8 @@ class Triaxial_(_NamedEnumItem):
|
|
|
595
663
|
raise TriaxialError(a=a, b=b, c=c, txt=t)
|
|
596
664
|
return Ellipsoid(a, b=b, name=self._name__(name))
|
|
597
665
|
|
|
666
|
+
toBiaxial = toEllipsoid
|
|
667
|
+
|
|
598
668
|
def toStr(self, prec=9, **name): # PYCHOK signature
|
|
599
669
|
'''Return this C{Triaxial} as a string.
|
|
600
670
|
|
|
@@ -605,11 +675,11 @@ class Triaxial_(_NamedEnumItem):
|
|
|
605
675
|
@return: This C{Triaxial}'s attributes (C{str}).
|
|
606
676
|
'''
|
|
607
677
|
T = Triaxial_
|
|
608
|
-
t = T.a,
|
|
609
|
-
J =
|
|
678
|
+
t = T.a, # props
|
|
679
|
+
J = ConformalSphere
|
|
610
680
|
t += (J.ab, J.bc) if isinstance(self, J) else (T.b, T.c)
|
|
611
681
|
t += T.e2ab, T.e2bc, T.e2ac
|
|
612
|
-
J =
|
|
682
|
+
J = ConformalTriaxial
|
|
613
683
|
if isinstance(self, J):
|
|
614
684
|
t += J.xyQ2,
|
|
615
685
|
t += T.volume, T.area
|
|
@@ -655,9 +725,12 @@ class Triaxial(Triaxial_):
|
|
|
655
725
|
|
|
656
726
|
@Property_RO
|
|
657
727
|
def _a2b2_a2c2(self):
|
|
658
|
-
'''@see: Methods C{.forwardBetaOmega} and C{.
|
|
728
|
+
'''@see: Methods C{.forwardBetaOmega} and property C{._k2E_kp2E}.
|
|
659
729
|
'''
|
|
660
|
-
|
|
730
|
+
s = self._a2c2
|
|
731
|
+
if s:
|
|
732
|
+
s = self._a2b2 / s
|
|
733
|
+
return s or _0_0
|
|
661
734
|
|
|
662
735
|
@Property_RO
|
|
663
736
|
def area(self):
|
|
@@ -667,9 +740,9 @@ class Triaxial(Triaxial_):
|
|
|
667
740
|
'''
|
|
668
741
|
a, b, c = self._abc3
|
|
669
742
|
if a != b:
|
|
670
|
-
kp2, k2 = self.
|
|
743
|
+
kp2, k2 = self._k2E_kp2E # swapped!
|
|
671
744
|
aE = self._Elliptic(k2, _0_0, kp2, _1_0)
|
|
672
|
-
c2 = self.
|
|
745
|
+
c2 = self._c2_a2 # cos(phi)**2 = (c/a)**2
|
|
673
746
|
s = sqrt(self.e2ac) # sin(phi)**2 = 1 - c2
|
|
674
747
|
r = asin1(s) # phi = atan2(sqrt(c2), s)
|
|
675
748
|
b *= fsum1f_(aE.fE(r) * s, (c / a) * (c / b),
|
|
@@ -685,8 +758,8 @@ class Triaxial(Triaxial_):
|
|
|
685
758
|
|
|
686
759
|
@arg beta: Ellipsoidal latitude (C{radians} or L{Degrees}).
|
|
687
760
|
@arg omega: Ellipsoidal longitude (C{radians} or L{Degrees}).
|
|
688
|
-
@arg height: Height above or below the ellipsoid's surface (C{meter},
|
|
689
|
-
units as this triaxial's C{a},
|
|
761
|
+
@arg height: Height above or below the ellipsoid's surface (C{meter},
|
|
762
|
+
same units as this triaxial's C{a}, semi-axes).
|
|
690
763
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
691
764
|
|
|
692
765
|
@return: A L{Vector3Tuple}C{(x, y, z)}.
|
|
@@ -709,13 +782,13 @@ class Triaxial(Triaxial_):
|
|
|
709
782
|
sb, cb = SinCos2(omega)
|
|
710
783
|
|
|
711
784
|
r = self._a2b2_a2c2
|
|
712
|
-
x *= cb * _sqrt0(ca**2 + sa**2 * r)
|
|
713
|
-
y *= ca *
|
|
714
|
-
z *= sa * _sqrt0(_1_0 - cb**2 * r)
|
|
785
|
+
x *= cb * (_sqrt0(ca**2 + sa**2 * r) if r else fabs(ca))
|
|
786
|
+
y *= ca * sb
|
|
787
|
+
z *= sa * (_sqrt0(_1_0 - cb**2 * r) if r else _1_0)
|
|
715
788
|
return Vector3Tuple(x, y, z, **name)
|
|
716
789
|
|
|
717
790
|
def forwardBetaOmega_(self, sbeta, cbeta, somega, comega, **name):
|
|
718
|
-
'''Convert I{ellipsoidal} lat-
|
|
791
|
+
'''Convert I{ellipsoidal} lat- C{beta} and longitude C{omega}
|
|
719
792
|
to cartesian coordinates I{on the triaxial's surface}.
|
|
720
793
|
|
|
721
794
|
@arg sbeta: Ellipsoidal latitude C{sin(beta)} (C{scalar}).
|
|
@@ -741,7 +814,7 @@ class Triaxial(Triaxial_):
|
|
|
741
814
|
|
|
742
815
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
743
816
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
744
|
-
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}}
|
|
817
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} is C{scalar},
|
|
745
818
|
ignored otherwise.
|
|
746
819
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
747
820
|
@kwarg normal_eps_name: Optional keyword arguments C{B{normal}=True},
|
|
@@ -759,7 +832,7 @@ class Triaxial(Triaxial_):
|
|
|
759
832
|
@arg lat: Geodetic latitude (C{degrees}).
|
|
760
833
|
@arg lon: Geodetic longitude (C{degrees}).
|
|
761
834
|
@arg height: Height above the ellipsoid (C{meter}, same units
|
|
762
|
-
as this triaxial's
|
|
835
|
+
as this triaxial's semi-axes).
|
|
763
836
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
764
837
|
|
|
765
838
|
@return: A L{Vector3Tuple}C{(x, y, z)}.
|
|
@@ -777,7 +850,7 @@ class Triaxial(Triaxial_):
|
|
|
777
850
|
@arg slon: Geodetic longitude C{sin(lon)} (C{scalar}).
|
|
778
851
|
@arg clon: Geodetic longitude C{cos(lon)} (C{scalar}).
|
|
779
852
|
@arg height: Height above the ellipsoid (C{meter}, same units
|
|
780
|
-
as this triaxial's axes
|
|
853
|
+
as this triaxial's semi-axes).
|
|
781
854
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
782
855
|
|
|
783
856
|
@return: A L{Vector3Tuple}C{(x, y, z)}.
|
|
@@ -795,11 +868,11 @@ class Triaxial(Triaxial_):
|
|
|
795
868
|
ca_x_sb = ca * sb
|
|
796
869
|
h = self._Height(height)
|
|
797
870
|
# 1 - (1 - (c/a)**2) * sa**2 - (1 - (b/a)**2) * ca**2 * sb**2
|
|
798
|
-
t =
|
|
799
|
-
n = self.a
|
|
871
|
+
t = fsumf_(_1_0, -self.e2ac * sa**2, -self.e2ab * ca_x_sb**2)
|
|
872
|
+
n = _over(self.a, _sqrt0(t)) # prime vertical
|
|
800
873
|
x = (h + n) * ca * cb
|
|
801
|
-
y = (h + n * self.
|
|
802
|
-
z = (h + n * self.
|
|
874
|
+
y = (h + n * self._b2_a2) * ca_x_sb
|
|
875
|
+
z = (h + n * self._c2_a2) * sa
|
|
803
876
|
return Vector3Tuple(x, y, z, **name)
|
|
804
877
|
|
|
805
878
|
def _Height(self, height):
|
|
@@ -808,8 +881,8 @@ class Triaxial(Triaxial_):
|
|
|
808
881
|
return Height_(height=height, low=-self.c, Error=TriaxialError)
|
|
809
882
|
|
|
810
883
|
@Property_RO
|
|
811
|
-
def
|
|
812
|
-
'''(INTERNAL) Get C{k2} and C{kp2} for C{._xE}, C{._yE} and C{.area}.
|
|
884
|
+
def _k2E_kp2E(self):
|
|
885
|
+
'''(INTERNAL) Get elliptic C{k2} and C{kp2} for C{._xE}, C{._yE} and C{.area}.
|
|
813
886
|
'''
|
|
814
887
|
# k2 = a2b2 / a2c2 * c2_b2
|
|
815
888
|
# kp2 = b2c2 / a2c2 * a2_b2
|
|
@@ -817,8 +890,9 @@ class Triaxial(Triaxial_):
|
|
|
817
890
|
# xE = Elliptic(k2, -a2b2 / b2, kp2, a2_b2)
|
|
818
891
|
# yE = Elliptic(kp2, +b2c2 / b2, k2, c2_b2)
|
|
819
892
|
# aE = Elliptic(kp2, 0, k2, 1)
|
|
820
|
-
|
|
821
|
-
|
|
893
|
+
k2 = self._c2_b2 * self._a2b2_a2c2
|
|
894
|
+
kp2 = (self._a2_b2 * self._b2c2 / self._a2c2) if k2 else _1_0
|
|
895
|
+
return (k2, kp2)
|
|
822
896
|
|
|
823
897
|
def _radialTo3(self, sbeta, cbeta, somega, comega):
|
|
824
898
|
'''(INTERNAL) Convert I{ellipsoidal} lat- and longitude C{beta} and
|
|
@@ -828,8 +902,8 @@ class Triaxial(Triaxial_):
|
|
|
828
902
|
sa, ca = self._norm2(sbeta, cbeta)
|
|
829
903
|
sb, cb = self._norm2(somega, comega)
|
|
830
904
|
|
|
831
|
-
b2_a2 = self.
|
|
832
|
-
c2_a2 = -self.
|
|
905
|
+
b2_a2 = self._b2_a2 # == (b/a)**2
|
|
906
|
+
c2_a2 = -self._c2_a2 # == -(c/a)**2
|
|
833
907
|
a2c2_a2 = self. e2ac # (a**2 - c**2) / a**2 == 1 - (c/a)**2
|
|
834
908
|
|
|
835
909
|
x2 = _Fsumf_(_1_0, -b2_a2 * sa**2, c2_a2 * ca**2).fover(a2c2_a2)
|
|
@@ -847,34 +921,34 @@ class Triaxial(Triaxial_):
|
|
|
847
921
|
|
|
848
922
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
849
923
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
850
|
-
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}}
|
|
924
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} is C{scalar},
|
|
851
925
|
ignored otherwise.
|
|
852
926
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
853
927
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
854
928
|
|
|
855
929
|
@return: A L{BetaOmega3Tuple}C{(beta, omega, height)} with C{beta} and
|
|
856
930
|
C{omega} in L{Radians} and (radial) C{height} in C{meter}, same
|
|
857
|
-
units as this triaxial's axes.
|
|
931
|
+
units as this triaxial's semi-axes.
|
|
858
932
|
|
|
859
933
|
@see: Methods L{Triaxial.forwardBetaOmega} and L{Triaxial.forwardBetaOmega_}
|
|
860
934
|
and U{expressions (21-22)<https://www.Topo.Auth.GR/wp-content/uploads/
|
|
861
935
|
sites/111/2021/12/09_Panou.pdf>}.
|
|
862
936
|
'''
|
|
863
937
|
v = _otherV3d_(x_xyz, y, z)
|
|
864
|
-
a, b, h =
|
|
938
|
+
a, b, h = _reverseLatLon3(v, atan2, v, self.forwardBetaOmega_)
|
|
865
939
|
return BetaOmega3Tuple(Radians(beta=a), Radians(omega=b), h, **name)
|
|
866
940
|
|
|
867
941
|
def reverseCartesian(self, x_xyz, y=None, z=None, h=0, normal=True, eps=_EPS2e4, **name):
|
|
868
|
-
'''Unproject" a cartesian I{on} this triaxial's surface to a cartesion I{off}
|
|
942
|
+
'''"Unproject" a cartesian I{on} this triaxial's surface to a cartesion I{off}
|
|
869
943
|
this triaxial's surface.
|
|
870
944
|
|
|
871
945
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
872
946
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
873
|
-
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}}
|
|
947
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} is C{scalar},
|
|
874
948
|
ignored otherwise.
|
|
875
949
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
876
950
|
@arg h: Height above or below this triaxial's surface (C{meter}, same units
|
|
877
|
-
as this triaxial's axes).
|
|
951
|
+
as this triaxial's semi-axes).
|
|
878
952
|
@kwarg normal: If C{True}, the height is C{normal} to the surface, otherwise
|
|
879
953
|
C{radially} to the center of this triaxial (C{bool}).
|
|
880
954
|
@kwarg eps: Tolerance for on-surface test (C{scalar}), see method L{Triaxial.sideOf}.
|
|
@@ -904,40 +978,30 @@ class Triaxial(Triaxial_):
|
|
|
904
978
|
|
|
905
979
|
@arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
|
|
906
980
|
L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
|
|
907
|
-
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}}
|
|
981
|
+
@kwarg y: Y component (C{scalar}), required if B{C{x_xyz}} is C{scalar},
|
|
908
982
|
ignored otherwise.
|
|
909
983
|
@kwarg z: Z component (C{scalar}), like B{C{y}}.
|
|
910
984
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
911
985
|
|
|
912
986
|
@return: A L{LatLon3Tuple}C{(lat, lon, height)} with C{lat} and C{lon}
|
|
913
987
|
in C{degrees} and (radial) C{height} in C{meter}, same units
|
|
914
|
-
as this triaxial's axes.
|
|
988
|
+
as this triaxial's semi-axes.
|
|
915
989
|
|
|
916
990
|
@see: Methods L{Triaxial.forwardLatLon} and L{Triaxial.forwardLatLon_}
|
|
917
991
|
and U{expressions (4-5)<https://www.Topo.Auth.GR/wp-content/uploads/
|
|
918
992
|
sites/111/2021/12/09_Panou.pdf>}.
|
|
919
993
|
'''
|
|
920
994
|
v = _otherV3d_(x_xyz, y, z)
|
|
921
|
-
s = v.times_(self.
|
|
922
|
-
self.
|
|
995
|
+
s = v.times_(self._c2_a2, # == 1 - e_sub_x**2
|
|
996
|
+
self._c2_b2, # == 1 - e_sub_y**2
|
|
923
997
|
_1_0)
|
|
924
|
-
a, b, h =
|
|
998
|
+
a, b, h = _reverseLatLon3(s, atan2d, v, self.forwardLatLon_)
|
|
925
999
|
return LatLon3Tuple(Degrees(lat=a), Degrees(lon=b), h, **name)
|
|
926
1000
|
|
|
927
|
-
def _reverseLatLon3(self, s, atan2_, v, forward_):
|
|
928
|
-
'''(INTERNAL) Helper for C{.reverseBetOmg} and C{.reverseLatLon}.
|
|
929
|
-
'''
|
|
930
|
-
x, y, z = s.xyz3
|
|
931
|
-
d = hypot( x, y)
|
|
932
|
-
a = atan2_(z, d)
|
|
933
|
-
b = atan2_(y, x)
|
|
934
|
-
h = v.minus_(*forward_(z, d, y, x)).length
|
|
935
|
-
return a, b, h
|
|
936
|
-
|
|
937
1001
|
|
|
938
|
-
class
|
|
939
|
-
'''This is a
|
|
940
|
-
C{X} and C{Y} grid lines are straight.
|
|
1002
|
+
class ConformalTriaxial(Triaxial):
|
|
1003
|
+
'''This is a I{Jacobi Conformal} projection of a triaxial ellipsoid to a plane
|
|
1004
|
+
where the C{X} and C{Y} grid lines are straight.
|
|
941
1005
|
|
|
942
1006
|
Ellipsoidal coordinates I{beta} and I{omega} are converted to Jacobi Conformal
|
|
943
1007
|
I{y} respectively I{x} separately. Jacobi's coordinates have been multiplied
|
|
@@ -948,7 +1012,7 @@ class JacobiConformal(Triaxial):
|
|
|
948
1012
|
licensed under the MIT/X11 License.
|
|
949
1013
|
|
|
950
1014
|
@note: This constructor can I{not be used to specify a sphere}, see alternate
|
|
951
|
-
L{
|
|
1015
|
+
L{ConformalSphere}.
|
|
952
1016
|
|
|
953
1017
|
@see: L{Triaxial}, C++ class U{JacobiConformal<https://GeographicLib.SourceForge.io/
|
|
954
1018
|
C++/doc/classGeographicLib_1_1JacobiConformal.html#details>}, U{Jacobi's conformal
|
|
@@ -961,12 +1025,12 @@ class JacobiConformal(Triaxial):
|
|
|
961
1025
|
def _xE(self):
|
|
962
1026
|
'''(INTERNAL) Get the x-elliptic function.
|
|
963
1027
|
'''
|
|
964
|
-
k2, kp2 = self.
|
|
1028
|
+
k2, kp2 = self._k2E_kp2E
|
|
965
1029
|
# -a2b2 / b2 == (b2 - a2) / b2 == 1 - a2 / b2 == 1 - a2_b2
|
|
966
1030
|
return self._Elliptic(k2, _1_0 - self._a2_b2, kp2, self._a2_b2)
|
|
967
1031
|
|
|
968
1032
|
def xR(self, omega):
|
|
969
|
-
'''Compute a Jacobi Conformal C{x} projection.
|
|
1033
|
+
'''Compute a I{Jacobi Conformal} C{x} projection.
|
|
970
1034
|
|
|
971
1035
|
@arg omega: Ellipsoidal longitude (C{radians} or L{Degrees}).
|
|
972
1036
|
|
|
@@ -975,7 +1039,7 @@ class JacobiConformal(Triaxial):
|
|
|
975
1039
|
return self.xR_(*SinCos2(omega))
|
|
976
1040
|
|
|
977
1041
|
def xR_(self, somega, comega):
|
|
978
|
-
'''Compute a Jacobi Conformal C{x} projection.
|
|
1042
|
+
'''Compute a I{Jacobi Conformal} C{x} projection.
|
|
979
1043
|
|
|
980
1044
|
@arg somega: Ellipsoidal longitude C{sin(omega)} (C{scalar}).
|
|
981
1045
|
@arg comega: Ellipsoidal longitude C{cos(omega)} (C{scalar}).
|
|
@@ -987,26 +1051,26 @@ class JacobiConformal(Triaxial):
|
|
|
987
1051
|
|
|
988
1052
|
@Property_RO
|
|
989
1053
|
def xyQ2(self):
|
|
990
|
-
'''Get the Jacobi Conformal quadrant size (L{
|
|
1054
|
+
'''Get the I{Jacobi Conformal} quadrant size (L{Conformal2Tuple}C{(x, y)}).
|
|
991
1055
|
'''
|
|
992
|
-
return
|
|
993
|
-
|
|
994
|
-
|
|
1056
|
+
return Conformal2Tuple(Radians(x=self._a2_b2 * self._xE.cPi),
|
|
1057
|
+
Radians(y=self._c2_b2 * self._yE.cPi),
|
|
1058
|
+
name=ConformalTriaxial.xyQ2.name)
|
|
995
1059
|
|
|
996
1060
|
def xyR2(self, beta, omega, **name):
|
|
997
|
-
'''Compute a Jacobi Conformal C{x} and C{y} projection.
|
|
1061
|
+
'''Compute a I{Jacobi Conformal} C{x} and C{y} projection.
|
|
998
1062
|
|
|
999
1063
|
@arg beta: Ellipsoidal latitude (C{radians} or L{Degrees}).
|
|
1000
1064
|
@arg omega: Ellipsoidal longitude (C{radians} or L{Degrees}).
|
|
1001
1065
|
@kwarg name: Optional name (C{str}), overriding C{B{name}="xyR2"}.
|
|
1002
1066
|
|
|
1003
|
-
@return: A L{
|
|
1067
|
+
@return: A L{Conformal2Tuple}C{(x, y)}.
|
|
1004
1068
|
'''
|
|
1005
1069
|
return self.xyR2_(*(SinCos2(beta) + SinCos2(omega)),
|
|
1006
1070
|
name=_name__(name, name__=self.xyR2))
|
|
1007
1071
|
|
|
1008
1072
|
def xyR2_(self, sbeta, cbeta, somega, comega, **name):
|
|
1009
|
-
'''Compute a Jacobi Conformal C{x} and C{y} projection.
|
|
1073
|
+
'''Compute a I{Jacobi Conformal} C{x} and C{y} projection.
|
|
1010
1074
|
|
|
1011
1075
|
@arg sbeta: Ellipsoidal latitude C{sin(beta)} (C{scalar}).
|
|
1012
1076
|
@arg cbeta: Ellipsoidal latitude C{cos(beta)} (C{scalar}).
|
|
@@ -1014,22 +1078,22 @@ class JacobiConformal(Triaxial):
|
|
|
1014
1078
|
@arg comega: Ellipsoidal longitude C{cos(omega)} (C{scalar}).
|
|
1015
1079
|
@kwarg name: Optional name (C{str}), overriding C{B{name}="xyR2_"}.
|
|
1016
1080
|
|
|
1017
|
-
@return: A L{
|
|
1081
|
+
@return: A L{Conformal2Tuple}C{(x, y)}.
|
|
1018
1082
|
'''
|
|
1019
|
-
return
|
|
1020
|
-
|
|
1021
|
-
|
|
1083
|
+
return Conformal2Tuple(self.xR_(somega, comega),
|
|
1084
|
+
self.yR_(sbeta, cbeta),
|
|
1085
|
+
name=_name__(name, name__=self.xyR2_))
|
|
1022
1086
|
|
|
1023
1087
|
@Property_RO
|
|
1024
1088
|
def _yE(self):
|
|
1025
|
-
'''(INTERNAL) Get the
|
|
1089
|
+
'''(INTERNAL) Get the y-elliptic function.
|
|
1026
1090
|
'''
|
|
1027
|
-
kp2, k2 = self.
|
|
1091
|
+
kp2, k2 = self._k2E_kp2E # swapped!
|
|
1028
1092
|
# b2c2 / b2 == (b2 - c2) / b2 == 1 - c2 / b2 == e2bc
|
|
1029
1093
|
return self._Elliptic(k2, self.e2bc, kp2, self._c2_b2)
|
|
1030
1094
|
|
|
1031
1095
|
def yR(self, beta):
|
|
1032
|
-
'''Compute a Jacobi Conformal C{y} projection.
|
|
1096
|
+
'''Compute a I{Jacobi Conformal} C{y} projection.
|
|
1033
1097
|
|
|
1034
1098
|
@arg beta: Ellipsoidal latitude (C{radians} or L{Degrees}).
|
|
1035
1099
|
|
|
@@ -1038,7 +1102,7 @@ class JacobiConformal(Triaxial):
|
|
|
1038
1102
|
return self.yR_(*SinCos2(beta))
|
|
1039
1103
|
|
|
1040
1104
|
def yR_(self, sbeta, cbeta):
|
|
1041
|
-
'''Compute a Jacobi Conformal C{y} projection.
|
|
1105
|
+
'''Compute a I{Jacobi Conformal} C{y} projection.
|
|
1042
1106
|
|
|
1043
1107
|
@arg sbeta: Ellipsoidal latitude C{sin(beta)} (C{scalar}).
|
|
1044
1108
|
@arg cbeta: Ellipsoidal latitude C{cos(beta)} (C{scalar}).
|
|
@@ -1049,19 +1113,19 @@ class JacobiConformal(Triaxial):
|
|
|
1049
1113
|
return Radians(y=self._yE.fPi(s, c) * self._c2_b2)
|
|
1050
1114
|
|
|
1051
1115
|
|
|
1052
|
-
class
|
|
1053
|
-
'''An alternate, I{spherical
|
|
1116
|
+
class ConformalSphere(ConformalTriaxial):
|
|
1117
|
+
'''An alternate, I{spherical Jacobi Conformal} projection.
|
|
1054
1118
|
|
|
1055
|
-
@see: L{
|
|
1119
|
+
@see: L{ConformalTriaxial} for other and more details.
|
|
1056
1120
|
'''
|
|
1057
1121
|
_ab = _bc = 0
|
|
1058
1122
|
|
|
1059
1123
|
def __init__(self, radius_triaxial, ab=0, bc=0, **name):
|
|
1060
|
-
'''New L{
|
|
1124
|
+
'''New L{ConformalSphere}.
|
|
1061
1125
|
|
|
1062
1126
|
@arg radius_triaxial: Radius (C{scalar}, conventionally in
|
|
1063
|
-
C{meter}) or an other L{
|
|
1064
|
-
L{
|
|
1127
|
+
C{meter}) or an other L{ConformalSphere},
|
|
1128
|
+
L{ConformalTriaxial} or ordered L{Triaxial}.
|
|
1065
1129
|
@kwarg ab: Relative magnitude of C{B{a} - B{b}} (C{meter},
|
|
1066
1130
|
same units as C{scalar B{radius}}.
|
|
1067
1131
|
@kwarg bc: Relative magnitude of C{B{b} - B{c}} (C{meter},
|
|
@@ -1072,7 +1136,7 @@ class JacobiConformalSpherical(JacobiConformal):
|
|
|
1072
1136
|
B{C{ab}}, negative B{C{bc}} or C{(B{ab}
|
|
1073
1137
|
+ B{bc})} not positive.
|
|
1074
1138
|
|
|
1075
|
-
@note: If B{C{radius_triaxial}} is a L{
|
|
1139
|
+
@note: If B{C{radius_triaxial}} is a L{ConformalSphere}
|
|
1076
1140
|
and if B{C{ab}} and B{C{bc}} are both zero or C{None},
|
|
1077
1141
|
the B{C{radius_triaxial}}'s C{ab}, C{bc}, C{a}, C{b}
|
|
1078
1142
|
and C{c} are copied.
|
|
@@ -1081,17 +1145,17 @@ class JacobiConformalSpherical(JacobiConformal):
|
|
|
1081
1145
|
r = radius_triaxial
|
|
1082
1146
|
if isinstance(r, Triaxial): # ordered only
|
|
1083
1147
|
t = r._abc3
|
|
1084
|
-
j = isinstance(r,
|
|
1148
|
+
j = isinstance(r, ConformalSphere) and not bool(ab or bc)
|
|
1085
1149
|
else:
|
|
1086
|
-
t = (
|
|
1150
|
+
t = (Radius_(radius=r),) * 3
|
|
1087
1151
|
j = False
|
|
1088
1152
|
self._ab = r.ab if j else Scalar_(ab=ab) # low=0
|
|
1089
1153
|
self._bc = r.bc if j else Scalar_(bc=bc) # low=0
|
|
1090
1154
|
if (self.ab + self.bc) <= 0:
|
|
1091
1155
|
raise ValueError(_negative_)
|
|
1092
|
-
a, _,
|
|
1093
|
-
if not (a >= c and
|
|
1094
|
-
and
|
|
1156
|
+
a, _, c = self._abc3 = t
|
|
1157
|
+
if not (a >= c and _isfinite(self._a2b2)
|
|
1158
|
+
and _isfinite(self._a2c2)):
|
|
1095
1159
|
raise ValueError(_not_(_finite_))
|
|
1096
1160
|
except (TypeError, ValueError) as x:
|
|
1097
1161
|
raise TriaxialError(radius_triaxial=r, ab=ab, bc=bc, cause=x)
|
|
@@ -1205,16 +1269,16 @@ def _hartzell3(pov, los, Tun): # in .Ellipsoid.hartzell4, .formy.hartzell
|
|
|
1205
1269
|
|
|
1206
1270
|
a, b, c, T = Tun._ordered4
|
|
1207
1271
|
|
|
1208
|
-
a2 =
|
|
1209
|
-
b2, p2 = (
|
|
1210
|
-
c2, q2 = (
|
|
1272
|
+
a2 = T.a2 # largest, factored out
|
|
1273
|
+
b2, p2 = (T.b2, T._b2_a2) if b != a else (a2, _1_0)
|
|
1274
|
+
c2, q2 = (T.c2, T._c2_a2) if c != a else (a2, _1_0)
|
|
1211
1275
|
|
|
1212
1276
|
p3 = T._order3d(p3)
|
|
1213
1277
|
u3 = T._order3d(u3).unit() # unit vector, opposing signs
|
|
1214
1278
|
|
|
1215
|
-
x2, y2, z2 = p3.
|
|
1279
|
+
x2, y2, z2 = p3.x2y2z23 # p3.times_(p3).xyz3
|
|
1216
1280
|
ux, vy, wz = u3.times_(p3).xyz3
|
|
1217
|
-
u2, v2, w2 = u3.
|
|
1281
|
+
u2, v2, w2 = u3.x2y2z23 # u3.times_(u3).xyz3
|
|
1218
1282
|
|
|
1219
1283
|
t = (p2 * c2), c2, b2
|
|
1220
1284
|
m = fdot(t, u2, v2, w2) # a2 factored out
|
|
@@ -1250,8 +1314,8 @@ def hartzell4(pov, los=False, tri_biax=_WGS84, **name):
|
|
|
1250
1314
|
@kwarg los: Line-Of-Sight, I{direction} to the tri-/biaxial (L{Los}, L{Vector3d})
|
|
1251
1315
|
or C{True} for the I{normal, perpendicular, plumb} to the surface of
|
|
1252
1316
|
the tri-/biaxial or C{False} or C{None} to point to its center.
|
|
1253
|
-
@kwarg tri_biax: A triaxial (L{Triaxial}, L{Triaxial_}, L{
|
|
1254
|
-
L{
|
|
1317
|
+
@kwarg tri_biax: A triaxial (L{Triaxial}, L{Triaxial_}, L{ConformalTriaxial} or
|
|
1318
|
+
L{ConformalSphere}) or biaxial ellipsoid (L{Datum},
|
|
1255
1319
|
L{Ellipsoid}, L{Ellipsoid2}, L{a_f2Tuple}) or spherical earth
|
|
1256
1320
|
radius (C{scalar}, conventionally in C{meter}).
|
|
1257
1321
|
@kwarg name: Optional name (C{str}), overriding C{B{name}="hartzell4"}.
|
|
@@ -1292,6 +1356,13 @@ def _hypot2_1(x, y, z=0):
|
|
|
1292
1356
|
return fsumf_(_N_1_0, x*x, y*y, z*z)
|
|
1293
1357
|
|
|
1294
1358
|
|
|
1359
|
+
def _ordered(a, b, c):
|
|
1360
|
+
'''(INTERNAL) Is C{a >= b >= c > 0}?
|
|
1361
|
+
'''
|
|
1362
|
+
if not (_isfinite(a) and a >= b >= c > 0):
|
|
1363
|
+
raise TriaxialError(a=a, b=b, c=c, txt=_not_ordered_)
|
|
1364
|
+
|
|
1365
|
+
|
|
1295
1366
|
def _otherV3d_(x_xyz, y, z, **name):
|
|
1296
1367
|
'''(INTERNAL) Get a Vector3d from C{x_xyz}, C{y} and C{z}.
|
|
1297
1368
|
'''
|
|
@@ -1359,7 +1430,7 @@ def _plumbTo4(x, y, a, b, eps=EPS):
|
|
|
1359
1430
|
b, a, d, i = _plumbTo4(y, x, b, a, eps=eps)
|
|
1360
1431
|
return a, b, d, i
|
|
1361
1432
|
|
|
1362
|
-
if not (b > 0 and
|
|
1433
|
+
if not (b > 0 and _isfinite(a)):
|
|
1363
1434
|
raise _ValueError(a=a, b=b)
|
|
1364
1435
|
|
|
1365
1436
|
i = None
|
|
@@ -1379,7 +1450,7 @@ def _plumbTo4(x, y, a, b, eps=EPS):
|
|
|
1379
1450
|
else: # x == 0
|
|
1380
1451
|
if y < 0:
|
|
1381
1452
|
b = -b
|
|
1382
|
-
a = x #
|
|
1453
|
+
a = x # _copysign_0_0
|
|
1383
1454
|
d = fabs(y - b)
|
|
1384
1455
|
|
|
1385
1456
|
elif x: # y == 0
|
|
@@ -1393,11 +1464,11 @@ def _plumbTo4(x, y, a, b, eps=EPS):
|
|
|
1393
1464
|
elif x < 0:
|
|
1394
1465
|
a = -a
|
|
1395
1466
|
if d is None:
|
|
1396
|
-
b = y #
|
|
1467
|
+
b = y # _copysign_0_0
|
|
1397
1468
|
d = fabs(x - a)
|
|
1398
1469
|
|
|
1399
1470
|
else: # x == y == 0
|
|
1400
|
-
a = x #
|
|
1471
|
+
a = x # _copysign_0_0
|
|
1401
1472
|
d = b
|
|
1402
1473
|
|
|
1403
1474
|
return a, b, d, i
|
|
@@ -1415,7 +1486,7 @@ def _plumbTo5(x, y, z, Tun, eps=EPS): # in .testTriaxials
|
|
|
1415
1486
|
a, b, c, d, i = _plumbTo5(*t, eps=eps)
|
|
1416
1487
|
return T._order3(a, b, c, reverse=True) + (d, i)
|
|
1417
1488
|
|
|
1418
|
-
if not (c > 0 and
|
|
1489
|
+
if not (c > 0 and _isfinite(a)):
|
|
1419
1490
|
raise _ValueError(a=a, b=b, c=c)
|
|
1420
1491
|
|
|
1421
1492
|
if eps > 0:
|
|
@@ -1432,8 +1503,8 @@ def _plumbTo5(x, y, z, Tun, eps=EPS): # in .testTriaxials
|
|
|
1432
1503
|
w = fabs(z / c)
|
|
1433
1504
|
g = _hypot2_1(u, v, w)
|
|
1434
1505
|
if fabs(g) > EPS02:
|
|
1435
|
-
r = T.
|
|
1436
|
-
s = T.
|
|
1506
|
+
r = T._c2_a2 # (c / a)**2
|
|
1507
|
+
s = T._c2_b2 # (c / b)**2
|
|
1437
1508
|
t, i = _rootNd(_1_0 / r, _1_0 / s, u, v, w, g) # eps
|
|
1438
1509
|
a = _over(x, t * r + _1_0)
|
|
1439
1510
|
b = _over(y, t * s + _1_0)
|
|
@@ -1442,10 +1513,10 @@ def _plumbTo5(x, y, z, Tun, eps=EPS): # in .testTriaxials
|
|
|
1442
1513
|
else: # on the ellipsoid
|
|
1443
1514
|
a, b, c, d = x, y, z, _0_0
|
|
1444
1515
|
else: # x == 0
|
|
1445
|
-
a = x #
|
|
1516
|
+
a = x # = _copysign_0_0(x)
|
|
1446
1517
|
b, c, d, i = _plumbTo4(y, z, b, c, eps=eps)
|
|
1447
1518
|
elif x: # y == 0
|
|
1448
|
-
b = y #
|
|
1519
|
+
b = y # = _copysign_0_0(y)
|
|
1449
1520
|
a, c, d, i = _plumbTo4(x, z, a, c, eps=eps)
|
|
1450
1521
|
else: # x == y == 0
|
|
1451
1522
|
if z < 0:
|
|
@@ -1462,7 +1533,7 @@ def _plumbTo5(x, y, z, Tun, eps=EPS): # in .testTriaxials
|
|
|
1462
1533
|
c *= sqrt(-s)
|
|
1463
1534
|
d = hypot_(x - a, y - b, c)
|
|
1464
1535
|
else:
|
|
1465
|
-
c = z #
|
|
1536
|
+
c = z # _copysign_0_0(z)
|
|
1466
1537
|
a, b, d, i = _plumbTo4(x, y, a, b, eps=eps)
|
|
1467
1538
|
|
|
1468
1539
|
if val > 0:
|
|
@@ -1470,6 +1541,17 @@ def _plumbTo5(x, y, z, Tun, eps=EPS): # in .testTriaxials
|
|
|
1470
1541
|
return a, b, c, d, i
|
|
1471
1542
|
|
|
1472
1543
|
|
|
1544
|
+
def _reverseLatLon3(s, atan2_, v, forward_):
|
|
1545
|
+
'''(INTERNAL) Helper for C{.reverseBetaOmega} and C{.reverseLatLon}.
|
|
1546
|
+
'''
|
|
1547
|
+
x, y, z = s.xyz3
|
|
1548
|
+
d = hypot( x, y)
|
|
1549
|
+
a = atan2_(z, d)
|
|
1550
|
+
b = atan2_(y, x)
|
|
1551
|
+
h = v.minus_(*forward_(z, d, y, x)).length or INT0
|
|
1552
|
+
return a, b, h
|
|
1553
|
+
|
|
1554
|
+
|
|
1473
1555
|
def _rootNd(r, s, u, v, w, g, eps=EPS0):
|
|
1474
1556
|
'''(INTERNAL) Robust 2-D or 3-D root finder: 2-D if C{s == v == 0} else 3-D root.
|
|
1475
1557
|
|