Coverage for pygeodesy/ellipsoidalBase.py : 94%

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 -*-
and C{LatLonEllipsoidalBase}.
Pure Python implementation of geodesy tools for ellipsoidal earth models, transcoded in part from JavaScript originals by I{(C) Chris Veness 2005-2016} and published under the same MIT Licence**, see for example U{latlon-ellipsoidal <https://www.Movable-Type.co.UK/scripts/geodesy/docs/latlon-ellipsoidal.js.html>}. ''' # make sure int/int division yields float quotient, see .basics
TRFError, _ValueError, _xError, _xkwds_not _conversion_, _datum_, _DOT_, _N_, _no_, \ _reframe_, _SPACE_, _0_0 property_doc_, property_RO
'''(INTERNAL) Base class for ellipsoidal C{Cartesian}s. '''
'''(INTERNAL) Apply one I{or more} Helmert transforms. '''
'''DEPRECATED, use method L{toRefFrame}.'''
'''Convert this cartesian point from one to an other reference frame.
@arg reframe2: Reference frame to convert I{to} (L{RefFrame}). @arg reframe: Reference frame to convert I{from} (L{RefFrame}). @kwarg epoch: Optional epoch to observe (C{scalar}, fractional calendar year), overriding B{C{reframe}}'s epoch.
@return: The converted point (C{Cartesian}) or this point if conversion is C{nil}.
@raise TRFError: No conversion available from B{C{reframe}} to B{C{reframe2}} or invalid B{C{epoch}}.
@raise TypeError: B{C{reframe2}} or B{C{reframe}} not a L{RefFrame}. '''
'''(INTERNAL) Base class for ellipsoidal C{LatLon}s. '''
epoch=None, name=NN): '''Create an ellipsoidal C{LatLon} point frome the given lat-, longitude and height on the given datum and with the given reference frame and epoch.
@arg lat: Latitude (C{degrees} or DMS C{[N|S]}). @arg lon: Longitude (C{degrees} or DMS C{str[E|W]}). @kwarg height: Optional elevation (C{meter}, the same units as the datum's half-axes). @kwarg datum: Optional, ellipsoidal datum to use (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg reframe: Optional reference frame (L{RefFrame}). @kwarg epoch: Optional epoch to observe for B{C{reframe}} (C{scalar}), a non-zero, fractional calendar year; silently ignored if C{B{reframe}=None}. @kwarg name: Optional name (string).
@raise RangeError: Value of B{C{lat}} or B{C{lon}} outside the valid range and C{rangerrors} set to C{True}.
@raise TypeError: B{C{datum}} is not a L{datum}, B{C{reframe}} is not a L{RefFrame} or B{C{epoch}} is not C{scalar} non-zero.
@raise UnitError: Invalid B{C{lat}}, B{C{lon}} or B{C{height}}.
@example:
>>> p = LatLon(51.4778, -0.0016) # height=0, datum=Datums.WGS84 '''
'''Return the antipode, the point diametrically opposite to this point.
@kwarg height: Optional height of the antipode, height of this point otherwise (C{meter}).
@return: The antipodal point (C{LatLon}). ''' lla.datum = self.datum
'''Get this point's UTM or UPS meridian convergence (C{degrees}) or C{None} if not available or not converted from L{Utm} or L{Ups}. '''
'''DEPRECATED, use method L{toDatum}.'''
'''DEPRECATED, use method L{toRefFrame}.'''
'''Get this point's datum (L{Datum}). '''
'''Set this point's datum I{without conversion}.
@arg datum: New datum (L{Datum}).
@raise TypeError: The B{C{datum}} is not a L{Datum} or not ellipsoidal. ''' raise _IsnotError(_ellipsoidal_, datum=datum)
'''I{Approximate} the distance and (initial) bearing between this and an other (ellipsoidal) point based on the radii of curvature.
I{Suitable only for short distances up to a few hundred Km or Miles and only between points not near-polar}.
@arg other: The other point (C{LatLon}).
@return: An L{Distance2Tuple}C{(distance, initial)}.
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: Incompatible datum ellipsoids.
@see: Method L{Ellipsoid.distance2} and U{Local, flat earth approximation<https://www.EdWilliams.org/avform.htm#flat>} aka U{Hubeny<https://www.OVG.AT/de/vgi/files/pdf/3781/>} formula. ''' other.lat, other.lon)
'''(INTERNAL) Get elevation and data source. '''
'''Return elevation of this point for its or the given datum.
@kwarg adjust: Adjust the elevation for a B{C{datum}} other than C{NAD83} (C{bool}). @kwarg datum: Optional datum (L{Datum}). @kwarg timeout: Optional query timeout (C{seconds}).
@return: An L{Elevation2Tuple}C{(elevation, data_source)} or C{(None, error)} in case of errors.
@note: The adjustment applied is the difference in geocentric earth radius between the B{C{datum}} and C{NAV83} upon which the L{elevations.elevation2} is based.
@note: NED elevation is only available for locations within the U{Conterminous US (CONUS) <https://WikiPedia.org/wiki/Contiguous_United_States>}.
@see: Function L{elevations.elevation2} and method L{Ellipsoid.Rgeocentric} for further details and possible C{error}s. '''
'''Return the ellipsoid of this point's datum or the given datum.
@kwarg datum: Default datum (L{Datum}).
@return: The ellipsoid (L{Ellipsoid} or L{Ellipsoid2}). '''
'''Check the type and ellipsoid of this and an other point's datum.
@arg other: The other point (C{LatLon}).
@return: This point's datum ellipsoid (L{Ellipsoid} or L{Ellipsoid2}).
@raise TypeError: The B{C{other}} point is not C{LatLon}.
@raise ValueError: Incompatible datum ellipsoids. '''
except AttributeError: # PYCHOK no cover try: # no ellipsoid method, try datum e = other.datum.ellipsoid except AttributeError: e = E # no datum, XXX assume equivalent? raise _ValueError(e.named2, txt=_incompatible(E.named2))
'''Get this point's observed or C{reframe} epoch (C{float}) or C{None}. '''
'''Set or clear this point's observed epoch.
@arg epoch: Observed epoch, a fractional calendar year (L{Epoch}, C{scalar}) or C{None}.
@raise TRFError: Invalid B{C{epoch}}. '''
'''Get the prefered azimuthal equidistant projection I{class} (L{EquidistantKarney} or L{EquidistantExact}). '''
'''(INTERNAL) Get this C{LatLon} point as an ETM coordinate (L{toEtm8}). '''
'''(INTERNAL) Get geoid height and model. '''
'''Return geoid height of this point for its or the given datum.
@kwarg adjust: Adjust the geoid height for a B{C{datum}} other than C{NAD83/NADV88} (C{bool}). @kwarg datum: Optional datum (L{Datum}). @kwarg timeout: Optional query timeout (C{seconds}).
@return: A L{GeoidHeight2Tuple}C{(height, model_name)} or C{(None, error)} in case of errors.
@note: The adjustment applied is the difference in geocentric earth radius between the B{C{datum}} and C{NAV83/NADV88} upon which the L{elevations.geoidHeight2} is based.
@note: The geoid height is only available for locations within the U{Conterminous US (CONUS) <https://WikiPedia.org/wiki/Contiguous_United_States>}.
@see: Function L{elevations.geoidHeight2} and method L{Ellipsoid.Rgeocentric} for further details and possible C{error}s. '''
equidistant=None, tol=_TOL_M): '''Interatively compute the intersection point of two paths, each defined by a start and end point.
@arg end1: End point of this path (C{LatLon}). @arg other: Start point of the other path (C{LatLon}). @arg end2: End point of the other path (C{LatLon}). @kwarg height: Optional height at the intersection (C{meter}, conventionally) or C{None} for the mean height. @kwarg wrap: Wrap and unroll longitudes (C{bool}). @kwarg equidistant: An azimuthal equidistant projection (I{class} or function L{equidistant}), or C{None} for this point's preferred C{.Equidistant}. @kwarg tol: Tolerance for skew line distance and length and for convergence (C{meter}, conventionally).
@return: An L{Intersection3Tuple}C{(point, outside1, outside2)} with C{point} a C{LatLon} instance.
@raise ImportError: Package U{geographiclib <https://PyPI.org/project/geographiclib>} not installed or not found, but only if C{B{equidistant}=}L{EquidistantKarney}.
@raise IntersectionError: Skew, colinear, parallel or otherwise non-intersecting paths or no convergence for the B{C{tol}}.
@raise TypeError: If B{C{end1}}, B{C{other}} or B{C{end2}} point is not C{LatLon}. ''' equidistant=equidistant, tol=tol, LatLon=self.classof, datum=self.datum) except (TypeError, ValueError) as x: raise _xError(x, start1=self, end1=end1, other=other, end2=end2)
equidistant=None, tol=_TOL_M): '''Interatively compute the intersection points of two circles, each defined by a center point and a radius.
@arg radius1: Radius of this circle (C{meter}, conventionally). @arg other: Center of the other circle (C{LatLon}). @arg radius2: Radius of the other circle (C{meter}, same units as B{C{radius1}}). @kwarg height: Optional height for the intersection points (C{meter}, conventionally) or C{None} for the I{"radical height"} at the I{radical line} between both centers. @kwarg wrap: Wrap and unroll longitudes (C{bool}). @kwarg equidistant: An azimuthal equidistant projection (I{class} or function L{equidistant}), or C{None} for this point's preferred C{.Equidistant}. @kwarg tol: Convergence tolerance (C{meter}, same units as B{C{radius1}} and B{C{radius2}}).
@return: 2-Tuple of the intersection points, each a C{LatLon} instance. For abutting circles, both intersection points are the same instance.
@raise ImportError: Package U{geographiclib <https://PyPI.org/project/geographiclib>} not installed or not found, but only if C{B{equidistant}=}L{EquidistantKarney}.
@raise IntersectionError: Concentric, antipodal, invalid or non-intersecting circles or no convergence for B{C{tol}}.
@raise TypeError: Invalid B{C{other}} or B{C{equidistant}}.
@raise UnitError: Invalid B{C{radius1}}, B{C{radius2}} or B{C{height}}.
@see: U{The B{ellipsoidal} case<https://GIS.StackExchange.com/questions/48937/ calculating-intersection-of-two-circles>}, U{Karney's paper <https://ArXiv.org/pdf/1102.1215.pdf>}, pp 20-21, section B{14. MARITIME BOUNDARIES}, U{circle-circle<https://MathWorld.Wolfram.com/Circle-CircleIntersection.html>} and U{sphere-sphere<https://MathWorld.Wolfram.com/Sphere-SphereIntersection.html>} intersections. ''' equidistant=equidistant, tol=tol, LatLon=self.classof, datum=self.datum) except (AssertionError, TypeError, ValueError) as x: raise _xError(x, center=self, radius1=radius1, other=other, radius2=radius2)
'''Get the most recent C{intersections2} or C{nearestOn} iteration number (C{int}) or C{None} if not available/applicable. '''
'''(INTERNAL) Get this C{LatLon} point to a Lambert location (L{Lcc}). '''
equidistant=None, tol=_TOL_M): '''Interatively locate the closest point between two other points.
@arg point1: Start point (C{LatLon}). @arg point2: End point (C{LatLon}). @kwarg within: If C{True} return the closest point I{between} B{C{point1}} and B{C{point2}}, otherwise the closest point elsewhere on the arc (C{bool}). @kwarg height: Optional height for the closest point (C{meter}, conventionally) or C{None} or C{False} to interpolate the height. @kwarg height: Optional height for the closest point (C{meter}, conventionally) or C{None} or C{False} for the interpolated height. If C{False}, the distance between points takes height into account. @kwarg wrap: Wrap and unroll longitudes (C{bool}). @kwarg equidistant: An azimuthal equidistant projection (I{class} or function L{equidistant}), or C{None} for this point's preferred C{.Equidistant}. @kwarg tol: Convergence tolerance (C{meter}, conventionally).
@return: Closest point (C{LatLon}).
@raise ImportError: Package U{geographiclib <https://PyPI.org/project/geographiclib>} not installed or not found, but only if C{B{equidistant}=}L{EquidistantKarney}.
@raise TypeError: Invalid B{C{point1}}, B{C{point2}} or B{C{equidistant}}.
@raise ValueError: No convergence for the B{C{tol}}. ''' height=height, wrap=wrap, equidistant=equidistant, tol=tol, LatLon=self.classof, datum=self.datum) except (TypeError, ValueError) as x: raise _xError(x, point=self, point1=point1, point2=point2)
'''(INTERNAL) Get this C{LatLon} point to an OSGR coordinate (L{Osgr}). '''
sep=_COMMA_, name=NN): '''Parse a string representing a similar, ellipsoidal C{LatLon} point, consisting of C{"lat, lon[, height]"}.
@arg strllh: Lat, lon and optional height (C{str}), see function L{parse3llh}. @kwarg height: Optional, default height (C{meter} or C{None}). @kwarg datum: Optional datum (L{Datum}), overriding this datum I{without conversion}. @kwarg epoch: Optional datum (L{Epoch}), overriding this epoch I{without conversion}. @kwarg reframe: Optional datum (L{RefFrame}), overriding this reframe I{without conversion}. @kwarg sep: Optional separator (C{str}). @kwarg name: Optional instance name (C{str}), overriding this name.
@return: The similar point (ellipsoidal C{LatLon}).
@raise ParseError: Invalid B{C{strllh}}. ''' r.datum = datum r.epoch = epoch r.reframe = reframe r = _xnamed(r, name, force=True)
'''(INTERNAL) Adjust elevation or geoidHeight with difference in Gaussian radii of curvature of given datum and NAD83.
@note: This is an arbitrary, possibly incorrect adjustment. ''' # use ratio, datum and NAD83 units may differ
'''Get this point's reference frame (L{RefFrame}) or C{None}. '''
'''Set or clear this point's reference frame.
@arg reframe: Reference frame (L{RefFrame}) or C{None}.
@raise TypeError: The B{C{reframe}} is not a L{RefFrame}. ''' self._reframe = None
'''Get this point's UTM grid or UPS point scale factor (C{float}) or C{None} if not converted from L{Utm} or L{Ups}. '''
'''Convert this point to an other datum.
@arg datum2: Datum to convert I{to} (L{Datum}). @kwarg height: Optional height, overriding the converted height (C{meter}). @kwarg name: Optional name (C{str}), iff converted.
@return: The converted point (ellipsoidal C{LatLon}) or a copy of this point if B{C{datum2}} matches this point's C{datum}.
@raise TypeError: Invalid B{C{datum2}}.
@example:
>>> p = LatLon(51.4778, -0.0016) # default Datums.WGS84 >>> p.toDatum(Datums.OSGB36) # 51.477284°N, 000.00002°E '''
LatLon=self.classof, name=n, **r)
'''Convert this C{LatLon} point to an ETM coordinate.
@return: The ETM coordinate (L{Etm}).
@see: Function L{toEtm8}. '''
'''Convert this C{LatLon} point to a Lambert location.
@see: Function L{toLcc} in module L{lcc}.
@return: The Lambert location (L{Lcc}). '''
'''Convert this C{LatLon} point to an MGRS coordinate.
@kwarg center: If C{True}, try to I{un}-center MGRS to its C{lowerleft} (C{bool}) or by C{B{center} meter} (C{scalar}).
@return: The MGRS coordinate (L{Mgrs}).
@see: Method L{Mgrs.toLatLon} and L{toUtm}. '''
'''Convert this C{LatLon} point to an OSGR coordinate.
@see: Function L{toOsgr} in module L{osgr}.
@return: The OSGR coordinate (L{Osgr}). '''
'''Convert this point to an other reference frame.
@arg reframe2: Reference frame to convert I{to} (L{RefFrame}). @kwarg height: Optional height, overriding the converted height (C{meter}). @kwarg name: Optional name (C{str}), iff converted.
@return: The converted point (ellipsoidal C{LatLon}) or this point if conversion is C{nil}, or a copy of this point if the B{C{name}} is non-empty.
@raise TRFError: This point's C{reframe} is not defined or conversion from this point's C{reframe} to B{C{reframe2}} is not available.
@raise TypeError: Invalid B{C{reframe2}}, not a L{RefFrame}.
@example:
>>> p = LatLon(51.4778, -0.0016, reframe=RefFrames.ETRF2000) # default Datums.WGS84 >>> p.toRefFrame(RefFrames.ITRF2014) # 51.477803°N, 000.001597°W, +0.01m >>> p.toRefFrame(RefFrames.ITRF2014, height=0) # 51.477803°N, 000.001597°W ''' raise TRFError(_no_(_conversion_), txt=t)
LatLon=self.classof, name=n, reframe=reframe2) else:
'''Convert this C{LatLon} point to a UPS coordinate.
@kwarg pole: Optional top/center of (stereographic) projection (C{str}, 'N[orth]' or 'S[outh]'). @kwarg falsed: False easting and northing (C{bool}).
@return: The UPS coordinate (L{Ups}).
@see: Function L{toUps8}. ''' else: from pygeodesy.ups import toUps8, Ups u = toUps8(self, datum=self.datum, Ups=Ups, pole=pole, falsed=falsed)
'''Convert this C{LatLon} point to a UTM coordinate.
@kwarg center: If C{True}, I{un}-center the UTM to its C{lowerleft} (C{bool}) or by C{B{center} meter} (C{scalar}).
@return: The UTM coordinate (L{Utm}).
@see: Method L{Mgrs.toUtm} and function L{toUtm8}. ''' else: from pygeodesy.utm import _lowerleft u = _lowerleft(self._utm, center)
'''Convert this C{LatLon} point to a UTM or UPS coordinate.
@kwarg pole: Optional top/center of UPS (stereographic) projection (C{str}, 'N[orth]' or 'S[outh]').
@return: The UTM or UPS coordinate (L{Utm} or L{Ups}).
@raise TypeError: Result in L{Utm} or L{Ups}.
@see: Function L{toUtmUps}. ''' else: # no cover from pygeodesy.utmups import toUtmUps8, Utm, Ups u = toUtmUps8(self, datum=self.datum, Utm=Utm, Ups=Ups, pole=pole, name=self.name) if isinstance(u, Utm): self._overwrite(_utm=u) elif isinstance(u, Ups): self._overwrite(_ups=u) else: _xinstanceof(Utm, Ups, toUtmUps8=u)
'''Convert this C{LatLon} point to a WM coordinate.
@see: Function L{toWm} in module L{webmercator}.
@return: The WM coordinate (L{Wm}). '''
def to3xyz(self): # PYCHOK no cover '''DEPRECATED, use method C{toEcef}.
@return: A L{Vector3Tuple}C{(x, y, z)}.
@note: Overloads C{LatLonBase.to3xyz} ''' r = self.toEcef() return Vector3Tuple(r.x, r.y, r.z, name=self.name)
area=True, eps=EPS1, wrap=False): '''Trilaterate three points by area overlap or perimeter intersection of three intersecting circles.
@arg distance1: Distance to this point (C{meter}), same units as B{C{eps}}). @arg point2: Second center point (C{LatLon}). @arg distance2: Distance to point2 (C{meter}, same units as B{C{eps}}). @arg point3: Third center point (C{LatLon}). @arg distance3: Distance to point3 (C{meter}, same units as B{C{eps}}). @kwarg area: If C{True} compute the area overlap, otherwise the perimeter intersection of the circles (C{bool}). @kwarg eps: The required I{minimal overlap} for C{B{area}=True} or the I{intersection margin} for C{B{area}=False} (C{meter}, conventionally). @kwarg wrap: Wrap/unroll angular distances (C{bool}).
@return: A L{Trilaterate5Tuple}C{(min, minPoint, max, maxPoint, n)} with C{min} and C{max} in C{meter}, same units as B{C{eps}}, the corresponding trilaterated points C{minPoint} and C{maxPoint} as I{ellipsoidal} C{LatLon} and C{n}, the number of trilatered points found for the given B{C{eps}}.
If only a single trilaterated point is found, C{min I{is} max}, C{minPoint I{is} maxPoint} and C{n = 1}.
For C{B{area}=True}, C{min} and C{max} are the smallest respectively largest I{radial} overlap found.
For C{B{area}=False}, C{min} and C{max} represent the nearest respectively farthest intersection margin.
If C{B{area}=True} and all 3 circles are concentric, C{n=0} and C{minPoint} and C{maxPoint} are the B{C{point#}} with the smallest B{C{distance#}} C{min} respectively C{max} the largest B{C{distance#}}.
@raise IntersectionError: Trilateration failed for the given B{C{eps}}, insufficient overlap for C{B{area}=True} or no intersection or all (near-)concentric for C{B{area}=False}.
@raise TypeError: Invalid B{C{point2}} or B{C{point3}}.
@raise ValueError: Coincident B{C{points}} or invalid B{C{distance1}}, B{C{distance2}} or B{C{distance3}}.
@note: Ellipsoidal trilateration invokes methods C{LatLon.intersections2} and C{LatLon.nearestOn} based on I{Karney}'s Python U{geographiclib <https://PyPI.org/project/geographiclib>} if installed, otherwise using the accurate (but slower) C{ellipsoidalExact.LatLon} methods. ''' self.others(point2=point2), distance2, self.others(point3=point3), distance3, area=area, eps=eps, wrap=wrap)
'''(INTERNAL) Get this C{LatLon} point as UPS coordinate (L{Ups}), see L{toUps8}. ''' pole=NN, falsed=True, name=self.name)
'''(INTERNAL) Check matching C{Ups}. ''' except RangeError: return False
'''(INTERNAL) Get this C{LatLon} point as UTM coordinate (L{Utm}), see L{toUtm8}. '''
'''(INTERNAL) Check C{Utm}. '''
'''(INTERNAL) Get this C{LatLon} point as webmercator (L{Wm}). '''
# **) MIT License # # Copyright (C) 2016-2021 -- 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. |