waxy 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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +16 -0
- data/README.md +86 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/img/random.png +0 -0
- data/examples/img/rectangle.png +0 -0
- data/lib/waxy.rb +71 -0
- data/lib/waxy/geometry.rb +60 -0
- data/lib/waxy/geometry/fractional_hex.rb +62 -0
- data/lib/waxy/geometry/hex.rb +93 -0
- data/lib/waxy/geometry/layout.rb +130 -0
- data/lib/waxy/geometry/orientation.rb +50 -0
- data/lib/waxy/geometry/point.rb +30 -0
- data/lib/waxy/meta.rb +71 -0
- data/lib/waxy/render.rb +20 -0
- data/lib/waxy/render/canvas.rb +28 -0
- data/lib/waxy/render/svg.rb +134 -0
- data/lib/waxy/render/templates/close_svg.erb +1 -0
- data/lib/waxy/render/templates/hex.erb +6 -0
- data/lib/waxy/render/templates/hex_pie.erb +32 -0
- data/lib/waxy/render/templates/open_svg.erb +1 -0
- data/lib/waxy/render/templates/svg.erb +59 -0
- data/lib/waxy/version.rb +3 -0
- data/waxy.gemspec +46 -0
- metadata +163 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module Waxy
|
2
|
+
module Geometry
|
3
|
+
|
4
|
+
class FractionalHex
|
5
|
+
|
6
|
+
attr_accessor :q, :r, :mq, :mr
|
7
|
+
|
8
|
+
# Ints
|
9
|
+
def initialize(_q, _r, _mq, _mr)
|
10
|
+
@q = _q
|
11
|
+
@r = _r
|
12
|
+
@mq = _mq
|
13
|
+
@mr = _mr
|
14
|
+
end
|
15
|
+
|
16
|
+
# def == (b)
|
17
|
+
# q == b.q && r == b.r && s == b.s
|
18
|
+
# end
|
19
|
+
|
20
|
+
# def != (b)
|
21
|
+
# !(self == b)
|
22
|
+
# end
|
23
|
+
|
24
|
+
# def + (b)
|
25
|
+
# Hex.new(q + b.q, r + b.r, s + b.s)
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def - (b)
|
29
|
+
# Hex.new(q - b.q, r - b.r, s - b.s)
|
30
|
+
# end
|
31
|
+
|
32
|
+
# # @param a [Hex]
|
33
|
+
# # @param k [Int]
|
34
|
+
# def * (k)
|
35
|
+
# Hex.new(q * k, r * k, s * k)
|
36
|
+
# end
|
37
|
+
|
38
|
+
# def hex_length(hex)
|
39
|
+
# ((hex.q.abs + hex.r.abs + hex.s.abs) / 2).to_i
|
40
|
+
# end
|
41
|
+
|
42
|
+
# def distance(b)
|
43
|
+
# hex_length(self - b)
|
44
|
+
# end
|
45
|
+
|
46
|
+
# def hex_direction(i)
|
47
|
+
# raise if !(0..5).include?(i)
|
48
|
+
# HEX_DIRECTIONS[i]
|
49
|
+
# end
|
50
|
+
|
51
|
+
# # (0..5, requires modulo prior)
|
52
|
+
# def hex_neighbor(i)
|
53
|
+
# self + hex_direction(i)
|
54
|
+
# end
|
55
|
+
|
56
|
+
# def polygon_corners(layout)
|
57
|
+
|
58
|
+
# end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Waxy
|
2
|
+
module Geometry
|
3
|
+
class Hex
|
4
|
+
|
5
|
+
attr_accessor :q, :r, :s
|
6
|
+
|
7
|
+
# Vector of 6 x (0.0 - 1.0)
|
8
|
+
# Used to scale the pie slices
|
9
|
+
# !! @size is typically set during render through a Waxy::Meta
|
10
|
+
|
11
|
+
attr_accessor :size
|
12
|
+
|
13
|
+
# All params are Int
|
14
|
+
def initialize(_q, _r, _s = nil)
|
15
|
+
@q = _q
|
16
|
+
@r = _r
|
17
|
+
@s = _s
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array]
|
21
|
+
# initialized here for foreseable geometry calculations,
|
22
|
+
# but in general this should be handled through a Meta
|
23
|
+
def size
|
24
|
+
@size ||= [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
25
|
+
@size
|
26
|
+
end
|
27
|
+
|
28
|
+
def == (b)
|
29
|
+
q == b.q && r == b.r && s == b.s
|
30
|
+
end
|
31
|
+
|
32
|
+
def != (b)
|
33
|
+
!(self == b)
|
34
|
+
end
|
35
|
+
|
36
|
+
def + (b)
|
37
|
+
Hex.new(q + b.q, r + b.r, ( s ? s + b.s : nil))
|
38
|
+
end
|
39
|
+
|
40
|
+
def - (b)
|
41
|
+
Hex.new(q - b.q, r - b.r, (s ? s - b.s : nil))
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param a [Hex]
|
45
|
+
# @param k [Int]
|
46
|
+
def * (k)
|
47
|
+
Hex.new(q * k, r * k, (s ? s * k : nil))
|
48
|
+
end
|
49
|
+
|
50
|
+
def hex_length(hex)
|
51
|
+
((hex.q.abs + hex.r.abs + hex.s.abs) / 2).to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
def distance(b)
|
55
|
+
hex_length(self - b)
|
56
|
+
end
|
57
|
+
|
58
|
+
def hex_direction(i)
|
59
|
+
raise if !(0..5).include?(i)
|
60
|
+
HEX_DIRECTIONS_FLAT[i]
|
61
|
+
end
|
62
|
+
|
63
|
+
# (0..5, requires modulo prior)
|
64
|
+
def hex_neighbor(i)
|
65
|
+
self + hex_direction(i)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#TODO(mjy) fix
|
70
|
+
def self.point(center, size, i)
|
71
|
+
angle_deg = 60.0 * i
|
72
|
+
angle_rad = Math::PI / 180 * angle_deg
|
73
|
+
Waxy::Geometry::Point.new(
|
74
|
+
((center.x + size) * Math.cos(angle_rad)),
|
75
|
+
((center.y + size ) * Math.sin(angle_rad))
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.hexagon(center, size)
|
80
|
+
Hexagon.new(
|
81
|
+
outer_coords: (1..6).collect{|i| point(center, size, i)}
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.triangle(center, size, i)
|
86
|
+
points = [[0,0]]
|
87
|
+
points.push point(center, size, i)
|
88
|
+
points.push point(center, size, (i + 1 == 7 ? 1 : i + 1))
|
89
|
+
points
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Waxy
|
2
|
+
module Geometry
|
3
|
+
|
4
|
+
class Layout
|
5
|
+
|
6
|
+
# Waxy::Geometry::Orientation
|
7
|
+
attr_accessor :orientation
|
8
|
+
|
9
|
+
# Waxy::Geometry::Point
|
10
|
+
attr_accessor :size
|
11
|
+
|
12
|
+
# Waxy::Geometry::Point
|
13
|
+
attr_accessor :origin
|
14
|
+
|
15
|
+
# pixels between hexes
|
16
|
+
# !! Padding is applied at render time, not geometry compute time, i.e. using this will currently
|
17
|
+
# !! break things like pixel_to_hex
|
18
|
+
attr_accessor :padding
|
19
|
+
|
20
|
+
attr_reader :pad_h_offset, :pad_w_offset
|
21
|
+
|
22
|
+
def initialize(_orientation, _size, _origin, _padding = 0.0)
|
23
|
+
@orientation = _orientation
|
24
|
+
@size = _size
|
25
|
+
@origin = _origin
|
26
|
+
@padding = _padding
|
27
|
+
reset_padding
|
28
|
+
end
|
29
|
+
|
30
|
+
def hex_to_pixel(hex)
|
31
|
+
m = orientation
|
32
|
+
x = (m.f0 * hex.q + m.f1 * hex.r) * size.x
|
33
|
+
y = (m.f2 * hex.q + m.f3 * hex.r) * size.y
|
34
|
+
|
35
|
+
Waxy::Geometry::Point.new(x + origin.x, y + origin.y)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pixel_to_hex(p)
|
39
|
+
m = orientation
|
40
|
+
pt = Waxy::Geometry::Point.new((p.x - origin.x) / size.x,
|
41
|
+
(p.y - origin.y) / size.y)
|
42
|
+
q = m.b0 * pt.x + m.b1 * pt.y
|
43
|
+
r = m.b2 * pt.x + m.b3 * pt.y
|
44
|
+
|
45
|
+
Waxy::Geometry::FractionalHex.new(q, r, q * -1.0, r * -1.0)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param corner [Integer]
|
49
|
+
def hex_corner_offset(corner, s = nil)
|
50
|
+
s ||= size
|
51
|
+
angle = hex_corner_angle(corner)
|
52
|
+
Waxy::Geometry::Point.new(s.x * Math.cos(angle), s.y * Math.sin(angle))
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param corner [Integer]
|
56
|
+
def hex_corner_angle(corner)
|
57
|
+
2.0 * Math::PI * (orientation.start_angle + corner) / 6
|
58
|
+
end
|
59
|
+
|
60
|
+
# @params h [Waxy::Geometry::Hex]
|
61
|
+
def polygon_corners(h)
|
62
|
+
corners = []
|
63
|
+
center = hex_to_pixel(h)
|
64
|
+
(0..5).each do |i|
|
65
|
+
offset = hex_corner_offset(i)
|
66
|
+
|
67
|
+
corners.push Waxy::Geometry::Point.new(
|
68
|
+
center.x + offset.x,
|
69
|
+
center.y + offset.y)
|
70
|
+
end
|
71
|
+
corners
|
72
|
+
end
|
73
|
+
|
74
|
+
# Departing from Redblob here
|
75
|
+
|
76
|
+
def point(hex, i, scale = 1.0 )
|
77
|
+
center = hex_to_pixel(hex)
|
78
|
+
|
79
|
+
resized = size.dup
|
80
|
+
resized.x = resized.x * scale
|
81
|
+
resized.y = resized.y * scale
|
82
|
+
|
83
|
+
offset = hex_corner_offset(i, resized)
|
84
|
+
|
85
|
+
Waxy::Geometry::Point.new( center.x + offset.x, center.y + offset.y )
|
86
|
+
end
|
87
|
+
|
88
|
+
def triangle(hex, i)
|
89
|
+
scale = hex.size[i]
|
90
|
+
|
91
|
+
points = [ hex_to_pixel(hex) ]
|
92
|
+
points.push point(hex, i, scale)
|
93
|
+
points.push point(hex, (i + 1 == 6 ? 0 : i + 1), scale)
|
94
|
+
points
|
95
|
+
end
|
96
|
+
|
97
|
+
def triangles(hex)
|
98
|
+
(0..5).each_with_index.collect{|t,i| triangle(hex, i) }
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Padding methods are not part of Amit's original code. They are not integrated into geometry compute.
|
103
|
+
#
|
104
|
+
|
105
|
+
def reset_padding
|
106
|
+
reset_h_padding
|
107
|
+
reset_w_padding
|
108
|
+
end
|
109
|
+
|
110
|
+
def reset_h_padding
|
111
|
+
@pad_h_offset = 0.0
|
112
|
+
end
|
113
|
+
|
114
|
+
def reset_w_padding
|
115
|
+
@pad_w_offset = 0.0
|
116
|
+
end
|
117
|
+
|
118
|
+
def increase_h_padding
|
119
|
+
@pad_h_offset += padding
|
120
|
+
end
|
121
|
+
|
122
|
+
def increase_w_padding
|
123
|
+
@pad_w_offset += padding
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Waxy
|
2
|
+
module Geometry
|
3
|
+
|
4
|
+
class Orientation
|
5
|
+
attr_accessor :f0, :f1, :f2, :f3,
|
6
|
+
:b0, :b1, :b2, :b3,
|
7
|
+
:start_angle
|
8
|
+
|
9
|
+
def initialize(_f0, _f1, _f2, _f3, _b0, _b1, _b2, _b3, _start_angle)
|
10
|
+
@f0 = _f0
|
11
|
+
@f1 = _f1
|
12
|
+
@f2 = _f2
|
13
|
+
@f3 = _f3
|
14
|
+
@b0 = _b0
|
15
|
+
@b1 = _b1
|
16
|
+
@b2 = _b2
|
17
|
+
@b3 = _b3
|
18
|
+
@start_angle = _start_angle
|
19
|
+
end
|
20
|
+
|
21
|
+
LAYOUT_POINTY = Orientation.new(
|
22
|
+
Math.sqrt(3.0),
|
23
|
+
Math.sqrt(3.0) / 2.0,
|
24
|
+
0.0,
|
25
|
+
3.0 / 2.0,
|
26
|
+
Math.sqrt(3.0) / 3.0,
|
27
|
+
-1.0 / 3.0,
|
28
|
+
0.0,
|
29
|
+
2.0 / 3.0,
|
30
|
+
0.5
|
31
|
+
)
|
32
|
+
|
33
|
+
LAYOUT_FLAT = Orientation.new(
|
34
|
+
3.0 / 2.0,
|
35
|
+
0.0,
|
36
|
+
Math.sqrt(3.0) / 2.0,
|
37
|
+
Math.sqrt(3.0),
|
38
|
+
2.0 / 3.0,
|
39
|
+
0.0,
|
40
|
+
-1.0 / 3.0,
|
41
|
+
Math.sqrt(3.0) / 3.0,
|
42
|
+
0.0
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Waxy
|
2
|
+
module Geometry
|
3
|
+
|
4
|
+
class Point
|
5
|
+
attr_accessor :x, :y
|
6
|
+
|
7
|
+
def initialize(_x, _y)
|
8
|
+
@x = _x
|
9
|
+
@y = _y
|
10
|
+
end
|
11
|
+
|
12
|
+
def hex_to_pixel(layout, h)
|
13
|
+
m = layout.orientation
|
14
|
+
x = (m.f0 * h.q + m.f1 * h.r) * layout.size.x
|
15
|
+
y = (m.f2 * h.q + m.f3 * h.r) * layout.size.y
|
16
|
+
return Point.new(x + layout.origin.x, y + layout.origin.y)
|
17
|
+
end
|
18
|
+
|
19
|
+
def hex_corner_offset(layout, corner)
|
20
|
+
size = Point.new(layout.size)
|
21
|
+
angle = 2.0 * M_PI * (layout.orientation.start_angle + corner ) / 6
|
22
|
+
Point.new(size.x * cos(angle), size.y * sin(angle))
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/waxy/meta.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Waxy
|
2
|
+
|
3
|
+
# Instances of Meta contain attributes
|
4
|
+
# that describe the visual appearance of a single hexagon.
|
5
|
+
class Meta
|
6
|
+
|
7
|
+
## -- Attributes for solid hex layouts
|
8
|
+
|
9
|
+
# Hex border SVG stroke
|
10
|
+
attr_accessor :stroke
|
11
|
+
|
12
|
+
# Hex fill
|
13
|
+
# not applicable to all templates
|
14
|
+
attr_accessor :fill
|
15
|
+
|
16
|
+
# a URL for the whole hexagon
|
17
|
+
# not applicable to all templates
|
18
|
+
attr_accessor :link
|
19
|
+
|
20
|
+
# title value for hex <a>
|
21
|
+
attr_accessor :link_title
|
22
|
+
|
23
|
+
## -- Attributes for "pie" layouts
|
24
|
+
|
25
|
+
# Array of 6 * (0.0..1.0)
|
26
|
+
# scales "pie" slices
|
27
|
+
attr_accessor :size
|
28
|
+
|
29
|
+
# An Array (0..5) of links, one for each slice of 'Pie'
|
30
|
+
attr_accessor :pie_links
|
31
|
+
|
32
|
+
# An Array (0..5) of SVG color values
|
33
|
+
attr_accessor :colors
|
34
|
+
|
35
|
+
# @return [Array]
|
36
|
+
# 6 strings with SVG color= values
|
37
|
+
def colors
|
38
|
+
@colors.nil? ? Waxy::COLORS.values : @colors
|
39
|
+
end
|
40
|
+
|
41
|
+
def pie_links
|
42
|
+
@pie_links.nil? ? [] : @pie_links
|
43
|
+
end
|
44
|
+
|
45
|
+
# Describes how "full" a pie hexagon is
|
46
|
+
def sum_size
|
47
|
+
size.sum
|
48
|
+
end
|
49
|
+
|
50
|
+
# Helper methods
|
51
|
+
|
52
|
+
def hex_link_start
|
53
|
+
return nil unless link
|
54
|
+
[
|
55
|
+
'<a href="' + link + '"',
|
56
|
+
'class="waxy__link"',
|
57
|
+
'>'
|
58
|
+
].compact.join(' ')
|
59
|
+
end
|
60
|
+
|
61
|
+
def hex_link_title
|
62
|
+
return nil unless link_title
|
63
|
+
"<title>#{link_title}</title>"
|
64
|
+
end
|
65
|
+
|
66
|
+
def hex_link_end
|
67
|
+
'</a>' if link
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/waxy/render.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'tilt'
|
3
|
+
|
4
|
+
require_relative 'render/svg'
|
5
|
+
require_relative 'render/canvas'
|
6
|
+
|
7
|
+
module Waxy
|
8
|
+
|
9
|
+
module Render
|
10
|
+
COLORS = {
|
11
|
+
1 => 'yellow',
|
12
|
+
2 => 'orange',
|
13
|
+
3 => 'red',
|
14
|
+
4 => 'purple',
|
15
|
+
5 => 'blue',
|
16
|
+
6 => 'green'
|
17
|
+
}
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|