I use python's module operator (%) to accomplish what I think those ring classes are meant to accomplish.
def AngleDiff(a, b): return (a - b + 180.0) % 360.0 - 180.0 the function above will return a number from -180.0 to 180 that does the kind of difference you are talking about. i.e. AngleDiff(370, 20) return -10, cause 20 - 10 = 10, and 370 is the same as 10. So to tell what "direction" one angle is from another, you'd just look at the sign of the AngleDiff note that the simple code works because python does a mathematically correct mod - where the result of the mod op always matches the sign of the modulo. So if you are used to other languages, you are probably used to the sign of the result matching the left hand side, which is generally less useful and needs a bunch of ifs and crap to write a similar function. ...I've often thought about writing an "Angle" class that is derivied from numbers and overrides arithmetic (so I can say diff = Angle(370) - Angle(20) and diff will be Angle(-10)) but sometimes doing that stuff leads to extra confusion... On Sun, Feb 22, 2009 at 11:51 AM, Daniel Jo <[email protected]> wrote: > What I mean by "circular" is sort of like a clock, where passing the > upper limit takes one back to the start again. Two hours passed 11 on > a 12-hour clock is 1 o'clock. Similarily three hours before 2 is 11 > o'clock. Another example is a compass. Forty-five degrees left of > north, 0 degrees, is 315 degrees, rather than -45. > > My need for it is for the latter example. In such an example, > comparisons such as "less-than" and "greater-than" aren't so important > as "left-of" and "right-of", respectively. Anything in the range > [180,360) is left of 0 and anything in the range (0, 180] is right of > 0. Similarily, anything in the range [270,360) and [0,90) is left of > 0. > > My implementation is more of a utility class than a data-type: > > import math > > class RingBase (object): > def __init__ (self, lower, upper): > self.lower = lower > self.upper = upper > self.span = upper - lower > > def __call__ (self, value): > if value > self.upper: > loops = int (value / self.span) > return value - self.span * loops > if value < self.lower: > loops = int (abs (value) / self.span) + 1 > return value + self.span * loops > return value > > def _lo (self, v1, v2): > v1 = self (v1) > v2 = self (v2) > half = self.span * 0.5 > > left = v2 - half > > if left < self.lower: > if v1 >= self.upper - (v2 - self.lower): > return True > elif v1 < v2: > return True > elif v1 < v2 and v1 > left: > return True > > return False > > def _ro (self, v1, v2): > v1 = self (v1) > v2 = self (v2) > half = self.span * 0.5 > > right = v2 + half > > if right >= self.upper: > if v1 <= self.lower + (self.upper - v2): > return True > elif v1 > v2: > return True > elif v1 > v2 and v1 < right: > return True > > return False > > class Ring (RingBase): > def __init__ (self, lower, upper): > super (Ring, self).__init__ (lower, upper) > > lo = RingBase._lo > ro = RingBase._ro > > class Radian (RingBase): > def __init__ (self): > super (Radian, self).__init__ (0.0, 2.0 * math.pi) > > lo = RingBase._ro > ro = RingBase._lo > > An instance of Ring is callable and is used to clamp a value within > the Ring's limits. For example. . . > > ring = Ring (0, 12) > print ring (13) > > . . . yields 1. > > print ring (-1) > > . . . yields 11. > > ring.lo (11, 1) > > . . . asks if 11 is left of 1 and returns True. > > So is there anything else like this out there? > > -Daniel >
