Coverage for pygeodesy/ellipsoidalBaseDI.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
class C{LatLonEllipsoidalBaseDI} and functions. ''' # make sure int/int division yields float quotient, see .basics
_0_0, _0_5, _1_5, _3_0 property_RO, _TOL_M _or, _ValueError, _xellipsoidal, _xError, _xkwds_not _near_, _SPACE_, _too_ Intersection3Tuple, NearestOn2Tuple, \ NearestOn8Tuple, _LL4Tuple # from pygeodesy.props import Property_RO, property_RO # from .ellipsoidalBase # from pygeodesy.streprs import Fmt # from .fsums
'''(INTERNAL) Base class for C{ellipsoidal*.LatLon} classes with I{overloaded} C{Direct} and C{Inverse} methods. '''
'''Compute the initial and final bearing (forward and reverse azimuth) from this to an other point, using this C{Inverse} method. See methods L{initialBearingTo} and L{finalBearingTo} for more details.
@arg other: The other point (C{LatLon}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: A L{Bearing2Tuple}C{(initial, final)}.
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
'''Compute the destination point after having travelled for the given distance from this point along a geodesic given by an initial bearing, using this C{Direct} method. See method L{destination2} for more details.
@arg distance: Distance (C{meter}). @arg bearing: Initial bearing in (compass C{degrees360}). @kwarg height: Optional height, overriding the default height (C{meter}, same units as C{distance}).
@return: The destination point (C{LatLon}). '''
'''Compute the destination point and the final bearing (reverse azimuth) after having travelled for the given distance from this point along a geodesic given by an initial bearing, using this C{Direct} method.
The distance must be in the same units as this point's datum axes, conventionally C{meter}. The distance is measured on the surface of the ellipsoid, ignoring this point's height.
The initial and final bearing (forward and reverse azimuth) are in compass C{degrees360}.
The destination point's height and datum are set to this point's height and datum, unless the former is overridden.
@arg distance: Distance (C{meter}). @arg bearing: Initial bearing (compass C{degrees360}). @kwarg height: Optional height, overriding the default height (C{meter}, same units as C{distance}).
@return: A L{Destination2Tuple}C{(destination, final)}. '''
'''(INTERNAL) I{Karney}'s C{Direct} method.
@return: A L{Destination2Tuple}C{(destination, final)} or a L{Destination3Tuple}C{(lat, lon, final)} if B{C{LL}} is C{None}. '''
'''(INTERNAL) Helper for C{._Direct} result L{Destination2Tuple}. ''' **_xkwds_not(None, epoch=self.epoch, reframe=self.reframe))
'''Compute the distance between this and an other point along a geodesic, using this C{Inverse} method. See method L{distanceTo3} for more details.
@arg other: The other point (C{LatLon}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: Distance (C{meter}).
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
'''Compute the distance, the initial and final bearing along a geodesic between this and an other point, using this C{Inverse} method.
The distance is in the same units as this point's datum axes, conventionally meter. The distance is measured on the surface of the ellipsoid, ignoring this point's height.
The initial and final bearing (forward and reverse azimuth) are in compass C{degrees360} from North.
@arg other: Destination point (C{LatLon}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: A L{Distance3Tuple}C{(distance, initial, final)}.
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
'''Compute the final bearing (reverse azimuth) after having travelled for the given distance along a geodesic given by an initial bearing from this point, using this C{Direct} method. See method L{destination2} for more details.
@arg distance: Distance (C{meter}). @arg bearing: Initial bearing (compass C{degrees360}).
@return: Final bearing (compass C{degrees360}). '''
'''Compute the final bearing (reverse azimuth) after having travelled along a geodesic from this point to an other point, using this C{Inverse} method. See method L{distanceTo3} for more details.
@arg other: The other point (C{LatLon}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: Final bearing (compass C{degrees360}).
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
'''N/A, invalid (C{None} I{always}). ''' return None # PYCHOK no cover
'''Compute the initial bearing (forward azimuth) to travel along a geodesic from this point to an other point, using this C{Inverse} method. See method L{distanceTo3} for more details.
@arg other: The other point (C{LatLon}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: Initial bearing (compass C{degrees360}).
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
'''Return the point at given fraction along the geodesic between this and an other point, using this C{Direct} and C{Inverse} methods.
@arg other: The other point (C{LatLon}). @arg fraction: Fraction between both points (C{scalar}, 0.0 at this and 1.0 at the other point. @kwarg height: Optional height, overriding the fractional height (C{meter}). @kwarg wrap: Wrap and unroll longitudes (C{bool}).
@return: Intermediate point (C{LatLon}).
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise UnitError: Invalid B{C{fraction}} or B{C{height}}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible.
@see: Methods L{distanceTo3}, L{destination}, C{midpointTo} and C{rhumbMidpointTo}. ''' r = self r = self.others(other) else: # negative fraction OK
'''(INTERNAL) I{Karney}'s C{Inverse} method.
@return: A L{Distance3Tuple}C{(distance, initial, final)}.
@raise TypeError: The B{C{other}} point is not L{LatLon}.
@raise ValueError: If this and the B{C{other}} point's L{Datum} ellipsoids are not compatible. '''
equidistant=None, tol=_TOL_M): '''Iteratively locate the point on a path or polygon closest to this point.
@arg points: The path or polygon points (C{LatLon}[]). @kwarg closed: Optionally, close the polygon (C{bool}). @kwarg height: Optional height, overriding the height of this and all other points (C{meter}, conventionally). If B{C{height}} is C{None}, the height of each point is taken into account for distances.
@return: A L{NearestOn8Tuple}C{(closest, distance, fi, j, start, end, initial, final)} with C{distance} in C{meter}, conventionally and with the C{closest}, the C{start} the C{end} point each an instance of this C{LatLon}.
@raise PointsError: Insufficient number of B{C{points}}.
@raise TypeError: Some B{C{points}} or B{C{equidistant}} invalid.
@raise ValueError: Some B{C{points}}' datum or ellipsoid incompatible or no convergence for the given B{C{tol}}.
@see: Function L{pygeodesy.nearestOn6} and method C{nearestOn6}. '''
except (TypeError, ValueError) as x: raise _xError(x, Fmt.SQUARE(points=0), p1, this=self, tol=tol, closed=closed, height=height, wrap=wrap)
# get the azimuthal equidistant projection, once
LatLon=self.classof, # this LatLon datum=self.datum, epoch=self.epoch, reframe=self.reframe) p2 = _unrollon(p1, p2) # skip edge if no overlap with box around closest
except (TypeError, ValueError) as x: raise _xError(x, Fmt.SQUARE(points=i), p1, Fmt.SQUARE(points=j), p2, this=self, tol=tol, closed=closed, height=height, wrap=wrap)
iteration=m) # ._iteration for tests
'''Bounding box around a C{LatLon} point.
@see: Function C{_box4} in .clipy.py. ''' '''New L{_Box} around point.
@arg center: The center point (C{LatLon}). @arg distance: Radius, half-size of the box (C{meter}, conventionally) '''
'''Check whether this box overlaps a line between 2 points.
@arg lat1: Latitude of first point (C{degrees}). @arg lon1: Longitude of first point (C{degrees}). @arg lat2: Latitude of second point (C{degrees}). @arg lon2: Longitude of second point (C{degrees}).
@return: C{False} if there is certainly no overlap, C{True} otherwise (C{bool}). ''' non_ = ((lat1 > self._N or lat2 < self._S) if lat1 < lat2 else (lat2 > self._N or lat1 < self._S)) or \ ((lon1 > self._E or lon2 < self._W) if lon1 < lon2 else (lon2 > self._E or lon1 < self._W)) return not non_
'''Handle a tolerance in C{meter} as C{degrees} and C{meter}. '''
'''New L{_Tol}.
@arg tol_m: Tolerance (C{meter}, only). @arg E: Earth ellipsoid (L{Ellipsoid}). @arg lat: Latitude (C{degrees}). @arg lats: Additional latitudes (C{degrees}). '''
'''Get this tolerance in C{degrees}. '''
'''Convert B{C{deg}} to meter at the same C{lat} and earth radius. '''
'''Compose an error with C{deg}rees minimum. '''
'''Get the mean latitude in C{degrees}. ''' return self._lat
'''Compose an error with B{C{m}}eter minimum. '''
'''Get this tolerance in C{meter}. '''
'''Get the earth radius in C{meter}. '''
'''(INTERNAL) Get an C{Equidistant*(0, 0, ...)} instance. ''' elif not issubclassof(equidistant, *_MODS.azimuthal._Equidistants): # PYCHOK no cover t = tuple(_.__name__ for _ in _MODS.azimuthal._Equidistants) raise _IsnotError(*t, equidistant=equidistant)
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds): '''(INTERNAL) Intersect two (ellipsoidal) path, see ellipsoidal method L{intersection3}, separated to allow callers to embellish any exceptions. '''
# compute opposing and distance
# compute an end point along the initial bearing # about 1.5 times the distance to the gu-/estimate, at # least 1/8 and at most 3/8 of the earth perimeter like # radians in .sphericalTrigonometry._int3d2 and bearing # comparison in .sphericalTrigonometry._intb
# return 2-tuple (end, False if bearing else True)
# determine C{o}utside before, on or after start point return o
s2.lat, (e2.lat if ll2 else s2.lat))
# get the azimuthal equidistant projection
# gu-/estimate initial intersection, spherically ... (_LLS(e1.lat, e1.lon, height=e1.height) if ll1 else e1), _LLS(s2.lat, s2.lon, height=s2.height), (_LLS(e2.lat, e2.lon, height=e2.height) if ll2 else e2), height=height, wrap=False, LatLon=_LLS) # unrolled already
# ... and iterate as Karney describes, @see: # LatLonEllipsoidalBase.LatLon.intersections2 # convert start and end points to projection # space and compute an intersection there A.forward(e1.lat, e1.lon), A.forward(s2.lat, s2.lon), A.forward(e2.lat, e2.lon), eps=e.meter, useZ=False) # convert intersection back to geodetic # break if below tolerance or if unchanged else: raise e.degError(m, Error=IntersectionError)
# like .sphericalTrigonometry._intersect, if this intersection # is "before" the first point, use the antipodal intersection t = t.antipodal() b1 = not b1
iteration=t._iteration, name=n) (o2 if ll2 else _o(o2, b2, 2, s2, t, e)))
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds): '''(INTERNAL) Iteratively compute the intersection point of two paths, each defined by two (ellipsoidal) points or an (ellipsoidal) start point and an initial bearing from North. ''' equidistant=equidistant, tol=tol, LatLon=LatLon, **LatLon_kwds) except (TypeError, ValueError) as x: raise _xError(x, start1=start1, end1=end1, start2=start2, end2=end2)
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds): '''(INTERNAL) Iteratively compute the intersection points of two circles, each defined by an (ellipsoidal) center point and a radius. ''' equidistant=equidistant, tol=tol, LatLon=LatLon, **LatLon_kwds) except (TypeError, ValueError) as x: raise _xError(x, center1=center1, radius1=radius1, center2=center2, radius2=radius2)
equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds): '''(INTERNAL) Intersect two (ellipsoidal) circles, see L{_intersections2} above, separated to allow callers to embellish any exceptions. '''
iteration=t.iteration, name=n)
# get the azimuthal equidistant projection
raise _ValueError(_exceed_PI_radians_)
# distance between centers and radii are # measured along the ellipsoid's surface raise IntersectionError(_near_(_concentric_)) raise IntersectionError(_too_(Fmt.distant(m)))
# gu-/estimate initial intersections, spherically ... _LLS(c2.lat, c2.lon, height=c2.height), r2, radius=e.radius, height=height, wrap=False, too_d=m) # unrolled already
# ... and iterate as Karney describes, @see: # LatLonEllipsoidalBase.LatLon.intersections2 # convert centers to projection space # compute intersections in projection space t2, r2, # XXX * t2.scale?, sphere=False, too_d=m) # convert intersections back to geodetic t, d = t1, d1 # PYCHOK no cover else: # consider only the closer intersection # break if below tolerance or if unchanged ta = t # PYCHOK no coves else: raise e.degError(m, Error=IntersectionError)
pass # PYCHOK no cover _latlon4(ts[1], h, n, c2)) elif len(ts) == 1: # PYCHOK no cover ta = ts[0] # assume abutting else: # PYCHOK no cover raise _AssertionError(ts=ts) r = _latlon4(ta, h, n, c1) return r, r
equidistant=None, tol=_TOL_M, **LatLon_and_kwds): '''(INTERNAL) Closest point and fraction, like L{_intersects2} above, separated to allow callers to embellish any exceptions. '''
# E = p.ellipsoids(p2) # done in __nearestOn2__
# get the azimuthal equidistant projection
tol=tol, **LatLon_and_kwds)
LatLon=None, **LatLon_kwds): # Only function C{_nearestOn2} and method C{nearestOn8} above
# gu-/estimate initial nearestOn, spherically ... wrap=False, only! # using sphericalNvector.LatLon.nearestOn for within=False support _LLS(p1.lat, p1.lon, height=p1.height), _LLS(p2.lat, p2.lon, height=p2.height), within=within, height=height) else: # ignore heights in distances, Z=0
# ... and iterate as Karney describes, @see: # LatLonEllipsoidalBase.LatLon.intersections2 # closest to origin, .z to interpolate height # convert points to projection space # and compute the nearest one there _v3d(A.forward(p2.lat, p2.lon), h2), within=within) # convert nearest one back to geodetic # break if below tolerance or if unchanged else: raise e.degError(m)
iteration=t.iteration, name=n)
# **) MIT License # # Copyright (C) 2016-2022 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |