def __init__(self, a_ellipsoid, f, name): '''(INTERNAL) New C{Ecef...}. ''' try: E = a_ellipsoid if f is None: if isinstance(E, Datum): self._datum = E E = E.ellipsoid elif not isinstance(E, Ellipsoid): raise TypeError self.name = E.name elif isscalar(E) and isscalar(f): a = float(E) f_ = (1.0 / f) if f else 0 # sphere b = None if f_ else a E = Ellipsoid(a, b, f_, name='_' + name) else: raise ValueError if not (E.a > 0 and E.f < 1): raise ValueError except (TypeError, ValueError): t = unStr(self.classname, a=E, f=f) raise EcefError('%s invalid: %s' % ('ellipsoid', t)) self._E = E if name: self.name = name
def _height(self, lats, lons, Error=HeightError): if isscalar(lats) and isscalar(lons): llis = LatLon_(lats, lons) else: n, lats = len2(lats) m, lons = len2(lons) if n != m: raise Error('non-matching %s: %s vs %s' % ('len', n, m)) llis = [LatLon_(*ll) for ll in zip(lats, lons)] return self(llis) # __call__(lli) or __call__(llis)
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 fractional(points, fi, LatLon=None): '''Return the point at a given fractional index. @param points: The points (C{LatLon}[], C{Numpy2LatLon}[], C{Tuple2LatLon}[] or C{other}[]). @param fi: The fractional index (C{int} or C{float}). @keyword LatLon: Optional (sub-)class to return the I{intermediate} point (C{LatLon}) or C{None}. @return: The B{C{points}}[B{C{fi}}] if fractional index B{C{fi}} is C{int}, otherwise the intermediate point at C{float} B{C{fi}} (B{C{LatLon}} or a L{LatLon2Tuple}C{(lat, lon)} if B{C{LatLon}} is C{None}). @raise IndexError: Fractional index B{C{fi}} invalid or B{C{points}} not subscriptable. ''' try: if not (isscalar(fi) and 0 <= fi < len(points)): raise IndexError p = _fractional(points, fi) except (IndexError, TypeError): raise IndexError('%s invalid: %r' % ('fractional', fi)) if LatLon and isinstance(p, LatLon2Tuple): p = LatLon(*p) return p
def toStr(self, prec=3, sep=' ', radius=False): # PYCHOK expected '''Return a string representation of this WM coordinate. @keyword prec: Optional number of decimals, unstripped (C{int}). @keyword sep: Optional separator to join (C{str}). @keyword radius: Optionally, include radius (C{bool} or C{scalar}). @return: This WM as "meter meter" (C{str}) plus " radius" if B{C{radius}} is C{True} or C{scalar}. @raise WebMercatorError: Invalid B{C{radius}}. @example: >>> w = Wm(448251, 5411932.0001) >>> w.toStr(4) # 448251.0 5411932.0001 >>> w.toStr(sep=', ') # 448251, 5411932 ''' fs = self._x, self._y if radius in (False, None): pass elif radius is True: fs += (self._radius,) elif isscalar(radius): fs += (radius,) else: raise WebMercatorError('% invalid: %r' % ('radius', radius)) return fStr(fs, prec=prec, sep=sep)
def _fraction(fraction): f = 1 # int, no fractional indices if fraction is None: pass elif not (isscalar(fraction) and EPS < fraction <= 1): raise FrechetError('%s invalid: %r' % ('fraction', fraction)) elif fraction < EPS1: f = float(fraction) return f
def __init__(self, knots, weight=None, name=''): '''New L{HeightLSQBiSpline} interpolator. @param knots: The points with known height (C{LatLon}s). @keyword weight: Optional weight or weights for each B{C{knot}} (C{scalar} or C{scalar}s). @keyword name: Optional height interpolator name (C{str}). @raise HeightError: Insufficient number of B{C{knots}} or B{C{weight}}s or invalid B{C{knot}} or B{C{weight}}. @raise ImportError: Package C{numpy} or C{scipy} not found or not installed. @raise SciPyError: A C{LSQSphereBivariateSpline} issue. @raise SciPyWarning: A C{LSQSphereBivariateSpline} warning as exception. ''' np, spi = self._NumSciPy() xs, ys, hs = self._xyhs3(knots) m = len(hs) if not weight: w = None # default elif isscalar(weight): w = float(weight) if w <= 0: raise HeightError('invalid %s: %.6f' % ('weight', w)) else: n, w = len2(weight) if n != m: raise HeightError('invalid %s: %s, not %s' % ('number of weights', n, m)) w = np.array(map(float, w)) for i in range(m): if w[i] <= 0: raise HeightError('invalid %s[%s]: %.6f' % ('weight', i, w[i])) try: T = 1.0e-4 # like SciPy example ps = np.array(_ordedup(xs, T, PI2 - T)) ts = np.array(_ordedup(ys, T, PI - T)) self._ev = spi.LSQSphereBivariateSpline(ys, xs, hs, ts, ps, eps=EPS, w=w).ev except Exception as x: raise _SciPyIssue(x) if name: self.name = name
def times(self, factor): '''Multiply this vector by a scalar. @param factor: Scale factor (C{scalar}). @return: New, scaled vector (L{Vector3d}). @raise TypeError: Non-scalar B{C{factor}}. ''' if not isscalar(factor): raise _IsNotError('scalar', factor=factor) return self.classof(self.x * factor, self.y * factor, self.z * factor)
def _gc3(self, start, end, namend, raiser='points'): '''(INTERNAL) Return great circle, start and end Nvectors. ''' s = start.toNvector() if isscalar(end): # bearing gc = s.greatCircle(end) e = None else: self.others(end, name=namend) e = end.toNvector() gc = s.cross(e, raiser=raiser) # XXX .unit()? return gc, s, e
def dividedBy(self, factor): '''Divide this vector by a scalar. @param factor: The divisor (C{scalar}). @return: New, scaled vector (L{Vector3d}). @raise TypeError: Non-scalar B{C{factor}}. @raise VectorError: Invalid or zero B{C{factor}}. ''' if not isscalar(factor): raise _IsNotError('scalar', factor=factor) try: return self.times(1.0 / factor) except (ValueError, ZeroDivisionError): raise VectorError('%s invalid: %r' % ('factor', factor))
def _to3zBhp(zone, band, hemipole=''): # imported by .epsg, .ups, .utm, .utmups '''Parse UTM/UPS zone, Band letter and hemisphere/pole letter. @param zone: Zone with/-out Band (C{scalar} or C{str}). @keyword band: Optional (longitudinal/polar) Band letter (C{str}). @keyword hemipole: Optional hemisphere/pole letter (C{str}). @return: 3-Tuple (C{zone, Band, hemisphere/pole}) as (C{int, str, 'N'|'S'}) where C{zone} is C{0} for UPS or C{1..60} for UTM and C{Band} is C{'A'..'Z'} I{NOT} checked for valid UTM/UPS bands. @raise ValueError: Invalid B{C{zone}}, B{C{band}} or B{C{hemipole}}. ''' B = band try: z = _UTMUPS_ZONE_INVALID if isscalar(zone) or zone.isdigit(): z = int(zone) elif zone and isinstance(zone, _Strs): if len(zone) > 1: B = zone[-1:] z = int(zone[:-1]) elif zone in 'AaBbYyZz': # single letter B = zone z = _UPS_ZONE if _UTMUPS_ZONE_MIN <= z <= _UTMUPS_ZONE_MAX: hp = hemipole[:1].upper() if hp in ('N', 'S') or not hp: B = B.upper() if B.isalpha(): return z, B, (hp or ('S' if B < 'N' else 'N')) elif not B: return z, B, hp except (AttributeError, TypeError, ValueError): pass raise ValueError('%s, %s or %s invalid: %r' % ('zone', 'band', 'hemipole', (zone, B, hemipole)))
def intersection(start1, end1, start2, end2, height=None, wrap=False, LatLon=LatLon): '''Compute the intersection point of two paths both defined by two points or a start point and bearing from North. @param start1: Start point of the first path (L{LatLon}). @param end1: End point ofthe first path (L{LatLon}) or the initial bearing at the first start point (compass C{degrees360}). @param start2: Start point of the second path (L{LatLon}). @param end2: End point of the second path (L{LatLon}) or the initial bearing at the second start point (compass C{degrees360}). @keyword height: Optional height for the intersection point, overriding the mean height (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @keyword LatLon: Optional (sub-)class to return the intersection point (L{LatLon}) or C{None}. @return: The intersection point (B{C{LatLon}}) or a L{LatLon3Tuple}C{(lat, lon, height)} if B{C{LatLon}} is C{None}. An alternate intersection point might be the L{antipode} to the returned result. @raise TypeError: A B{C{start}} or B{C{end}} point not L{LatLon}. @raise ValueError: Intersection is ambiguous or infinite or the paths are parallel, coincident or null. @example: >>> p = LatLon(51.8853, 0.2545) >>> s = LatLon(49.0034, 2.5735) >>> i = intersection(p, 108.547, s, 32.435) # '50.9078°N, 004.5084°E' ''' _Trll.others(start1, name='start1') _Trll.others(start2, name='start2') hs = [start1.height, start2. height] a1, b1 = start1.to2ab() a2, b2 = start2.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) r12 = haversine_(a2, a1, db) if abs(r12) < EPS: # [nearly] coincident points a, b = map1(degrees, favg(a1, a2), favg(b1, b2)) # see <https://www.EdWilliams.org/avform.htm#Intersection> elif isscalar(end1) and isscalar(end2): # both bearings sa1, ca1, sa2, ca2, sr12, cr12 = sincos2(a1, a2, r12) x1, x2 = (sr12 * ca1), (sr12 * ca2) if abs(x1) < EPS or abs(x2) < EPS: raise ValueError('intersection %s: %r vs %r' % ('parallel', (start1, end1), (start2, end2))) # handle domain error for equivalent longitudes, # see also functions asin_safe and acos_safe at # <https://www.EdWilliams.org/avform.htm#Math> t1, t2 = map1(acos1, (sa2 - sa1 * cr12) / x1, (sa1 - sa2 * cr12) / x2) if sin(db) > 0: t12, t21 = t1, PI2 - t2 else: t12, t21 = PI2 - t1, t2 t13, t23 = map1(radiansPI2, end1, end2) x1, x2 = map1(wrapPI, t13 - t12, # angle 2-1-3 t21 - t23) # angle 1-2-3 sx1, cx1, sx2, cx2 = sincos2(x1, x2) if sx1 == 0 and sx2 == 0: # max(abs(sx1), abs(sx2)) < EPS raise ValueError('intersection %s: %r vs %r' % ('infinite', (start1, end1), (start2, end2))) sx3 = sx1 * sx2 # if sx3 < 0: # raise ValueError('intersection %s: %r vs %r' % ('ambiguous', # (start1, end1), (start2, end2))) x3 = acos1(cr12 * sx3 - cx2 * cx1) r13 = atan2(sr12 * sx3, cx2 + cx1 * cos(x3)) a, b = _destination2(a1, b1, r13, t13) # choose antipode for opposing bearings if _xb(a1, b1, end1, a, b, wrap) < 0 or \ _xb(a2, b2, end2, a, b, wrap) < 0: a, b = antipode(a, b) else: # end point(s) or bearing(s) x1, d1 = _x3d2(start1, end1, wrap, '1', hs) x2, d2 = _x3d2(start2, end2, wrap, '2', hs) x = x1.cross(x2) if x.length < EPS: # [nearly] colinear or parallel paths raise ValueError('intersection %s: %r vs %r' % ('colinear', (start1, end1), (start2, end2))) a, b = x.to2ll() # choose intersection similar to sphericalNvector d1 = _xdot(d1, a1, b1, a, b, wrap) d2 = _xdot(d2, a2, b2, a, b, wrap) if (d1 < 0 and d2 > 0) or (d1 > 0 and d2 < 0): a, b = antipode(a, b) h = fmean(hs) if height is None else height r = LatLon3Tuple(a, b, h) if LatLon is None else \ LatLon(a, b, height=h) return _xnamed(r, intersection.__name__)
def _2epoch(epoch): # imported by .ellipsoidalBase.py '''(INTERNAL) Validate an C{epoch}. ''' if isscalar(epoch) and epoch > 0: # XXX 1970? return _F(epoch) raise _IsNotError('scalar', epoch=epoch)
def _2epoch(epoch): # imported by .ellipsoidalBase.py '''(INTERNAL) Validate an C{epoch}. ''' if isscalar(epoch) and epoch > 0: # XXX 1970? return _F(epoch) raise TypeError('%s not %s: %r' % ('epoch', 'scalar', epoch))