pygeodesy 25.5.25__py2.py3-none-any.whl → 25.7.25__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 CHANGED
@@ -125,7 +125,7 @@ C{epydoc --html --no-private --no-source --name=pygeodesy --url=... -v pygeodesy
125
125
  Tests
126
126
  =====
127
127
 
128
- The tests ran with Python 3.13.3 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0),
128
+ The tests ran with Python 3.13.5 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0),
129
129
  Python 3.12.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
130
130
  U{numpy<https://PyPI.org/project/numpy>} 2.1.0, U{scipy<https://PyPI.org/project/scipy>} 1.14.1,
131
131
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
@@ -150,13 +150,13 @@ env variable C{PYGEODESY_WARNINGS=on} for all Python versions. The results of t
150
150
  the distribution files.
151
151
 
152
152
  Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.1 using Python
153
- 3.13.3, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
153
+ 3.13.4, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
154
154
  the distribution files.
155
155
 
156
- Python 3.13.3, 3.12.7, 3.11.5 and 3.10.8 run on Apple M4 Si (C{arm64}), I{natively}. Python 2.7.18 runs
156
+ Python 3.13.5, 3.12.7, 3.11.5 and 3.10.8 run on Apple M4 Si (C{arm64}), I{natively}. Python 2.7.18 runs
157
157
  on Intel (C{x86_64}) or Intel I{emulation} ("C{arm64_x86_64}", see function L{machine<pygeodesy.machine>}).
158
158
 
159
- The tests also ran with Python 3.13.3 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on
159
+ The tests also ran with Python 3.13.5 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on
160
160
  U{Debian 12<https://Cirrus-CI.com/github/mrJean1/PyGeodesy/master>} in 64-bit only, with Python 3.12.8 (and
161
161
  U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Windows 2019Server
162
162
  <https://CI.AppVeyor.com/project/mrJean1/pygeodesy>} in 64-bit only and with Python 2.7.18 (and U{geographiclib
@@ -166,7 +166,7 @@ in 64- and 32-bit.
166
166
  A single-File and single-Directory application with C{pygeodesy} has been bundled using U{PyInstaller
167
167
  <https://PyPI.org/project/pyinstaller>} 3.4 and 64-bit Python 3.7.3 on macOS 10.13.6 High Sierra.
168
168
 
169
- Previously, the tests were run with Python 3.13.0-2, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
169
+ Previously, the tests were run with Python 3.13.0-4, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
170
170
  U{PyPy<https://PyPy.org>} 7.3.12 (Python 3.10.12), 7.3.1 (Python 3.6.9) and U{PyPy<https://PyPy.org>} 7.1.1 (Python
171
171
  2.7.13) (and U{geographiclib <https://PyPI.org/project/geographiclib>} 1.52, U{numpy<https://PyPI.org/project/numpy>}
172
172
  1.16.3, 1.16.4, 1.16.6, 1.19.0, 1.19.4, 1.19.5 or 1.22.4 and U{scipy<https://PyPI.org/project/scipy>} 1.2.1, 1.4.1,
@@ -187,10 +187,10 @@ Notes
187
187
  =====
188
188
 
189
189
  All Python source code has been statically U{checked<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
190
- 546532_PyChecker_postprocessor>} with U{Ruff<https://GitHub.com/astral-sh/ruff>} using Python 3.13.3 and with
190
+ 546532_PyChecker_postprocessor>} with U{Ruff<https://GitHub.com/astral-sh/ruff>} using Python 3.13.5 and with
191
191
  U{PyChecker<https://PyPI.org/project/pychecker>}, U{PyFlakes<https://PyPI.org/project/pyflakes>}, U{PyCodeStyle
192
192
  <https://PyPI.org/project/pycodestyle>} (formerly Pep8) and U{McCabe<https://PyPI.org/project/mccabe>} using Python
193
- 2.7.18, both in 64-bit on macOS 15.5 Sequoia only.
193
+ 2.7.18, both in 64-bit on macOS 15.5 Sequoia.
194
194
 
195
195
  For a summary of all I{Karney}-based functionality in C{pygeodesy}, see module U{karney
196
196
  <https://mrJean1.GitHub.io/PyGeodesy/docs/pygeodesy.karney-module.html>}.
@@ -604,7 +604,7 @@ else:
604
604
 
605
605
  from pygeodesy.internals import _version2, _DOT_ # noqa: E402
606
606
  # from pygeodesy.interns import _DOT_ # from .internals
607
- __version__ = '25.05.25'
607
+ __version__ = '25.07.25'
608
608
  # see setup.py for similar logic
609
609
  version = _DOT_(*_version2(__version__, n=3))
610
610
 
pygeodesy/__main__.py CHANGED
@@ -5,7 +5,7 @@ u'''Print L{pygeodesy} version, etc. using C{python -m pygeodesy}.
5
5
  '''
6
6
 
7
7
  __all__ = ()
8
- __version__ = '25.04.12'
8
+ __version__ = '25.06.26'
9
9
 
10
10
  from os.path import basename, dirname
11
11
 
@@ -28,6 +28,7 @@ def _main(): # PYCHOK no cover
28
28
  ('isLazy', isLazy),
29
29
  ('_isfrozen', _isfrozen),
30
30
  ('_floats', len(constants._floats)),
31
+ # ('_interns', len(interns.__dict__) - 22),
31
32
  (_DALL_, len(_all_imports())),
32
33
  (_DEPRECATED_, len(_all_deprecates()))))
33
34
 
pygeodesy/booleans.py CHANGED
@@ -45,7 +45,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
45
45
  # from math import fabs # from .utily
46
46
 
47
47
  __all__ = _ALL_LAZY.booleans
48
- __version__ = '25.05.12'
48
+ __version__ = '25.05.26'
49
49
 
50
50
  _0EPS = EPS # near-zero, positive
51
51
  _EPS0 = -EPS # near-zero, negative
@@ -199,8 +199,8 @@ class _LatLonBool(_Named):
199
199
 
200
200
  def __sub__(self, other):
201
201
  _other(self, other)
202
- return self.__class__(self.y - other.y, # classof
203
- self.x - other.x)
202
+ return type(self)(self.y - other.y, # classof
203
+ self.x - other.x)
204
204
 
205
205
  def _2A(self, p2, p3):
206
206
  # I{Signed} area of a triangle, I{doubled}.
@@ -314,7 +314,7 @@ class LatLonFHP(_LatLonBool):
314
314
 
315
315
  def __add__(self, other):
316
316
  _other(self, other)
317
- return self.__class__(self.y + other.y, self.x + other.x)
317
+ return type(self)(self.y + other.y, self.x + other.x)
318
318
 
319
319
  def __mod__(self, other): # cross product
320
320
  _other(self, other)
@@ -326,7 +326,7 @@ class LatLonFHP(_LatLonBool):
326
326
 
327
327
  def __rmul__(self, other): # scalar product
328
328
  _xscalar(other=other)
329
- return self.__class__(self.y * other, self.x * other)
329
+ return type(self)(self.y * other, self.x * other)
330
330
 
331
331
  # def _edge2(self):
332
332
  # # Return the start and end point of the
@@ -959,7 +959,7 @@ class _CompositeBase(_Named):
959
959
  # Return a new instance
960
960
  _g = kwds.get
961
961
  kwds = dict((n, _g(n, v)) for n, v in dflts.items())
962
- return self.__class__(corners or (), **kwds)
962
+ return type(self)(corners or (), **kwds)
963
963
 
964
964
  @property_RO
965
965
  def _clipids(self): # PYCHOK no cover
@@ -1549,7 +1549,7 @@ class _EdgeFHP(object):
1549
1549
  dq = q2 - q1
1550
1550
  dq2 = dq * dq # dot product, hypot2
1551
1551
  if dq2 > EPS2: # like ._clip
1552
- T, _E = None, _EdgeFHP # self.__class__
1552
+ T, _E = None, _EdgeFHP # type(self)
1553
1553
  p1, p2 = self._p1_p2
1554
1554
  ap1 = p1._2A(q1, q2)
1555
1555
  ap2_1 = p2._2A(q1, q2) - ap1
@@ -1750,8 +1750,8 @@ class _BooleanBase(object):
1750
1750
 
1751
1751
  def _boolean4(self, other, op):
1752
1752
  # Set up a new C{Boolean[FHP|GH]}.
1753
- C = self.__class__
1754
- kwds = C._kwds(self, op)
1753
+ C = type(self)
1754
+ kwds = C._kwds(self, op) # PYCHOK in _Composite[FHP|GH]
1755
1755
  a = C(self, **kwds)
1756
1756
  b = _other(self, other)
1757
1757
  return a, b, C, kwds
@@ -1964,7 +1964,7 @@ def _min_max_eps2(*xs):
1964
1964
  def _other(this, other):
1965
1965
  '''(INTERNAL) Check for compatible C{type}s.
1966
1966
  '''
1967
- C = this.__class__
1967
+ C = type(this)
1968
1968
  if isinstance(other, C):
1969
1969
  return other
1970
1970
  raise _IsnotError(C, other=other)
pygeodesy/constants.py CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- u'''Single-instance C{float} and C{int} constants across C{pygeodesy} modules and
5
- related functions L{pygeodesy.float_}, L{pygeodesy.isclose}, L{pygeodesy.isfinite},
4
+ u'''Single-instance C{float} and C{int} constants across C{pygeodesy} modules and related
5
+ functions L{pygeodesy.float_}, L{pygeodesy.float0_}, L{pygeodesy.isclose}, L{pygeodesy.isfinite},
6
6
  L{pygeodesy.isinf}, L{pygeodesy.isint0}, L{pygeodesy.isnan}, L{pygeodesy.isnear0},
7
7
  L{pygeodesy.isnear1}, L{pygeodesy.isnear90}, L{pygeodesy.isneg0}, L{pygeodesy.isninf},
8
8
  L{pygeodesy.isnon0} and L{pygeodesy.remainder}.
@@ -26,7 +26,7 @@ except ImportError: # Python 2-
26
26
  _inf, _nan = float(_INF_), float(_NAN_)
27
27
 
28
28
  __all__ = _ALL_LAZY.constants
29
- __version__ = '25.05.12'
29
+ __version__ = '25.05.26'
30
30
 
31
31
 
32
32
  def _copysign_0_0(y):
@@ -495,12 +495,12 @@ def _umod_PI2(rad):
495
495
 
496
496
  if __name__ == _DMAIN_:
497
497
 
498
- def _main(locals):
498
+ def _main(globalocals):
499
499
  from pygeodesy import itemsorted, printf
500
500
  from pygeodesy.interns import _DALL_, _UNDER_
501
501
 
502
502
  t = n = v = []
503
- for n, v in itemsorted(locals):
503
+ for n, v in itemsorted(globalocals):
504
504
  if isinstance(v, (Float, Int, Radius)):
505
505
  printf('%9s: %r', n, v.toRepr(std=False))
506
506
  if v.name != n:
@@ -512,7 +512,7 @@ if __name__ == _DMAIN_:
512
512
  t.append(typename(float_))
513
513
  printf('%s = %r', _DALL_, tuple(t))
514
514
 
515
- _main(locals())
515
+ _main(globals()) # or locals()
516
516
 
517
517
  # **) MIT License
518
518
  #
pygeodesy/css.py CHANGED
@@ -470,7 +470,7 @@ class Css(_NamedBase):
470
470
  # h=self.height, cs0=self.cs0,
471
471
  # name=_name__(name, _or_nameof(self)))
472
472
  # args, kwds = _args_kwds(**kwds)
473
- # return self.__class__(*args, **kwds) # .classof
473
+ # return type(self)(*args, **kwds) # .classof
474
474
 
475
475
  @Property_RO
476
476
  def easting(self):
@@ -46,7 +46,7 @@ from pygeodesy.units import Epoch, _isDegrees, Radius_, _1mm as _TOL_M
46
46
  # from math import fabs # from .latlonBase
47
47
 
48
48
  __all__ = _ALL_LAZY.ellipsoidalBase
49
- __version__ = '25.05.12'
49
+ __version__ = '25.07.21'
50
50
 
51
51
 
52
52
  class CartesianEllipsoidalBase(CartesianBase):
@@ -136,7 +136,7 @@ class CartesianEllipsoidalBase(CartesianBase):
136
136
 
137
137
  If C{B{sphere} is False}, a 2-tuple with the two intersection points
138
138
  of the I{circles}. For abutting circles, both points are the same
139
- instance, aka the I{radical center}.
139
+ instance (aka the I{radical center}).
140
140
 
141
141
  @raise IntersectionError: Concentric, invalid or non-intersecting spheres or circles.
142
142
 
@@ -449,8 +449,7 @@ class LatLonEllipsoidalBase(LatLonBase):
449
449
  def _etm(self):
450
450
  '''(INTERNAL) Get this C{LatLon} point as an ETM coordinate (L{pygeodesy.toEtm8}).
451
451
  '''
452
- etm = _MODS.etm
453
- return etm.toEtm8(self, datum=self.datum, Etm=etm.Etm)
452
+ return self._toX8(_MODS.etm.toEtm8)
454
453
 
455
454
  @property_RO
456
455
  def gamma(self):
@@ -523,8 +522,8 @@ class LatLonEllipsoidalBase(LatLonBase):
523
522
  a C{LatLon} instance.
524
523
 
525
524
  @raise ImportError: Package U{geographiclib
526
- <https://PyPI.org/project/geographiclib>} not
527
- installed or not found, but only in case
525
+ <https://PyPI.org/project/geographiclib>}
526
+ not installed or not found, but only if
528
527
  C{B{equidistant}=}L{EquidistantKarney}.
529
528
 
530
529
  @raise IntersectionError: Skew, colinear, parallel or otherwise non-intersecting
@@ -676,8 +675,8 @@ class LatLonEllipsoidalBase(LatLonBase):
676
675
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll both B{C{point1}} and
677
676
  B{C{point2}} (C{bool}).
678
677
  @kwarg equidistant: An azimuthal equidistant projection (I{class} or function
679
- L{pygeodesy.equidistant}) or C{None} for this point's preferred
680
- C{Equidistant}, like L{Equidistant<LatLonEllipsoidalBase.Equidistant>}.
678
+ L{pygeodesy.equidistant}) or C{None} for this point's
679
+ preferred C{Equidistant}, like L{Equidistant}.
681
680
  @kwarg tol: Convergence tolerance (C{meter}, conventionally).
682
681
 
683
682
  @return: Closest point (C{LatLon}).
@@ -778,6 +777,11 @@ class LatLonEllipsoidalBase(LatLonBase):
778
777
  '''
779
778
  return self._scale
780
779
 
780
+ def _toX8(self, toX8, **kwds):
781
+ '''(INTERNAL) Return toX8(self, ...).
782
+ '''
783
+ return toX8(self, **_xkwds(kwds, datum=self.datum, name=self.name))
784
+
781
785
  def toCartesian(self, height=None, **Cartesian_and_kwds): # PYCHOK signature
782
786
  '''Convert this point to cartesian, I{geocentric} coordinates,
783
787
  also known as I{Earth-Centered, Earth-Fixed} (ECEF).
@@ -793,11 +797,10 @@ class LatLonEllipsoidalBase(LatLonBase):
793
797
  def toCss(self, **toCss_kwds):
794
798
  '''Convert this C{LatLon} point to a Cassini-Soldner location.
795
799
 
796
- @kwarg toCss_kwds: Optional L{pygeodesy.toCss} keyword arguments.
800
+ @kwarg toCss_kwds: Optional keyword arguments for function
801
+ L{pygeodesy.toCss}.
797
802
 
798
803
  @return: The Cassini-Soldner location (L{Css}).
799
-
800
- @see: Function L{pygeodesy.toCss}.
801
804
  '''
802
805
  return _MODS.css.toCss(self, **self._name1__(toCss_kwds))
803
806
 
@@ -829,39 +832,38 @@ class LatLonEllipsoidalBase(LatLonBase):
829
832
  def toEtm(self, **toEtm8_kwds):
830
833
  '''Convert this C{LatLon} point to an ETM coordinate.
831
834
 
832
- @kwarg toEtm8_kwds: Optional L{pygeodesy.toEtm8} keyword arguments.
835
+ @kwarg toEtm8_kwds: Optional keyword arguments for
836
+ function L{pygeodesy.toEtm8}.
833
837
 
834
838
  @return: The ETM coordinate (L{Etm}).
835
-
836
- @see: Function L{pygeodesy.toEtm8}.
837
839
  '''
838
- return _MODS.etm.toEtm8(self, **self._name1__(toEtm8_kwds)) if toEtm8_kwds else self._etm
840
+ return self._etm if not toEtm8_kwds else \
841
+ self._toX8(_MODS.etm.toEtm8, **toEtm8_kwds)
839
842
 
840
843
  def toLcc(self, **toLcc_kwds):
841
844
  '''Convert this C{LatLon} point to a Lambert location.
842
845
 
843
- @kwarg toLcc_kwds: Optional L{pygeodesy.toLcc} keyword arguments.
846
+ @kwarg toLcc_kwds: Optional keyword arguments for
847
+ function L{pygeodesy.toLcc}.
844
848
 
845
849
  @return: The Lambert location (L{Lcc}).
846
-
847
- @see: Function L{pygeodesy.toLcc}.
848
850
  '''
849
851
  return _MODS.lcc.toLcc(self, **self._name1__(toLcc_kwds))
850
852
 
851
- def toMgrs(self, center=False, pole=NN):
853
+ def toMgrs(self, center=False, **toUtmUps_kwds):
852
854
  '''Convert this C{LatLon} point to an MGRS coordinate.
853
855
 
854
856
  @kwarg center: If C{True}, try to I{un}-center MGRS
855
857
  to its C{lowerleft} (C{bool}) or by
856
858
  C{B{center} meter} (C{scalar}).
857
- @kwarg pole: Optional top/center for the MGRS UPS
858
- projection (C{str}, 'N[orth]' or 'S[outh]').
859
+ @kwarg toUtmUps_kwds: Optional keyword arguments for
860
+ method L{toUtmUps}.
859
861
 
860
862
  @return: The MGRS coordinate (L{Mgrs}).
861
863
 
862
- @see: Method L{toUtmUps} and L{Mgrs.toLatLon}.
864
+ @see: Methods L{toUtmUps} and L{toMgrs<pygeodesy.utmupsBase.UtmUpsBase.toMgrs>}.
863
865
  '''
864
- return self.toUtmUps(center=center, pole=pole).toMgrs(center=False)
866
+ return self.toUtmUps(center=center, **toUtmUps_kwds).toMgrs(center=False)
865
867
 
866
868
  def toOsgr(self, kTM=False, **toOsgr_kwds):
867
869
  '''Convert this C{LatLon} point to an OSGR coordinate.
@@ -869,11 +871,10 @@ class LatLonEllipsoidalBase(LatLonBase):
869
871
  @kwarg kTM: If C{True}, use I{Karney}'s Krüger method from module
870
872
  L{ktm}, otherwise I{Ordinance Survery}'s recommended
871
873
  formulation (C{bool}).
872
- @kwarg toOsgr_kwds: Optional L{pygeodesy.toOsgr} keyword arguments.
874
+ @kwarg toOsgr_kwds: Optional keyword arguments for function
875
+ L{pygeodesy.toOsgr}.
873
876
 
874
877
  @return: The OSGR coordinate (L{Osgr}).
875
-
876
- @see: Function L{pygeodesy.toOsgr}.
877
878
  '''
878
879
  return _MODS.osgr.toOsgr(self, kTM=kTM, **self._name1__(toOsgr_kwds))
879
880
 
@@ -928,42 +929,40 @@ class LatLonEllipsoidalBase(LatLonBase):
928
929
  r = c.toLatLon(LatLon=self.classof, **_xkwds(LatLon_kwds, height=self.height))
929
930
  return r
930
931
 
931
- def toUps(self, pole=NN, falsed=True, center=False):
932
+ def toUps(self, center=False, **toUps8_kwds):
932
933
  '''Convert this C{LatLon} point to a UPS coordinate.
933
934
 
934
- @kwarg pole: Optional top/center of (stereographic)
935
- projection (C{str}, 'N[orth]' or 'S[outh]').
936
- @kwarg falsed: False easting and northing (C{bool}).
937
935
  @kwarg center: If C{True}, I{un}-center the UPS to its
938
936
  C{lowerleft} (C{bool}) or by C{B{center}
939
937
  meter} (C{scalar}).
938
+ @kwarg toUps8_kwds: Optional keyword arguments for
939
+ function L{pygeodesy.toUps8}.
940
940
 
941
941
  @return: The UPS coordinate (L{Ups}).
942
-
943
- @see: Function L{pygeodesy.toUps8}.
944
942
  '''
945
- if self._upsOK(pole, falsed):
946
- u = self._ups
947
- else:
948
- ups = _MODS.ups
949
- u = ups.toUps8(self, datum=self.datum, Ups=ups.Ups,
950
- pole=pole, falsed=falsed)
943
+ u = self._ups if (not toUps8_kwds) and self._upsOK() else \
944
+ self._toX8(_MODS.ups.toUps8, **toUps8_kwds)
951
945
  return _lowerleft(u, center)
952
946
 
953
- def toUtm(self, center=False):
947
+ def toUtm(self, center=False, **toUtm8_kwds):
954
948
  '''Convert this C{LatLon} point to a UTM coordinate.
955
949
 
956
950
  @kwarg center: If C{True}, I{un}-center the UTM to its
957
951
  C{lowerleft} (C{bool}) or by C{B{center}
958
952
  meter} (C{scalar}).
953
+ @kwarg toUtm8_kwds: Optional keyword arguments for function
954
+ L{pygeodesy.toUtm8}.
959
955
 
960
956
  @return: The UTM coordinate (L{Utm}).
961
957
 
962
- @see: Method L{Mgrs.toUtm} and function L{pygeodesy.toUtm8}.
958
+ @note: For the highest accuracy, use method L{toEtm} and
959
+ class L{pygeodesy.Etm} instead of L{pygeodesy.Utm}.
963
960
  '''
964
- return _lowerleft(self._utm, center)
961
+ u = self._utm if not toUtm8_kwds else \
962
+ self._toX8(_MODS.utm.toUtm8, **toUtm8_kwds)
963
+ return _lowerleft(u, center)
965
964
 
966
- def toUtmUps(self, pole=NN, center=False):
965
+ def toUtmUps(self, pole=NN, center=False, **toUtmUps8_kwds):
967
966
  '''Convert this C{LatLon} point to a UTM or UPS coordinate.
968
967
 
969
968
  @kwarg pole: Optional top/center of UPS (stereographic)
@@ -971,19 +970,19 @@ class LatLonEllipsoidalBase(LatLonBase):
971
970
  @kwarg center: If C{True}, I{un}-center the UTM or UPS to
972
971
  its C{lowerleft} (C{bool}) or by C{B{center}
973
972
  meter} (C{scalar}).
973
+ @kwarg toUtmUps8_kwds: Optional keyword arguments for
974
+ function L{pygeodesy.toUtmUps8}.
974
975
 
975
976
  @return: The UTM or UPS coordinate (L{Utm} or L{Ups}).
976
-
977
- @see: Function L{pygeodesy.toUtmUps8}.
978
977
  '''
979
- if self._utmOK():
978
+ x = not toUtmUps8_kwds
979
+ if x and self._utmOK():
980
980
  u = self._utm
981
- elif self._upsOK(pole):
981
+ elif x and self._upsOK(pole):
982
982
  u = self._ups
983
983
  else: # no cover
984
984
  utmups = _MODS.utmups
985
- u = utmups.toUtmUps8(self, datum=self.datum, pole=pole, name=self.name,
986
- Utm=utmups.Utm, Ups=utmups.Ups)
985
+ u = self._toX8(utmups.toUtmUps8, pole=pole, **toUtmUps8_kwds)
987
986
  if isinstance(u, utmups.Utm):
988
987
  self._update(False, _utm=u) # PYCHOK kwds
989
988
  elif isinstance(u, utmups.Ups):
@@ -1011,13 +1010,11 @@ class LatLonEllipsoidalBase(LatLonBase):
1011
1010
  @arg other: The other point (C{LatLon}).
1012
1011
  @arg bearing2: Bearing at the B{C{other}} point (compass C{degrees360}).
1013
1012
  @kwarg height_wrap_tol: Optional keyword arguments C{B{height}=None},
1014
- C{B{wrap}=False} and C{B{tol}}, see method L{intersection3
1015
- <pygeodesy.ellipsoidalBase.LatLonEllipsoidalBase>}.
1013
+ C{B{wrap}=False} and C{B{tol}}, see method L{intersection3}.
1016
1014
 
1017
1015
  @return: Triangulated point (C{LatLon}).
1018
1016
 
1019
- @see: Method L{intersection3<pygeodesy.ellipsoidalBase.LatLonEllipsoidalBase>}
1020
- for further details.
1017
+ @see: Method L{intersection3} for further details.
1021
1018
  '''
1022
1019
  if _isDegrees(bearing1) and _isDegrees(bearing2):
1023
1020
  r = self.intersection3(bearing1, other, bearing2, **height_wrap_tol)
@@ -1086,11 +1083,9 @@ class LatLonEllipsoidalBase(LatLonBase):
1086
1083
  '''(INTERNAL) Get this C{LatLon} point as UPS coordinate (L{Ups}),
1087
1084
  see L{pygeodesy.toUps8}.
1088
1085
  '''
1089
- ups = _MODS.ups
1090
- return ups.toUps8(self, datum=self.datum, Ups=ups.Ups,
1091
- pole=NN, falsed=True, name=self.name)
1086
+ return self._toX8(_MODS.ups.toUps8) # pole=NN, falsed=True
1092
1087
 
1093
- def _upsOK(self, pole=NN, falsed=True):
1088
+ def _upsOK(self, pole=NN, falsed=True, **unused):
1094
1089
  '''(INTERNAL) Check matching C{Ups}.
1095
1090
  '''
1096
1091
  try:
@@ -1104,8 +1099,7 @@ class LatLonEllipsoidalBase(LatLonBase):
1104
1099
  '''(INTERNAL) Get this C{LatLon} point as UTM coordinate (L{Utm}),
1105
1100
  see L{pygeodesy.toUtm8}.
1106
1101
  '''
1107
- utm = _MODS.utm
1108
- return utm.toUtm8(self, datum=self.datum, Utm=utm.Utm, name=self.name)
1102
+ return self._toX8(_MODS.utm.toUtm8)
1109
1103
 
1110
1104
  def _utmOK(self):
1111
1105
  '''(INTERNAL) Check C{Utm}.
@@ -24,7 +24,7 @@ from pygeodesy.points import _areaError, ispolar # PYCHOK exported
24
24
  # from math import fabs # from .karney
25
25
 
26
26
  __all__ = _ALL_LAZY.ellipsoidalExact
27
- __version__ = '25.05.12'
27
+ __version__ = '25.05.28'
28
28
 
29
29
 
30
30
  class Cartesian(CartesianEllipsoidalBase):
@@ -88,17 +88,19 @@ class LatLon(LatLonEllipsoidalBaseDI):
88
88
  return LatLonEllipsoidalBaseDI.toCartesian(self, **kwds)
89
89
 
90
90
 
91
- def areaOf(points, datum=_WGS84, wrap=True):
91
+ def areaOf(points, datum=_WGS84, wrap=True, polar=False):
92
92
  '''Compute the area of an (ellipsoidal) polygon or composite.
93
93
 
94
- @arg points: The polygon points (L{LatLon}[], L{BooleanFHP} or
95
- L{BooleanGH}).
94
+ @arg points: The polygon points (L{LatLon}[], L{BooleanFHP} or L{BooleanGH}).
96
95
  @kwarg datum: Optional datum (L{Datum}).
97
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
98
- B{C{points}} (C{bool}).
96
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{points}}
97
+ (C{bool}).
98
+ @kwarg polar: Use C{B{polar}=True} if the polygon encloses a pole (C{bool}), see
99
+ function L{ispolar<pygeodesy.points.ispolar>} and U{area of a polygon
100
+ enclosing a pole<https://GeographicLib.SourceForge.io/C++/doc/
101
+ classGeographicLib_1_1GeodesicExact.html#a3d7a9155e838a09a48dc14d0c3fac525>}.
99
102
 
100
- @return: Area (C{meter} I{squared}, same units as the B{C{datum}}'s
101
- ellipsoid axes).
103
+ @return: Area (C{meter} I{squared}, same units as the B{C{datum}}'s ellipsoid axes).
102
104
 
103
105
  @raise PointsError: Insufficient number of B{C{points}}.
104
106
 
@@ -110,12 +112,8 @@ def areaOf(points, datum=_WGS84, wrap=True):
110
112
  @see: Functions L{pygeodesy.areaOf}, L{ellipsoidalGeodSolve.areaOf},
111
113
  L{ellipsoidalKarney.areaOf}, L{sphericalNvector.areaOf} and
112
114
  L{sphericalTrigonometry.areaOf}.
113
-
114
- @note: The U{area of a polygon enclosing a pole<https://GeographicLib.SourceForge.io/
115
- C++/doc/classGeographicLib_1_1GeodesicExact.html#a3d7a9155e838a09a48dc14d0c3fac525>}
116
- can be found by adding half the datum's ellipsoid surface area to the polygon's area.
117
115
  '''
118
- return fabs(_polygon(datum.ellipsoid.geodesicx, points, True, False, wrap))
116
+ return fabs(_polygon(datum.ellipsoid.geodesicx, points, True, False, wrap, polar))
119
117
 
120
118
 
121
119
  def intersection3(start1, end1, start2, end2, height=None, wrap=False, # was=True
@@ -216,13 +214,14 @@ def intersections2(center1, radius1, center2, radius2, height=None, wrap=False,
216
214
  equidistant=equidistant, tol=tol, **kwds)
217
215
 
218
216
 
219
- def isclockwise(points, datum=_WGS84, wrap=True):
217
+ def isclockwise(points, datum=_WGS84, wrap=True, polar=False):
220
218
  '''Determine the direction of a path or polygon.
221
219
 
222
220
  @arg points: The path or polygon points (C{LatLon}[]).
223
221
  @kwarg datum: Optional datum (L{Datum}).
224
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
225
- B{C{points}} (C{bool}).
222
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{points}} (C{bool}).
223
+ @kwarg polar: Use C{B{polar}=True} if the C{B{points}} enclose a pole (C{bool}),
224
+ see function U{ispolar<pygeodeys.points.ispolar>}.
226
225
 
227
226
  @return: C{True} if B{C{points}} are clockwise, C{False} otherwise.
228
227
 
@@ -234,7 +233,7 @@ def isclockwise(points, datum=_WGS84, wrap=True):
234
233
 
235
234
  @see: L{pygeodesy.isclockwise}.
236
235
  '''
237
- a = _polygon(datum.ellipsoid.geodesicx, points, True, False, wrap)
236
+ a = _polygon(datum.ellipsoid.geodesicx, points, True, False, wrap, polar)
238
237
  if a < 0:
239
238
  return True
240
239
  elif a > 0:
@@ -288,29 +287,25 @@ def nearestOn(point, point1, point2, within=True, height=None, wrap=False,
288
287
  def perimeterOf(points, closed=False, datum=_WGS84, wrap=True):
289
288
  '''Compute the perimeter of an (ellipsoidal) polygon or composite.
290
289
 
291
- @arg points: The polygon points (L{LatLon}[], L{BooleanFHP} or
292
- L{BooleanGH}).
290
+ @arg points: The polygon points (L{LatLon}[], L{BooleanFHP} or L{BooleanGH}).
293
291
  @kwarg closed: Optionally, close the polygon (C{bool}).
294
292
  @kwarg datum: Optional datum (L{Datum}).
295
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
296
- B{C{points}} (C{bool}).
293
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{points}} (C{bool}).
297
294
 
298
- @return: Perimeter (C{meter}, same units as the B{C{datum}}'s
299
- ellipsoid axes).
295
+ @return: Perimeter (C{meter}, same units as the B{C{datum}}'s ellipsoid axes).
300
296
 
301
297
  @raise PointsError: Insufficient number of B{C{points}}.
302
298
 
303
299
  @raise TypeError: Some B{C{points}} are not L{LatLon}.
304
300
 
305
- @raise ValueError: Invalid C{B{wrap}=False}, unwrapped, unrolled
306
- longitudes not supported or C{B{closed}=False}
307
- with C{B{points}} a composite.
301
+ @raise ValueError: Invalid C{B{wrap}=False}, unwrapped, unrolled longitudes not
302
+ supported or C{B{closed}=False} with C{B{points}} a composite.
308
303
 
309
304
  @see: Functions L{pygeodesy.perimeterOf}, L{ellipsoidalGeodSolve.perimeterOf},
310
305
  L{ellipsoidalKarney.perimeterOf}, L{sphericalNvector.perimeterOf} and
311
306
  L{sphericalTrigonometry.perimeterOf}.
312
307
  '''
313
- return _polygon(datum.ellipsoid.geodesicx, points, closed, True, wrap)
308
+ return _polygon(datum.ellipsoid.geodesicx, points, closed, True, wrap, False)
314
309
 
315
310
 
316
311
  __all__ += _ALL_OTHER(Cartesian, LatLon, # classes