pygeodesy 25.4.25__py2.py3-none-any.whl → 25.5.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 +8 -6
- pygeodesy/basics.py +1 -1
- pygeodesy/booleans.py +7 -7
- pygeodesy/cartesianBase.py +6 -5
- pygeodesy/ecef.py +13 -23
- pygeodesy/ecefLocals.py +186 -0
- pygeodesy/ellipsoids.py +20 -27
- pygeodesy/fmath.py +21 -6
- pygeodesy/fsums.py +2 -2
- pygeodesy/latlonBase.py +8 -5
- pygeodesy/lazily.py +46 -22
- pygeodesy/ltp.py +50 -53
- pygeodesy/ltpTuples.py +34 -35
- pygeodesy/named.py +2 -147
- pygeodesy/resections.py +73 -71
- pygeodesy/utmupsBase.py +54 -32
- pygeodesy/vector2d.py +4 -4
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/METADATA +6 -5
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/RECORD +21 -20
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/WHEEL +0 -0
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/top_level.txt +0 -0
pygeodesy/named.py
CHANGED
|
@@ -28,16 +28,14 @@ from pygeodesy.interns import MISSING, NN, _AT_, _COLON_, _COLONSPACE_, _COMMA_,
|
|
|
28
28
|
_EQUAL_, _exists_, _immutable_, _name_, _NL_, _NN_, \
|
|
29
29
|
_no_, _other_, _s_, _SPACE_, _std_, _UNDER_, _vs_
|
|
30
30
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
31
|
-
# from pygeodesy.ltp import Ltp, _toLocal, _toLtp # _MODS
|
|
32
|
-
# from pygeodesy.ltpTuples import Aer, Enu, Ned # _MODS
|
|
33
31
|
from pygeodesy.props import _allPropertiesOf_n, deprecated_method, _hasProperty, \
|
|
34
32
|
_update_all, property_doc_, Property_RO, property_RO, \
|
|
35
|
-
_update_attrs
|
|
33
|
+
_update_attrs
|
|
36
34
|
from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
|
|
37
35
|
# from pygeodesy.units import _toUnit # _MODS
|
|
38
36
|
|
|
39
37
|
__all__ = _ALL_LAZY.named
|
|
40
|
-
__version__ = '25.04.
|
|
38
|
+
__version__ = '25.04.28'
|
|
41
39
|
|
|
42
40
|
_COMMANL_ = _COMMA_ + _NL_
|
|
43
41
|
_COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
|
|
@@ -915,148 +913,6 @@ class _NamedEnumItem(_NamedBase):
|
|
|
915
913
|
raise _AssertionError(t)
|
|
916
914
|
|
|
917
915
|
|
|
918
|
-
class _NamedLocal(object):
|
|
919
|
-
'''(INTERNAL) Base class for C{CartesianBase}, C{Ecef9Tuple} and C{LatLonBase}.
|
|
920
|
-
'''
|
|
921
|
-
|
|
922
|
-
@property_ROver
|
|
923
|
-
def Ecef(self):
|
|
924
|
-
'''Get the ECEF I{class} (L{EcefKarney}), I{once}.
|
|
925
|
-
'''
|
|
926
|
-
return _MODS.ecef.EcefKarney
|
|
927
|
-
|
|
928
|
-
@property_RO
|
|
929
|
-
def _ecef9(self):
|
|
930
|
-
'''I{Must be overloaded}.'''
|
|
931
|
-
notOverloaded(self)
|
|
932
|
-
|
|
933
|
-
@Property_RO
|
|
934
|
-
def _Ltp(self):
|
|
935
|
-
'''(INTERNAL) Cache this instance' LTP (L{Ltp}).
|
|
936
|
-
'''
|
|
937
|
-
return self._ltp.Ltp(self._ecef9, ecef=self.Ecef(self.datum), name=self.name)
|
|
938
|
-
|
|
939
|
-
@property_ROver
|
|
940
|
-
def _ltp(self):
|
|
941
|
-
'''(INTERNAL) Get module L{pygeodesy.ltp}, I{once}.
|
|
942
|
-
'''
|
|
943
|
-
return _MODS.ltp
|
|
944
|
-
|
|
945
|
-
def _ltp_toLocal(self, ltp, Xyz_kwds, **Xyz): # overloaded in C{Ecef9Tuple}
|
|
946
|
-
'''(INTERNAL) Invoke C{ltp._toLocal}.
|
|
947
|
-
'''
|
|
948
|
-
Xyz_ = self._ltp_toLocal2(Xyz_kwds, **Xyz)
|
|
949
|
-
return self._ltp._toLocal(self, ltp, *Xyz_) # self._ecef9
|
|
950
|
-
|
|
951
|
-
def _ltp_toLocal2(self, Xyz_kwds, _None=None, **Xyz):
|
|
952
|
-
'''(INTERNAL) Return 2-tuple C{(Xyz_Class, Xyz_kwds)}.
|
|
953
|
-
'''
|
|
954
|
-
C, _ = Xyz_ = _xkwds_pop2(Xyz_kwds, **Xyz)
|
|
955
|
-
if C is not _None: # validate C
|
|
956
|
-
n, X = _xkwds_item2(Xyz)
|
|
957
|
-
if X is not C:
|
|
958
|
-
_xsubclassof(X, **{n: C})
|
|
959
|
-
return Xyz_
|
|
960
|
-
|
|
961
|
-
@property_ROver
|
|
962
|
-
def _ltpTuples(self):
|
|
963
|
-
'''(INTERNAL) Get module L{pygeodesy.ltpTuples}, I{once}.
|
|
964
|
-
'''
|
|
965
|
-
return _MODS.ltpTuples
|
|
966
|
-
|
|
967
|
-
def toAer(self, ltp=None, **Aer_and_kwds):
|
|
968
|
-
'''Convert this instance to I{local} I{Azimuth, Elevation, slant Range} (AER) components.
|
|
969
|
-
|
|
970
|
-
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
971
|
-
instance' L{LTP<pygeodesy.named._NamedLocal.toLtp>}.
|
|
972
|
-
@kwarg Aer_and_kwds: Optional AER class C{B{Aer}=}L{Aer<pygeodesy.ltpTuples.Aer>}
|
|
973
|
-
to use and optionally, additional B{C{Aer}} keyword arguments.
|
|
974
|
-
|
|
975
|
-
@return: An B{C{Aer}} instance.
|
|
976
|
-
|
|
977
|
-
@raise TypeError: Invalid B{C{ltp}}.
|
|
978
|
-
|
|
979
|
-
@see: Method L{toLocal<pygeodesy.named._NamedLocal.toLocal>}.
|
|
980
|
-
'''
|
|
981
|
-
return self._ltp_toLocal(ltp, Aer_and_kwds, Aer=self._ltpTuples.Aer)
|
|
982
|
-
|
|
983
|
-
def toEnu(self, ltp=None, **Enu_and_kwds):
|
|
984
|
-
'''Convert this instance to I{local} I{East, North, Up} (ENU) components.
|
|
985
|
-
|
|
986
|
-
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
987
|
-
instance' L{LTP<pygeodesy.named._NamedLocal.toLtp>}.
|
|
988
|
-
@kwarg Enu_and_kwds: Optional ENU class C{B{Enu}=}L{Enu<pygeodesy.ltpTuples.Enu>}
|
|
989
|
-
to use and optionally, additional B{C{Enu}} keyword arguments.
|
|
990
|
-
|
|
991
|
-
@return: An B{C{Enu}} instance.
|
|
992
|
-
|
|
993
|
-
@raise TypeError: Invalid B{C{ltp}}.
|
|
994
|
-
|
|
995
|
-
@see: Method L{toLocal<pygeodesy.named._NamedLocal.toLocal>}.
|
|
996
|
-
'''
|
|
997
|
-
return self._ltp_toLocal(ltp, Enu_and_kwds, Enu=self._ltpTuples.Enu)
|
|
998
|
-
|
|
999
|
-
def toLocal(self, Xyz=None, ltp=None, **Xyz_kwds):
|
|
1000
|
-
'''Convert this instance to I{local} components in a I{local tangent plane} (LTP)
|
|
1001
|
-
|
|
1002
|
-
@kwarg Xyz: Optional I{local} components class (L{XyzLocal}, L{Aer},
|
|
1003
|
-
L{Enu}, L{Ned}) or C{None}.
|
|
1004
|
-
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
1005
|
-
cartesian's L{LTP<pygeodesy.named._NamedLocal.toLtp>}.
|
|
1006
|
-
@kwarg Xyz_kwds: Optionally, additional B{C{Xyz}} keyword arguments, ignored
|
|
1007
|
-
if C{B{Xyz} is None}.
|
|
1008
|
-
|
|
1009
|
-
@return: An B{C{Xyz}} instance or a L{Local9Tuple}C{(x, y, z, lat, lon,
|
|
1010
|
-
height, ltp, ecef, M)} if C{B{Xyz} is None} (with C{M=None}).
|
|
1011
|
-
|
|
1012
|
-
@raise TypeError: Invalid B{C{ltp}}.
|
|
1013
|
-
'''
|
|
1014
|
-
return self._ltp_toLocal(ltp, Xyz_kwds, Xyz=Xyz, _None=Xyz)
|
|
1015
|
-
|
|
1016
|
-
def toLtp(self, Ecef=None, **name):
|
|
1017
|
-
'''Return the I{local tangent plane} (LTP) for this instance.
|
|
1018
|
-
|
|
1019
|
-
@kwarg Ecef: Optional ECEF I{class} (L{EcefKarney}, ... L{EcefYou}), overriding
|
|
1020
|
-
this instance' L{Ecef<pygeodesy.named._NamedLocal.Ecef>}.
|
|
1021
|
-
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
1022
|
-
|
|
1023
|
-
@return: An B{C{Ltp}} instance.
|
|
1024
|
-
'''
|
|
1025
|
-
return self._ltp._toLtp(self, Ecef, self._ecef9, name) # needs self.Ecef and self._Ltp
|
|
1026
|
-
|
|
1027
|
-
def toNed(self, ltp=None, **Ned_and_kwds):
|
|
1028
|
-
'''Convert this instance to I{local} I{North, East, Down} (NED) components.
|
|
1029
|
-
|
|
1030
|
-
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
1031
|
-
instance' L{LTP<pygeodesy.named._NamedLocal.toLtp>}.
|
|
1032
|
-
@kwarg Ned_and_kwds: Optional NED class C{B{Ned}=}L{Ned<pygeodesy.ltpTuples.Ned>}
|
|
1033
|
-
to use and optionally, additional B{C{Ned}} keyword arguments.
|
|
1034
|
-
|
|
1035
|
-
@return: An B{C{Ned}} instance.
|
|
1036
|
-
|
|
1037
|
-
@raise TypeError: Invalid B{C{ltp}}.
|
|
1038
|
-
|
|
1039
|
-
@see: Method L{toLocal<pygeodesy.named._NamedLocal.toLocal>}.
|
|
1040
|
-
'''
|
|
1041
|
-
return self._ltp_toLocal(ltp, Ned_and_kwds, Ned=self._ltpTuples.Ned)
|
|
1042
|
-
|
|
1043
|
-
def toXyz(self, ltp=None, **Xyz_and_kwds):
|
|
1044
|
-
'''Convert this instance to I{local} I{X, Y, Z} (XYZ) components.
|
|
1045
|
-
|
|
1046
|
-
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
1047
|
-
instance' L{LTP<pygeodesy.named._NamedLocal.toLtp>}.
|
|
1048
|
-
@kwarg Xyz_and_kwds: Optional XYZ class C{B{Xyz}=}L{Xyz<pygeodesy.ltpTuples.XyzLocal>}
|
|
1049
|
-
to use and optionally, additional B{C{Xyz}} keyword arguments.
|
|
1050
|
-
|
|
1051
|
-
@return: An B{C{Xyz}} instance.
|
|
1052
|
-
|
|
1053
|
-
@raise TypeError: Invalid B{C{ltp}}.
|
|
1054
|
-
|
|
1055
|
-
@see: Method L{toLocal<pygeodesy.named._NamedLocal.toLocal>}.
|
|
1056
|
-
'''
|
|
1057
|
-
return self._ltp_toLocal(ltp, Xyz_and_kwds, Xyz=self._ltpTuples.XyzLocal)
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
916
|
# from pygeodesy.props import _NamedProperty
|
|
1061
917
|
|
|
1062
918
|
|
|
@@ -1611,7 +1467,6 @@ def _xvalid(name, underOK=False):
|
|
|
1611
1467
|
__all__ += _ALL_DOCS(_Named,
|
|
1612
1468
|
_NamedBase, # _NamedDict,
|
|
1613
1469
|
_NamedEnum, _NamedEnumItem,
|
|
1614
|
-
_NamedLocal,
|
|
1615
1470
|
_NamedTuple)
|
|
1616
1471
|
|
|
1617
1472
|
# **) MIT License
|
pygeodesy/resections.py
CHANGED
|
@@ -18,12 +18,11 @@ from pygeodesy.constants import EPS, EPS0, EPS02, INT0, PI, PI2, PI_2, PI_4, \
|
|
|
18
18
|
_16_0, _180_0, _360_0, isnear0, _over, _umod_360
|
|
19
19
|
from pygeodesy.errors import _and, _or, TriangleError, _ValueError, _xcallable, \
|
|
20
20
|
_xkwds, _xkwds_pop2
|
|
21
|
-
from pygeodesy.fmath import favg, Fdot, fidw, fmean, hypot, hypot2_
|
|
21
|
+
from pygeodesy.fmath import favg, Fdot, Fdot_, fidw, _fma, fmean, hypot, hypot2_
|
|
22
22
|
from pygeodesy.fsums import _Fsumf_, fsumf_, fsum1, fsum1f_
|
|
23
23
|
# from pygeodesy.internals import typename # from .basics
|
|
24
24
|
from pygeodesy.interns import _a_, _A_, _area_, _b_, _B_, _c_, _C_, _coincident_, \
|
|
25
|
-
_colinear_, _d_, _invalid_, _negative_,
|
|
26
|
-
_rIn_, _SPACE_
|
|
25
|
+
_colinear_, _d_, _invalid_, _negative_, _rIn_, _SPACE_
|
|
27
26
|
# from pygeodesy.lazily import _ALL_LAZY # from .basics
|
|
28
27
|
from pygeodesy.named import _NamedTuple, _Pass, Fmt
|
|
29
28
|
# from pygeodesy.streprs import Fmt # from .named
|
|
@@ -35,7 +34,7 @@ from pygeodesy.vector3d import _otherV3d, Vector3d
|
|
|
35
34
|
from math import cos, degrees, fabs, radians, sin, sqrt
|
|
36
35
|
|
|
37
36
|
__all__ = _ALL_LAZY.resections
|
|
38
|
-
__version__ = '25.04
|
|
37
|
+
__version__ = '25.05.04'
|
|
39
38
|
|
|
40
39
|
_concyclic_ = 'concyclic'
|
|
41
40
|
_PA_ = 'PA'
|
|
@@ -43,7 +42,6 @@ _PB_ = 'PB'
|
|
|
43
42
|
_PC_ = 'PC'
|
|
44
43
|
_pointH_ = 'pointH'
|
|
45
44
|
_pointP_ = 'pointP'
|
|
46
|
-
_positive_ = 'positive'
|
|
47
45
|
_radA_ = 'radA'
|
|
48
46
|
_radB_ = 'radB'
|
|
49
47
|
_radC_ = 'radC'
|
|
@@ -170,11 +168,9 @@ def cassini(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
|
|
|
170
168
|
|
|
171
169
|
A, B, C = _ABC3(useZ, pointA, pointB, pointC)
|
|
172
170
|
try:
|
|
173
|
-
sa, sb =
|
|
174
|
-
if min(sa, sb) < 0:
|
|
175
|
-
raise ValueError(_negative_)
|
|
171
|
+
sa, sb = _noneg(alpha, beta)
|
|
176
172
|
if fsumf_(_360_0, -sa, -sb) < EPS0:
|
|
177
|
-
raise ValueError()
|
|
173
|
+
raise ValueError(_colinear_)
|
|
178
174
|
|
|
179
175
|
x1, y1 = _H(A, C, sa)
|
|
180
176
|
x2, y2 = _H(B, C, -sb)
|
|
@@ -253,15 +249,15 @@ def collins5(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
|
|
|
253
249
|
|
|
254
250
|
def _xyz(d, r, A, B, C, useZ):
|
|
255
251
|
s, c = sincos2(r)
|
|
256
|
-
x =
|
|
257
|
-
y =
|
|
252
|
+
x = _fma(d, s, A.x)
|
|
253
|
+
y = _fma(d, c, A.y)
|
|
258
254
|
z = _zidw(x, y, useZ, A, B, C)
|
|
259
255
|
return x, y, z
|
|
260
256
|
|
|
261
257
|
A, B, C = _ABC3(useZ, pointA, pointB, pointC)
|
|
262
258
|
try:
|
|
263
|
-
ra, rb = radians(alpha), radians(beta)
|
|
264
|
-
if min(
|
|
259
|
+
ra, rb = t = radians(alpha), radians(beta)
|
|
260
|
+
if min(t) < 0:
|
|
265
261
|
raise ValueError(_negative_)
|
|
266
262
|
|
|
267
263
|
sra, srH = sin(ra), sin(ra + rb - PI) # rH = PI - ((PI - ra) + (PI - rb))
|
|
@@ -294,6 +290,15 @@ def collins5(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
|
|
|
294
290
|
alpha=alpha, beta=beta, cause=x)
|
|
295
291
|
|
|
296
292
|
|
|
293
|
+
def _noneg(*xs):
|
|
294
|
+
'''(INTERNAL) Return non-negative C{float}s.
|
|
295
|
+
'''
|
|
296
|
+
xs = tuple(map(float, xs))
|
|
297
|
+
if min(xs) < 0:
|
|
298
|
+
raise ValueError(_negative_)
|
|
299
|
+
return xs
|
|
300
|
+
|
|
301
|
+
|
|
297
302
|
def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
|
|
298
303
|
**Clas_and_kwds):
|
|
299
304
|
'''3-Point resection using U{Pierlot<http://www.Telecom.ULg.ac.BE/publi/publications/
|
|
@@ -342,7 +347,7 @@ def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
|
|
|
342
347
|
if eps > 0:
|
|
343
348
|
return c / (min(s, -eps) if s < 0 else max(s, eps))
|
|
344
349
|
t = Fmt.PARENSPACED(eps=eps)
|
|
345
|
-
raise ValueError(_SPACE_(t,
|
|
350
|
+
raise ValueError(_SPACE_(t, _invalid_))
|
|
346
351
|
|
|
347
352
|
B1, B2, B3 = _B3(useZ, point1, point2, point3)
|
|
348
353
|
try:
|
|
@@ -400,8 +405,8 @@ def _pierlot3(B1, B2, B3, a12, a23, useZ, _cot):
|
|
|
400
405
|
# = (x31 - x23) * (y12 - y23) - (x12 - x23) * (y31 - y23)
|
|
401
406
|
# x = (d * B2.x + K * Y12_23).fover(d)
|
|
402
407
|
# y = (d * B2.y - K * X12_23).fover(d)
|
|
403
|
-
x, y = _pierlotxy2(B2, -K, Y12_23, X12_23, (X31_23
|
|
404
|
-
|
|
408
|
+
x, y = _pierlotxy2(B2, -K, Y12_23, X12_23, Fdot_(X31_23, Y12_23,
|
|
409
|
+
-X12_23, Y31_23))
|
|
405
410
|
else:
|
|
406
411
|
x, y, _ = B2.xyz3
|
|
407
412
|
return x, y, _zidw(x, y, useZ, B1, B2, B3)
|
|
@@ -492,11 +497,11 @@ def _pierlotx3(a_z_Bs, useZ, _cot, Cs):
|
|
|
492
497
|
if K:
|
|
493
498
|
cot23 = _cot(*sincos2d(a23))
|
|
494
499
|
|
|
495
|
-
# x23 = x2_ + cot23 * y2_
|
|
496
|
-
# y23 = y2_ - cot23 * x2_
|
|
500
|
+
# x23 = x2_ + cot23 * y2_ # _fma( cot23, y2_, x2_)
|
|
501
|
+
# y23 = y2_ - cot23 * x2_ # _fma(-cot23, x2_, y2_)
|
|
497
502
|
|
|
498
|
-
# x31 = x1_ + cot23 * y1_
|
|
499
|
-
# y31 = y1_ - cot23 * x1_
|
|
503
|
+
# x31 = x1_ + cot23 * y1_ # _fma( cot23, y1_, x1_)
|
|
504
|
+
# y31 = y1_ - cot23 * x1_ # _fma(-cot23, x1_, y1_)
|
|
500
505
|
|
|
501
506
|
# x31 - x23 = x1_ + cot23 * y1_ - x2_ - cot23 * y2_
|
|
502
507
|
X31_23 = _Fsumf_(x1_, cot23 * y1_, -x2_, -cot23 * y2_)
|
|
@@ -504,10 +509,10 @@ def _pierlotx3(a_z_Bs, useZ, _cot, Cs):
|
|
|
504
509
|
Y31_23 = _Fsumf_(y1_, -cot23 * x1_, -y2_, cot23 * x2_)
|
|
505
510
|
|
|
506
511
|
# d = (x31 - x23) * (x2_ - x1_) + (y31 - y23) * (y2_ - y1_)
|
|
507
|
-
# x = (
|
|
508
|
-
# y = (
|
|
509
|
-
x, y = _pierlotxy2(B3, K, Y31_23, X31_23, (X31_23
|
|
510
|
-
|
|
512
|
+
# x = (d * B3.x - K * Y31_23).fover(d)
|
|
513
|
+
# y = (d * B3.y + K * X31_23).fover(d)
|
|
514
|
+
x, y = _pierlotxy2(B3, K, Y31_23, X31_23, Fdot_(X31_23, _Fsumf_(x2_, -x1_),
|
|
515
|
+
Y31_23, _Fsumf_(y2_, -y1_)))
|
|
511
516
|
else:
|
|
512
517
|
x, y, _ = B3.xyz3
|
|
513
518
|
return x, y, _zidw(x, y, useZ, B1, B2, B3)
|
|
@@ -519,8 +524,8 @@ def _pierlotxy2(B, K, X, Y, D):
|
|
|
519
524
|
d = float(D)
|
|
520
525
|
if isnear0(d):
|
|
521
526
|
raise ValueError(_or(_coincident_, _colinear_, _concyclic_))
|
|
522
|
-
x = (D
|
|
523
|
-
y = (D
|
|
527
|
+
x = Fdot_(D, B.x, -K, X).fover(d)
|
|
528
|
+
y = Fdot_(D, B.y, K, Y).fover(d)
|
|
524
529
|
return x, y
|
|
525
530
|
|
|
526
531
|
|
|
@@ -551,9 +556,7 @@ def snellius3(a, b, degC, alpha, beta):
|
|
|
551
556
|
@see: Function L{wildberger3}.
|
|
552
557
|
'''
|
|
553
558
|
try:
|
|
554
|
-
a, b, degC, alpha, beta =
|
|
555
|
-
if min(t) < 0:
|
|
556
|
-
raise ValueError(_negative_)
|
|
559
|
+
a, b, degC, alpha, beta = _noneg(a, b, degC, alpha, beta)
|
|
557
560
|
ra, rb, rC = map1(radians, alpha, beta, degC)
|
|
558
561
|
|
|
559
562
|
r = fsum1f_(ra, rb, rC) * _0_5
|
|
@@ -705,17 +708,15 @@ def triAngle(a, b, c):
|
|
|
705
708
|
|
|
706
709
|
def _triAngle(a, b, c):
|
|
707
710
|
# (INTERNAL) To allow callers to embellish errors
|
|
708
|
-
a, b, c =
|
|
709
|
-
if
|
|
711
|
+
a, b, c = _noneg(a, b, c)
|
|
712
|
+
if b > a:
|
|
710
713
|
a, b = b, a
|
|
711
|
-
if b < 0 or c < 0:
|
|
712
|
-
raise ValueError(_negative_)
|
|
713
714
|
if a < EPS0:
|
|
714
715
|
raise ValueError(_coincident_)
|
|
715
716
|
b_a = b / a
|
|
716
717
|
if b_a < EPS0:
|
|
717
718
|
raise ValueError(_coincident_)
|
|
718
|
-
t =
|
|
719
|
+
t = _Fsumf_(_1_0, b_a**2, -(c / a)**2).fover(b_a * _2_0)
|
|
719
720
|
return acos1(t)
|
|
720
721
|
|
|
721
722
|
|
|
@@ -733,7 +734,7 @@ def triAngle5(a, b, c):
|
|
|
733
734
|
C{radA}, C{radB} and C{radC} at triangle corners C{A}, C{B}
|
|
734
735
|
and C{C}, all in C{radians}, the C{InCircle} radius C{rIn}
|
|
735
736
|
aka C{inradius}, same units as triangle sides B{C{a}},
|
|
736
|
-
B{C{b}} and B{C{c}} and the triangle C{area} in
|
|
737
|
+
B{C{b}} and B{C{c}} and the triangle C{area} in the same
|
|
737
738
|
units I{squared}.
|
|
738
739
|
|
|
739
740
|
@raise TriangleError: Invalid or negative B{C{a}}, B{C{b}} or B{C{c}}.
|
|
@@ -797,15 +798,15 @@ def triArea(a, b, c):
|
|
|
797
798
|
try:
|
|
798
799
|
r, y, x = sorted(map1(float, a, b, c))
|
|
799
800
|
if r > 0: # r = min(a, b, c)
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
r = (x + y) * (r - ab) * (r + ab) * (x + bc)
|
|
801
|
+
z = r
|
|
802
|
+
d = x - y
|
|
803
|
+
r = (z + d) * (z - d)
|
|
804
804
|
if r:
|
|
805
|
-
|
|
806
|
-
|
|
805
|
+
x += y
|
|
806
|
+
r *= (x + z) * (x - z)
|
|
807
|
+
if r < 0:
|
|
807
808
|
raise ValueError(_negative_)
|
|
808
|
-
return r
|
|
809
|
+
return sqrt(r / _16_0) if r else _0_0
|
|
809
810
|
|
|
810
811
|
except (TypeError, ValueError) as x:
|
|
811
812
|
raise TriangleError(a=a, b=b, c=c, cause=x)
|
|
@@ -837,11 +838,8 @@ def triSide(a, b, radC):
|
|
|
837
838
|
|
|
838
839
|
def _triSide(a, b, radC):
|
|
839
840
|
# (INTERNAL) To allow callers to embellish errors
|
|
840
|
-
a, b, r =
|
|
841
|
-
if
|
|
842
|
-
raise ValueError(_negative_)
|
|
843
|
-
|
|
844
|
-
if a < b:
|
|
841
|
+
a, b, r = _noneg(a, b, radC)
|
|
842
|
+
if b < a:
|
|
845
843
|
a, b = b, a
|
|
846
844
|
if a > EPS0:
|
|
847
845
|
ba = b / a
|
|
@@ -880,18 +878,21 @@ def triSide2(b, c, radB):
|
|
|
880
878
|
|
|
881
879
|
def _triSide2(b, c, radB):
|
|
882
880
|
# (INTERNAL) To allow callers to embellish errors
|
|
883
|
-
b, c, rB =
|
|
884
|
-
if min(b, c, rB) < 0:
|
|
885
|
-
raise ValueError(_negative_)
|
|
881
|
+
b, c, rB = _noneg(b, c, radB)
|
|
886
882
|
sB, cB = sincos2(rB)
|
|
887
|
-
if isnear0(sB):
|
|
888
|
-
if
|
|
883
|
+
if isnear0(b) or isnear0(sB):
|
|
884
|
+
if isnear0(b) and isnear0(sB):
|
|
885
|
+
if cB < 0:
|
|
886
|
+
rA = PI
|
|
887
|
+
a = b + c
|
|
888
|
+
else:
|
|
889
|
+
rA = _0_0
|
|
890
|
+
a = fabs(b - c)
|
|
891
|
+
else:
|
|
889
892
|
raise ValueError(_invalid_)
|
|
890
|
-
a, rA = ((b + c), PI) if cB < 0 else (fabs(b - c), _0_0)
|
|
891
|
-
elif isnear0(b):
|
|
892
|
-
raise ValueError(_invalid_)
|
|
893
893
|
else:
|
|
894
|
-
|
|
894
|
+
rC = asin1(c * sB / b)
|
|
895
|
+
rA = max(fsumf_(PI, -rB, -rC), _0_0)
|
|
895
896
|
a = sin(rA) * b / sB
|
|
896
897
|
return TriSide2Tuple(a, rA, name=typename(triSide2))
|
|
897
898
|
|
|
@@ -918,9 +919,9 @@ def triSide4(radA, radB, c):
|
|
|
918
919
|
and functions L{sqrt_a}, L{triSide} and L{triSide2}.
|
|
919
920
|
'''
|
|
920
921
|
try:
|
|
921
|
-
rA, rB, c =
|
|
922
|
+
rA, rB, c = _noneg(radA, radB, c)
|
|
922
923
|
rC = fsumf_(PI, -rA, -rB)
|
|
923
|
-
if
|
|
924
|
+
if rC < 0:
|
|
924
925
|
raise ValueError(_negative_)
|
|
925
926
|
sa, ca, sb, cb = sincos2_(rA, rB)
|
|
926
927
|
sc = fsum1f_(sa * cb, sb * ca)
|
|
@@ -965,18 +966,18 @@ def wildberger3(a, b, c, alpha, beta, R3=min):
|
|
|
965
966
|
return sin(x)**2
|
|
966
967
|
|
|
967
968
|
def _vpa(r3, q2, q3, s2, s3):
|
|
968
|
-
r1 =
|
|
969
|
-
r =
|
|
970
|
-
|
|
969
|
+
r1 = s2 * q3 / s3
|
|
970
|
+
r = r1 * r3 * _4_0
|
|
971
|
+
R = _Fsumf_(r1, r3, -q2)
|
|
972
|
+
R *= R # -(R**2 ...
|
|
973
|
+
R -= r # ... - r) / s3
|
|
974
|
+
n = -R.fover(s3)
|
|
971
975
|
if n < 0 or r < EPS0:
|
|
972
976
|
raise ValueError(_coincident_)
|
|
973
977
|
return sqrt((n / r) * q3) if n else _0_0
|
|
974
978
|
|
|
975
979
|
try:
|
|
976
|
-
a, b, c, da, db =
|
|
977
|
-
if min(q) < 0:
|
|
978
|
-
raise ValueError(_negative_)
|
|
979
|
-
|
|
980
|
+
a, b, c, da, db = _noneg(a, b, c, alpha, beta)
|
|
980
981
|
q1, q2, q3 = q = a**2, b**2, c**2
|
|
981
982
|
if min(q) < EPS02:
|
|
982
983
|
raise ValueError(_coincident_)
|
|
@@ -986,18 +987,19 @@ def wildberger3(a, b, c, alpha, beta, R3=min):
|
|
|
986
987
|
if min(s) < EPS02:
|
|
987
988
|
raise ValueError(_or(_coincident_, _colinear_))
|
|
988
989
|
|
|
989
|
-
|
|
990
|
-
Qs = _Fsumf_(*q) # == hypot2_(a, b, c)
|
|
991
|
-
d0 = (Qs**2 - q4).fmul(s1 * s2).fover(s3)
|
|
992
|
-
if d0 < 0:
|
|
993
|
-
raise ValueError(_negative_)
|
|
990
|
+
Q = _Fsumf_(*q) # == a**2 + b**2 + ...
|
|
994
991
|
s += _Fsumf_(*s), # == fsum1(s),
|
|
995
|
-
C0 = Fdot(s, q1, q2, q3, -
|
|
992
|
+
C0 = Fdot(s, q1, q2, q3, -Q * _0_5)
|
|
996
993
|
r3 = C0.fover(-s3) # C0 /= -s3
|
|
994
|
+
Q *= Q # Q**2 - 2 * (a**4 + b**4 ...
|
|
995
|
+
Q -= hypot2_(*q) *_2_0 # ... + c**4)
|
|
996
|
+
d0 = Q.fmul(s1 * s2).fover(s3)
|
|
997
997
|
if d0 > EPS02: # > c0
|
|
998
998
|
_xcallable(R3=R3)
|
|
999
999
|
d0 = sqrt(d0)
|
|
1000
1000
|
r3 = R3(float(C0 + d0), float(C0 - d0)) # XXX min or max
|
|
1001
|
+
elif d0 < (-EPS02):
|
|
1002
|
+
raise ValueError(_negative_)
|
|
1001
1003
|
|
|
1002
1004
|
pa = _vpa(r3, q2, q3, s2, s3)
|
|
1003
1005
|
pb = _vpa(r3, q1, q3, s1, s3)
|
pygeodesy/utmupsBase.py
CHANGED
|
@@ -7,8 +7,8 @@ for modules L{epsg}, L{etm}, L{mgrs}, L{ups} and L{utm}.
|
|
|
7
7
|
# make sure int/int division yields float quotient, see .basics
|
|
8
8
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
9
9
|
|
|
10
|
-
from pygeodesy.basics import _isin, isint, isscalar, isstr,
|
|
11
|
-
|
|
10
|
+
from pygeodesy.basics import _copysign, _isin, isint, isscalar, isstr, \
|
|
11
|
+
neg_, _xinstanceof, _xsubclassof
|
|
12
12
|
from pygeodesy.constants import _float, _0_0, _0_5, _N_90_0, _180_0
|
|
13
13
|
from pygeodesy.datums import _ellipsoidal_datum, _WGS84
|
|
14
14
|
from pygeodesy.dms import degDMS, parseDMS2
|
|
@@ -29,10 +29,10 @@ from pygeodesy.streprs import Fmt, fstr, _fstrENH2, _xzipairs
|
|
|
29
29
|
from pygeodesy.units import Band, Easting, Lat, Northing, Phi, Scalar, Zone
|
|
30
30
|
from pygeodesy.utily import atan1, _Wrap, wrap360
|
|
31
31
|
|
|
32
|
-
from math import cos, degrees, fabs, sin, tan
|
|
32
|
+
from math import cos, degrees, fabs, sin, tan # copysign as _copysign
|
|
33
33
|
|
|
34
34
|
__all__ = _ALL_LAZY.utmupsBase
|
|
35
|
-
__version__ = '25.04.
|
|
35
|
+
__version__ = '25.04.26'
|
|
36
36
|
|
|
37
37
|
_UPS_BANDS = _A_, _B_, _Y_, _Z_ # UPS polar bands SE, SW, NE, NW
|
|
38
38
|
# _UTM_BANDS = _MODS.utm._Bands
|
|
@@ -195,43 +195,65 @@ class UtmUpsBase(_NamedBase):
|
|
|
195
195
|
self._notOverloaded(self)
|
|
196
196
|
|
|
197
197
|
def _footpoint(self, y, lat0, makris):
|
|
198
|
-
'''(INTERNAL)
|
|
198
|
+
'''(INTERNAL) Return the foot-point latitude in C{radians}.
|
|
199
199
|
'''
|
|
200
|
+
F = _MODS.fsums.Fsum
|
|
201
|
+
E = self.datum.ellipsoid
|
|
200
202
|
if y is None:
|
|
201
203
|
_, y = self.eastingnorthing2(falsed=False)
|
|
202
|
-
|
|
203
|
-
E = self.datum.ellipsoid
|
|
204
|
-
P = S(E.Llat(lat0), y)
|
|
204
|
+
B = F(E.Llat(lat0), y)
|
|
205
205
|
if E.isSpherical:
|
|
206
|
-
|
|
206
|
+
r = B.fover(E.a) # == E.b
|
|
207
|
+
|
|
207
208
|
elif makris:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if
|
|
209
|
+
b = B.fover(E.b)
|
|
210
|
+
r = fabs(b)
|
|
211
|
+
if r:
|
|
211
212
|
e2 = E.e22 # E.e22abs?
|
|
212
213
|
e4 = E.e4
|
|
213
214
|
|
|
214
|
-
e1 =
|
|
215
|
-
e2 =
|
|
216
|
-
e4 *= cos(
|
|
217
|
-
|
|
218
|
-
s = sin(
|
|
219
|
-
|
|
220
|
-
U =
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
215
|
+
e1 = F(-1, e2 / 4, -11 / 64 * e4).as_iscalar
|
|
216
|
+
e2 = F( e2 / 8, -13 / 128 * e4).as_iscalar
|
|
217
|
+
e4 *= cos(r)**2 / 8
|
|
218
|
+
|
|
219
|
+
s = sin(r * 2)
|
|
220
|
+
r = -r
|
|
221
|
+
U = F(e1 * r, e2 * s, e4 * r, e4 / 8 * 5 * s**2)
|
|
222
|
+
r = _copysign(atan1(E.a * tan(float(U)) / E.b), b)
|
|
223
|
+
|
|
224
|
+
# elif clins: # APRIL-ZJU/clins/include/utils/gps_convert_utils.h
|
|
225
|
+
# n = E.n
|
|
226
|
+
# n2 = n**2
|
|
227
|
+
# n3 = n**3
|
|
228
|
+
# n4 = n**4
|
|
229
|
+
# n5 = n**5
|
|
230
|
+
# A = F(1, n2 / 4, n4 / 64).fmul((E.a + E.b) / 2)
|
|
231
|
+
# r = B.fover(A)
|
|
232
|
+
# R = F(r)
|
|
233
|
+
# if clins: # FootpointLatitude, GPS-Theory-Practice, 1994
|
|
234
|
+
# R += F(3 / 2 * n, -27 / 32 * n3, 269 / 512 * n5).fmul(sin(r * 2))
|
|
235
|
+
# R += F( 21 / 16 * n2, -55 / 32 * n4).fmul(sin(r * 4))
|
|
236
|
+
# R += F( 151 / 96 * n3, -417 / 128 * n5).fmul(sin(r * 6))
|
|
237
|
+
# R += (1097 / 512 * n4) * sin(r * 8)
|
|
238
|
+
# else: # GPS-Theory-Practice, 1992, page 234-235
|
|
239
|
+
# R += F(-3 / 2 * n, 9 / 16 * n3, -3 / 32 * n5).fmul(sin(r * 2))
|
|
240
|
+
# R += F( 15 / 16 * n2, -15 / 32 * n4).fmul(sin(r * 4))
|
|
241
|
+
# R += F( -35 / 48 * n3, 105 / 256 * n4).fmul(sin(r * 6)) # n5?
|
|
242
|
+
# r = float(R)
|
|
243
|
+
|
|
244
|
+
else: # PyGeodetics/src/geodetics/footpoint_latitude.py
|
|
225
245
|
f = E.f
|
|
226
246
|
f2 = f**2
|
|
227
247
|
f3 = f**3
|
|
228
|
-
B0 =
|
|
229
|
-
r =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
B0 = F(1, -f / 2, f2 / 16, f3 / 32).fmul(E.a)
|
|
249
|
+
r = B.fover(B0)
|
|
250
|
+
R = F(r)
|
|
251
|
+
R += F(3 / 4 * f, 3 / 8 * f2, 21 / 256 * f3).fmul(sin(r * 2))
|
|
252
|
+
R += F( 21 / 64 * f2, 21 / 64 * f3).fmul(sin(r * 4))
|
|
253
|
+
R += (151 / 768 * f3) * sin(r * 6)
|
|
254
|
+
r = float(R)
|
|
255
|
+
|
|
256
|
+
return r
|
|
235
257
|
|
|
236
258
|
@Property_RO
|
|
237
259
|
def gamma(self):
|
|
@@ -251,8 +273,8 @@ class UtmUpsBase(_NamedBase):
|
|
|
251
273
|
def latFootPoint(self, northing=None, lat0=0, makris=False):
|
|
252
274
|
'''Compute the foot-point latitude in C{degrees}.
|
|
253
275
|
|
|
254
|
-
@arg northing: Northing (C{meter}, same units this
|
|
255
|
-
overriding this I{unfalsed}
|
|
276
|
+
@arg northing: Northing (C{meter}, same units this ellipsoid's axes),
|
|
277
|
+
overriding this northing, I{unfalsed}.
|
|
256
278
|
@kwarg lat0: Geodetic latitude of the meridian's origin (C{degrees}).
|
|
257
279
|
@kwarg makris: If C{True}, use C{Makris}' formula, otherwise C{PyGeodetics}'.
|
|
258
280
|
|
pygeodesy/vector2d.py
CHANGED
|
@@ -16,7 +16,7 @@ from pygeodesy.constants import EPS, EPS0, EPS02, EPS4, INF, INT0, \
|
|
|
16
16
|
_1_0, _1_0_1T, _N_1_0, _2_0, _N_2_0, _4_0
|
|
17
17
|
from pygeodesy.errors import _and, _AssertionError, IntersectionError, NumPyError, \
|
|
18
18
|
PointsError, TriangleError, _xError, _xkwds
|
|
19
|
-
from pygeodesy.fmath import fabs, fdot, fdot_, hypot, hypot2_, sqrt
|
|
19
|
+
from pygeodesy.fmath import fabs, fdot, Fdot_, fdot_, hypot, hypot2_, sqrt
|
|
20
20
|
from pygeodesy.fsums import _Fsumf_, fsumf_, fsum1f_
|
|
21
21
|
# from pygeodesy.internals import typename # from .basics
|
|
22
22
|
from pygeodesy.interns import NN, _a_, _and_, _b_, _c_, _center_, _coincident_, \
|
|
@@ -36,7 +36,7 @@ from contextlib import contextmanager
|
|
|
36
36
|
# from math import fabs, sqrt # from .fmath
|
|
37
37
|
|
|
38
38
|
__all__ = _ALL_LAZY.vector2d
|
|
39
|
-
__version__ = '25.04.
|
|
39
|
+
__version__ = '25.04.30'
|
|
40
40
|
|
|
41
41
|
_cA_ = 'cA'
|
|
42
42
|
_cB_ = 'cB'
|
|
@@ -755,8 +755,8 @@ def _trilaterate2d2(x1, y1, radius1, x2, y2, radius2, x3, y3, radius3,
|
|
|
755
755
|
raise IntersectionError(_and(_astr(x1=x1, y1=y1, radius1=r1),
|
|
756
756
|
_astr(x2=x2, y2=y2, radius2=r2),
|
|
757
757
|
_astr(x3=x3, y3=y3, radius3=r3)), txt=t)
|
|
758
|
-
t = Vector2Tuple(
|
|
759
|
-
|
|
758
|
+
t = Vector2Tuple(Fdot_(c, e, -b, f).fover(q),
|
|
759
|
+
Fdot_(a, f, -c, d).fover(q), name=typename(trilaterate2d2))
|
|
760
760
|
|
|
761
761
|
if eps and eps > 0: # check distances to center vs radius
|
|
762
762
|
for x, y, r in ((x1, y1, r1), (x2, y2, r2), (x3, y3, r3)):
|