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 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 I{radius} is C{True} or C{scalar}. @raise ValueError: Invalid I{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 ValueError('% invalid: %r' % ('radius', radius)) return fStr(fs, prec=prec, sep=sep)
def _toZBlat3(zone, band, mgrs=False): # used by mgrs.Mgrs '''(INTERNAL) Check and return zone, Band and band latitude. @param zone: Zone number or string. @param band: Band letter. @param mgrs: Optionally, raise UTMError (C{bool}). @return: 3-Tuple (zone, Band, latitude). ''' try: if isscalar(zone) or zone.isdigit(): z, B, x = int(zone), str(band), band else: z, B, x = int(zone[:-1] or 0), zone[-1:], zone if 1 > z or z > 60: raise ValueError except (AttributeError, TypeError, ValueError): raise UTMError('%s invalid: %r' % ('zone', zone)) b = None if B: b = _Bands.find(B) if b < 0: raise UTMError('%s invalid: %r' % ('band', x)) b = (b << 3) - 80 elif mgrs: raise UTMError('%s missing' % ('band', )) return z, B, b
def _x3d2(start, end, wrap, n): # see <http://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) 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 cb21, cb12 = map1(cos, b21, b12) sb21, sb12 = map1(sin, b21, b12) sa21, sa12 = map1(sin, 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 __init__(self, knots, weight=None): '''New L{HeightLSQBiSpline} interpolator. @param knots: The points with known height (C{LatLon}s). @keyword weight: Optional weight or weights for each I{knot} (C{scalar} or C{scalar}s). @raise HeightError: Insufficient number of I{knots} or I{weight}s or invalid I{knot} or I{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])) T = 1.0e-4 # like SciPy example ps = np.array(_ordedup(xs, T, PI2 - T)) ts = np.array(_ordedup(ys, T, PI - T)) try: self._ev = spi.LSQSphereBivariateSpline(ys, xs, hs, ts, ps, eps=EPS, w=w).ev except Exception as x: raise _SciPyIssue(x)
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 I{factor}. ''' if not isscalar(factor): raise TypeError('%s not scalar: %r' % ('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 I{factor}. @raise ValueError: Invalid or zero I{factor}. ''' if not isscalar(factor): raise TypeError('%s not scalar: %r' % ('factor', factor)) try: return self.times(1.0 / factor) except (ValueError, ZeroDivisionError): raise ValueError('%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 for the intersection point (L{LatLon}) or C{None}. @return: The intersection point (I{LatLon}) or 3-tuple (C{degrees90}, C{degrees180}, height) if I{LatLon} is C{None}. An alternate intersection point might be the L{antipode} to the returned result. @raise TypeError: Start or end point(s) 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') 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 <http://www.EdWilliams.org/avform.htm#Intersection> elif isscalar(end1) and isscalar(end2): # both bearings ca1, ca2, cr12 = map1(cos, a1, a2, r12) sa1, sa2, sr12 = map1(sin, 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 # <http://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, sx2 = map1(sin, 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))) cx1, cx2 = map1(cos, x1, x2) 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') x2, d2 = _x3d2(start2, end2, wrap, '2') 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 = start1._havg(start2) if height is None else height return (a, b, h) if LatLon is None else LatLon(a, b, height=h)
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))