I'm both new to stack overflow and programming in general. I'm doing a basic python course at university and I've got to hand in a final project soon. I decided to try making some generative art in Python mode in Processing. My plan is to create a basic (abstracted) image of the skyline of a city by using lines of various length, height and color, with some semi-random spacing in between the lines. I've written some code that is able to do it to a degree. However, I am struggling to write it in a way that obeys some of the global variables I define at the start. I do likely get 50 lines but they don't cover the entire image and frequently overlap one another, making it difficult to tell them apart. Plus, I would like to incorporate some code which would specify where the buildings end, to get even blank space on the left and right side of the image. I tried using the building_start and building_end variables for this but clearly my way of adding separation between the buildings is off. Could you help me out with this?
Thanks in advance. The code and its output is shown below.
import random as rd
w, h = 1000, 500
building_start = 25
building_end = 975
n_buildings = 50
building_sep = (building_end - building_start)/(n_buildings*1.2)
roof_style = [ROUND, SQUARE]
def setup():
size(w,h)
background(60, 60, 60)
building_x = building_start
building_y = 500
for i in range(n_buildings):
building_x = building_sep * i
building_top = rd.randrange(50, 370, 10)
line(building_x, building_y, building_x, building_y - building_length)
stroke(rd.randint(200, 255), rd.randint(200, 255), rd.randint(200, 255))
strokeWeight(rd.randrange(10, 28, 2))
strokeCap(rd.choice(roof_style))
noFill()
rect(0, 0, 1000, 500)
stroke(255, 247, 247)
Even easier implementation with random.sample()
function:
import random
num_of_buildings = 5
total_width = 100
max_height = 50
min_height = 10
x_coords = sorted(random.sample(range(0, total_width), num_of_buildings * 2))
print('x_coords:', x_coords)
heights = random.sample(range(min_height, max_height), num_of_buildings)
print('heights:', heights)
buildings = list(zip(x_coords[0::2], x_coords[1::2], heights))
print('buildings:', buildings)
for b in buildings:
x = b[0]
w = b[1] - b[0]
h = b[2]
print (f'Make the building: x = {x :2}, width = {w :2}, height = {h :2}')
Output:
x_coords: [2, 7, 9, 13, 21, 46, 47, 62, 79, 83]
heights: [35, 14, 28, 20, 12]
buildings: [(2, 7, 35), (9, 13, 14), (21, 46, 28), (47, 62, 20), (79, 83, 12)]
Make the building: x = 2, width = 5, height = 35
Make the building: x = 9, width = 4, height = 14
Make the building: x = 21, width = 25, height = 28
Make the building: x = 47, width = 15, height = 20
Make the building: x = 79, width = 4, height = 12
One of drawbacks of this implementation is you rare will get a building at the very edge of your area. There will be almost always a gap an the begin and at the end. It can be fixed roughly: just make for the first building x = 0
and for the last building width = total_width - x
. Not exactly pretty solution, though.
https://docs.python.org/3/library/random.html
Full variant:
import random
from PIL import Image, ImageDraw
num_of_buildings = 30
total_width = 800
max_height = 400
min_height = 100
im = Image.new('RGB', (total_width, max_height), (255, 255, 255))
draw = ImageDraw.Draw(im)
x_coords = sorted(random.sample(range(0, total_width), num_of_buildings * 2))
heights = random.sample(range(min_height, max_height), num_of_buildings)
buildings = zip(x_coords[0::2], x_coords[1::2], heights)
for b in buildings:
x1 = b[0]
x2 = b[1]
h = max_height - b[2]
color = (random.randint(128, 230), random.randint(128, 230), random.randint(128, 230))
draw.rectangle((x1, max_height, x2, h), fill=color)
im.save('image.jpg')
Output:
It's obviously desperate for max and min width limits for buildings.