def line(ctx, y, line_interval, color, x_increment=(IMG_WIDTH // 40)): line_width = line_interval // 20 x = 0 ctx.move_to(x, y) nodes = [] while x < IMG_WIDTH: x += random.randint(x_increment // 2, x_increment) y_offset = random.randint(0, line_interval // 2 - SPACING) y_offset = y_offset if random.random() < 0.5 else -1 * y_offset nodes.append((x, y + y_offset)) ctx.line_to(x, y + y_offset) ctx.set_source_rgb(*color) ctx.set_line_width(line_width) ctx.stroke() for node in nodes: (node_x, node_y) = node r = random.randint(line_width * 2, line_width * 4) ctx.arc(node_x, node_y, r, 0, 2 * math.pi) ctx.set_source_rgb(*color) ctx.fill() # Ring around the node ctx.arc(node_x, node_y, r, 0, 2 * math.pi) ctx.set_source_rgb(*random.choice(colors.shades(color, 5))) ctx.set_line_width(line_width) ctx.stroke()
def pyramid(ctx, x, y, width, height, color, random_center=True): if random_center: center = (random.randint(x + 3, x + width - 3), random.randint(y + 3, y + height - 3)) else: center = (x + width // 2, y + height // 2) tl = (x, y) tr = (x + width, y) bl = (x, y + height) br = (x + width, y + height) cols = colors.shades(color, 5) triangle(ctx, tl, tr, center, cols[0]) triangle(ctx, tr, br, center, cols[1]) triangle(ctx, br, bl, center, cols[2]) triangle(ctx, bl, tl, center, cols[3])
def draw_line(ctx, x, y, x2, y2, line_width, color): def draw_it(width, col): ctx.move_to(x, y) ctx.line_to(x2, y2) ctx.set_line_width(width) ctx.set_line_cap(cairo.LineCap.ROUND) ctx.set_source_rgb(*col) ctx.stroke() outline_col = colors.shades(color, 3)[-2] outline_width = max(2, line_width / 8) # Draw slightly thicker "outline" first, then thinner "inner" line draw_it(line_width, outline_col) draw_it(line_width - outline_width, color)
def sphere(ctx, color, img_width, img_height, existing_shapes, min_radius=10, max_attempts=100): def getStartXY(): x = random.randint(min_radius, img_width - min_radius) y = random.randint(min_radius, img_height - min_radius) return (x, y) # 1. Get a start point that doesn't overlap with anything we already have. (start_x, start_y) = getStartXY() sphere = Point(start_x, start_y).buffer(min_radius, resolution=8) for _ in range(max_attempts * 100): if not existing_shapes.intersects(sphere): break (start_x, start_y) = getStartXY() sphere = Point(start_x, start_y).buffer(min_radius, resolution=8) # For the rare case that we did not find a working point. if existing_shapes.intersects(sphere): print("Could not find valid start point!") return existing_shapes # 2. Grow the sphere as far as possible, randomly. failed_attempts = 0 max_increment = 500 radius = min_radius while failed_attempts < max_attempts: new_radius = radius + max_increment new_sphere = Point(start_x, start_y).buffer(new_radius, resolution=12) if not existing_shapes.intersects(new_sphere) and within_canvas( start_x, start_y, img_width, img_height, new_radius): radius = new_radius sphere = new_sphere else: failed_attempts += 1 max_increment = int(max_increment * 3 / 4) if max_increment < 1: break # 3. Draw the sphere color_t = palettes.hex_to_tuple(color) tints = colors.tints(color_t, 5) shades = colors.shades(color_t, 3) ctx.arc(start_x, start_y, radius, 0, 2 * math.pi) gradient = cairo.RadialGradient(start_x - (1 / 2) * radius, start_y + (1 / 2) * radius, 0, start_x - (1 / 4) * radius, start_y + (1 / 4) * radius, radius * (5 / 4)) gradient.add_color_stop_rgb(0, 1, 1, 1) gradient.add_color_stop_rgb(0.9, *tints[-1]) gradient.add_color_stop_rgb(1, *shades[-1]) ctx.set_source(gradient) ctx.fill() buffered_sphere = Point(start_x, start_y).buffer(radius + 5, resolution=12) return existing_shapes.union(buffered_sphere)
def bar(ctx, color, line_width, img_width, img_height, existing_shapes, max_attempts=100): def getStartXY(): x = random.randint(line_width, img_width - line_width) y = random.randint(line_width, img_height - line_width) return (x, y) # 1. Get a start point that doesn't overlap with anything we already have. (start_x, start_y) = getStartXY() startPoint = Point(start_x, start_y).buffer(line_width // 2, resolution=8) for _ in range(max_attempts * 100): if not existing_shapes.intersects(startPoint): break (start_x, start_y) = getStartXY() startPoint = Point(start_x, start_y).buffer(line_width // 2, resolution=8) # For the rare case that we did not find a working point. if existing_shapes.intersects(startPoint): print("Could not find valid start point!") return existing_shapes end_x = start_x end_y = start_y bar = LineString([(start_x, start_y), (start_x, start_y)]).buffer(line_width) # 2. Grow the bar as far as possible, randomly. failed_attempts = 0 max_increment = 500 while failed_attempts < max_attempts: new_end_x = end_x new_end_y = end_y increment = random.randint(1, max_increment) if random.random() < 0.5: increment = -1 * increment if random.random() < 0.5: new_end_x += increment else: new_end_y += increment new_bar = LineString([(start_x, start_y), (new_end_x, new_end_y)]).buffer(line_width) if not existing_shapes.intersects(new_bar) and within_canvas( new_end_x, new_end_y, img_width, img_height, line_width): end_x = new_end_x end_y = new_end_y bar = new_bar else: failed_attempts += 1 max_increment = int(max_increment * 3 / 4) if max_increment < 1: break if end_x == start_x and end_y == start_y: print("Couldn't grow bar") return existing_shapes # 3. Draw the bar color_t = palettes.hex_to_tuple(color) tints = colors.tints(color_t, 5) shades = colors.shades(color_t, 3) ctx.move_to(start_x, start_y) ctx.line_to(end_x, end_y) ctx.set_line_width(line_width) ctx.set_line_cap(cairo.LineCap.ROUND) # Compute vector for highlight vector dx = end_x - start_x dy = end_y - start_y length = math.sqrt(pow(end_x - start_x, 2) + pow(end_y - start_y, 2)) # Center point of the bar center_x = start_x + (dx / 2) center_y = start_y + (dy / 2) # Start and end of highlight vector -- perpendicular to bar grad_start_x = (center_x + (dy / length) * line_width / 2) grad_start_y = (center_y + (-1) * (dx / length) * line_width / 2) grad_end_x = (center_x + (-1) * (dy / length) * (line_width / 2)) grad_end_y = (center_y + (dx / length) * (line_width / 2)) gradient = cairo.LinearGradient(grad_start_x, grad_start_y, grad_end_x, grad_end_y) gradient.add_color_stop_rgb(0, *shades[-2]) gradient.add_color_stop_rgb(0.7, *tints[-1]) gradient.add_color_stop_rgb(0.7, *tints[-1]) gradient.add_color_stop_rgb(0.75, 1, 1, 1) gradient.add_color_stop_rgb(0.75, 1, 1, 1) gradient.add_color_stop_rgb(0.8, *tints[-1]) gradient.add_color_stop_rgb(1, *shades[-1]) ctx.set_source(gradient) ctx.stroke() return existing_shapes.union(bar)