def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = (color) self.angle = random() * pi self.freq = (random() + 0.5) * 0.06 self.direction = direction self.y = 0 if direction == "up" else self.matrix.height - 1
def main(): global matrix sys.excepthook = exceptionHandler matrix = OPCMatrix(dpyinfo.WIDTH, dpyinfo.HEIGHT, dpyinfo.ADDRESS, dpyinfo.ZIGZAG) arts = ImportPlugins("art", ["template.py"], sys.argv[1:], matrix) if len(arts) == 0: logging.error("Couldn't find any art to execute") exit(1) sleep(3) while True: seed(time()) for art in arts: matrix.setFirmwareConfig() art.start(matrix) t = time() while time()-t < FLIPTIME: art.refresh(matrix) matrix.show() sleep(art.interval()/1000.0)
class Art(ArtBaseClass): description = "Traverse procedurally generated terrain" def __init__(self, matrix, config): self.width = matrix.width*SCALE self.height = matrix.height*SCALE self.matrix = OPCMatrix(self.width, self.height, None) self.diamond = DiamondSquareAlgorithm(self.matrix.width, self.matrix.height, (self.matrix.width + self.matrix.height) / 4) self.colormap = Colormap(palette=OrderedDict([ (rgb["NavyBlue"], 20), (rgb["blue"], 15), (rgb["yellow3"], 5), (rgb["LawnGreen"], 10), (rgb["ForestGreen"], 20), (rgb["gray50"], 15), (rgb["snow1"], 5), ])) self.diamond.generate() self.diamond.translate(self.matrix, colormap=self.colormap) self.matrix.blur() self.theta = 0 self.radius = 0 def start(self, matrix): matrix.setFirmwareConfig(nointerp=True) def refresh(self, matrix): # XXX: # The change in angle per frame increases as we get closer to the # center of the matrix: # - when radius is max, then deltatheta is about .005 radians. # - when radius is min, then deltatheta is about .1 radians. deltatheta = 0.01 self.theta += deltatheta self.radius -= 0.05 if self.radius < CENTERZONE: self.radius = (self.width+self.height)/4 x = self.width/2 + self.radius * sin(self.theta) y = self.height/2 + self.radius * cos(self.theta) matrix.copy(self.matrix, x, y) def interval(self): return 60
def __init__(self): matrix = OPCMatrix(M_WIDTH, M_HEIGHT, "echo", fliplr=True) arts = ImportPlugins("art", ["template.py"], [], None, matrix, config.config) if len(arts) == 0: matrix.terminate() print "Couldn't find any art to execute" exit(1) self.generator = self._frameGenerator(arts, matrix) self.packet = None
def initialize(): global generator matrix = OPCMatrix(M_WIDTH, M_HEIGHT, "raw") arts = ImportPlugins("art", ["template.py"], [], matrix) if len(arts) == 0: matrix.terminate() print("Couldn't find any art to execute") exit(1) generator = frameGenerator(arts, matrix)
def __init__(self): matrix = OPCMatrix(M_WIDTH, M_HEIGHT, "echo", fliplr=True) arts = ImportPlugins("art", ["template.py"], [], None, matrix, config.config) if len(arts) == 0: matrix.terminate() print("Couldn't find any art to execute") exit(1) self.generator = self._frameGenerator(arts, matrix) self.packet = None
def initialize(): global generator matrix = OPCMatrix(M_WIDTH, M_HEIGHT, "raw") arts = ImportPlugins("art", ["template.py"], [], matrix) if len(arts) == 0: matrix.terminate() print "Couldn't find any art to execute" exit(1) generator = frameGenerator(arts, matrix)
class Art(ArtBaseClass): description = "Traverse procedurally generated terrain" def __init__(self, matrix, config): self.width = matrix.width * SCALE self.height = matrix.height * SCALE self.matrix = OPCMatrix(self.width, self.height, None) self.diamond = DiamondSquareAlgorithm( self.matrix.width, self.matrix.height, (self.matrix.width + self.matrix.height) / 4) self.colormap = Colormap(palette=OrderedDict([ (rgb["NavyBlue"], 20), (rgb["blue"], 15), (rgb["yellow3"], 5), (rgb["LawnGreen"], 10), (rgb["ForestGreen"], 20), (rgb["gray50"], 15), (rgb["snow1"], 5), ])) self.diamond.generate() self.diamond.translate(self.matrix, colormap=self.colormap) self.matrix.blur() self.theta = 0 self.radius = 0 def start(self, matrix): matrix.setFirmwareConfig(nointerp=True) def refresh(self, matrix): # XXX: # The change in angle per frame increases as we get closer to the # center of the matrix: # - when radius is max, then deltatheta is about .005 radians. # - when radius is min, then deltatheta is about .1 radians. deltatheta = 0.01 self.theta += deltatheta self.radius -= 0.05 if self.radius < CENTERZONE: self.radius = (self.width + self.height) / 4 x = self.width / 2 + self.radius * sin(self.theta) y = self.height / 2 + self.radius * cos(self.theta) matrix.copy(self.matrix, x, y) def interval(self): return 60
def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = (color) self.angle = random()*pi self.freq = (random()+0.5)*0.06 self.direction = direction self.y = 0 if direction == "up" else self.matrix.height-1
def __init__(self, matrix, config): self.width = matrix.width*SCALE self.height = matrix.height*SCALE self.matrix = OPCMatrix(self.width, self.height, None) self.diamond = DiamondSquareAlgorithm(self.matrix.width, self.matrix.height, (self.matrix.width + self.matrix.height) / 4) self.colormap = Colormap(palette=OrderedDict([ (rgb["NavyBlue"], 20), (rgb["blue"], 15), (rgb["yellow3"], 5), (rgb["LawnGreen"], 10), (rgb["ForestGreen"], 20), (rgb["gray50"], 15), (rgb["snow1"], 5), ])) self.diamond.generate() self.diamond.translate(self.matrix, colormap=self.colormap) self.matrix.blur() self.theta = 0 self.radius = 0
def __init__(self, matrix): self.hue = getHueGen(0.001) self.theta = 0.0 self.matrix = OPCMatrix(SCALE*matrix.width, SCALE*matrix.height, None, True) self.x = SCALE * matrix.width / 2.0 self.y = SCALE * matrix.height / 2.0 self.r = 6.5 * SCALE
def __init__(self, matrix, generate, maxticks=DFLTTICKS, interpolate=True): self.diamond = DiamondSquareAlgorithm(matrix.width, matrix.height) self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.generate = generate self.ticks = 0 self.maxticks = maxticks self.interpolate = interpolate
def main(): global matrix parser = argparse.ArgumentParser() parser.add_argument("-c", "--count", type=int, help="run for count cycles through all of the art", default=DFLT_CYCLE_COUNT) parser.add_argument("-f", "--fliptime", type=int, help="run art for FLIPTIME secs before transitioning", default=DFLT_FLIPTIME_SECS) parser.add_argument("-p", "--profile", help="switch on and report profiling detail", action="store_true") parser.add_argument("art", help="Optional list of arts", nargs="*") args = parser.parse_args() if args.profile: if args.count: prof.on() else: logging.error("Will not profile without --count being set") matrix = OPCMatrix(_v("WIDTH", 16), _v("HEIGHT", 16), _v("DRIVER", "ansi"), _v("ZIGZAG", False), _v("FLIPUP", False), _v("FLIPLR", False)) progress(0, 10) arts = ImportPlugins("art", [], args.art, progress, matrix, config.config) if len(arts) == 0: matrix.terminate() print("Couldn't find any art to execute") exit(1) run(arts, args) matrixDone() if args.profile: prof.dumptimings()
class Art(object): description = "Use a higher resolution image downsampled to improve perceived clarity" def __init__(self, matrix): self.hue = getHueGen(0.001) self.theta = 0.0 self.matrix = OPCMatrix(SCALE*matrix.width, SCALE*matrix.height, None, True) self.x = SCALE * matrix.width / 2.0 self.y = SCALE * matrix.height / 2.0 self.r = 6.5 * SCALE def irnd(self, n): return int(round(n)) def poly(self, r): tc = cos(self.theta) ts = sin(self.theta) poly = [ (self.irnd(self.x + r * tc - r * ts) , self.irnd(self.y + r * tc + r * ts)), # UL (self.irnd(self.x - r * tc - r * ts) , self.irnd(self.y + r * tc - r * ts)), # UR (self.irnd(self.x - r * tc + r * ts) , self.irnd(self.y - r * tc - r * ts)), # BR (self.irnd(self.x + r * tc + r * ts) , self.irnd(self.y - r * tc + r * ts)), # BL ] return poly def start(self, matrix): pass def refresh(self, matrix): self.theta += 0.05 color = self.hue.next() self.matrix.shift(dv=0.8) for polys in range(0, SCALE*7, 2): self.matrix.drawPoly(self.poly(self.r-0.2*polys), color) matrix.copy(self.matrix) def interval(self): return 30
def main(): global matrix parser = argparse.ArgumentParser() parser.add_argument("-c", "--count", type=int, help="run for count cycles through all of the art", default=DFLT_CYCLE_COUNT) parser.add_argument("-f", "--fliptime", type=int, help="run art for FLIPTIME secs before transitioning", default=DFLT_FLIPTIME_SECS) parser.add_argument("-p", "--profile", help="switch on and report profiling detail", action="store_true") parser.add_argument("art", help="Optional list of arts", nargs="*") args = parser.parse_args() if args.profile: if args.count: prof.on() else: logging.error("Will not profile without --count being set") matrix = OPCMatrix( _v("WIDTH", 16), _v("HEIGHT", 16), _v("DRIVER", "ansi"), _v("ZIGZAG", False), _v("FLIPUP", False), _v("FLIPLR", False) ) progress(0, 10) arts = ImportPlugins("art", [], args.art, progress, matrix, config.config) if len(arts) == 0: matrix.terminate() print("Couldn't find any art to execute") exit(1) run(arts, args) matrixDone() if args.profile: prof.dumptimings()
class Art(ArtBaseClass): description = "Barber-pole-esque (dirty)" def __init__(self, matrix, config): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.x = 5 self.hue = 0 self.ys = [] def start(self, matrix): self.ys = [random() for y in range(matrix.height)] def refresh(self, matrix): self.matrix.clear() self.hue += 1.0 / (6 * 4 * matrix.width) for y, z in enumerate(self.ys): val = (1 + sin(radians(360 * z))) / 2 self.matrix.drawPixel(self.x, y, hsvToRgb(self.hue, 1, val)) self.ys = [y + 0.08 * random() for y in self.ys] self.x = (self.x + 1) % matrix.width self.matrix.maskbelow(55, BLACK) matrix.fade(0.99) matrix.add(self.matrix) def interval(self): return 120
class Art(ArtBaseClass): description = "Barber-pole-esque (dirty)" def __init__(self, matrix, config): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.x = 5 self.hue = 0 self.ys = [] def start(self, matrix): self.ys = [random() for y in range(matrix.height)] def refresh(self, matrix): self.matrix.clear() self.hue += 1.0/(6*4*matrix.width) for y, z in enumerate(self.ys): val = (1+sin(radians(360*z)))/2 self.matrix.drawPixel(self.x, y, hsvToRgb(self.hue, 1, val)) self.ys = [y+0.08*random() for y in self.ys] self.x = (self.x+1)%matrix.width self.matrix.maskbelow(55, BLACK) matrix.fade(0.99) matrix.add(self.matrix) def interval(self): return 120
def main(): global matrix parser = argparse.ArgumentParser() parser.add_argument("-c", "--count", type=int, help="run for count cycles through all of the art", default=DFLT_CYCLE_COUNT) parser.add_argument("-f", "--fliptime", type=int, help="run art for FLIPTIME secs before transitioning", default=DFLT_FLIPTIME_SECS) parser.add_argument("-p", "--profile", help="switch on and report profiling detail", action="store_true") parser.add_argument("art", help="Optional list of arts", nargs="*") args = parser.parse_args() if args.profile: prof.on() matrix = OPCMatrix( _v("WIDTH", 16), _v("HEIGHT", 16), _v("ADDRESS", "ansi"), _v("ZIGZAG", False), _v("FLIPUP", False), _v("FLIPLR", False) ) arts = ImportPlugins("art", ["template.py"], args.art, matrix) if len(arts) == 0: matrix.terminate() print "Couldn't find any art to execute" exit(1) run(arts, args) matrix.terminate() if args.profile: prof.dumptimings()
def __init__(self, matrix, config): self.width = matrix.width * SCALE self.height = matrix.height * SCALE self.matrix = OPCMatrix(self.width, self.height, None) self.diamond = DiamondSquareAlgorithm( self.matrix.width, self.matrix.height, (self.matrix.width + self.matrix.height) / 4) self.colormap = Colormap(palette=OrderedDict([ (rgb["NavyBlue"], 20), (rgb["blue"], 15), (rgb["yellow3"], 5), (rgb["LawnGreen"], 10), (rgb["ForestGreen"], 20), (rgb["gray50"], 15), (rgb["snow1"], 5), ])) self.diamond.generate() self.diamond.translate(self.matrix, colormap=self.colormap) self.matrix.blur() self.theta = 0 self.radius = 0
def __init__(self, matrix, config): self.angle = 0 self.hue = getHueGen(0.01) self.radius = sqrt(matrix.numpix) * self.FITHALF self.center = Point(matrix.midWidth, matrix.midHeight) self.pieslice = self._pieslice(-30, 30) # used to help with scaling small displays # freq will have a value of 1 for kilopix displays and hold a # larger value for smaller displays (up to 4) self.freq = min(4, max(1, 1024.0/matrix.numpix)) self.clock = 0 # create mask self.mask = OPCMatrix(matrix.width, matrix.height, None) self.mask.fillPoly(self.pieslice, WHITE) matrix.fillPoly(self.pieslice, WHITE) # create intermediate buffers self.intermediate1 = OPCMatrix(matrix.width, matrix.height, None) self.intermediate2 = OPCMatrix(matrix.width, matrix.height, None) # create private buffer for final rendering before rotate/display self.private = OPCMatrix(matrix.width, matrix.height, None)
class Phase(object): def __init__(self, matrix, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = color self.angle = random() * pi self.freq = (random() + 0.5) * 0.6 def clock(self, matrix): w = self.matrix.width h = self.matrix.height self.matrix.clear(self.color) for x in range(0, w, w / 4): self.matrix.fillRect(x, 0, w / 8, h, BLACK) for y in range(0, h, h / 4): self.matrix.fillRect(0, y, w, h / 8, BLACK) self.matrix.rotate(self.angle) self.angle += self.freq matrix.add(self.matrix)
class Phase(object): def __init__(self, matrix, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = color self.angle = random()*pi self.freq = (random()+0.5)*0.6 def clock(self, matrix): w = self.matrix.width h = self.matrix.height self.matrix.clear(self.color) for x in range(0, w, w/4): self.matrix.fillRect(x, 0, w/8, h, BLACK) for y in range(0, h, h/4): self.matrix.fillRect(0, y, w, h/8, BLACK) self.matrix.rotate(self.angle) self.angle += self.freq matrix.add(self.matrix)
class Phase(object): def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = color self.angle = random() * pi self.freq = (random() + 0.5) * 0.06 self.direction = direction self.x = 0 if direction == "left" else self.matrix.width - 1 def clock(self, matrix): self.matrix.fade(0.96) self.matrix.scroll(self.direction) y = self.matrix.midHeight + self.matrix.midHeight * sin(self.angle) h = self.matrix.height / 8 self.matrix.drawLine(self.x, y - h, self.x, y + h, self.color) self.angle += self.freq matrix.add(self.matrix)
class Phase(object): def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = (color) self.angle = random() * pi self.freq = (random() + 0.5) * 0.06 self.direction = direction self.x = 0 if direction == "left" else self.matrix.width - 1 def clock(self, matrix): self.matrix.fade(0.96) self.matrix.scroll(self.direction) y = self.matrix.midHeight + self.matrix.midHeight * sin(self.angle) h = self.matrix.height / 8 self.matrix.drawLine(self.x, y - h, self.x, y + h, self.color) self.angle += self.freq matrix.add(self.matrix)
def __init__(self, matrix, config): self.angle = 0 self.hue = getHueGen(0.01) self.radius = sqrt(matrix.numpix) * self.FITHALF self.center = Point(matrix.midWidth, matrix.midHeight) self.pieslice = self._pieslice(-30, 30) # used to help with scaling small displays # freq will have a value of 1 for kilopix displays and hold a # larger value for smaller displays (up to 4) self.freq = min(4, max(1, 1024.0 / matrix.numpix)) self.clock = 0 # create mask self.mask = OPCMatrix(matrix.width, matrix.height, None) self.mask.fillPoly(self.pieslice, WHITE) matrix.fillPoly(self.pieslice, WHITE) # create intermediate buffers self.intermediate1 = OPCMatrix(matrix.width, matrix.height, None) self.intermediate2 = OPCMatrix(matrix.width, matrix.height, None) # create private buffer for final rendering before rotate/display self.private = OPCMatrix(matrix.width, matrix.height, None)
class Phase(object): def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = (color) self.angle = random() * pi self.freq = (random() + 0.5) * 0.06 self.direction = direction self.y = 0 if direction == "up" else self.matrix.height - 1 #self.x = self.matrix.width/2 if direction == "left" else self.matrix.width/2+1 def clock(self, matrix): self.matrix.fade(0.96) self.matrix.scroll(self.direction) x = self.matrix.midWidth + self.matrix.midWidth * sin(self.angle) w = self.matrix.width / 8 self.matrix.drawLine(x - w, self.y, x + w, self.y, self.color) self.angle += self.freq matrix.add(self.matrix)
class Phase(object): def __init__(self, matrix, direction, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = (color) self.angle = random()*pi self.freq = (random()+0.5)*0.06 self.direction = direction self.y = 0 if direction == "up" else self.matrix.height-1 #self.x = self.matrix.width/2 if direction == "left" else self.matrix.width/2+1 def clock(self, matrix): self.matrix.fade(0.96) self.matrix.scroll(self.direction) x = self.matrix.midWidth + self.matrix.midWidth*sin(self.angle) w = self.matrix.width/8 self.matrix.drawLine(x-w, self.y, x+w, self.y, self.color) self.angle += self.freq matrix.add(self.matrix)
class Art(ArtBaseClass): description = "Kaleidoscope" FITHALF = 0.45 # squeeze radius into 90% of display area def __init__(self, matrix, config): self.angle = 0 self.hue = getHueGen(0.01) self.radius = sqrt(matrix.numpix) * self.FITHALF self.center = Point(matrix.midWidth, matrix.midHeight) self.pieslice = self._pieslice(-30, 30) # used to help with scaling small displays # freq will have a value of 1 for kilopix displays and hold a # larger value for smaller displays (up to 4) self.freq = min(4, max(1, 1024.0/matrix.numpix)) self.clock = 0 # create mask self.mask = OPCMatrix(matrix.width, matrix.height, None) self.mask.fillPoly(self.pieslice, WHITE) matrix.fillPoly(self.pieslice, WHITE) # create intermediate buffers self.intermediate1 = OPCMatrix(matrix.width, matrix.height, None) self.intermediate2 = OPCMatrix(matrix.width, matrix.height, None) # create private buffer for final rendering before rotate/display self.private = OPCMatrix(matrix.width, matrix.height, None) def _offset(self, angle): return Point( self.center.x+self.radius*sin(radians(angle)), self.center.y+self.radius*cos(radians(angle)), ) def _pieslice(self, offset1, offset2): return [ self._offset(offset1).coords(), self._offset(offset2).coords(), self.center.coords(), ] def start(self, matrix): pass def _draw(self, matrix): x = matrix.width*random() y = self.center.y + (self.pieslice[0][1]-self.center.y)*random() z = 2 + random()*10/self.freq if random() < 0.1: color = WHITE else: offset = int(random()*4)/4.0 if random() < 0.5 else 0 color = hsvToRgb(offset+self.hue.next(), 1, 1) if random() < 0.5: matrix.drawRect(x, y, z, z, color) else: matrix.fillRect(x, y, z, z, color) def _update(self, matrix): self.clock += 1 if self.clock % ceil(self.freq/2.0) == 0: if self.clock % self.freq == 0: matrix.copy(matrix, 1, 0) for draws in range(5-self.freq): self._draw(matrix) def refresh(self, matrix): # # use a copy-flip-rotate strategy to build a set of mirrored segments # # modify the display self._update(self.private) # we just want the top 1/6th pie slice to start self.private.mask(self.mask) # the other slices need to be reversed (see later) self.private.flip(lr=True) # create the left and right pie slices self.intermediate1.copy(self.private) self.intermediate1.rotate(60) self.intermediate2.copy(self.private) self.intermediate2.rotate(-60) # the original needs to be flipped back to its original state # if it isn't then there'll be flip-flopping between frames self.private.flip(lr=True) # drop the slices into the (flipped) original self.private.add(self.intermediate1) self.private.add(self.intermediate2) # the other half is a mirror of what we already have self.intermediate1.copy(self.private) self.intermediate1.flip(ud=True) # drop the mirror onto the matrix self.private.add(self.intermediate1) self.private.flip(ud=True) matrix.copy(self.private) self.angle -= 1 matrix.rotate(self.angle) def interval(self): if self.freq > 2: return 200 else: return 150
def __init__(self, matrix, config): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.x = 5 self.hue = 0 self.ys = []
def __init__(self, matrix, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = color self.angle = random() * pi self.freq = (random() + 0.5) * 0.6
class Art(ArtBaseClass): description = "Kaleidoscope" FITHALF = 0.45 # squeeze radius into 90% of display area def __init__(self, matrix, config): self.angle = 0 self.hue = getHueGen(0.01) self.radius = sqrt(matrix.numpix) * self.FITHALF self.center = Point(matrix.midWidth, matrix.midHeight) self.pieslice = self._pieslice(-30, 30) # used to help with scaling small displays # freq will have a value of 1 for kilopix displays and hold a # larger value for smaller displays (up to 4) self.freq = min(4, max(1, 1024.0 / matrix.numpix)) self.clock = 0 # create mask self.mask = OPCMatrix(matrix.width, matrix.height, None) self.mask.fillPoly(self.pieslice, WHITE) matrix.fillPoly(self.pieslice, WHITE) # create intermediate buffers self.intermediate1 = OPCMatrix(matrix.width, matrix.height, None) self.intermediate2 = OPCMatrix(matrix.width, matrix.height, None) # create private buffer for final rendering before rotate/display self.private = OPCMatrix(matrix.width, matrix.height, None) def _offset(self, angle): return Point( self.center.x + self.radius * sin(radians(angle)), self.center.y + self.radius * cos(radians(angle)), ) def _pieslice(self, offset1, offset2): return [ self._offset(offset1).coords(), self._offset(offset2).coords(), self.center.coords(), ] def start(self, matrix): pass def _draw(self, matrix): x = matrix.width * random() y = self.center.y + (self.pieslice[0][1] - self.center.y) * random() z = 2 + random() * 10 / self.freq if random() < 0.1: color = WHITE else: offset = int(random() * 4) / 4.0 if random() < 0.5 else 0 color = hsvToRgb(offset + self.hue.next(), 1, 1) if random() < 0.5: matrix.drawRect(x, y, z, z, color) else: matrix.fillRect(x, y, z, z, color) def _update(self, matrix): self.clock += 1 if self.clock % ceil(self.freq / 2.0) == 0: if self.clock % self.freq == 0: matrix.copy(matrix, 1, 0) for draws in range(5 - self.freq): self._draw(matrix) def refresh(self, matrix): # # use a copy-flip-rotate strategy to build a set of mirrored segments # # modify the display self._update(self.private) # we just want the top 1/6th pie slice to start self.private.mask(self.mask) # the other slices need to be reversed (see later) self.private.flip(lr=True) # create the left and right pie slices self.intermediate1.copy(self.private) self.intermediate1.rotate(60) self.intermediate2.copy(self.private) self.intermediate2.rotate(-60) # the original needs to be flipped back to its original state # if it isn't then there'll be flip-flopping between frames self.private.flip(lr=True) # drop the slices into the (flipped) original self.private.add(self.intermediate1) self.private.add(self.intermediate2) # the other half is a mirror of what we already have self.intermediate1.copy(self.private) self.intermediate1.flip(ud=True) # drop the mirror onto the matrix self.private.add(self.intermediate1) self.private.flip(ud=True) matrix.copy(self.private) self.angle -= 1 matrix.rotate(self.angle) def interval(self): if self.freq > 2: return 200 else: return 150
def __init__(self, matrix, color): self.matrix = OPCMatrix(matrix.width, matrix.height, None) self.color = color self.angle = random()*pi self.freq = (random()+0.5)*0.6