[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Circular number system?



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