def meanOf(points, datum=Datums.WGS84, height=None, LatLon=LatLon): '''Compute the geographic mean of several points. @param points: Points to be averaged (L{LatLon}[]). @keyword datum: Optional datum to use (L{Datum}). @keyword height: Optional height at mean point, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the mean point (L{LatLon}) or C{None}. @return: Geographic mean point and mean height (B{C{LatLon}}) or a L{LatLon3Tuple}C{(lat, lon, height)} if B{C{LatLon}} is C{None}. @raise ValueError: Insufficient number of B{C{points}}. ''' _, points = _Nvll.points2(points, closed=False) # geographic mean m = sumOf(p.toNvector() for p in points) a, b, h = m.to3llh() if height is not None: h = height r = LatLon3Tuple(a, b, h) if LatLon is None else \ LatLon(a, b, height=h, datum=datum) return _xnamed(r, meanOf.__name__)
def meanOf(points, height=None, LatLon=LatLon): '''Compute the geographic mean of the supplied points. @param points: Array of points to be averaged (L{LatLon}[]). @keyword height: Optional height, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the mean point (L{LatLon}). @return: Point at geographic mean and mean height (B{C{LatLon}}). @raise ValueError: Insufficient number of B{C{points}}. ''' n, points = _Nvll.points2(points, closed=False) # geographic mean m = sumOf(points[i].toNvector() for i in range(n)) a, b, h = m.to3llh() return LatLon(a, b, height=h if height is None else height)
def intersection(start1, end1, start2, end2, height=None, LatLon=LatLon): '''Locate the intersection of two paths each defined by two points or by a start point and an initial bearing. @param start1: Start point of the first path (L{LatLon}). @param end1: End point of the 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 at the intersection point, overriding the mean height (C{meter}). @keyword LatLon: Optional (sub-)class to return the intersection point (L{LatLon}). @return: The intersection point (B{C{LatLon}}) or 3-tuple (C{degrees90}, C{degrees180}, height) if B{C{LatLon}} is C{None} or C{None} if no unique intersection exists. @raise TypeError: If B{C{start*}} or B{C{end*}} is 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) >>> q = LatLon(49.0034, 2.5735) >>> i = intersection(p, 108.55, q, 32.44) # 50.9076°N, 004.5086°E ''' _Nvll.others(start1, name='start1') _Nvll.others(start2, name='start2') # If gc1 and gc2 are great circles through start and end points # (or defined by start point and bearing), then the candidate # intersections are simply gc1 × gc2 and gc2 × gc1. Most of the # work is deciding the correct intersection point to select! If # bearing is given, that determines the intersection, but if both # paths are defined by start/end points, take closer intersection. gc1, s1, e1 = _Nvll._gc3(start1, end1, 'end1') gc2, s2, e2 = _Nvll._gc3(start2, end2, 'end2') hs = start1.height, start2.height # there are two (antipodal) candidate intersection # points ... we have to choose the one to return i1 = gc1.cross(gc2, raiser='paths') # postpone computing i2 until needed # i2 = gc2.cross(gc1, raiser='paths') # selection of intersection point depends on how # paths are defined (by bearings or endpoints) if e1 and e2: # endpoint+endpoint d = sumOf((s1, s2, e1, e2)).dot(i1) hs += end1.height, end2.height elif e1 and not e2: # endpoint+bearing # gc2 x v2 . i1 +ve means v2 bearing points to i1 d = gc2.cross(s2).dot(i1) hs += end1.height, elif e2 and not e1: # bearing+endpoint # gc1 x v1 . i1 +ve means v1 bearing points to i1 d = gc1.cross(s1).dot(i1) hs += end2.height, else: # bearing+bearing # if gc x v . i1 is +ve, initial bearing is # towards i1, otherwise towards antipodal i2 d1 = gc1.cross(s1).dot(i1) # +ve means p1 bearing points to i1 d2 = gc2.cross(s2).dot(i1) # +ve means p2 bearing points to i1 if d1 > 0 and d2 > 0: d = 1 # both point to i1 elif d1 < 0 and d2 < 0: d = -1 # both point to i2 else: # d1, d2 opposite signs # intersection is at further-away intersection # point, take opposite intersection from mid- # point of v1 and v2 [is this always true?] d = -s1.plus(s2).dot(i1) h = fmean(hs) if height is None else height i = i1 if d > 0 else gc2.cross(gc1, raiser='paths') return i.toLatLon(height=h, LatLon=LatLon) # Nvector(i.x, i.y, i.z).toLatLon(...)