def __init__(self, x, y=None, z=None, h=0, ll=None, datum=None, name=''): '''New n-vector normal to the earth's surface. @param x: An C{Nvector}, L{Vector3Tuple}, L{Vector4Tuple} or the C{X} coordinate (C{scalar}). @param y: The C{Y} coordinate (C{scalar}) if B{C{x}} C{scalar}. @param z: The C{Z} coordinate (C{scalar}) if B{C{x}} C{scalar}. @keyword h: Optional height above surface (C{meter}). @keyword ll: Optional, original latlon (C{LatLon}). @keyword datum: Optional, I{pass-thru} datum (C{Datum}). @keyword name: Optional name (C{str}). @raise TypeError: Non-scalar B{C{x}}, B{C{y}} or B{C{z}} coordinate or B{C{x}} not an C{Nvector}, L{Vector3Tuple} or L{Vector4Tuple}. @example: >>> from pygeodesy.sphericalNvector import Nvector >>> v = Nvector(0.5, 0.5, 0.7071, 1) >>> v.toLatLon() # 45.0°N, 045.0°E, +1.00m ''' x, y, z, h, d, n = _xyzhdn6(x, y, z, h, datum, ll) Vector3d.__init__(self, x, y, z, ll=ll, name=name or n) if h: self.h = h if d: # just pass-thru self._datum = d
def __init__(self, x, y=None, z=None, h=0, ll=None, datum=None, name=NN): '''New n-vector normal to the earth's surface. @arg x: An C{Nvector}, L{Vector3Tuple}, L{Vector4Tuple} or the C{X} coordinate (C{scalar}). @arg y: The C{Y} coordinate (C{scalar}) if B{C{x}} C{scalar}. @arg z: The C{Z} coordinate (C{scalar}) if B{C{x}} C{scalar}. @kwarg h: Optional height above surface (C{meter}). @kwarg ll: Optional, original latlon (C{LatLon}). @kwarg datum: Optional, I{pass-thru} datum (L{Datum}). @kwarg name: Optional name (C{str}). @raise TypeError: Non-scalar B{C{x}}, B{C{y}} or B{C{z}} coordinate or B{C{x}} not an C{Nvector}, L{Vector3Tuple} or L{Vector4Tuple} or invalid B{C{datum}}. @example: >>> from pygeodesy.sphericalNvector import Nvector >>> v = Nvector(0.5, 0.5, 0.7071, 1) >>> v.toLatLon() # 45.0°N, 045.0°E, +1.00m ''' x, y, z, h, d, n = _xyzhdn6(x, y, z, h, datum, ll) Vector3d.__init__(self, x, y, z, ll=ll, name=name or n) if h: self.h = h if d not in (None, self._datum): _xinstanceof(Datum, datum=d) self._datum = d # pass-thru
def greatCircle(self, bearing): '''Compute the vector normal to great circle obtained by heading on the given initial bearing from this point. Direction of vector is such that initial bearing vector b = c × n, where n is an n-vector representing this point. @param bearing: Bearing from this point (compass C{degrees360}). @return: Vector representing great circle (L{Vector3d}). @example: >>> p = LatLon(53.3206, -1.7297) >>> g = p.greatCircle(96.0) >>> g.toStr() # (-0.794, 0.129, 0.594) ''' a, b = self.to2ab() t = radians(bearing) sa, ca, sb, cb, st, ct = sincos2(a, b, t) return Vector3d(sb * ct - cb * sa * st, -cb * ct - sb * sa * st, ca * st) # XXX .unit()?
def toLatLon(self, height=None, LatLon=None, datum=None, **kwds): '''Convert this n-vector to an C{Nvector}-based geodetic point. @keyword height: Optional height, overriding this n-vector's height (C{meter}). @keyword LatLon: Optional (sub-)class to return the point (L{LatLon}) or C{None}. @keyword datum: Optional, spherical datum (C{Datum}). @keyword kwds: Optional, additional C{name=value} pairs for B{C{LatLon}} instance, provided B{C{LatLon}} is not C{None}. @return: The B{C{LatLon}} point (L{LatLon}) or if C{B{LatLon}=None} or a L{LatLon3Tuple}C{(lat, lon, height)} if B{C{LatLon}} is C{None}. @raise TypeError: Invalid B{C{LatLon}}. @example: >>> v = Nvector(0.5, 0.5, 0.7071) >>> p = v.toLatLon() # 45.0°N, 45.0°E ''' h = self.h if height is None else height d = datum or self.datum # XXX use self.Cartesian(Cartesian=None) if h == self.h # and d == self.datum, for better accuracy of the height r = self.Ecef(d).forward(Vector3d.to2ll(self), height=h, M=True) if LatLon is not None: # class or .classof r = LatLon(r.lat, r.lon, r.height, datum=r.datum, **kwds) return self._xnamed(r)
def toVector3d(self): '''Return this NED vector as a 3-d vector. @return: The vector(north, east, down) (L{Vector3d}). ''' from pygeodesy.vector3d import Vector3d return Vector3d(*self.to3ned(), name=self.name)
def _x3d2(start, end, wrap, n, hs): # see <https://www.EdWilliams.org/intersect.htm> (5) ff a1, b1 = start.to2ab() if isscalar(end): # bearing, make a point a2, b2 = _destination2_(a1, b1, PI_4, radians(end)) else: # must be a point _Trll.others(end, name='end' + n) hs.append(end.height) a2, b2 = end.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) if max(abs(db), abs(a2 - a1)) < EPS: raise ValueError('intersection %s%s null: %r' % ('path', n, (start, end))) # note, in EdWilliams.org/avform.htm W is + and E is - b21, b12 = db * 0.5, -(b1 + b2) * 0.5 sb21, cb21, sb12, cb12, \ sa21, _, sa12, _ = sincos2(b21, b12, a1 - a2, a1 + a2) x = Vector3d(sa21 * sb12 * cb21 - sa12 * cb12 * sb21, sa21 * cb12 * cb21 + sa12 * sb12 * sb21, cos(a1) * cos(a2) * sin(db), ll=start) return x.unit(), (db, (a2 - a1)) # negated d
def toVector3d(self): '''Convert this n-vector to a normalized 3-d vector, I{ignoring the height}. @return: Normalized vector (L{Vector3d}). ''' u = self.unit() return Vector3d(u.x, u.y, u.z, name=self.name)
def toVector3d(self): '''Convert this point to a vector normal to earth's surface. @return: Vector representing this point (L{Vector3d}). ''' if self._v3d is None: x, y, z = self.to3xyz() self._v3d = Vector3d(x, y, z) # XXX .unit() return self._v3d
def __init__(self, xyz, y=None, z=None, datum=None, ll=None, name=NN): '''New C{Cartesian...}. @arg xyz: An L{Ecef9Tuple}, L{Vector3Tuple}, L{Vector4Tuple} or the C{X} coordinate (C{scalar}). @arg y: The C{Y} coordinate (C{scalar}) if B{C{xyz}} C{scalar}. @arg z: The C{Z} coordinate (C{scalar}) if B{C{xyz}} C{scalar}. @kwarg datum: Optional datum (L{Datum}). @kwarg ll: Optional, original latlon (C{LatLon}). @kwarg name: Optional name (C{str}). @raise TypeError: Non-scalar B{C{xyz}}, B{C{y}} or B{C{z}} coordinate or B{C{xyz}} not an L{Ecef9Tuple}, L{Vector3Tuple} or L{Vector4Tuple}. ''' x, y, z, _, d, n = _xyzhdn6(xyz, y, z, None, datum, ll) Vector3d.__init__(self, x, y, z, ll=ll, name=name or n) if d: self.datum = d
def toStr(self, prec=3, fmt='[%s]', sep=', '): # PYCHOK expected '''Return the string representation of this cartesian. @keyword prec: Optional number of decimals, unstripped (C{int}). @keyword fmt: Optional enclosing backets format (string). @keyword sep: Optional separator to join (string). @return: Cartesian represented as "[x, y, z]" (string). ''' return Vector3d.toStr(self, prec=prec, fmt=fmt, sep=sep)
def __init__(self, x, y, z, h=0, ll=None, name=''): '''New n-vector normal to the earth's surface. @param x: X component (C{scalar}). @param y: Y component (C{scalar}). @param z: Z component (C{scalar}). @keyword h: Optional height above surface (C{meter}). @keyword ll: Optional, original latlon (C{LatLon}). @keyword name: Optional name (C{str}). @example: >>> from pygeodesy.sphericalNvector import Nvector >>> v = Nvector(0.5, 0.5, 0.7071, 1) >>> v.toLatLon() # 45.0°N, 045.0°E, +1.00m ''' Vector3d.__init__(self, x, y, z, ll=ll, name=name) if h: self._h = scalar(h, None, name='h')
def _to3LLh(self, LL, height, **kwds): '''(INTERNAL) Helper for C{subclass.toLatLon} and C{.to3llh}. ''' h = self.h if height is None else height r = Vector3d.to2ll(self) # LatLon2Tuple if LL is None: r = r._3Tuple(h) # already ._xnamed else: r = self._xnamed(LL(r.lat, r.lon, height=h, **kwds)) return r
def toVector3d(self, norm=True): '''Convert this n-vector to a 3-D vector, I{ignoring the height}. @kwarg norm: Normalize the 3-D vector (C{bool}). @return: The (normalized) vector (L{Vector3d}). ''' u = self.unit() v = Vector3d(u.x, u.y, u.z, name=self.name) return v.unit() if norm else v
def unit(self, ll=None): '''Normalize this n-vector to unit length. @kwarg ll: Optional, original latlon (C{LatLon}). @return: Normalized vector (C{Nvector}). ''' if self._united is None: u = Vector3d.unit(self, ll=ll) # .copy() self._united = u._united = _xattrs(u, self, '_h') return self._united
def to3abh(self, height=None): '''Convert this n-vector to (geodetic) lat-, longitude in C{radians} and height. @keyword height: Optional height, overriding this n-vector's height (C{meter}). @return: A L{PhiLam3Tuple}C{(phi, lam, height)}. ''' h = self.h if height is None else height return Vector3d.to2ab(self)._3Tuple(h)
def toStr(self, prec=3, fmt=Fmt.SQUARE, sep=_COMMASPACE_): # PYCHOK expected '''Return the string representation of this cartesian. @kwarg prec: Optional number of decimals, unstripped (C{int}). @kwarg fmt: Optional enclosing backets format (string). @kwarg sep: Optional separator to join (string). @return: Cartesian represented as "[x, y, z]" (string). ''' return Vector3d.toStr(self, prec=prec, fmt=fmt, sep=sep)
def toStr(self, prec=5, fmt=_PARENTH_, sep=_COMMA_SPACE_): # PYCHOK expected '''Return a string representation of this n-vector. Height component is only included if non-zero. @kwarg prec: Optional number of decimals, unstripped (C{int}). @kwarg fmt: Optional enclosing backets format (C{str}). @kwarg sep: Optional separator between components (C{str}). @return: Comma-separated C{"(x, y, z [, h])"} enclosed in B{C{fmt}} brackets (C{str}). @example: >>> Nvector(0.5, 0.5, 0.7071).toStr() # (0.5, 0.5, 0.7071) >>> Nvector(0.5, 0.5, 0.7071, 1).toStr(-3) # (0.500, 0.500, 0.707, +1.00) ''' t = Vector3d.toStr(self, prec=prec, fmt=NN, sep=sep) if self.h: t = sep.join((t, self.hStr())) return t if not fmt else (fmt % (t,))
def toStr(self, prec=5, fmt='(%s)', sep=', '): # PYCHOK expected '''Return a string representation of this n-vector. Height component is only included if non-zero. @kwarg prec: Optional number of decimals, unstripped (C{int}). @kwarg fmt: Optional enclosing backets format (C{str}). @kwarg sep: Optional separator between components (C{str}). @return: Comma-separated C{"(x, y, z [, h])"} enclosed in B{C{fmt}} brackets (C{str}). @example: >>> Nvector(0.5, 0.5, 0.7071).toStr() # (0.5, 0.5, 0.7071) >>> Nvector(0.5, 0.5, 0.7071, 1).toStr(-3) # (0.500, 0.500, 0.707, +1.00) ''' t = Vector3d.toStr(self, prec=prec, fmt='%s', sep=sep) if self.h: t = '%s%s%s%+.2f' % (t, sep, self.H, self.h) return fmt % (t, )
def _nearestOn(p, p1, p2, within=True, height=None, wrap=True, equidistant=None, tol=_TOL_M, LatLon=None, **LatLon_kwds): # (INTERNAL) Get closet point, like L{_intersects2} above, # separated to allow callers to embellish any exceptions from pygeodesy.sphericalNvector import LatLon as _LLS from pygeodesy.vector3d import _nearestOn as _vnOn, Vector3d def _v(t, h): return Vector3d(t.x, t.y, h) _ = p.ellipsoids(p1) E = p.ellipsoids(p2) if wrap: p1 = _unrollon(p, p1) p2 = _unrollon(p, p2) p2 = _unrollon(p1, p2) r = E.rocMean(fmean_(p.lat, p1.lat, p2.lat)) e = max(m2degrees(tol, radius=r), EPS) # get the azimuthal equidistant projection A = _Equidistant2(equidistant, p.datum) # gu-/estimate initial nearestOn, spherically ... wrap=False t = _LLS(p.lat, p.lon, height=p.height).nearestOn(_LLS(p1.lat, p1.lon, height=p1.height), _LLS(p2.lat, p2.lon, height=p2.height), within=within, height=height) n = t.name h = h1 = h2 = 0 if height is False: # use height as Z component h = t.height h1 = p1.height h2 = p2.height # ... and then iterate like Karney suggests to find # tri-points of median lines, @see: references under # method LatLonEllipsoidalBase.intersections2 above c = None # force first d == c to False # closest to origin, .z to interpolate height p = Vector3d(0, 0, h) for i in range(1, _TRIPS): A.reset(t.lat, t.lon) # gu-/estimate as origin # convert points to projection space t1 = A.forward(p1.lat, p1.lon) t2 = A.forward(p2.lat, p2.lon) # compute nearestOn in projection space v = _vnOn(p, _v(t1, h1), _v(t2, h2), within=within) # convert nearestOn back to geodetic r = A.reverse(v.x, v.y) d = euclid(r.lat - t.lat, r.lon - t.lon) # break if below tolerance or if unchanged t = r if d < e or d == c: t._iteration = i # _NamedTuple._iteration if height is False: h = v.z # nearest interpolated break c = d else: raise ValueError(_no_(Fmt.convergence(tol))) r = _LatLon4Tuple(t.lat, t.lon, h, t.datum, LatLon, LatLon_kwds) r._iteration = t.iteration # ._iteration for tests return _xnamed(r, n)
def _update(self, updated): if updated: # reset cached attrs self._e9t = self._v4t = None Vector3d._update(self, updated)
def _xcopy(self, *attrs): '''(INTERNAL) Make copy with add'l, subclass attributes. ''' return Vector3d._xcopy(self, '_h', *attrs)
def _update(self, updated, *attrs): '''(INTERNAL) Zap cached attributes if updated. ''' if updated: Vector3d._update(self, updated, '_latlon', '_philam', *attrs)
def _v(t, h): return Vector3d(t.x, t.y, h)
def _update(self, updated, *attrs): '''(INTERNAL) Zap cached attributes if updated. ''' if updated: Vector3d._update(self, updated, '_e9t', '_v4t', *attrs)