Source for: lesson6.py [raw]

  1class Box():
  2
  3    def __init__(self, x=0, y=0, w=1, h=1, stretchy=False):
  4        """Accept arguments to define our box, and store them."""
  5        self.x = x
  6        self.y = y
  7        self.w = w
  8        self.h = h
  9        self.stretchy = stretchy
 10
 11    def __repr__(self):
 12        return "Box(%s, %s, %s, %s)" % (self.x, self.y, self.w, self.h)
 13
 14
 15# Many boxes with varying widths, and about 1 in 10 will be stretchy
 16from random import randint
 17
 18many_boxes = [
 19    Box(w=1 + randint(-5, 5) / 10, stretchy=(randint(0, 5) == 4))
 20    for i in range(5000)
 21]
 22# A few pages all the same size
 23pages = [Box(i * 35, 0, 30, 50) for i in range(10)]
 24
 25# We add a "separation" constant so you can see the boxes individually
 26separation = .2
 27
 28
 29def layout(_boxes):
 30    # Because we modify the box list, we will work on a copy
 31    boxes = _boxes[:]
 32    # We start at page 0
 33    page = 0
 34    # The 1st box should be placed in the correct page
 35    previous = boxes.pop(0)
 36    previous.x = pages[page].x
 37    previous.y = pages[page].y
 38    row = []
 39    while boxes:
 40        # We take the new 1st box
 41        box = boxes.pop(0)
 42        # And put it next to the other
 43        box.x = previous.x + previous.w + separation
 44        # At the same vertical location
 45        box.y = previous.y
 46        # But if it's too far to the right...
 47        if (box.x + box.w) > (pages[page].x + pages[page].w):
 48            # We adjust the row
 49            slack = (pages[page].x + pages[page].w) - (
 50                row[-1].x + row[-1].w
 51            )
 52            # Get a list of all the ones that are stretchy
 53            stretchies = [b for b in row if b.stretchy]
 54            if not stretchies:  # Nothing stretches do as before.
 55                bump = slack / len(row)
 56                # The 1st box gets 0 bumps, the 2nd gets 1 and so on
 57                for i, b in enumerate(row):
 58                    b.x += bump * i
 59            else:
 60                bump = slack / len(stretchies)
 61                # Each stretchy gets wider
 62                for b in stretchies:
 63                    b.w += bump
 64                # And we put each thing next to the previous one
 65                for j, b in enumerate(row[1:], 1):
 66                    b.x = row[j - 1].x + row[j - 1].w + separation
 67
 68            # We start a new row
 69            row = []
 70            # We go all the way left and a little down
 71            box.x = pages[page].x
 72            box.y = previous.y + previous.h + separation
 73
 74        # But if we go too far down
 75        if box.y + box.h > pages[page].y + pages[page].h:
 76            # We go to the next page
 77            page += 1
 78            # And put the box at the top-left
 79            box.x = pages[page].x
 80            box.y = pages[page].y
 81
 82        # Put the box in the row
 83        row.append(box)
 84        previous = box
 85
 86
 87layout(many_boxes)
 88
 89
 90import svgwrite
 91
 92
 93def draw_boxes(boxes, fname, size):
 94    dwg = svgwrite.Drawing(fname, profile="full", size=size)
 95    # Draw the pages
 96    for page in pages:
 97        dwg.add(
 98            dwg.rect(
 99                insert=(f"{page.x}cm", f"{page.y}cm"),
100                size=(f"{page.w}cm", f"{page.h}cm"),
101                fill="lightblue",
102            )
103        )
104    # Draw all the boxes
105    for box in boxes:
106        # The box color depends on its features
107        color = "green" if box.stretchy else "red"
108        dwg.add(
109            dwg.rect(
110                insert=(f"{box.x}cm", f"{box.y}cm"),
111                size=(f"{box.w}cm", f"{box.h}cm"),
112                fill=color,
113            )
114        )
115    dwg.save()
116
117
118draw_boxes(many_boxes, "lesson6.svg", ("100cm", "50cm"))
119