At a high level, we need to:
- take a copy of whatever is going to be fractalized
- compute where the fractalized image can be repeated
(the bounding rectangles, here called "recursion points")
- create a temporary surface for drawing
- scale said copy to the size of the temp surface
- draw the scaled copy onto the temp surface
In other words:
def draw_background (self, temp):
App.draw_background (self, temp) # default background for apps is to show a default image
self.child.draw_scene (temp) # draw whatever is going to be fractalized
def draw_foreground (self, temp): # fractalization function
TR = temp.get_rect () # bounding rect for parent
X, Y, W, H = TR
ts = pygame.Surface ((W, H)) # get a fresh surface for working
pic = temp.copy () # could be anything
for rp in self.recursion_points (temp):
x, y, w, h = rp
w, h = tr ((w, h)) # round coordinates
trans = pygame.transform.scale (pic, (w, h)) # scale fake screen to bounding rect
ts.blit (trans, (x, y)) # blit fake screen onto working surface
temp.blit (ts, (X, Y)) # blit working-surface onto real surface
Client code:
d = None # default behavior for no app is to not display a foreground
# these adapters handle differing window geometries
c = CircledSquare (d, rotation=STRAIGHT) # middle circle, inner square
b = SquaredCircle (c, background=SECONDARY_BACKGROUND) # outer square, middle circle
a = RecursiveComposite (b) # without this layer, the inner square is not visible... boring!
Geometry functions:
def recursive_affine (rect, dx, dy, rw, rh, n):
x, y, w, h = rect
for k in range (1, n + 1):
dx, dy = dx * rw, dy * rh
x, y = x + dx, y + dy
w, h = w * rw, h * rh
yield x, y, w, h
def recurse_point (rect, rp, minsz):
X, Y, W, H = rect
x, y, w, h = rp
# get scale and offset for recursion point
dx, dy = x - X, y - Y
rw, rh = w / W, h / H
# get number of recursions until < minsz
f = lambda a, b, c: (log (a) - log (b)) / log (c)
xmin, ymin = minsz
xn, yn = f (xmin, w, rw), f (ymin, h, rh)
n = min (xn, yn)
n = ceil (n)
# recursively apply scale and offset
tail = recursive_affine (rp, dx, dy, rw, rh, n)
return rp, *tail