Hi all, recently I stumbled (once more) over a posting by our friend Daniel Ajoy about the superformula (I think it was in a Logo-Forum):
http://en.wikipedia.org/wiki/Superformula On the other side Kirby wrote interesting suggestions about using generators. Now, weekend, bad weather, some sparetime, I assembled an implementation of a superformula-viewer using pygame. It runs with Python 2.6 or higher, also 3.x, of course You'll find it here for download: http://dl.dropbox.com/u/2016850/superformula.py or appended (which sometimes / for some of you) doesn't work well depending on the browser or whatever. The script uses generators for generating the pointlists of the graph of the superformula and also for generating colors for the segments of the graph-area. Morover I've prepared a q&d slider class, which possibly doesn't use the canonical way of processing events in pygame but works fine for this application. Critical comments and feedback and also questions, of course, are welcome. Perhaps someone is willing to amend the docstrings, which suffer from my clumsy English and could well be more clear. Amendments of the code, espercially ones, which make it more readable and easier to understand, also. Useful for classroom use? Perhaps to difficult? Best regards, Gregor
# Autor: Gregor Lingl # Superformula # http://en.wikipedia.org/wiki/Superformula # Version: 1.0 for Python 2.6 or higher; for 3.x also (!) # Date: 2011-05-21 from math import sin, cos, pi import sys import os import pygame import random os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() SCREEN_SIZE = (SX, SY) = (540, 750) CX, CY = 270, 270 R = 250 # colours RED = (255, 0, 0) GREEN = (0, 255, 0) YELLOW = (255, 255, 0) BLACK = (0, 0, 0) # more ressources CLOCK = pygame.time.Clock() SMALLFONT = pygame.font.SysFont("Lucida Console", 12) SMALLFONT.set_bold(True) DEMO_TITLE = "SUPER-FORULA" class Slider: """Sliders of this class change values in the mutable value_list argument. If fl=True, the slider sets floatingpoint-values, otherweise integer values. """ def __init__(self, surf, left, top, name, minval, maxval, value_list, defaultval = None, fl=True): """Slider-Position: (left, top) on surf name is used to label the Slider, Determine from the length of value_list the index of the values the slider sets, and append a default-value to value_list. """ self.surface = surf self.name = name self.minval = minval self.maxval = maxval self.values = value_list self.index = len(value_list) self.fl = fl if defaultval is None: self.val = (minval+maxval) / 2 else: self.val = defaultval if not fl: self.val = int(round(self.val)) # int() for compatibility with 2.7 value_list.append(self.val) self.image = pygame.Surface((240, 50)) self.left = left self.top = top self.marker = int(round(20 + (self.val - minval) * 200 / (maxval - minval))) def value(self): """Calculate value from marker position. """ v = self.minval + (self.marker - 20) * (self.maxval - self.minval) / 200 return v if self.fl else int(round(v)) def draw(self): """Draw the slider, its label and its value to self.surface. """ self.image.fill((32, 32, 32)) pygame.draw.rect(self.image, YELLOW, (0, 14, 239, 35), 2) pygame.draw.line(self.image, GREEN, (20, 32), (220,32), 3) pygame.draw.circle(self.image, RED, (self.marker, 32), 12) val = (": {0:3.1f}" if self.fl else ": {0}").format(self.value()) text = SMALLFONT.render(self.name + val, True, BLACK, YELLOW) w, h = text.get_size() w += 12 h += 5 ts = pygame.Surface((w,h)) ts.fill(YELLOW) ts.blit(text, (6, 3)) self.image.blit(ts, (10, 0)) self.surface.blit(self.image, (self.left, self.top)) def process(self, event): """If mouse is on slider-marker, left mouse-button is pressed and mouse is moved, change marker-position and value in value_list accordingly. """ if event.type != pygame.MOUSEMOTION or event.buttons[0] != 1: return x, y = event.pos x -= self.left y -= self.top if (x - self.marker)**2 + (y - 32)**2 < 12**2: self.marker = min(max(20, x), 220) self.values[self.index] = self.value() def superformula(params): """Calculate graph (list of paris of coordinates) for superformula from http://en.wikipedia.org/wiki/Superformula M, N1, N2, N3 are used according to that source. The graph may be rotated by changing the value of angle_offset. params is the value_list, whose values are changed by the sliders. params = [M, N1, N2, N3, Change_of_angle_offset, colour-rotation(here unused)] """ M = N1 = N2 = N3 = None angles = [i * pi/255 for i in range(511)] angle_offset = 0.0 while True: if M != params[0]: m = params[0] trigfuntable = [(w, abs(sin(m*w/4)), abs(cos(m*w/4))) for w in angles] if [M, N1, N2, N3] != params[:4]: M, N1, N2, N3 = params[:4] e1 = -1/N1 points = [] for (w, s4, c4) in trigfuntable: r = (c4**N2 + s4**N3) ** e1 points.append((r, w)) rmax = max(r for (r, w) in points) points = [(R*r/rmax, w) for (r,w) in points] pointlist = [] angle_offset += params[4] * pi / 360 for (r, w) in points: angle = w + angle_offset point = (CX + r*cos(angle), CY - r*sin(angle)) pointlist.append(point) yield zip(pointlist, pointlist[1:]) def colours(): """Generator that generates colour-triples starting from some startindex that can be sent to the generator. """ cl1 = [(abs(i), 32, 255 - abs(i)) for i in range(-255, 255)] cl2 = [(3*r//4, 0, 3*b//4) for (r, g, b) in cl1] cl = list(zip(cl1, cl2)) i = startindex = 0 while True: dcc = yield cl[i] if dcc is not None: i = startindex = (startindex + dcc) % 510 else: i = (i + 1) % 510 def demo(screen): """ Show and rotate the superformula-shape. Rotate colour shading with reference to the shape. Control via a set of four (form) + two (rotation) sliders. """ # Startwerte: M, N1, N2, N3, dWO, dCC = 3, 2., 8., 3., 0, 8 values = [] sliders = [Slider(screen, 30, 550, "M", 0, 20, values, M, False), Slider(screen, 280, 550, "N1", 0.1, 20, values, N1, True), Slider(screen, 30, 610, "N2", 0, 20, values, N2, True), Slider(screen, 280, 610, "N3", 0, 20, values, N3, True), Slider(screen, 30, 690, "angle velocity", -10, 10, values, dWO, True), Slider(screen, 280, 690, "colour rotation", -10, 10, values, dCC, False) ] # Schleife für die Erkennung des QUIT-Ereignisses sf_gen = superformula(values) colour_gen = colours() while True: screen.fill(BLACK) pygame.draw.line(screen, (0, 128, 0), (10,675), (530,675), 3) for slider in sliders: slider.draw() for (p1, p2) in next(sf_gen): # segments: f1, f2 = next(colour_gen) pygame.draw.polygon(screen, f2, (p1, p2, (CX, CY))) pygame.draw.line(screen, f1, p1, p2, 7) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: print(CLOCK.get_fps()) sys.exit() for slider in sliders: slider.process(event) colour_gen.send(values[5]) # change start-index for colours CLOCK.tick() if __name__ == "__main__": pygame.display.set_caption(DEMO_TITLE) screen = pygame.display.set_mode(SCREEN_SIZE) try: demo(screen) except SystemExit: pass finally: pygame.quit()
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig