def toNvector(self, h=None, Nvector=None, **kwds):
        '''Convert this point to C{n-vector} (normal to the earth's
           surface) components, I{including height}.

           @keyword h: Optional height, overriding this point's
                       height (C{meter}).
           @keyword Nvector: Optional (sub-)class to return the
                             C{n-vector} components (C{Nvector})
                             or C{None}.
           @keyword kwds: Optional, additional B{C{Nvector}} keyword
                          arguments, ignored if C{B{Nvector}=None}.

           @return: A B{C{Nvector}} or an L{Vector4Tuple}C{(x, y, z, h)}
                    if C{B{Nvector}=None}.

           @raise TypeError: Invalid B{C{Nvector}} or B{C{kwds}}.
        '''
        if kwds or h not in (None, self.height):
            r = Vector3Tuple(*self.toVector3d().to3xyz())
            r = r._4Tuple(self.height if h is None else h)
            if Nvector is not None:
                r = Nvector(r.x, r.y, r.z, h=r.h, ll=self, **kwds)
        else:  # self.height, no kwds
            r = self._v4t
            if r is None:
                r = Vector3Tuple(*self.toVector3d().to3xyz())
                self._v4t = r = r._4Tuple(self.height)
            if Nvector is not None:
                r = Nvector(r.x, r.y, r.z, h=r.h, ll=self)
        return self._xnamed(r)
Exemple #2
0
def parse3d(str3d, sep=_COMMA_, name=NN, Vector=Vector3d, **Vector_kwds):
    '''Parse an C{"x, y, z"} string.

       @arg str3d: X, y and z values (C{str}).
       @kwarg sep: Optional separator (C{str}).
       @kwarg name: Optional instance name (C{str}).
       @kwarg Vector: Optional class (L{Vector3d}).
       @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments,
                           ignored if B{C{Vector=None}}.

       @return: New B{C{Vector}} or if B{C{Vector}} is C{None},
                a L{Vector3Tuple}C{(x, y, z)}.

       @raise VectorError: Invalid B{C{str3d}}.
    '''
    try:
        v = [float(v.strip()) for v in str3d.split(sep)]
        if len(v) != 3:
            raise ValueError
    except (TypeError, ValueError) as x:
        raise VectorError(str3d=str3d, txt=str(x))

    r = Vector3Tuple(*v) if Vector is None else \
              Vector(*v, **Vector_kwds)
    return _xnamed(r, name, force=True)
Exemple #3
0
    def to3xyz(self):  # overloads LatLonBase.to3xyz  # PYCHOK no cover
        '''DEPRECATED, use method C{toEcef}.

           @return: A L{Vector3Tuple}C{(x, y, z)}.
        '''
        if self._3xyz is None:
            r = self.toEcef()
            self._3xyz = Vector3Tuple(r.x, r.y, r.z)
        return self._xrenamed(self._3xyz)
    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 self._xnamed(Vector3Tuple(r.x, r.y, r.z))
Exemple #5
0
    def toVector(self, Vector=None):
        '''Return the geocentric C{(x, y, z)} coordinates as vector.

           @keyword Vector: Optional vector (sub-)class to return
                            C{(x, y, z)} or C{None}.

           @return: A C{Vector}C{(x, y, z)} instance or if B{C{Vector}}
                    is C{None} a L{Vector3Tuple}C{(x, y, z)}.
        '''
        r = Vector3Tuple(self.x, self.y, self.z) if Vector is None else \
                  Vector(self.x, self.y, self.z)  # PYCHOK x, y, z
        return self._xnamed(r)
Exemple #6
0
    def to3xyz(self):
        '''Convert this (geodetic) point to (n-)vector (normal
           to the earth's surface) x/y/z components, ignoring
           the height.

           @return: A L{Vector3Tuple}C{(x, y, z)} in C{units},
                    NOT C{meter}.
        '''
        # Kenneth Gade eqn 3, but using right-handed
        # vector x -> 0°E,0°N, y -> 90°E,0°N, z -> 90°N
        a, b = self.to2ab()
        sa, ca, sb, cb = sincos2(a, b)
        r = Vector3Tuple(ca * cb, ca * sb, sa)
        return self._xnamed(r)
Exemple #7
0
def philam2n_xyz(phi, lam):
    '''Convert lat-, longitude to C{n-vector} (normal to the
       earth's surface) X, Y and Z components.

       @arg phi: Latitude (C{radians}).
       @arg lam: Longitude (C{radians}).

       @return: A L{Vector3Tuple}C{(x, y, z)}.

       @see: Function L{latlon2n_xyz}.

       @note: These are C{n-vector} x, y and z components,
              I{NOT} geocentric ECEF x, y and z coordinates!
    '''
    # Kenneth Gade eqn 3, but using right-handed
    # vector x -> 0°E,0°N, y -> 90°E,0°N, z -> 90°N
    sa, ca, sb, cb = sincos2(phi, lam)
    return Vector3Tuple(ca * cb, ca * sb, sa)
Exemple #8
0
def sumOf(vectors, Vector=Vector3d, **kwds):
    '''Compute the vectorial sum of several vectors.

       @param vectors: Vectors to be added (L{Vector3d}[]).
       @keyword Vector: Optional class for the vectorial sum (L{Vector3d}).
       @keyword kwds: Optional, additional B{C{Vector}} keyword arguments,
                      ignored if C{B{Vector}=None}.

       @return: Vectorial sum (B{C{Vector}}).

       @raise VectorError: No B{C{vectors}}.
    '''
    n, vectors = len2(vectors)
    if n < 1:
        raise VectorError('no vectors: %r' & (n, ))

    r = Vector3Tuple(fsum(v.x for v in vectors), fsum(v.y for v in vectors),
                     fsum(v.z for v in vectors))
    if Vector is not None:
        r = Vector(r.x, r.y, r.z, **kwds)  # PYCHOK x, y, z
    return r
Exemple #9
0
def sumOf(vectors, Vector=Vector3d, **Vector_kwds):
    '''Compute the vectorial sum of several vectors.

       @arg vectors: Vectors to be added (L{Vector3d}[]).
       @kwarg Vector: Optional class for the vectorial sum (L{Vector3d}).
       @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments,
                           ignored if B{C{Vector=None}}.

       @return: Vectorial sum (B{C{Vector}}).

       @raise VectorError: No B{C{vectors}}.
    '''
    n, vectors = len2(vectors)
    if n < 1:
        raise VectorError(vectors=n, txt=_Missing)

    r = Vector3Tuple(fsum(v.x for v in vectors), fsum(v.y for v in vectors),
                     fsum(v.z for v in vectors))
    if Vector is not None:
        r = Vector(r.x, r.y, r.z, **Vector_kwds)  # PYCHOK x, y, z
    return r
    def toVector(self, Vector=None, **kwds):
        '''Convert this point to C{n-vector} (normal to the earth's
           surface) components, I{ignoring height}.

           @keyword Vector: Optional (sub-)class to return the
                            C{n-vector} components (L{Vector3d})
                            or C{None}.
           @keyword kwds: Optional, additional B{C{Vector}} keyword
                          arguments, ignored if C{B{Vector}=None}.

           @return: A B{C{Vector}} or if C{B{Vector}=None}, an
                    L{Vector3Tuple}C{(x, y, z)}.

           @raise TypeError: Invalid B{C{Vector}} or B{C{kwds}}.
        '''
        # Kenneth Gade eqn 3, but using right-handed
        # vector x -> 0°E,0°N, y -> 90°E,0°N, z -> 90°N
        a, b = self.to2ab()
        sa, ca, sb, cb = sincos2(a, b)
        r = Vector3Tuple(ca * cb, ca * sb, sa)
        if Vector is not None:
            r = Vector(r.x, r.y, r.z, **kwds)  # PYCHOK Vector3Tuple
        return self._xnamed(r)
Exemple #11
0
    def transform(self, x, y, z, inverse=False):
        '''Transform a (geocentric) Cartesian point, forward or inverse.

           @arg x: X coordinate (C{meter}).
           @arg y: Y coordinate (C{meter}).
           @arg z: Z coordinate (C{meter}).
           @kwarg inverse: Optional direction, forward or inverse (C{bool}).

           @return: A L{Vector3Tuple}C{(x, y, z)}, transformed.
        '''
        if inverse:
            _xyz = -1, -x, -y, -z
            _s1 = self.s1 - 2  # == -(1 - s * 1e-6)) == -(1 - (s1 - 1))
        else:
            _xyz = 1, x, y, z
            _s1 = self.s1
        # x', y', z' = (.tx + x * .s1 - y * .rz + z * .ry,
        #               .ty + x * .rz + y * .s1 - z * .rx,
        #               .tz - x * .ry + y * .rx + z * .s1)
        r = Vector3Tuple(fdot(_xyz, self.tx, _s1, -self.rz, self.ry),
                         fdot(_xyz, self.ty, self.rz, _s1, -self.rx),
                         fdot(_xyz, self.tz, -self.ry, self.rx, _s1))
        return self._xnamed(r)
Exemple #12
0
    def to3xyz(self):  # overloads _LatLonHeightBase.to3xyz
        '''Convert this (ellipsoidal) geodetic C{LatLon} point to
           (geocentric) cartesian x/y/z components.

           @return: A L{Vector3Tuple}C{(x, y, z)}.
        '''
        if self._3xyz is None:
            a, b = self.to2ab()
            sa, ca, sb, cb = sincos2(a, b)

            E = self.ellipsoid()
            # radius of curvature in prime vertical
            t = E.e2s2(sa)  # r, _ = E.roc2_(sa, 1)
            if t < EPS:
                r = 0
            elif t > EPS1:
                r = E.a
            else:
                r = E.a / sqrt(t)

            h = self.height
            t = (h + r) * ca
            self._3xyz = Vector3Tuple(t * cb, t * sb, (h + r * E.e12) * sa)
        return self._xrenamed(self._3xyz)
Exemple #13
0
    def to3xyz(self):
        '''Return this vector as a 3-tuple.

           @return: A L{Vector3Tuple}C{(x, y, z)}.
        '''
        return self._xnamed(Vector3Tuple(self.x, self.y, self.z))
Exemple #14
0
    def testCartesian(self, module, Sph=False, Nv=True):  # MCCABE 45

        self.subtitle(module, 'Cartesian')

        Cartesian = module.Cartesian
        LatLon = module.LatLon
        Nvector = module.Nvector if Nv else Vector4Tuple

        datum = Datums.Sphere if Sph else Datums.WGS84
        datum2 = None if Sph else Datums.WGS72
        # <https://www.Movable-Type.co.UK/scripts/geodesy/docs/
        #        latlon-nvector-ellipsoidal.js.html#line309>
        c = Cartesian(3980581, 97, 4966825, datum=datum)
        self.test('Cartesian0', c.toStr(prec=0), '[3980581, 97, 4966825]')
        self.test('Cartesian4', c.toStr(prec=4),
                  '[3980581.0, 97.0, 4966825.0]')

        self.test('isEllipsoidal', c.isEllipsoidal, not Sph)
        self.test('isSpherical', c.isSpherical, Sph)
        self.testCopy(c)

        n = c.toNvector()  # (x=0.622818, y=0.00002, z=0.782367, h=0.242887)
        t = n.classname  # Nvector.__name__
        if Nv:
            self.test(
                t, repr(n), 'Nvector(0.62538, 0.00002, 0.78032, -5918.38)'
                if Sph else 'Nvector(0.62282, 0.00002, 0.78237, +0.24)')
            self.test(
                t + '3', n.toStr(prec=3), '(0.625, 0.0, 0.78, -5918.38)'
                if Sph else '(0.623, 0.0, 0.782, +0.24)')
            self.test(
                t + '6', n.toStr(prec=6),
                '(0.625377, 0.000015, 0.780323, -5918.38)' if Sph else
                '(0.622818, 0.000015, 0.782367, +0.24)')  # PYCHOK attribute
        else:
            self.test(
                t,
                repr(n),
                '(x=0.6253769790183048, y=1.5239375097448227e-05, z=0.7803227754472505, h=-5918.3802583276365)'
                if Sph else
                '(x=0.6228177647454303, y=1.517701139112776e-05, z=0.782366941841975, h=0.24288680875513333)',
                known=True)

        for ll in (
            (50.0379, 8.5622),  # FRA
            (51.47, 0.4543),  # LHR
                # <https://www.EdWilliams.org/avform.htm#XTE>
            (degrees(0.709186), -degrees(1.287762)),  # JFK
            (33. + 57. / 60, -(118. + 24. / 60)),  # LAX
                # <https://GeographicLib.SourceForge.io/html/python/examples.html>
            (-41.32, 174.81),  # WNZ, Wellington, NZ
            (40.96, 5.50),  # SAL, Salamanca, Spain
            (40.1, 116.6),  # BJS, Beijing Airport
            (37.6, -122.4)):  # SFO
            if datum2:
                t = c.convertDatum(datum2).convertDatum(datum)
                self.test('convertDatum', t, c)  # PYCHOK attribute
            p = LatLon(*ll)
            q = p.toCartesian().toLatLon()
            t = str(q)
            self.test('LatLon', t, p,
                      known=t.endswith('m'))  # PYCHOK attribute

        # c = Cartesian(3980581, 97, 4966825, datum=datum)
        t = c.copy()
        self.test('copy', t.isequalTo(c), True)
        self.test('__eq__', t == c, True)
        self.test('__ne__', t != c, False)

        if hasattr(Cartesian, 'convertRefFrame'):
            pass  # PYCHOK attribute

        for B in (False, True):  # check return types
            t = c.__class__
            self.test('Cartesian', t, t)
            # self.testReturnType(c.Ecef,             Ecef,       c.Ecef.__name__)
            self.testReturnType(c.latlon, LatLon2Tuple, 'latlon')
            self.testReturnType(c.latlonheight, LatLon3Tuple, 'latlonheight')
            self.testReturnType(c.latlonheightdatum, LatLon4Tuple,
                                'latlonheightdatum')
            self.testReturnType(c.isequalTo(c), bool, 'isequalTo')
            self.testReturnType(c.philam, PhiLam2Tuple, 'philam')
            self.testReturnType(c.philamheight, PhiLam3Tuple, 'philamheight')
            self.testReturnType(c.philamheightdatum, PhiLam4Tuple,
                                'philamheightdatum')
            self.testReturnType(c.to3llh(), LatLon4Tuple, 'to3llh')
            self.testReturnType(c.toEcef(), Ecef9Tuple, 'toEcef')
            self.testReturnType(c.toLatLon(), Ecef9Tuple if B else LatLon,
                                'toLatLon')
            self.testReturnType(c.toNvector(), Vector4Tuple if B else Nvector,
                                'toNvector')
            self.testReturnType(c.xyz, Vector3Tuple, 'xyz')
            c = CartesianBase(c)  # PYCHOK attribute

        if hasattr(Cartesian, 'intersections2'):
            # <https://GIS.StackExchange.com/questions/48937/calculating-intersection-of-two-circles>
            c = Cartesian(-0.00323306, -0.7915, 0.61116)
            self.test('intersections2', c.toLatLon(height=0),
                      '37.673442°N, 090.234036°W')
            d = Cartesian(-0.0134464, -0.807775, 0.589337)
            self.test('intersections2', d.toLatLon(height=0),
                      '36.109987°N, 090.95367°W')
            x, y = c.intersections2(0.0312705, d, 0.0421788,
                                    radius=None)  # radii in radians
            self.test('intersections2', x.toStr(prec=6),
                      '[-0.032779, -0.784769, 0.61892]'
                      )  # -0.0327606, -0.784759, 0.618935
            self.test('intersections2', x.toLatLon(height=0),
                      '38.237342°N, 092.391779°W')  # 38.23838°N, 092.390487°W
            if y is not x:
                self.test('intersections2', y.toStr(prec=6),
                          '[0.025768, -0.798347, 0.601646]'
                          )  # 0.0257661, -0.798332, 0.601666
                self.test(
                    'intersections2', y.toLatLon(height=0),
                    '36.987868°N, 088.151309°W')  # 36.98931°N, 088.151425°W

        try:
            from pygeodesy.vector3d import intersections2

            u = Vector3Tuple(-0.00323306, -0.7915, 0.61116)
            v = Vector3Tuple(-0.0134464, -0.807775, 0.589337)
            c, r = intersections2(u, 0.0312705, v, 0.0421788, sphere=True)
            self.test('intersections2', c.toStr(prec=6),
                      '(-0.0035, -0.791926, 0.610589)')
            self.test('intersections2',
                      r.toStr(prec=6),
                      '0.031261',
                      known=True)  # XXX G and g formats may add 1 decimal
            v1, v2 = intersections2(u, 0.0312705, v, 0.0421788, sphere=False)
            self.test('intersections2', v1.toStr(prec=6),
                      '(-0.021973, -0.766467, 0)')
            if v2 is not v1:
                self.test('intersections2', v2.toStr(prec=6),
                          '(0.027459, -0.797488, 0)')
        except ImportError:
            pass
Exemple #15
0
 def xyz(self):
     '''Get the X, Y and Z components (L{Vector3Tuple}C{(x, y, z)}).
     '''
     if self._xyz is None:
         self._xyz = Vector3Tuple(self.x, self.y, self.z)
     return self._xnamed(self._xyz)
Exemple #16
0
 def xyz(self):
     '''Get the geocentric C{(x, y, z)} coordinates (L{Vector3Tuple}C{(x, y, z)}).
     '''
     return self._xnamed(Vector3Tuple(self.x, self.y, self.z))