-
Notifications
You must be signed in to change notification settings - Fork 1
/
pack.py
138 lines (98 loc) · 3.19 KB
/
pack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from math import *
from operator import concat
from random import randint, random
import colorsys
import Image, ImageDraw
import pysvg.structure
import pysvg.builders
grace_border = 0
img_dim = (1024, 1024)
img_height = img_dim[0]
img_width = img_dim[1]
img_xmid = img_width/2
img_ymid = img_height/2
min_circ_rad = 50
max_circ_rad = 100
class Circle:
__slots__ = ('x', 'y', 'rad', 'neighbors')
def __init__(self, x, y, rad):
self.x = x
self.y = y
self.rad = rad
self.neighbors = 0
def draw_circle(x, y, rad, draw, color = "black"):
draw.ellipse((x - rad, y - rad, x + rad, y + rad), fill = color)
def coll_dist(c1, c2):
return sqrt((c1.x - c2.x)**2 + (c1.y - c2.y)**2) - (c1.rad + c2.rad)
def colliding(c1, c2):
return coll_dist(c1, c2) < 0
# The radius c1 needs to be to kiss c2
def kiss_dist(c1, c2):
return sqrt((c1.x - c2.x)**2 + (c1.y - c2.y)**2) - c2.rad
def point_in_circ(x, y, c):
return sqrt((x - c.x)**2 + (y - c.y)**2) <= c.rad
def rand_color():
return (randint(0, 256), randint(0, 256), randint(0, 256))
def rand_in_circle(x, y, rad):
# First, generate random polar coordinates
prad = sqrt(random()) * rad
pang = random() * (2 * pi)
px = prad * cos(pang)
py = prad * sin(pang)
return (px, py)
def rgb_to_hex(rgb):
return "#" + reduce(concat, map(lambda x: "%02x" % x, rgb))
im = Image.new("RGB", img_dim, "white")
draw = ImageDraw.Draw(im)
svg = pysvg.structure.svg()
sb = pysvg.builders.ShapeBuilder()
# start coming up with circles
num_circles = 3000
circles = []
for i in range(num_circles):
crand = rand_in_circle(img_xmid, img_ymid, img_xmid)
x = crand[0] + img_xmid
y = crand[1] + img_xmid
# x = randint(grace_border, img_dim[0] - grace_border + 1)
# y = randint(grace_border, img_dim[1] - grace_border + 1)
while any([point_in_circ(x, y, c) for c in circles]):
crand = rand_in_circle(img_xmid, img_ymid, img_xmid)
x = crand[0] + img_xmid
y = crand[1] + img_xmid
max = randint(min_circ_rad, max_circ_rad)
circ = Circle(x, y, max)
min_dist = 1000000
min_c = None
for c in circles:
cd = coll_dist(circ, c)
if cd >= 0:
continue
circ.neighbors += 1
if coll_dist(circ, c) < min_dist:
min_dist = coll_dist(circ, c)
min_c = c
#if len(colliding) > 0:
# print "collided with " + str(len(colliding))
if min_dist < 0:
circ.rad = kiss_dist(circ, min_c)
circles.append(circ)
# Note: put circles in big circles, see if perception is maintained?
max_neighbors = 0
for circ in circles:
if circ.neighbors > max_neighbors:
max_neighbors = circ.neighbors
for circ in circles:
# The darkness is partially determined by its neighbors
clr1 = 240 - int((float(circ.neighbors) / max_neighbors) * 240)
# The other part is determined by its size
clr2 = int((float(circ.rad) / max_circ_rad) * 15)
clr = clr1 + clr2
light = float(clr) / 255
hue = float(circ.y) / img_height
sat = 1
rgb = map(lambda x: int(255 * x), colorsys.hls_to_rgb(hue, light, sat))
draw_circle(circ.x, circ.y, circ.rad - 1, draw, color = (rgb[0], rgb[1], rgb[2]))
svg.addElement(sb.createCircle(circ.x, circ.y, circ.rad, strokewidth = 0, fill = rgb_to_hex(rgb)))
# print ["%d, %d, %d" % (c.x, c.y, c.rad) for c in circles]
im.save("pack.png", "PNG")
svg.save("pack.svg")