def initialBearingTo(self, other, wrap=False, raiser=False): '''Compute the initial bearing (forward azimuth) from this to an other point. @param other: The other point (spherical L{LatLon}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @keyword raiser: Optionally, raise L{CrossError} (C{bool}), use I{raiser}=C{True} for behavior like C{sphericalNvector.LatLon.initialBearingTo}. @return: Initial bearing (compass C{degrees360}). @raise CrossError: If this and the I{other} point coincide, provided I{raiser} is C{True} and L{crosserrors} is C{True}. @raise TypeError: The I{other} point is not L{LatLon}. @example: >>> p1 = LatLon(52.205, 0.119) >>> p2 = LatLon(48.857, 2.351) >>> b = p1.initialBearingTo(p2) # 156.2 @JSname: I{bearingTo}. ''' self.others(other) a1, b1 = self.to2ab() a2, b2 = other.to2ab() # XXX behavior like sphericalNvector.LatLon.initialBearingTo if raiser and crosserrors() and max(abs(a2 - a1), abs(b2 - b1)) < EPS: raise CrossError('%s %s: %r' % ('coincident', 'points', other)) return degrees(bearing_(a1, b1, a2, b2, final=False, wrap=wrap))
def isconvex_(points, adjust=False, wrap=True): '''Determine whether a polygon is convex and clockwise. @param points: The polygon points (C{LatLon}[]). @keyword adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the mean latitude (C{bool}). @keyword wrap: Wrap lat-, wrap and unroll longitudes (C{bool}). @return: C{+1} if I{points} are convex clockwise, C{-1} for convex counter-clockwise I{points}, C{0} otherwise. @raise CrossError: Some I{points} are colinear. @raise TypeError: Some I{points} are not C{LatLon}. @raise ValueError: Insufficient number of I{points}. @example: >>> t = LatLon(45,1), LatLon(46,1), LatLon(46,2) >>> isconvex_(t) # +1 >>> f = LatLon(45,1), LatLon(46,2), LatLon(45,2), LatLon(46,1) >>> isconvex_(f) # 0 ''' def _unroll_adjust(x1, y1, x2, y2, wrap): x21, x2 = unroll180(x1, x2, wrap=wrap) if adjust: x21 *= cos(radians(y1 + y2) * 0.5) return x21, x2 pts = LatLon2psxy(points, closed=True, radius=None, wrap=wrap) c, n, s = crosserrors(), len(pts), 0 x1, y1, _ = pts[n - 2] x2, y2, _ = pts[n - 1] x21, x2 = _unroll_adjust(x1, y1, x2, y2, False) for i in range(n): x3, y3, ll = pts[i] x32, x3 = _unroll_adjust(x2, y2, x3, y3, wrap if i < (n - 2) else False) # get the sign of the distance from point # x3, y3 to the line from x1, y1 to x2, y2 # <http://WikiPedia.org/wiki/Distance_from_a_point_to_a_line> s3 = fdot((x3, y3, x1, y1), y2 - y1, -x21, -y2, x2) if s3 > 0: # x3, y3 on the right if s < 0: # non-convex return 0 s = +1 elif s3 < 0: # x3, y3 on the left if s > 0: # non-convex return 0 s = -1 elif c and fdot((x32, y1 - y2), y3 - y2, -x21) < 0: # colinear u-turn: x3, y3 not on the # opposite side of x2, y2 as x1, y1 raise CrossError('%s %s: %r' % ('colinear', 'point', ll)) x1, y1, x2, y2, x21 = x2, y2, x3, y3, x32 return s # all points on the same side