예제 #1
0
    def _all(globalocals):
        from pygeodesy.interns import _dot_  # PYCHOK expected
        # collect all public module and attribute names and check
        # that modules are imported from this package, 'pygeodesy'
        # (but the latter only when not bundled with PyInstaller or
        # Py2Exe, since the file-layout is different.  Courtesy of
        # GilderGeek<https://GitHub.com/mrJean1/PyGeodesy/issues/31>)
        ns = list(lazily._ALL_INIT)
# XXX   ps = () if _isfrozen else set([_pygeodesy] + __name__.split('.'))
        for mod, attrs in lazily._ALL_LAZY.enums():
            if mod not in globalocals:
                raise ImportError('missing %s: %s' % ('module', _dot_(_pygeodesy, mod)))
            ns.append(mod)
            # check that all other public attributes do exist
            if attrs and isinstance(attrs, tuple):
                for a in attrs:
                    if a not in globalocals:
                        raise ImportError('missing %s: %s' % ('attribute', _dot_(mod, a)))
                ns.extend(attrs)
# XXX       if ps:  # check that mod is a _pygeodesy module
# XXX           m = globalocals[mod]  # assert(m.__name__ == mod)
# XXX           f = getattr(m, '__file__', NN)
# XXX           d = dirname(abspath(f)) if f else pygeodesy_abspath
# XXX           p = getattr(m, '__package__', NN) or _pygeodesy
# XXX           if p not in ps or d != pygeodesy_abspath:
# XXX               raise ImportError('foreign module: %s from %r' % (_dot_(p, mod), f or p))
        return tuple(set(ns))  # remove duplicates, only R_M?
예제 #2
0
def _all_missing2(_all_):
    '''(INTERNAL) Get deltas between pygeodesy.__all__ and lazily._all_imports.
    '''
    _alzy = _all_imports(**_NamedEnum_RO((a, ()) for a in _ALL_INIT))
    return ((_dot_('lazily', _all_imports.__name__),
             _COMMA_SPACE_.join(a for a in _all_ if a not in _alzy)),
            (_dot_('pygeodesy', '__all__'),
             _COMMA_SPACE_.join(a for a in _alzy if a not in _all_)))
예제 #3
0
 def __new__(cls, *args):
     '''New L{_NamedTuple} initialized with B{C{positional}} arguments.
     '''
     self = tuple.__new__(cls, args)
     ns = self._Names_
     if not (isinstance(ns, tuple) and len(ns) > 1):  # XXX > 0
         raise _TypeError(_dot_(self.classname, _Names_), ns)
     if len(ns) != len(args) or not ns:
         raise LenError(cls, args=len(args), ns=len(ns))
     if _name_ in ns:
         t = unstr(_dot_(self.classname, _Names_), *ns)
         raise _NameError(_name_, _name_, txt=t)
     return self
예제 #4
0
    def __getattr__(name):  # __getattr__ only for Python 3.7+
        # only called once for each undefined pygeodesy attribute
        if name in imports:
            # importlib.import_module() implicitly sets sub-modules
            # on this module as appropriate for direct imports (see
            # note in the _lazy_import.__doc__ above).
            mod, _, attr = imports[name].partition(_DOT_)
            if mod not in imports:
                raise LazyImportError('no module', txt=_dot_(parent, mod))
            imported = import_module(import_ + mod, parent)  # XXX '.' + mod
            if imported.__package__ not in (parent, '__main__', ''):
                raise LazyImportError(_dot_(mod, '__package__'),
                                      imported.__package__)
            # import the module or module attribute
            if attr:
                imported = getattr(imported, attr, _Missing)
            elif name != mod:
                imported = getattr(imported, name, _Missing)
            if imported is _Missing:
                raise LazyImportError('no attribute',
                                      txt=_dot_(mod, attr or name))

        elif name in ('__all__', ):  # XXX '__dir__', '__members__'?
            imported = _ALL_INIT + tuple(imports.keys())
            mod = NN
        else:
            raise LazyImportError('no module or attribute',
                                  txt=_dot_(parent, name))

        setattr(package, name, imported)
        if isLazy > 1:
            z = NN
            if mod and mod != name:
                z = ' from .%s' % (mod, )
            if isLazy > 2:
                # sys._getframe(1) ... 'importlib._bootstrap' line 1032,
                # may throw a ValueError('call stack not deep enough')
                try:
                    f = sys._getframe(2)  # get importing file and line
                    n = f.f_code.co_filename
                    if cwdir and n.startswith(cwdir):
                        n = n[len(cwdir):]
                    z = '%s by %s line %d' % (z, n, f.f_lineno)
                except ValueError:  # PYCHOK no cover
                    pass
            print('# lazily imported %s%s' % (_dot_(parent, name), z))

        return imported  # __getattr__
예제 #5
0
 def __getattr__(self, attr):
     try:
         return self[attr]
     except KeyError:
         t = '%s %s' % (_dot_(self._name, attr), _doesn_t_exist_
                        )  # PYCHOK _name
         raise AttributeError(t)
예제 #6
0
    def discrete(self, points, fraction=None):
        '''Compute the C{forward, discrete Fréchet} distance.

           @arg points: Second set of points (C{LatLon}[], L{Numpy2LatLon}[],
                        L{Tuple2LatLon}[] or C{other}[]).
           @kwarg fraction: Index fraction (C{float} in L{EPS}..L{EPS1}) to
                            interpolate intermediate B{C{points}} or use
                            C{None}, C{0} or C{1} for no intermediate
                            B{C{points}} and no I{fractional} indices.

           @return: A L{Frechet6Tuple}C{(fd, fi1, fi2, r, n, units)}.

           @raise FrechetError: Insufficient number of B{C{points}} or an
                                invalid B{C{point}} or B{C{fraction}}.

           @raise RecursionError: Recursion depth exceeded, see U{sys.getrecursionlimit()
                                  <https://docs.Python.org/3/library/sys.html#sys.getrecursionlimit>}.
        '''
        n2, ps2 = self._points2(points)

        f2 = _fraction(fraction, n2)
        p2 = self.points_fraction if f2 < EPS1 else self.points_  # PYCHOK expected

        f1 = self.fraction
        p1 = self.points_fraction if f1 < EPS1 else self.points_  # PYCHOK expected

        def dF(fi1, fi2):
            return self.distance(p1(self._ps1, fi1), p2(ps2, fi2))

        try:
            return _frechet_(self._n1, f1, n2, f2, dF, self.units)
        except TypeError as x:
            t = _dot_(self.classname, self.discrete.__name__)
            raise FrechetError(t, txt=str(x))
예제 #7
0
 def __getattr__(self, name):
     try:
         return tuple.__getitem__(self, self._Names_.index(name))
     except IndexError:
         raise _IndexError(_dot_(self.classname, '<name>'), name)
     except ValueError:
         return tuple.__getattribute__(self, name)
예제 #8
0
def _notError(inst, name, args, kwds):  # PYCHOK no cover
    '''(INTERNAL) Format an error message.
    '''
    n = _dot_(classname(inst, prefixed=True), _dunder_name(name, name))
    m = _COMMA_SPACE_.join(
        modulename(c, prefixed=True) for c in inst.__class__.__mro__[1:-1])
    t = '%s, MRO(%s)' % (unstr(n, *args, **kwds), m)
    return t
예제 #9
0
def _callname(name, class_name, self_name, up=1):  # imported by .points
    '''(INTERNAL) Assemble the name for an invokation.
    '''
    n, c = class_name, callername(up=up + 1)
    if c:
        n = _dot_(n, _item_ps(c, name))
    if self_name:
        n = '%s %r' % (n, self_name)
    return n
예제 #10
0
 def __setattr__(self, name, value):
     if name in self._Names_:
         raise _TypeError(_dot_(self.classname, name),
                          value,
                          txt=_immutable_)
     elif name in (_name_, _name):
         _Named.__setattr__(self, name,
                            value)  # XXX _Named.name.fset(self, value)
     else:
         tuple.__setattr__(self, name, value)
예제 #11
0
 def __delattr__(self, name):
     if name in self._Names_:
         raise _TypeError('del',
                          _dot_(self.classname, name),
                          txt=_immutable_)
     elif name in (_name_, _name):
         _Named.__setattr__(self, name,
                            '')  # XXX _Named.name.fset(self, '')
     else:
         tuple.__delattr__(self, name)
예제 #12
0
    def __getattr__(name):  # __getattr__ only for Python 3.7+
        # only called once for each undefined pygeodesy attribute
        if name in imports:
            # importlib.import_module() implicitly sets sub-modules
            # on this module as appropriate for direct imports (see
            # note in the _lazy_import.__doc__ above).
            mod, _, attr = imports[name].partition(_DOT_)
            if mod not in imports:
                raise LazyImportError('no module', txt=_dot_(parent, mod))
            imported = import_module(import_ + mod, parent)  # XXX '.' + mod
            if imported.__package__ not in (parent, '__main__', NN):
                raise LazyImportError(_dot_(mod, '__package__'),
                                      imported.__package__)
            # import the module or module attribute
            if attr:
                imported = getattr(imported, attr, _Missing)
            elif name != mod:
                imported = getattr(imported, name, _Missing)
            if imported is _Missing:
                raise LazyImportError('no attribute',
                                      txt=_dot_(mod, attr or name))

        elif name in ('__all__', ):  # XXX '__dir__', '__members__'?
            imported = _ALL_INIT + tuple(imports.keys())
            mod = NN
        else:
            raise LazyImportError('no module or attribute',
                                  txt=_dot_(parent, name))

        setattr(package, name, imported)
        if isLazy > 1:
            z = NN
            if mod and mod != name:
                z = ' from .%s' % (mod, )
            if isLazy > 2:
                try:  # see _caller3
                    _, f, s = _caller3(2)
                    z = '%s by %s line %d' % (z, f, s)
                except ValueError:  # PYCHOK no cover
                    pass
            print('# lazily imported %s%s' % (_dot_(parent, name), z))

        return imported  # __getattr__
예제 #13
0
def clipCS3(points, lowerleft, upperright, closed=False, inull=False):
    '''Clip a path against a rectangular clip box using the
       U{Cohen-Sutherland
       <https://WikiPedia.org/wiki/Cohen-Sutherland_algorithm>} algorithm.

       @arg points: The points (C{LatLon}[]).
       @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}).
       @arg upperright: Top-right corner of the clip box (C{LatLon}).
       @kwarg closed: Optionally, close the path (C{bool}).
       @kwarg inull: Optionally, include null edges if inside (C{bool}).

       @return: Yield a L{ClipCS3Tuple}C{(start, end, index)} for each
                edge of the clipped path.

       @raise ClipError: The B{C{lowerleft}} and B{C{upperright}} corners
                         specify an invalid clip box.

       @raise PointsError: Insufficient number of B{C{points}}.
    '''

    cs = _CS(lowerleft, upperright, name=clipCS3.__name__)
    n, pts = _points2(points, closed, inull)

    i, m = _imdex2(closed, n)
    cmbp = cs.code4(pts[i])
    for i in range(m, n):
        c1, m1, b1, p1 = cmbp
        c2, m2, b2, p2 = cmbp = cs.code4(pts[i])
        if c1 & c2:  # edge outside
            continue

        if not cs.edge(p1, p2):
            if inull:  # null edge
                if not c1:
                    yield ClipCS3Tuple(p1, p1, i)
                elif not c2:
                    yield ClipCS3Tuple(p2, p2, i)
            continue

        for _ in range(5):
            if c1:  # clip p1
                c1, m1, b1, p1 = m1(b1, p1)
            elif c2:  # clip p2
                c2, m2, b2, p2 = m2(b2, p2)
            else:  # inside
                if inull or _neq(p1, p2):
                    yield ClipCS3Tuple(p1, p2, i)
                break
            if c1 & c2:  # edge outside
                break
        else:  # PYCHOK no cover
            raise _AssertionError(_dot_(cs.name, 'for_else'))
예제 #14
0
 def intersect(self, p1, p2, edge):  # compute intersection
     # of polygon edge p1 to p2 and the current clip edge,
     # where p1 and p2 are known to NOT be located on the
     # same side or on top of the current clip edge
     # <https://StackOverflow.com/questions/563198/
     #        how-do-you-detect-where-two-line-segments-intersect>
     fy = float(p2.lat - p1.lat)
     fx = float(p2.lon - p1.lon)
     fp = fy * self._dx - fx * self._dy
     if abs(fp) < EPS:  # PYCHOK no cover
         raise _AssertionError(_dot_(self.name, self.intersect.__name__))
     r = fsum_(self._xy, -p1.lat * self._dx, p1.lon * self._dy) / fp
     y = p1.lat + r * fy
     x = p1.lon + r * fx
     return _LLi_(y, x, p1.classof, edge)
예제 #15
0
def modulename(clas, prefixed=None):
    '''Return the class name optionally prefixed with the
       module name.

       @arg clas: The class (any C{class}).
       @kwarg prefixed: Include the module name (C{bool}), see
                        function C{classnaming}.

       @return: The B{C{class}}'s C{[module.]class} name (C{str}).
    '''
    try:
        n = clas.__name__
    except AttributeError:
        n = '--'
    if prefixed or (classnaming() if prefixed is None else False):
        try:
            m = clas.__module__.rsplit(_DOT_, 1)
            n = _dot_(*(m[1:] + [n]))
        except AttributeError:
            pass
    return n
예제 #16
0
    def register(self, item):
        '''Registed a new item.

           @arg item: The item (any C{type}).

           @return: The item name (C{str}).

           @raise NameError: An B{C{item}} already registered with
                             that name or the B{C{item}} has no, an
                             empty or an invalid name.

           @raise TypeError: The B{C{item}} type invalid.
        '''
        try:
            n = item.name
            if not (n and n.replace(_UNDERSCORE_, NN).isalnum() and isstr(n)):
                raise ValueError
        except (AttributeError, ValueError, TypeError) as x:
            raise _NameError(_dot_('item', _name_), item, txt=str(x))
        if n in self:
            raise _NameError(self._dot_(n), item, txt='exists')
        if not (self._item_Classes and isinstance(item, self._item_Classes)):
            raise _TypesError(self._dot_(n), item, *self._item_Classes)
        self[n] = item
예제 #17
0
def _lazy_import2(_package_):  # MCCABE 15
    '''Check for and set up lazy importing.

       @arg _package_: The name of the package (C{str}) performing
                       the imports, to help facilitate resolving
                       relative imports, usually C{__package__}.

       @return: 2-Tuple C{(package, getattr)} of the importing package
                for easy reference within itself and the callable to
                be set to `__getattr__`.

       @raise LazyImportError: Lazy import not supported or not enabled,
                               an import failed or the package name or
                               module name or attribute name is invalid
                               or does not exist.

       @note: This is the original function U{modutil.lazy_import
              <https://GitHub.com/brettcannon/modutil/blob/master/modutil.py>}
              modified to handle the C{__all__} and C{__dir__} attributes
              and call C{importlib.import_module(<module>.<name>, ...)}
              without causing a C{ModuleNotFoundError}.

       @see: The original U{modutil<https://PyPi.org/project/modutil>} and
             U{PEP 562<https://www.Python.org/dev/peps/pep-0562>}.
    '''
    if _sys.version_info[:2] < (3, 7):  # not supported before 3.7
        t = 'no ' + _dot_(_package_, _lazy_import2.__name__)
        raise LazyImportError(t, txt='Python ' + _sys.version.split()[0])

    import_module, package, parent = _lazy_init3(_package_)

    import_ = _dot_(_package_, NN)  # namespace
    imports = _all_imports()

    def __getattr__(name):  # __getattr__ only for Python 3.7+
        # only called once for each undefined pygeodesy attribute
        if name in imports:
            # importlib.import_module() implicitly sets sub-modules
            # on this module as appropriate for direct imports (see
            # note in the _lazy_import.__doc__ above).
            mod, _, attr = imports[name].partition(_DOT_)
            if mod not in imports:
                raise LazyImportError('no module', txt=_dot_(parent, mod))
            imported = import_module(import_ + mod, parent)  # XXX '.' + mod
            if imported.__package__ not in (parent, '__main__', NN):
                raise LazyImportError(_dot_(mod, '__package__'),
                                      imported.__package__)
            # import the module or module attribute
            if attr:
                imported = getattr(imported, attr, _Missing)
            elif name != mod:
                imported = getattr(imported, name, _Missing)
            if imported is _Missing:
                raise LazyImportError('no attribute',
                                      txt=_dot_(mod, attr or name))

        elif name in ('__all__', ):  # XXX '__dir__', '__members__'?
            imported = _ALL_INIT + tuple(imports.keys())
            mod = NN
        else:
            raise LazyImportError('no module or attribute',
                                  txt=_dot_(parent, name))

        setattr(package, name, imported)
        if isLazy > 1:
            z = NN
            if mod and mod != name:
                z = ' from .%s' % (mod, )
            if isLazy > 2:
                try:  # see _caller3
                    _, f, s = _caller3(2)
                    z = '%s by %s line %d' % (z, f, s)
                except ValueError:  # PYCHOK no cover
                    pass
            print('# lazily imported %s%s' % (_dot_(parent, name), z))

        return imported  # __getattr__

    return package, __getattr__  # _lazy_import2
예제 #18
0
 def _dot_(self, name):
     '''(INTERNAL) Period-join C{self.name} and C{name}.
     '''
     return _dot_(self.name, name)
예제 #19
0
 def __setattr__(self, attr, value):
     t = 'Read_Only %s = %r' % (_dot_(self._name, attr), value
                                )  # PYCHOK _name
     raise TypeError(t)
예제 #20
0
 def name2(self):
     '''Get the conic and datum names as "conic.datum" (C{str}).
     '''
     return _dot_(self.name, self.datum.name)
예제 #21
0
 def nop4(self, b, p):  # PYCHOK no cover
     if p:  # should never get here
         raise _AssertionError(_dot_(self.name, self.nop4.__name__))
     return _CS._IN, self.nop4, b, p
예제 #22
0
    def toLatLon(self, LatLon=None, datum=Datums.WGS84):
        '''Convert this OSGR coordinate to an (ellipsoidal) geodetic
           point.

           While OS grid references are based on the OSGB36 datum, the
           I{Ordnance Survey} have deprecated the use of OSGB36 for
           lat-/longitude coordinates (in favour of WGS84). Hence, this
           method returns WGS84 by default with OSGB36 as an option,
           U{see<https://www.OrdnanceSurvey.co.UK/blog/2014/12/2>}.

           I{Note formulation implemented here due to Thomas, Redfearn,
           etc. is as published by OS, but is inferior to Krüger as
           used by e.g. Karney 2011.}

           @kwarg LatLon: Optional ellipsoidal class to return the
                          geodetic point (C{LatLon}) or C{None}.
           @kwarg datum: Optional datum to convert to (L{Datum},
                         L{Ellipsoid}, L{Ellipsoid2}, L{Ellipsoid2}
                         or L{a_f2Tuple}).

           @return: The geodetic point (B{C{LatLon}}) or a
                    L{LatLonDatum3Tuple}C{(lat, lon, datum)}
                    if B{C{LatLon}} is C{None}.

           @raise OSGRError: No convergence.

           @raise TypeError: If B{C{LatLon}} is not ellipsoidal or
                             B{C{datum}} is invalid or conversion failed.

           @example:

           >>> from pygeodesy import ellipsoidalVincenty as eV
           >>> g = Osgr(651409.903, 313177.270)
           >>> p = g.toLatLon(eV.LatLon)  # 52°39′28.723″N, 001°42′57.787″E
           >>> # to obtain (historical) OSGB36 lat-/longitude point
           >>> p = g.toLatLon(eV.LatLon, datum=Datums.OSGB36)  # 52°39′27.253″N, 001°43′04.518″E
        '''
        if self._latlon:
            return self._latlon3(LatLon, datum)

        E = self.datum.ellipsoid  # _Datums_OSGB36.ellipsoid, Airy130
        a_F0 = E.a * _F0
        b_F0 = E.b * _F0

        e, n = self.easting, self.northing
        n_N0 = n - _N0

        a, m = _A0, n_N0
        sa = Fsum(a)
        for self._iteration in range(1, _TRIPS):
            a = sa.fsum_(m / a_F0)
            m = n_N0 - b_F0 * _M(E.Mabcd, a)  # meridional arc
            if abs(m) < _10um:
                break
        else:
            t = _dot_(_item_ps(self.classname, self.toStr(prec=-3)),
                      self.toLatLon.__name__)
            raise OSGRError(_no_convergence_, txt=t)
        sa, ca = sincos2(a)

        s = E.e2s2(sa)  # r, v = E.roc2_(sa, _F0)
        v = a_F0 / sqrt(s)  # nu
        r = v * E.e12 / s  # rho = a_F0 * E.e12 / pow(s, 1.5) == a_F0 * E.e12 / (s * sqrt(s))

        vr = v / r  # == s / E.e12
        x2 = vr - 1  # η2
        ta = tan(a)

        v3, v5, v7 = fpowers(v, 7, 3)  # PYCHOK false!
        ta2, ta4, ta6 = fpowers(ta**2, 3)  # PYCHOK false!

        tar = ta / r
        V4 = (a, tar / (2 * v), tar / (24 * v3) * fdot(
            (1, 3, -9), 5 + x2, ta2, ta2 * x2), tar / (720 * v5) * fdot(
                (61, 90, 45), 1, ta2, ta4))

        csa = 1.0 / ca
        X5 = (_B0, csa / v, csa / (6 * v3) * fsum_(vr, ta2, ta2),
              csa / (120 * v5) * fdot(
                  (5, 28, 24), 1, ta2, ta4), csa / (5040 * v7) * fdot(
                      (61, 662, 1320, 720), 1, ta2, ta4, ta6))

        d, d2, d3, d4, d5, d6, d7 = fpowers(e - _E0, 7)  # PYCHOK false!
        a = fdot(V4, 1, -d2, d4, -d6)
        b = fdot(X5, 1, d, -d3, d5, -d7)

        r = _LLEB(degrees90(a),
                  degrees180(b),
                  datum=self.datum,
                  name=self.name)
        r._iteration = self._iteration  # only ellipsoidal LatLon
        self._latlon = r
        return self._latlon3(LatLon, datum)
예제 #23
0
if __name__ == '__main__':

    from sys import argv, exit  # PYCHOK shadows exit

    from pygeodesy.lazily import _FOR_DOCS

    if not _FOR_DOCS:
        exit('%s\n' %
             (' '.join('usage: env PYGEODESY_FOR_DOCS=1 python -m'.split() +
                       argv), ))

    ls = locals()
    for n in __all__:
        if n not in ls:
            raise NameError('%s %r not in %s' %
                            ('__all__', n, _dot_('named', 'locals')))
    for n, o in ls.items():
        if n not in __all__ and not n.startswith(_UNDERSCORE_) \
                            and getattr(o, '__module__', '') == __name__:
            raise NameError('%s %r not in %s' %
                            ('locals', n, _dot_('named', '__all__')))

    print('%s: %s vs %s OK' % (argv[0], '__all__', 'locals'))

# **) MIT License
#
# Copyright (C) 2016-2020 -- 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