tiledenticon 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/face.rb +31 -3
- data/lib/tiledenticon.rb +19 -11
- data/lib/tiler.rb +63 -38
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91badaf0443b9bb80e880a8a54881c93c2335fd2
|
4
|
+
data.tar.gz: 3af121955ad819c7a80d7d95e78ba921bcde29b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3db670823e703c28d7a8a66d90c64bea4c447bc62eea83f7aa0a32138481f67a3b237622ec077ab4db7453db0fe0b9273a53d81831c5332d8d0f453cced8ac79
|
7
|
+
data.tar.gz: f16c265b4dbab6475b9461aa53e6859cdd285fbe2ca53fecf859af2042177c8ef0fbef9934e5f9e2f23107f1868e7d22b7049b43af1115129b3c213e73bffd48
|
data/lib/face.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
|
+
# Warning, documentation written in mathsspeak
|
2
|
+
#
|
1
3
|
class Face
|
2
|
-
|
3
|
-
|
4
|
+
# Represents a 2-dimensional tile with sides of unit length in 4-dimensional
|
5
|
+
# space
|
6
|
+
# V is a vector4 representing the position of the faces base vertex
|
7
|
+
# Axis1 and axis2 are the two canonical axis that the face is aligned with
|
8
|
+
|
9
|
+
def initialize v, axis1, axis2
|
10
|
+
@pos = v
|
4
11
|
@a_min = min(axis1, axis2)
|
5
12
|
@a_max = max(axis1, axis2)
|
6
13
|
end
|
7
14
|
|
15
|
+
# One iteration of the system
|
16
|
+
# Position is multiplied by translation_matrix
|
17
|
+
# Faces are updated based on algorithm encoded here with switch statements
|
18
|
+
#
|
19
|
+
# There are some cases where the face splits in two, so we return either a new
|
20
|
+
# face or nil
|
21
|
+
|
8
22
|
def tick translation_matrix
|
9
23
|
ret = nil
|
10
24
|
@pos = translation_matrix * @pos
|
@@ -45,11 +59,15 @@ class Face
|
|
45
59
|
return ret
|
46
60
|
end
|
47
61
|
|
62
|
+
# There are several cases in tick where we 'shunt' the position of the face by
|
63
|
+
# a constant translation
|
48
64
|
private def shunt_pos
|
49
65
|
a = @pos.to_a
|
50
|
-
@pos = Vector[a[0] -
|
66
|
+
@pos = Vector[a[0] - 1, a[1], a[2], a[3] + 1]
|
51
67
|
end
|
52
68
|
|
69
|
+
# Getters
|
70
|
+
|
53
71
|
def pos
|
54
72
|
@pos
|
55
73
|
end
|
@@ -62,3 +80,13 @@ class Face
|
|
62
80
|
@a_max
|
63
81
|
end
|
64
82
|
end
|
83
|
+
|
84
|
+
# Return min of a series of values
|
85
|
+
def min(*values)
|
86
|
+
values.min
|
87
|
+
end
|
88
|
+
|
89
|
+
# Return max of a series of values
|
90
|
+
def max(*values)
|
91
|
+
values.max
|
92
|
+
end
|
data/lib/tiledenticon.rb
CHANGED
@@ -1,32 +1,40 @@
|
|
1
1
|
require 'tiler.rb'
|
2
2
|
|
3
3
|
class Tiledenticon
|
4
|
+
# Wrapper for the classes defined in this library
|
5
|
+
|
4
6
|
def initialize out_folder
|
5
7
|
@out_folder = out_folder
|
6
8
|
end
|
7
|
-
|
9
|
+
|
10
|
+
def create str
|
11
|
+
# Create a new md5 hasher and feed in the input string
|
8
12
|
md5 = Digest::MD5.new
|
9
|
-
md5 <<
|
13
|
+
md5 << str
|
10
14
|
hash = md5.hexdigest
|
15
|
+
hr = Hashrander.new hash
|
11
16
|
|
12
|
-
|
17
|
+
fromHashrander "#{@out_folder}/#{str}.png", hr
|
13
18
|
end
|
14
19
|
|
20
|
+
# Create a series of parameters from an Hashrander
|
15
21
|
private
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
s2 = 0.5 + (r.get_rand 2, 0.5 * s1)
|
22
|
+
def fromHashrander filename, hr
|
23
|
+
hue = hr.get_rand 3, 360
|
24
|
+
s1 = 0.5 + (hr.get_rand 2, 0.5)
|
25
|
+
s2 = 0.4 + (hr.get_rand 2, 0.6 * s1)
|
21
26
|
|
22
|
-
p_x = 0.5 + (
|
23
|
-
p_y = 0.5 + (
|
27
|
+
p_x = 0.5 + (hr.get_rand 2, 1.15)
|
28
|
+
p_y = 0.5 + (hr.get_rand 2, 1.15)
|
24
29
|
|
25
|
-
TilerBuilder.new(filename).set_hue(hue).set_sat_major(s1).set_sat_minor(s2).set_projection_lambda(p_x, p_y).build
|
30
|
+
TilerBuilder.new(filename).set_hue(hue).set_sat_major(s1).set_sat_minor(s2).set_projection_lambda(p_x, p_y).set_ticks(16).build
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
29
34
|
class Hashrander
|
35
|
+
|
36
|
+
# Generate random numbers of arbitrary size from a hash
|
37
|
+
|
30
38
|
def initialize hash
|
31
39
|
@hash_i = 0
|
32
40
|
@hash = hash
|
data/lib/tiler.rb
CHANGED
@@ -1,30 +1,22 @@
|
|
1
|
-
# From here
|
2
|
-
# http://www.mathematicians.org.uk/eoh/files/Harriss_ANGASRP.pdf
|
3
|
-
|
4
1
|
require 'face'
|
5
2
|
|
6
3
|
require 'chunky_png'
|
7
4
|
require 'matrix'
|
8
5
|
require 'digest'
|
9
6
|
|
10
|
-
|
11
|
-
values.min
|
12
|
-
end
|
13
|
-
|
14
|
-
def max(*values)
|
15
|
-
values.max
|
16
|
-
end
|
7
|
+
# Warning, documentation written in mathsspeak
|
17
8
|
|
9
|
+
# Convert min axis, max axis tuple to an orientation index
|
10
|
+
# where axis is between 1 and 4
|
11
|
+
# and min_axis < max_axis
|
18
12
|
def min_max_to_i min, max
|
19
13
|
return max - 1 if min == 0
|
20
14
|
return 1 + max if min == 1
|
21
15
|
return 5
|
22
16
|
end
|
23
|
-
$dirmultx = 1
|
24
|
-
$dirmulty = 1
|
25
|
-
|
26
17
|
|
27
18
|
class TilerBuilder
|
19
|
+
# Builder class for Tiler
|
28
20
|
|
29
21
|
def initialize filename
|
30
22
|
@hue = 345
|
@@ -87,32 +79,44 @@ end
|
|
87
79
|
|
88
80
|
class Tiler
|
89
81
|
|
82
|
+
# The matrix that we multiply against the position of every face on tick
|
90
83
|
@@translation_matrix =
|
91
84
|
Matrix[[0, 0, 0, -1],
|
92
|
-
[1, 0, 0,
|
93
|
-
[0, 1, 0,
|
94
|
-
[0, 0, 1,
|
85
|
+
[1, 0, 0, 0],
|
86
|
+
[0, 1, 0, 0],
|
87
|
+
[0, 0, 1, 1]]
|
95
88
|
|
96
89
|
def initialize image_width, image_height, scale, hue, sat_major, sat_minor, projection_lambda
|
90
|
+
|
91
|
+
# We colour based on face orientation index,
|
92
|
+
# 0 and 1 being white
|
93
|
+
# 2 and 4 based on hue
|
94
|
+
# 3 and 5 based on the compliment of hue
|
95
|
+
|
97
96
|
@h1 = hue
|
98
97
|
@h2 = (hue + 360/2) % 360
|
99
|
-
|
98
|
+
|
100
99
|
@colors = [
|
101
100
|
ChunkyPNG::Color.from_hsv(0, 0, 1),
|
102
101
|
ChunkyPNG::Color.from_hsv(0, 0.0, 1),
|
103
|
-
ChunkyPNG::Color.from_hsv(@h1, sat_major,
|
104
|
-
ChunkyPNG::Color.from_hsv(@h2, sat_major,
|
102
|
+
ChunkyPNG::Color.from_hsv(@h1, sat_major, 0.9),
|
103
|
+
ChunkyPNG::Color.from_hsv(@h2, sat_major, 0.9),
|
105
104
|
ChunkyPNG::Color.from_hsv(@h1, sat_minor, 0.6),
|
106
105
|
ChunkyPNG::Color.from_hsv(@h2, sat_minor, 0.6)
|
107
106
|
]
|
108
107
|
|
109
|
-
|
110
108
|
@image_width = image_width
|
111
109
|
@image_height = image_height
|
110
|
+
|
111
|
+
# (ox,oy) describes the centre of the image
|
112
112
|
@ox = @image_width/2
|
113
113
|
@oy = @image_height/2
|
114
|
+
|
115
|
+
# Scale is the length in pixels of the unit distance when rendered
|
114
116
|
@scale = scale
|
115
117
|
|
118
|
+
# Construct the projection of 4 dimensional space onto the output image
|
119
|
+
# (cononical_x[i],cononical_y[i]) describes the projection of e_i
|
116
120
|
@canonical_x = []
|
117
121
|
@canonical_y = []
|
118
122
|
for i in 0..3 do
|
@@ -120,19 +124,23 @@ class Tiler
|
|
120
124
|
@canonical_x << c.real
|
121
125
|
@canonical_y << c.imaginary
|
122
126
|
end
|
123
|
-
@all_faces = [Face.new(Vector[0, 0, 0, 0], 2, 3)]
|
124
|
-
end
|
125
127
|
|
128
|
+
# Add an initial face to the list of faces
|
129
|
+
@all_faces = [Face.new(Vector[0, 0, 0, 0], 2, 3)]
|
126
130
|
|
131
|
+
end
|
127
132
|
|
128
|
-
|
129
|
-
|
133
|
+
# Convert a positional vector 4 to image space
|
134
|
+
def to_image_space p, origin_x, origin_y
|
135
|
+
{x: (origin_x - @scale * (p[0] * @canonical_x[0] + p[1] * @canonical_x[1] +
|
130
136
|
p[2] * @canonical_x[2] + p[3] * @canonical_x[3])),
|
131
|
-
y: (
|
137
|
+
y: (origin_y + @scale * (p[0] * @canonical_y[0] + p[1] * @canonical_y[1] +
|
132
138
|
p[2] * @canonical_y[2] + p[3] * @canonical_y[3]))};
|
133
139
|
end
|
134
140
|
|
135
141
|
def tile ticks, filename
|
142
|
+
|
143
|
+
# Iterate all faces ticks times
|
136
144
|
for i in 1 .. ticks
|
137
145
|
new_list = []
|
138
146
|
@all_faces.each do |face|
|
@@ -141,42 +149,59 @@ class Tiler
|
|
141
149
|
new_list << ret unless ret.nil?
|
142
150
|
end
|
143
151
|
@all_faces = new_list
|
152
|
+
end
|
144
153
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
# (global_xo, global_yo) is a translation of the entire rendered surface
|
155
|
+
# we do this to centre on a region that is actually tiled
|
156
|
+
|
157
|
+
@global_xo = 0
|
158
|
+
@global_yo = 0
|
159
|
+
|
160
|
+
# For now we focus on the average position of all faces
|
161
|
+
@all_faces.each do |face|
|
162
|
+
p = to_image_space(face.pos.to_a, @ox, @oy)
|
163
|
+
@global_xo += (@ox - p[:x])/@all_faces.length
|
164
|
+
@global_yo += (@oy - p[:y])/@all_faces.length
|
151
165
|
end
|
152
166
|
|
153
167
|
# Draw
|
154
|
-
image = ChunkyPNG::Image.new(@image_width, @image_height, ChunkyPNG::Color::TRANSPARENT)
|
155
|
-
|
156
168
|
puts "Tiledenticon: Drawing image"
|
169
|
+
|
170
|
+
# Create a new, blank image
|
171
|
+
image = ChunkyPNG::Image.new @image_width, @image_height, @colors[5]
|
172
|
+
|
173
|
+
draw_x = @global_xo + @ox
|
174
|
+
draw_y = @global_yo + @oy
|
175
|
+
|
157
176
|
@all_faces.each_with_index do |face, i|
|
158
177
|
print "Tiledenticon: Face #{i}\r"
|
159
178
|
|
160
|
-
|
179
|
+
# Generate the points to a from each face for rendering
|
180
|
+
|
181
|
+
p1 = to_image_space face.pos.to_a, draw_x, draw_y
|
161
182
|
|
162
183
|
p2_m = face.pos.to_a
|
163
184
|
p2_m[face.min_axis] += 1
|
164
|
-
p2 = to_image_space
|
185
|
+
p2 = to_image_space p2_m, draw_x, draw_y
|
165
186
|
|
166
187
|
p3_m = face.pos.to_a
|
167
188
|
p3_m[face.max_axis] += 1
|
168
|
-
p3 = to_image_space
|
189
|
+
p3 = to_image_space p3_m, draw_x, draw_y
|
169
190
|
|
170
191
|
p4_m = face.pos.to_a
|
171
192
|
p4_m[face.min_axis] += 1
|
172
193
|
p4_m[face.max_axis] += 1
|
173
|
-
p4 = to_image_space
|
174
|
-
|
194
|
+
p4 = to_image_space p4_m, draw_x, draw_y
|
175
195
|
|
176
196
|
points = ChunkyPNG::Vector.new([p1, p2, p4, p3])
|
197
|
+
|
198
|
+
# Pick colour based on colour scheme in @colors array and the direcion the
|
199
|
+
# face is orientated
|
177
200
|
color = @colors[min_max_to_i face.min_axis, face.max_axis]
|
201
|
+
|
178
202
|
image.polygon(points, ChunkyPNG::Color::TRANSPARENT, color)
|
179
203
|
end
|
204
|
+
|
180
205
|
puts "\nTiledenticon: Saving image to #{filename}"
|
181
206
|
image.save(filename, :interlace => false)
|
182
207
|
end
|