pygeodesy 24.10.24__py2.py3-none-any.whl → 24.11.11__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-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +4 -4
- {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/RECORD +54 -54
- {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
- pygeodesy/__init__.py +2 -2
- pygeodesy/azimuthal.py +51 -61
- pygeodesy/basics.py +34 -33
- pygeodesy/booleans.py +36 -36
- pygeodesy/cartesianBase.py +5 -5
- pygeodesy/constants.py +4 -4
- pygeodesy/css.py +7 -8
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/classes.py +9 -9
- pygeodesy/deprecated/functions.py +6 -6
- pygeodesy/ecef.py +11 -14
- pygeodesy/ellipsoidalBase.py +105 -120
- pygeodesy/ellipsoidalBaseDI.py +114 -118
- pygeodesy/ellipsoidalExact.py +35 -37
- pygeodesy/ellipsoids.py +3 -3
- pygeodesy/errors.py +24 -24
- pygeodesy/etm.py +80 -72
- pygeodesy/fmath.py +39 -37
- pygeodesy/formy.py +3 -2
- pygeodesy/fsums.py +51 -40
- pygeodesy/geodesicw.py +15 -14
- pygeodesy/geodesicx/__init__.py +2 -2
- pygeodesy/geodsolve.py +7 -16
- pygeodesy/geoids.py +5 -5
- pygeodesy/heights.py +2 -2
- pygeodesy/internals.py +63 -79
- pygeodesy/karney.py +2 -2
- pygeodesy/ktm.py +11 -13
- pygeodesy/latlonBase.py +6 -6
- pygeodesy/lazily.py +5 -5
- pygeodesy/lcc.py +4 -4
- pygeodesy/ltp.py +10 -10
- pygeodesy/ltpTuples.py +74 -75
- pygeodesy/mgrs.py +9 -10
- pygeodesy/named.py +4 -0
- pygeodesy/osgr.py +9 -12
- pygeodesy/props.py +2 -2
- pygeodesy/resections.py +9 -10
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/solve.py +3 -3
- pygeodesy/simplify.py +5 -5
- pygeodesy/sphericalNvector.py +80 -123
- pygeodesy/sphericalTrigonometry.py +60 -66
- pygeodesy/units.py +2 -2
- pygeodesy/utm.py +6 -6
- pygeodesy/vector2d.py +13 -13
- pygeodesy/vector3d.py +19 -21
- pygeodesy/vector3dBase.py +18 -15
- pygeodesy/webmercator.py +4 -4
- pygeodesy/wgrs.py +4 -4
- {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
pygeodesy/ellipsoidalBaseDI.py
CHANGED
|
@@ -9,7 +9,7 @@ from __future__ import division as _; del _ # PYCHOK semicolon
|
|
|
9
9
|
|
|
10
10
|
from pygeodesy.basics import isLatLon, _xsubclassof
|
|
11
11
|
from pygeodesy.constants import EPS, MAX, PI, PI2, PI_4, isnear0, isnear1, \
|
|
12
|
-
_EPSqrt as _TOL, _0_0,
|
|
12
|
+
_EPSqrt as _TOL, _0_0, _0_01, _1_0, _1_5, _3_0
|
|
13
13
|
# from pygeodesy.dms import F_DMS # _MODS
|
|
14
14
|
from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase, _TOL_M, property_RO
|
|
15
15
|
from pygeodesy.errors import _AssertionError, IntersectionError, _IsnotError, \
|
|
@@ -34,11 +34,10 @@ from pygeodesy.utily import m2km, unroll180, _unrollon, _unrollon3, \
|
|
|
34
34
|
from math import degrees, radians
|
|
35
35
|
|
|
36
36
|
__all__ = _ALL_LAZY.ellipsoidalBaseDI
|
|
37
|
-
__version__ = '24.
|
|
37
|
+
__version__ = '24.11.04'
|
|
38
38
|
|
|
39
|
-
_polar__
|
|
40
|
-
|
|
41
|
-
_TRIPS = 33 # _intersect3, _intersects2, _nearestOn interations, 6..9 sufficient?
|
|
39
|
+
_polar__ = 'polar?'
|
|
40
|
+
_TRIPS = 33 # _intersect3, _intersects2, _nearestOn interations, 6..9 sufficient?
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
@@ -52,13 +51,13 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
52
51
|
method. See methods L{initialBearingTo} and L{finalBearingTo}
|
|
53
52
|
for more details.
|
|
54
53
|
|
|
55
|
-
@arg other: The other point (C{LatLon}).
|
|
54
|
+
@arg other: The other point (this C{LatLon}).
|
|
56
55
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
|
|
57
56
|
B{C{other}} point (C{bool}).
|
|
58
57
|
|
|
59
58
|
@return: A L{Bearing2Tuple}C{(initial, final)}.
|
|
60
59
|
|
|
61
|
-
@raise TypeError:
|
|
60
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
62
61
|
|
|
63
62
|
@raise ValueError: If this and the B{C{other}} point's L{Datum}
|
|
64
63
|
ellipsoids are not compatible.
|
|
@@ -69,13 +68,8 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
69
68
|
def destination(self, distance, bearing, height=None):
|
|
70
69
|
'''Compute the destination point after having travelled for
|
|
71
70
|
the given distance from this point along a geodesic given
|
|
72
|
-
by an initial bearing
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@arg distance: Distance (C{meter}).
|
|
76
|
-
@arg bearing: Initial bearing in (compass C{degrees360}).
|
|
77
|
-
@kwarg height: Optional height, overriding the default
|
|
78
|
-
height (C{meter}, same units as C{distance}).
|
|
71
|
+
by an initial bearing. See method L{destination2} for
|
|
72
|
+
further details.
|
|
79
73
|
|
|
80
74
|
@return: The destination point (C{LatLon}).
|
|
81
75
|
'''
|
|
@@ -84,15 +78,16 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
84
78
|
def destination2(self, distance, bearing, height=None):
|
|
85
79
|
'''Compute the destination point and the final bearing (reverse
|
|
86
80
|
azimuth) after having travelled for the given distance from
|
|
87
|
-
this point along a geodesic given by an initial bearing
|
|
88
|
-
|
|
81
|
+
this point along a geodesic (line) given by an initial bearing
|
|
82
|
+
at this point.
|
|
89
83
|
|
|
90
|
-
The distance must be in the same units as this point's datum
|
|
91
|
-
axes, conventionally C{meter}. The distance is
|
|
92
|
-
the surface of the ellipsoid, ignoring this point's
|
|
84
|
+
The distance must be in the same units as this point's datum's
|
|
85
|
+
ellipsoid's axes, conventionally C{meter}. The distance is
|
|
86
|
+
measured on the surface of the ellipsoid, ignoring this point's
|
|
87
|
+
height.
|
|
93
88
|
|
|
94
89
|
The initial and final bearing (forward and reverse azimuth)
|
|
95
|
-
are in compass C{degrees360}.
|
|
90
|
+
are in compass C{degrees360}, clockwise from North.
|
|
96
91
|
|
|
97
92
|
The destination point's height and datum are set to this
|
|
98
93
|
point's height and datum, unless the former is overridden.
|
|
@@ -104,8 +99,7 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
104
99
|
|
|
105
100
|
@return: A L{Destination2Tuple}C{(destination, final)}.
|
|
106
101
|
'''
|
|
107
|
-
|
|
108
|
-
return self._xnamed(r)
|
|
102
|
+
return self._Direct(distance, bearing, self.classof, height)
|
|
109
103
|
|
|
110
104
|
def _Direct(self, distance, bearing, LL, height): # overloaded by I{Vincenty}
|
|
111
105
|
'''(INTERNAL) I{Karney}'s C{Direct} method.
|
|
@@ -122,27 +116,26 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
122
116
|
def _Direct2Tuple(self, LL, height, r):
|
|
123
117
|
'''(INTERNAL) Helper for C{._Direct} result L{Destination2Tuple}.
|
|
124
118
|
'''
|
|
125
|
-
h =
|
|
126
|
-
d =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return Destination2Tuple(d, wrap360(r.final))
|
|
119
|
+
h = self._heigHt(height)
|
|
120
|
+
d = _xkwds_not(None, datum=self.datum, name=self.name,
|
|
121
|
+
epoch=self.epoch, reframe=self.reframe)
|
|
122
|
+
d = LL(*_Wrap.latlon(r.lat, r.lon), height=h, **d)
|
|
123
|
+
return Destination2Tuple(d, wrap360(r.final), name=self.name)
|
|
130
124
|
|
|
131
|
-
def distanceTo(self, other, wrap=False, **unused): #
|
|
125
|
+
def distanceTo(self, other, wrap=False, **unused): # radius=R_M
|
|
132
126
|
'''Compute the distance between this and an other point along
|
|
133
|
-
a geodesic
|
|
134
|
-
L{distanceTo3} for more details.
|
|
127
|
+
a geodesic. See method L{distanceTo3} for more details.
|
|
135
128
|
|
|
136
|
-
@arg other: The other point (C{LatLon}).
|
|
129
|
+
@arg other: The other point (this C{LatLon}).
|
|
137
130
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
|
|
138
131
|
B{C{other}} point (C{bool}).
|
|
139
132
|
|
|
140
133
|
@return: Distance (C{meter}).
|
|
141
134
|
|
|
142
|
-
@raise TypeError:
|
|
135
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
143
136
|
|
|
144
|
-
@raise ValueError:
|
|
145
|
-
ellipsoids are
|
|
137
|
+
@raise ValueError: This and the B{C{other}} point's L{Datum}
|
|
138
|
+
ellipsoids are incompatible.
|
|
146
139
|
'''
|
|
147
140
|
return self._Inverse(other, wrap, azis=False).distance
|
|
148
141
|
|
|
@@ -151,12 +144,13 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
151
144
|
a geodesic between this and an other point, using this
|
|
152
145
|
C{Inverse} method.
|
|
153
146
|
|
|
154
|
-
The distance is in the same units as this point's datum
|
|
155
|
-
conventionally meter. The distance is
|
|
156
|
-
of the ellipsoid, ignoring this
|
|
147
|
+
The distance is in the same units as this point's datum's
|
|
148
|
+
ellipsoid's axes, conventionally meter. The distance is
|
|
149
|
+
measured on the surface of the ellipsoid, ignoring this
|
|
150
|
+
point's height.
|
|
157
151
|
|
|
158
152
|
The initial and final bearing (forward and reverse azimuth)
|
|
159
|
-
are in compass C{degrees360} from North.
|
|
153
|
+
are in compass C{degrees360}, clockwise from North.
|
|
160
154
|
|
|
161
155
|
@arg other: Destination point (C{LatLon}).
|
|
162
156
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
|
|
@@ -164,18 +158,18 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
164
158
|
|
|
165
159
|
@return: A L{Distance3Tuple}C{(distance, initial, final)}.
|
|
166
160
|
|
|
167
|
-
@raise TypeError:
|
|
161
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
168
162
|
|
|
169
|
-
@raise ValueError:
|
|
163
|
+
@raise ValueError: This and the B{C{other}} point's L{Datum}
|
|
170
164
|
ellipsoids are not compatible.
|
|
171
165
|
'''
|
|
172
166
|
return self._xnamed(self._Inverse(other, wrap))
|
|
173
167
|
|
|
174
168
|
def finalBearingOn(self, distance, bearing):
|
|
175
169
|
'''Compute the final bearing (reverse azimuth) after having
|
|
176
|
-
travelled for the given distance along a geodesic given
|
|
177
|
-
an initial bearing from this point
|
|
178
|
-
|
|
170
|
+
travelled for the given distance along a geodesic given
|
|
171
|
+
by an initial bearing from this point. See method
|
|
172
|
+
L{destination2} for more details.
|
|
179
173
|
|
|
180
174
|
@arg distance: Distance (C{meter}).
|
|
181
175
|
@arg bearing: Initial bearing (compass C{degrees360}).
|
|
@@ -187,8 +181,7 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
187
181
|
def finalBearingTo(self, other, wrap=False):
|
|
188
182
|
'''Compute the final bearing (reverse azimuth) after having
|
|
189
183
|
travelled along a geodesic from this point to an other
|
|
190
|
-
point
|
|
191
|
-
L{distanceTo3} for more details.
|
|
184
|
+
point. See method L{distanceTo3} for more details.
|
|
192
185
|
|
|
193
186
|
@arg other: The other point (C{LatLon}).
|
|
194
187
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll
|
|
@@ -196,10 +189,10 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
196
189
|
|
|
197
190
|
@return: Final bearing (compass C{degrees360}).
|
|
198
191
|
|
|
199
|
-
@raise TypeError:
|
|
192
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
200
193
|
|
|
201
|
-
@raise ValueError:
|
|
202
|
-
ellipsoids are
|
|
194
|
+
@raise ValueError: This and the B{C{other}} point's L{Datum}
|
|
195
|
+
ellipsoids are incompatible.
|
|
203
196
|
'''
|
|
204
197
|
return self._Inverse(other, wrap).final
|
|
205
198
|
|
|
@@ -209,40 +202,38 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
209
202
|
'''
|
|
210
203
|
return None # PYCHOK no cover
|
|
211
204
|
|
|
212
|
-
def _g_gl_p3(self,
|
|
205
|
+
def _g_gl_p3(self, start, end, exact, wrap):
|
|
213
206
|
'''(INTERNAL) Helper for methods C{.intersecant2} and C{.plumbTo}.
|
|
214
207
|
'''
|
|
215
|
-
p = _unrollon(self, self.others(
|
|
208
|
+
p = _unrollon(self, self.others(start=start), wrap=wrap)
|
|
216
209
|
g = self.datum.ellipsoid.geodesic_(exact=exact)
|
|
217
|
-
gl = g._DirectLine( p,
|
|
218
|
-
g._InverseLine(p, self.others(
|
|
210
|
+
gl = g._DirectLine( p, end) if _isDegrees(end) else \
|
|
211
|
+
g._InverseLine(p, self.others(end=end), wrap)
|
|
219
212
|
return g, gl, p
|
|
220
213
|
|
|
221
214
|
def initialBearingTo(self, other, wrap=False):
|
|
222
215
|
'''Compute the initial bearing (forward azimuth) to travel
|
|
223
|
-
along a geodesic from this point to an other point
|
|
224
|
-
|
|
225
|
-
for more details.
|
|
216
|
+
along a geodesic from this point to an other point. See
|
|
217
|
+
method L{distanceTo3} for more details.
|
|
226
218
|
|
|
227
|
-
@arg other: The other point (C{LatLon}).
|
|
219
|
+
@arg other: The other point (this C{LatLon}).
|
|
228
220
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll
|
|
229
221
|
the B{C{other}} point (C{bool}).
|
|
230
222
|
|
|
231
223
|
@return: Initial bearing (compass C{degrees360}).
|
|
232
224
|
|
|
233
|
-
@raise TypeError:
|
|
225
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
234
226
|
|
|
235
227
|
@raise ValueError: If this and the B{C{other}} point's L{Datum}
|
|
236
|
-
ellipsoids are
|
|
228
|
+
ellipsoids are incompatible.
|
|
237
229
|
'''
|
|
238
230
|
return self._Inverse(other, wrap).initial
|
|
239
231
|
|
|
240
232
|
def intermediateTo(self, other, fraction, height=None, wrap=False):
|
|
241
233
|
'''Return the point at given fraction along the geodesic between
|
|
242
|
-
this and an other point
|
|
243
|
-
methods.
|
|
234
|
+
this and an other point.
|
|
244
235
|
|
|
245
|
-
@arg other: The other point (C{LatLon}).
|
|
236
|
+
@arg other: The other point (this C{LatLon}).
|
|
246
237
|
@arg fraction: Fraction between both points (C{scalar}, 0.0
|
|
247
238
|
at this and 1.0 at the other point.
|
|
248
239
|
@kwarg height: Optional height, overriding the fractional
|
|
@@ -252,12 +243,12 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
252
243
|
|
|
253
244
|
@return: Intermediate point (C{LatLon}).
|
|
254
245
|
|
|
255
|
-
@raise TypeError:
|
|
246
|
+
@raise TypeError: If B{C{other}} not this C{LatLon} class.
|
|
256
247
|
|
|
257
248
|
@raise UnitError: Invalid B{C{fraction}} or B{C{height}}.
|
|
258
249
|
|
|
259
|
-
@raise ValueError:
|
|
260
|
-
ellipsoids are
|
|
250
|
+
@raise ValueError: This and the B{C{other}} point's L{Datum}
|
|
251
|
+
ellipsoids are incompatible.
|
|
261
252
|
|
|
262
253
|
@see: Methods L{distanceTo3}, L{destination}, C{midpointTo} and
|
|
263
254
|
C{rhumbMidpointTo}.
|
|
@@ -273,49 +264,47 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
273
264
|
r = self.destination(t.distance * f, t.initial, height=h)
|
|
274
265
|
return r
|
|
275
266
|
|
|
276
|
-
def intersecant2(self, circle,
|
|
277
|
-
|
|
278
|
-
'''Compute the intersections of a circle and a geodesic (line) given as
|
|
279
|
-
|
|
267
|
+
def intersecant2(self, circle, start, end, exact=False, height=None, # PYCHOK signature
|
|
268
|
+
wrap=False, tol=_TOL):
|
|
269
|
+
'''Compute the intersections of a circle and a geodesic (line) given as two
|
|
270
|
+
points or as a point and a bearing from North.
|
|
280
271
|
|
|
281
272
|
@arg circle: Radius of the circle centered at this location (C{meter},
|
|
282
|
-
conventionally) or a point on the circle (
|
|
283
|
-
@arg
|
|
284
|
-
@arg
|
|
285
|
-
|
|
273
|
+
conventionally) or a point on the circle (this C{LatLon}).
|
|
274
|
+
@arg start: Start point of the geodesic (line) (this C{LatLon}).
|
|
275
|
+
@arg end: End point of the geodesic (line) (this C{LatLon}) or the initial
|
|
276
|
+
bearing at the B{C{start}} point (compass C{degrees360}).
|
|
286
277
|
@kwarg exact: Exact C{geodesic...} to use (C{bool} or C{Geodesic...}), see
|
|
287
|
-
method L{Ellipsoid.geodesic_}.
|
|
278
|
+
method L{geodesic_<Ellipsoid.geodesic_>}.
|
|
288
279
|
@kwarg height: Optional height for the intersection points (C{meter},
|
|
289
280
|
conventionally) or C{None} for interpolated heights.
|
|
290
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{
|
|
291
|
-
B{C{
|
|
281
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{circle}},
|
|
282
|
+
B{C{start}} and/or B{C{end}} (C{bool}).
|
|
292
283
|
@kwarg tol: Convergence tolerance (C{scalar}).
|
|
293
284
|
|
|
294
285
|
@return: 2-Tuple of the intersection points (representing a geodesic chord),
|
|
295
|
-
each an instance of
|
|
286
|
+
each an instance of this C{LatLon} class. Both points are the same
|
|
296
287
|
instance if the geodesic (line) is tangential to the circle.
|
|
297
288
|
|
|
298
289
|
@raise IntersectionError: The circle and geodesic do not intersect.
|
|
299
290
|
|
|
300
|
-
@raise TypeError:
|
|
301
|
-
or B{C{other}} invalid.
|
|
291
|
+
@raise TypeError: Invalid B{C{circle}}, B{C{start}} or B{C{end}}.
|
|
302
292
|
|
|
303
|
-
@raise UnitError: Invalid B{C{circle}}, B{C{
|
|
304
|
-
B{C{height}}.
|
|
293
|
+
@raise UnitError: Invalid B{C{circle}}, B{C{end}}, B{C{exact}} or B{C{height}}.
|
|
305
294
|
|
|
306
295
|
@see: Method L{rhumbIntersecant2<LatLonBase.rhumbIntersecant2>}.
|
|
307
296
|
'''
|
|
308
297
|
try:
|
|
309
|
-
g, gl, p = self._g_gl_p3(
|
|
298
|
+
g, gl, p = self._g_gl_p3(start, end, exact, wrap)
|
|
310
299
|
r = Radius_(circle=circle) if _isRadius(circle) else \
|
|
311
300
|
g._Inverse(self, self.others(circle=circle), wrap).s12
|
|
312
301
|
|
|
313
302
|
P, Q = _MODS.geodesicw._Intersecant2(gl, self.lat, self.lon, r, tol=tol,
|
|
314
303
|
form=_MODS.dms.F_DMS)
|
|
315
|
-
return self._intersecend2(p,
|
|
316
|
-
|
|
304
|
+
return self._intersecend2(p, end, wrap, height, g, P, Q,
|
|
305
|
+
self.intersecant2)
|
|
317
306
|
except (TypeError, ValueError) as x:
|
|
318
|
-
raise _xError(x, center=self, circle=circle,
|
|
307
|
+
raise _xError(x, center=self, circle=circle, start=start, end=end,
|
|
319
308
|
exact=exact, wrap=wrap)
|
|
320
309
|
|
|
321
310
|
def _Inverse(self, other, wrap, **unused): # azis=False, overloaded by I{Vincenty}
|
|
@@ -341,11 +330,15 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
341
330
|
compute distances.
|
|
342
331
|
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{points}}
|
|
343
332
|
(C{bool}).
|
|
333
|
+
@kwarg equidistant: An azimuthal equidistant projection (I{class} or function
|
|
334
|
+
L{pygeodesy.equidistant}) or C{None} for the preferred
|
|
335
|
+
L{Equidistant<pygeodesy.ellipsoidalBase.Equidistant>}.
|
|
336
|
+
@kwarg tol: Convergence tolerance (C{meter}, conventionally).
|
|
344
337
|
|
|
345
338
|
@return: A L{NearestOn8Tuple}C{(closest, distance, fi, j, start, end,
|
|
346
339
|
initial, final)} with C{distance} in C{meter}, conventionally
|
|
347
340
|
and with the C{closest}, the C{start} the C{end} point each
|
|
348
|
-
an instance of
|
|
341
|
+
an instance of this C{LatLon} class.
|
|
349
342
|
|
|
350
343
|
@raise PointsError: Insufficient number of B{C{points}}.
|
|
351
344
|
|
|
@@ -406,37 +399,37 @@ class LatLonEllipsoidalBaseDI(LatLonEllipsoidalBase):
|
|
|
406
399
|
return NearestOn8Tuple(c, c3.distance, f, j, s, e, c3.initial, c3.final,
|
|
407
400
|
iteration=m) # ._iteration for tests
|
|
408
401
|
|
|
409
|
-
def plumbTo(self,
|
|
410
|
-
|
|
411
|
-
'''Compute the
|
|
412
|
-
a geodesic
|
|
402
|
+
def plumbTo(self, start, end, exact=False, height=None, # PYCHOK signature
|
|
403
|
+
wrap=False, tol=_TOL):
|
|
404
|
+
'''Compute the intersection of a geodesic from this point I{perpendicular} to
|
|
405
|
+
a geodesic (line) given as two points or as a point and a bearing from North.
|
|
413
406
|
|
|
414
|
-
@arg
|
|
415
|
-
@arg
|
|
416
|
-
|
|
407
|
+
@arg start: Start point of the geodesic (line) (this C{LatLon}).
|
|
408
|
+
@arg end: End point of the geodesic (line) (this C{LatLon}) or the initial
|
|
409
|
+
bearing at the B{C{start}} point (compass C{degrees360}).
|
|
417
410
|
@kwarg exact: Exact C{geodesic...} to use (C{bool} or C{Geodesic...}),
|
|
418
411
|
see method L{Ellipsoid.geodesic_}.
|
|
419
412
|
@kwarg height: Optional height for the intersection point (C{meter},
|
|
420
413
|
conventionally) or C{None} for an interpolated height.
|
|
421
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{
|
|
422
|
-
and/or B{C{
|
|
414
|
+
@kwarg wrap: If C{True}, wrap or I{normalize} and unroll the B{C{start}}
|
|
415
|
+
and/or B{C{end}} point (C{bool}).
|
|
423
416
|
@kwarg tol: Convergence tolerance (C{meter}).
|
|
424
417
|
|
|
425
|
-
@return: The intersection point, an instance of
|
|
418
|
+
@return: The intersection point, an instance of this C{LatLon} class.
|
|
426
419
|
|
|
427
|
-
@raise TypeError: If B{C{
|
|
420
|
+
@raise TypeError: If B{C{start}} or B{C{end}} not this C{LatLon} class.
|
|
428
421
|
|
|
429
|
-
@raise UnitError: Invalid B{C{
|
|
422
|
+
@raise UnitError: Invalid B{C{end}}, B{C{exact}} or B{C{height}}.
|
|
430
423
|
'''
|
|
431
424
|
try:
|
|
432
|
-
g, gl, p = self._g_gl_p3(
|
|
425
|
+
g, gl, p = self._g_gl_p3(start, end, exact, wrap)
|
|
433
426
|
|
|
434
427
|
P = _MODS.geodesicw._PlumbTo(gl, self.lat, self.lon, tol=tol)
|
|
435
428
|
h = self._havg(p, h=height)
|
|
436
429
|
p = self.classof(P.lat2, P.lon2, datum=self.datum, height=h) # name=n
|
|
437
430
|
p._iteration = P.iteration
|
|
438
431
|
except (TypeError, ValueError) as x:
|
|
439
|
-
raise _xError(x, plumb=self,
|
|
432
|
+
raise _xError(x, plumb=self, start=start, end=end,
|
|
440
433
|
exact=exact, wrap=wrap)
|
|
441
434
|
return p
|
|
442
435
|
|
|
@@ -446,6 +439,8 @@ class _Box(object):
|
|
|
446
439
|
|
|
447
440
|
@see: Function C{_box4} in .clipy.py.
|
|
448
441
|
'''
|
|
442
|
+
_1_01 = _1_0 + _0_01 # ~1% margin
|
|
443
|
+
|
|
449
444
|
def __init__(self, center, distance):
|
|
450
445
|
'''New L{_Box} around point.
|
|
451
446
|
|
|
@@ -454,8 +449,8 @@ class _Box(object):
|
|
|
454
449
|
(C{meter}, conventionally)
|
|
455
450
|
'''
|
|
456
451
|
m = Radius_(distance=distance)
|
|
457
|
-
E = center.ellipsoid()
|
|
458
|
-
d = E.m2degrees(m)
|
|
452
|
+
E = center.ellipsoid()
|
|
453
|
+
d = E.m2degrees(m) * self._1_01
|
|
459
454
|
self._N = center.lat + d
|
|
460
455
|
self._S = center.lat - d
|
|
461
456
|
self._E = center.lon + d
|
|
@@ -504,7 +499,7 @@ class _Tol(object):
|
|
|
504
499
|
self._lat = fmean_(lat, *lats) if lats else lat
|
|
505
500
|
self._r = max(EPS, E.rocMean(self._lat))
|
|
506
501
|
self._m = max(EPS, tol_m)
|
|
507
|
-
self._deg = max(EPS, degrees(self._m / self._r)) #
|
|
502
|
+
self._deg = max(EPS, degrees(self._m / self._r)) # NOT E.m2degrees!
|
|
508
503
|
|
|
509
504
|
@property_RO
|
|
510
505
|
def degrees(self):
|
|
@@ -515,7 +510,7 @@ class _Tol(object):
|
|
|
515
510
|
def degrees2m(self, deg):
|
|
516
511
|
'''Convert B{C{deg}} to meter at the same C{lat} and earth radius.
|
|
517
512
|
'''
|
|
518
|
-
return self.radius * radians(deg) / PI2 #
|
|
513
|
+
return self.radius * radians(deg) / PI2 # NOT E.degrees2m!
|
|
519
514
|
|
|
520
515
|
def degError(self, Error=_ValueError):
|
|
521
516
|
'''Compose an error with the C{deg}rees minimum.
|
|
@@ -523,7 +518,7 @@ class _Tol(object):
|
|
|
523
518
|
return self.mError(self.degrees2m(self._min), Error=Error)
|
|
524
519
|
|
|
525
520
|
def done(self, deg):
|
|
526
|
-
'''Check C{deg} vs
|
|
521
|
+
'''Check C{deg} vs tolerance and previous value.
|
|
527
522
|
'''
|
|
528
523
|
if deg < self._deg or deg == self._prev:
|
|
529
524
|
return True
|
|
@@ -533,7 +528,7 @@ class _Tol(object):
|
|
|
533
528
|
|
|
534
529
|
@property_RO
|
|
535
530
|
def lat(self):
|
|
536
|
-
'''Get the mean latitude
|
|
531
|
+
'''Get the mean latitude in C{degrees}.
|
|
537
532
|
'''
|
|
538
533
|
return self._lat
|
|
539
534
|
|
|
@@ -560,8 +555,8 @@ class _Tol(object):
|
|
|
560
555
|
def reset(self):
|
|
561
556
|
'''Reset tolerances.
|
|
562
557
|
'''
|
|
563
|
-
self._min = MAX
|
|
564
|
-
self._prev = None
|
|
558
|
+
self._min = MAX # delattrof()
|
|
559
|
+
self._prev = None # delattrof()
|
|
565
560
|
|
|
566
561
|
|
|
567
562
|
def _Equidistant00(equidistant, p1):
|
|
@@ -585,7 +580,9 @@ def intersecant2(center, circle, point, other, **exact_height_wrap_tol):
|
|
|
585
580
|
@arg point: A point of the geodesic (C{LatLon}, as B{C{center}}).
|
|
586
581
|
@arg other: An other point of the geodesic (C{LatLon}, as B{C{center}}) or
|
|
587
582
|
the (forward) bearing at the B{C{point}} (compass C{degrees}).
|
|
588
|
-
@kwarg exact_height_wrap_tol: Optional keyword arguments,
|
|
583
|
+
@kwarg exact_height_wrap_tol: Optional keyword arguments C{B{exact}=False},
|
|
584
|
+
C{B{height}=None}, C{B{wrap}=False} and C{B{tol}}, see method
|
|
585
|
+
L{intersecant2<LatLonEllipsoidalBaseDI.intersecant2>}.
|
|
589
586
|
|
|
590
587
|
@raise NotImplementedError: Method C{intersecant2} not available.
|
|
591
588
|
|
|
@@ -601,7 +598,7 @@ def intersecant2(center, circle, point, other, **exact_height_wrap_tol):
|
|
|
601
598
|
|
|
602
599
|
|
|
603
600
|
def _intersect3(s1, end1, s2, end2, height=None, wrap=False, # MCCABE 16 was=True
|
|
604
|
-
|
|
601
|
+
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds):
|
|
605
602
|
'''(INTERNAL) Intersect two (ellipsoidal) lines, see ellipsoidal method
|
|
606
603
|
L{intersection3}, separated to allow callers to embellish any exceptions.
|
|
607
604
|
'''
|
|
@@ -624,7 +621,7 @@ def _intersect3(s1, end1, s2, end2, height=None, wrap=False, # MCCABE 16 was=T
|
|
|
624
621
|
# comparison in .sphericaltrigonometry._intb
|
|
625
622
|
b, d = _b_d(s, e, w, t, h=t.height)
|
|
626
623
|
m = s.ellipsoid().R2x * PI_4 # authalic exact
|
|
627
|
-
d = min(max(d *
|
|
624
|
+
d = min(max(d * _1_5, m), m * _3_0)
|
|
628
625
|
e = s.destination(d, e)
|
|
629
626
|
return b, (_unrollon(s, e) if w else e)
|
|
630
627
|
|
|
@@ -697,7 +694,7 @@ def _intersect3(s1, end1, s2, end2, height=None, wrap=False, # MCCABE 16 was=T
|
|
|
697
694
|
|
|
698
695
|
|
|
699
696
|
def _intersection3(start1, end1, start2, end2, height=None, wrap=False, # was=True
|
|
700
|
-
|
|
697
|
+
**equidistant_tol_LatLon_and_kwds):
|
|
701
698
|
'''(INTERNAL) Iteratively compute the intersection point of two lines,
|
|
702
699
|
each defined by two (ellipsoidal) points or an (ellipsoidal) start
|
|
703
700
|
point and an initial bearing from North.
|
|
@@ -706,14 +703,13 @@ def _intersection3(start1, end1, start2, end2, height=None, wrap=False, # was=T
|
|
|
706
703
|
s2 = s1.others(start2=start2)
|
|
707
704
|
try:
|
|
708
705
|
return _intersect3(s1, end1, s2, end2, height=height, wrap=wrap,
|
|
709
|
-
|
|
710
|
-
LatLon=LatLon, **LatLon_kwds)
|
|
706
|
+
**equidistant_tol_LatLon_and_kwds)
|
|
711
707
|
except (TypeError, ValueError) as x:
|
|
712
708
|
raise _xError(x, start1=start1, end1=end1, start2=start2, end2=end2)
|
|
713
709
|
|
|
714
710
|
|
|
715
711
|
def _intersections2(center1, radius1, center2, radius2, height=None, wrap=False, # was=True
|
|
716
|
-
|
|
712
|
+
**equidistant_tol_LatLon_and_kwds):
|
|
717
713
|
'''(INTERNAL) Iteratively compute the intersection points of two circles,
|
|
718
714
|
each defined by an (ellipsoidal) center point and a radius.
|
|
719
715
|
'''
|
|
@@ -721,15 +717,14 @@ def _intersections2(center1, radius1, center2, radius2, height=None, wrap=False,
|
|
|
721
717
|
c2 = c1.others(center2=center2)
|
|
722
718
|
try:
|
|
723
719
|
return _intersects2(c1, radius1, c2, radius2, height=height, wrap=wrap,
|
|
724
|
-
|
|
725
|
-
LatLon=LatLon, **LatLon_kwds)
|
|
720
|
+
**equidistant_tol_LatLon_and_kwds)
|
|
726
721
|
except (TypeError, ValueError) as x:
|
|
727
722
|
raise _xError(x, center1=center1, radius1=radius1,
|
|
728
723
|
center2=center2, radius2=radius2)
|
|
729
724
|
|
|
730
725
|
|
|
731
726
|
def _intersects2(c1, radius1, c2, radius2, height=None, wrap=False, # MCCABE 16 was=True
|
|
732
|
-
|
|
727
|
+
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds):
|
|
733
728
|
'''(INTERNAL) Intersect two (ellipsoidal) circles, see L{_intersections2}
|
|
734
729
|
above, separated to allow callers to embellish any exceptions.
|
|
735
730
|
'''
|
|
@@ -771,7 +766,7 @@ def _intersects2(c1, radius1, c2, radius2, height=None, wrap=False, # MCCABE 16
|
|
|
771
766
|
|
|
772
767
|
# gu-/estimate initial intersections, spherically ...
|
|
773
768
|
t1, t2 = _si2(_LLS(c1), r1, _LLS(c2), r2, radius=e.radius,
|
|
774
|
-
height=height,
|
|
769
|
+
height=height, too_d=m, wrap=False) # unrolled already
|
|
775
770
|
h, n = t1.height, t1.name
|
|
776
771
|
|
|
777
772
|
# ... and iterate as Karney describes, for references
|
|
@@ -886,6 +881,7 @@ def _nearestOn3(p, p1, p2, A, within=True, height=None, tol=_TOL_M,
|
|
|
886
881
|
|
|
887
882
|
|
|
888
883
|
__all__ += _ALL_DOCS(LatLonEllipsoidalBaseDI, intersecant2)
|
|
884
|
+
del _1_0, _0_01
|
|
889
885
|
|
|
890
886
|
# **) MIT License
|
|
891
887
|
#
|