Random words on canvas – python/pillow

A program to place words randomly on a canvas. Words are place around a spiral starting from the center. Uses AABB – AABB bounding box collision detection for letter-letter collision.
Ref: Real-time Collision Detection by Christer Ericson

"""
May 9, 2019
A program to palce a list of words, randomly on a canvas. 
Places words around spiral. Uses bounding box collision detection.
Author: jithesh Kuyyalil https://jitheshkuyyalil.com
Date: April 26, 2019
"""
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from random import randint
from spiral import spiral

img = Image.new("L", (500, 500))
#word = "b"
word_list = ['a', 'b', 'c', 'd', 'e', 'f']
#word_list = 'thebookthiefishere'
font_size = 50
font_path = 'DroidSansMono.ttf'
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(font_path, font_size)
# save bounding box co-ordinates [[(), ()], [(), ()]]
box_coord = []  
for word in word_list:  # for each letter
    # x, y, where the word/letter is placed, somewhere top-left
    sp = spiral(500, 500, 250, 250)
    count = 0
    while True:
        x, y = next(sp)
        # font metrics to construct bounding box around letter
        (x1, y1, x2, y2) = font.getmask(word).getbbox()
        (width, baseline), (offset_x, offset_y) = font.font.getsize(word)
        # top left corner
        rect_1 = (x1 + x + offset_x, y1 + y + offset_y)   
        # bottom right corner. Not clear about -1  
        # Rectangle fits well with -1.
        rect_2 = (x2 + x + offset_x -1, y2 + y + offset_y) 
        intersect = False  # both letter-boundary, letter-letter collision
        # boundary collision testing - boundary (0,0), (500,500)
        # hitting the boundary
        if not (rect_2[0] < 500 and rect_2[1] < 500): 
            intersect = True
        # only if letter doesn't hit boundary
        if intersect == False: 
            # checking for collision
            if box_coord != []:
                #print(box_coord)
                for box in box_coord:
                    # not intersecting
                    if (rect_1[0] > box[1][0]) or (rect_2[0] < box[0][0]): 
                        continue 
                    # intersecting
                    if (rect_1[1] > box[1][1]) or (rect_2[1] < box[0][1]): 
                        continue
                    intersect = True
                    break # interesecting; find new x, y
        if not intersect :            
            #draw.rectangle([rect_1, rect_2], outline='white')
            draw.text((x, y), word, fill='white', font=font) # 175, 90
            box_coord.append([rect_1, rect_2])
            break
        count = count + 1;
        if count > 500 * 500:
            break
img.show()

Python code to generate spiral co-ordinates.

"""
A program to generate spiral co-ordinates in a 2D square lattice.
Algorithm due to Can Berk Güder at stackoverflow.com
author: jithesh kuyyalil
Date:   May 1, 2019
"""
def spiral(m, n, Xc = 0, Yc = 0):
    # 0, 0 at the top left corner
    # Xc, Yc somewhere on the canvas
    x = 0
    y = 0
    dx =  0
    dy = -1
    for i in range(max(m,n)**2): 
        if (-m/2 < x <= m/2) and (-n/2 < y <= n/2): # from each matrix \
                # what is necessary
            #print(x, y)
            if Xc != 0 or Yc != 0:
                yield x + Xc, y + Yc
            else:
                yield x, y
        if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y): # each turn \
                # change dx and dy
            temp = dx
            dx = -dy
            dy =  temp
            #print('dx, dy ', dx, dy)
        x = x + dx
        y = y + dy

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    sp = spiral(300,300, 150, 150)
    X = []
    Y = []
    for i in range(150):
        #print(next(x))
        x, y = next(sp)
        X.append(x)
        Y.append(y)
    plt.plot(X, Y, 'o')
    plt.show()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s