Source for: lesson5.py [raw]

  1class Box():
  2
  3    def __init__(self, x=0, y=0, w=1, h=1):
  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
 10    def __repr__(self):
 11        return "Box(%s, %s, %s, %s)" % (self.x, self.y, self.w, self.h)
 12
 13
 14# Many boxes with varying widths
 15from random import randint
 16
 17many_boxes = [Box(w=1 + randint(-5, 5) / 10) for i in range(5000)]
 18
 19# A few pages all the same size
 20pages = [Box(i * 35, 0, 30, 50) for i in range(10)]
 21
 22# We add a "separation" constant so you can see the boxes individually
 23separation = .2
 24
 25
 26def layout(_boxes):
 27    # Because we modify the box list, we will work on a copy
 28    boxes = _boxes[:]
 29    # We start at page 0
 30    page = 0
 31    # The 1st box should be placed in the correct page
 32    previous = boxes.pop(0)
 33    previous.x = pages[page].x
 34    previous.y = pages[page].y
 35    row = []
 36    while boxes:
 37        # We take the new 1st box
 38        box = boxes.pop(0)
 39        # And put it next to the other
 40        box.x = previous.x + previous.w + separation
 41        # At the same vertical location
 42        box.y = previous.y
 43        # But if it's too far to the right...
 44        if (box.x + box.w) > (pages[page].x + pages[page].w):
 45            # We adjust the row
 46            slack = (pages[page].x + pages[page].w) - (
 47                row[-1].x + row[-1].w
 48            )
 49            bump = slack / len(row)
 50            # The 1st box gets 0 bumps, the 2nd gets 1 and so on
 51            for i, b in enumerate(row):
 52                b.x += bump * i
 53            # We start a new row
 54            row = []
 55            # We go all the way left and a little down
 56            box.x = pages[page].x
 57            box.y = previous.y + previous.h + separation
 58
 59        # But if we go too far down
 60        if box.y + box.h > pages[page].y + pages[page].h:
 61            # We go to the next page
 62            page += 1
 63            # And put the box at the top-left
 64            box.x = pages[page].x
 65            box.y = pages[page].y
 66
 67        # Put the box in the row
 68        row.append(box)
 69        previous = box
 70
 71
 72layout(many_boxes)
 73
 74
 75import svgwrite
 76
 77
 78def draw_boxes(boxes, fname, size):
 79    dwg = svgwrite.Drawing(fname, profile="full", size=size)
 80    # Draw the pages
 81    for page in pages:
 82        dwg.add(
 83            dwg.rect(
 84                insert=(f"{page.x}cm", f"{page.y}cm"),
 85                size=(f"{page.w}cm", f"{page.h}cm"),
 86                fill="lightblue",
 87            )
 88        )
 89    # Draw all the boxes
 90    for box in boxes:
 91        dwg.add(
 92            dwg.rect(
 93                insert=(f"{box.x}cm", f"{box.y}cm"),
 94                size=(f"{box.w}cm", f"{box.h}cm"),
 95                fill="red",
 96            )
 97        )
 98    dwg.save()
 99
100
101draw_boxes(many_boxes, "lesson5.svg", ("100cm", "50cm"))
102