geo_pattern 1.3.2 → 1.4.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/.rubocop.yml +58 -0
- data/.simplecov +25 -0
- data/.travis.yml +12 -0
- data/Gemfile +3 -1
- data/README.md +125 -23
- data/Rakefile +72 -9
- data/fixtures/generated_patterns/chevrons.svg +1 -0
- data/fixtures/generated_patterns/concentric_circles.svg +1 -0
- data/fixtures/generated_patterns/diamonds.svg +1 -0
- data/fixtures/generated_patterns/diamonds_with_base_color.svg +1 -0
- data/fixtures/generated_patterns/diamonds_with_color.svg +1 -0
- data/fixtures/generated_patterns/hexagons.svg +1 -0
- data/fixtures/generated_patterns/mosaic_squares.svg +1 -0
- data/fixtures/generated_patterns/nested_squares.svg +1 -0
- data/fixtures/generated_patterns/octagons.svg +1 -0
- data/fixtures/generated_patterns/overlapping_circles.svg +1 -0
- data/fixtures/generated_patterns/overlapping_rings.svg +1 -0
- data/fixtures/generated_patterns/plaid.svg +1 -0
- data/fixtures/generated_patterns/plus_signs.svg +1 -0
- data/fixtures/generated_patterns/sine_waves.svg +1 -0
- data/fixtures/generated_patterns/squares.svg +1 -0
- data/fixtures/generated_patterns/tessellation.svg +1 -0
- data/fixtures/generated_patterns/triangles.svg +1 -0
- data/fixtures/generated_patterns/xes.svg +1 -0
- data/geo_pattern.gemspec +8 -2
- data/lib/geo_pattern.rb +42 -20
- data/lib/geo_pattern/background.rb +25 -0
- data/lib/geo_pattern/background_generators/solid_generator.rb +52 -0
- data/lib/geo_pattern/color.rb +25 -0
- data/lib/geo_pattern/color_generators/base_color_generator.rb +55 -0
- data/lib/geo_pattern/color_generators/simple_generator.rb +27 -0
- data/lib/geo_pattern/color_preset.rb +26 -0
- data/lib/geo_pattern/errors.rb +7 -0
- data/lib/geo_pattern/geo_pattern_task.rb +59 -0
- data/lib/geo_pattern/helpers.rb +47 -0
- data/lib/geo_pattern/pattern.rb +84 -0
- data/lib/geo_pattern/pattern_generator.rb +33 -82
- data/lib/geo_pattern/pattern_helpers.rb +31 -2
- data/lib/geo_pattern/pattern_preset.rb +23 -0
- data/lib/geo_pattern/pattern_sieve.rb +36 -0
- data/lib/geo_pattern/pattern_store.rb +63 -0
- data/lib/geo_pattern/pattern_validator.rb +27 -0
- data/lib/geo_pattern/rake_task.rb +109 -0
- data/lib/geo_pattern/roles/comparable_metadata.rb +35 -0
- data/lib/geo_pattern/roles/named_generator.rb +13 -0
- data/lib/geo_pattern/seed.rb +21 -0
- data/lib/geo_pattern/structure.rb +25 -0
- data/lib/geo_pattern/structure_generators/base_generator.rb +85 -0
- data/lib/geo_pattern/structure_generators/chevrons_generator.rb +55 -0
- data/lib/geo_pattern/structure_generators/concentric_circles_generator.rb +56 -0
- data/lib/geo_pattern/structure_generators/diamonds_generator.rb +66 -0
- data/lib/geo_pattern/structure_generators/hexagons_generator.rb +67 -0
- data/lib/geo_pattern/structure_generators/mosaic_squares_generator.rb +85 -0
- data/lib/geo_pattern/structure_generators/nested_squares_generator.rb +60 -0
- data/lib/geo_pattern/structure_generators/octagons_generator.rb +44 -0
- data/lib/geo_pattern/structure_generators/overlapping_circles_generator.rb +55 -0
- data/lib/geo_pattern/structure_generators/overlapping_rings_generator.rb +55 -0
- data/lib/geo_pattern/structure_generators/plaid_generator.rb +55 -0
- data/lib/geo_pattern/structure_generators/plus_signs_generator.rb +62 -0
- data/lib/geo_pattern/structure_generators/sine_waves_generator.rb +43 -0
- data/lib/geo_pattern/structure_generators/squares_generator.rb +36 -0
- data/lib/geo_pattern/structure_generators/tessellation_generator.rb +103 -0
- data/lib/geo_pattern/structure_generators/triangles_generator.rb +61 -0
- data/lib/geo_pattern/structure_generators/xes_generator.rb +67 -0
- data/lib/geo_pattern/svg_image.rb +101 -0
- data/lib/geo_pattern/version.rb +1 -1
- data/script/bootstrap +30 -0
- data/script/console +8 -0
- data/script/test +21 -0
- data/spec/background_generators/solid_generator_spec.rb +50 -0
- data/spec/background_spec.rb +25 -0
- data/spec/color_generators/base_color_generator_spec.rb +31 -0
- data/spec/color_generators/simple_generator_spec.rb +12 -0
- data/spec/color_preset_spec.rb +53 -0
- data/spec/color_spec.rb +15 -0
- data/spec/geo_pattern_spec.rb +95 -24
- data/spec/helpers_spec.rb +65 -0
- data/spec/pattern_preset_spec.rb +41 -0
- data/spec/pattern_sieve_spec.rb +66 -0
- data/spec/pattern_spec.rb +72 -0
- data/spec/pattern_store_spec.rb +47 -0
- data/spec/pattern_validator_spec.rb +28 -0
- data/spec/seed_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -6
- data/spec/structure_generators/chevrons_generator_spec.rb +5 -0
- data/spec/structure_generators/concentric_circles_generator_spec.rb +5 -0
- data/spec/structure_generators/diamonds_generator_spec.rb +5 -0
- data/spec/structure_generators/hexagons_generator_spec.rb +5 -0
- data/spec/structure_generators/mosaic_squares_generator_spec.rb +5 -0
- data/spec/structure_generators/nested_squares_generator_spec.rb +5 -0
- data/spec/structure_generators/octagons_generator_spec.rb +5 -0
- data/spec/structure_generators/overlapping_circles_generator_spec.rb +5 -0
- data/spec/structure_generators/overlapping_rings_generator_spec.rb +5 -0
- data/spec/structure_generators/plaid_generator_spec.rb +5 -0
- data/spec/structure_generators/plus_signs_generator_spec.rb +5 -0
- data/spec/structure_generators/sine_waves_generator_spec.rb +5 -0
- data/spec/structure_generators/squares_generator_spec.rb +5 -0
- data/spec/structure_generators/tessellation_generator_spec.rb +5 -0
- data/spec/structure_generators/triangles_generator_spec.rb +5 -0
- data/spec/structure_generators/xes_generator_spec.rb +5 -0
- data/spec/structure_spec.rb +38 -0
- data/spec/support/helpers/fixtures.rb +12 -0
- data/spec/support/kernel.rb +40 -0
- data/spec/support/matchers/image.rb +17 -0
- data/spec/support/matchers/name.rb +15 -0
- data/spec/support/rspec.rb +1 -1
- data/spec/support/shared_examples/generator.rb +46 -0
- data/spec/support/shared_examples/pattern.rb +31 -0
- data/spec/support/shared_examples/pattern_name.rb +7 -0
- data/spec/support/shared_examples/structure.rb +48 -0
- data/spec/svg_spec.rb +3 -3
- metadata +141 -25
- data/lib/geo_pattern/pattern/base_pattern.rb +0 -47
- data/lib/geo_pattern/pattern/chevron_pattern.rb +0 -45
- data/lib/geo_pattern/pattern/concentric_circles_pattern.rb +0 -47
- data/lib/geo_pattern/pattern/diamond_pattern.rb +0 -56
- data/lib/geo_pattern/pattern/hexagon_pattern.rb +0 -57
- data/lib/geo_pattern/pattern/mosaic_squares_pattern.rb +0 -76
- data/lib/geo_pattern/pattern/nested_squares_pattern.rb +0 -51
- data/lib/geo_pattern/pattern/octagon_pattern.rb +0 -35
- data/lib/geo_pattern/pattern/overlapping_circles_pattern.rb +0 -46
- data/lib/geo_pattern/pattern/overlapping_rings_pattern.rb +0 -46
- data/lib/geo_pattern/pattern/plaid_pattern.rb +0 -49
- data/lib/geo_pattern/pattern/plus_sign_pattern.rb +0 -53
- data/lib/geo_pattern/pattern/sine_wave_pattern.rb +0 -36
- data/lib/geo_pattern/pattern/square_pattern.rb +0 -27
- data/lib/geo_pattern/pattern/tessellation_pattern.rb +0 -93
- data/lib/geo_pattern/pattern/triangle_pattern.rb +0 -51
- data/lib/geo_pattern/pattern/xes_pattern.rb +0 -58
- data/lib/geo_pattern/svg.rb +0 -77
- data/spec/support/helpers.rb +0 -34
@@ -0,0 +1,35 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
# Roles
|
3
|
+
module Roles
|
4
|
+
# A comparable metadata
|
5
|
+
module ComparableMetadata
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def generator?(value)
|
11
|
+
return false unless value.is_a?(Class) || value.nil?
|
12
|
+
return true if value.nil? && @generator
|
13
|
+
|
14
|
+
return true if value == generator
|
15
|
+
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
# Class Methods
|
20
|
+
module ClassMethods
|
21
|
+
# Define comparators
|
22
|
+
def def_comparators(*methods)
|
23
|
+
methods.flatten.each do |m|
|
24
|
+
define_method "#{m}?".to_sym do |value|
|
25
|
+
return true if value.nil? && public_send(m)
|
26
|
+
return true if value == public_send(m)
|
27
|
+
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class Seed
|
3
|
+
private
|
4
|
+
|
5
|
+
attr_reader :seed
|
6
|
+
|
7
|
+
public
|
8
|
+
|
9
|
+
def initialize(string)
|
10
|
+
@seed = Digest::SHA1.hexdigest string.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](*args)
|
14
|
+
seed[*args]
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_i(index, length)
|
18
|
+
seed[index, length || 1].to_i(16)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
class Structure
|
3
|
+
include Roles::ComparableMetadata
|
4
|
+
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :image, :preset, :name, :generator
|
8
|
+
|
9
|
+
def_delegators :@preset, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@image = options[:image]
|
13
|
+
@preset = options[:preset]
|
14
|
+
@name = options[:name]
|
15
|
+
@generator = options[:generator]
|
16
|
+
|
17
|
+
fail ArgumentError, 'Argument name is missing' if @name.nil?
|
18
|
+
fail ArgumentError, 'Argument image is missing' if @image.nil?
|
19
|
+
fail ArgumentError, 'Argument preset is missing' if @preset.nil?
|
20
|
+
fail ArgumentError, 'Argument generator is missing' if @generator.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def_comparators :name, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class BaseGenerator
|
4
|
+
include Roles::NamedGenerator
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
attr_reader :svg, :seed, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max, :preset
|
9
|
+
attr_accessor :height, :width
|
10
|
+
|
11
|
+
public
|
12
|
+
|
13
|
+
def initialize(seed, preset, svg = SvgImage.new)
|
14
|
+
@svg = svg
|
15
|
+
@seed = seed
|
16
|
+
@preset = preset
|
17
|
+
|
18
|
+
@fill_color_dark = @preset.fill_color_dark
|
19
|
+
@fill_color_light = @preset.fill_color_light
|
20
|
+
@stroke_color = @preset.stroke_color
|
21
|
+
@stroke_opacity = @preset.stroke_opacity
|
22
|
+
@opacity_min = @preset.opacity_min
|
23
|
+
@opacity_max = @preset.opacity_max
|
24
|
+
|
25
|
+
@height = 100
|
26
|
+
@width = 100
|
27
|
+
|
28
|
+
after_initialize
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate(pattern)
|
32
|
+
pattern.structure = Structure.new(image: svg_image, preset: preset, generator: self.class, name: name)
|
33
|
+
|
34
|
+
pattern.height = height
|
35
|
+
pattern.width = width
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Set Svg Image
|
43
|
+
def svg_image
|
44
|
+
image = generate_structure
|
45
|
+
image.height = height
|
46
|
+
image.width = width
|
47
|
+
|
48
|
+
image
|
49
|
+
end
|
50
|
+
|
51
|
+
# Hook for generators
|
52
|
+
def after_initialize; end
|
53
|
+
|
54
|
+
# Generate the structure
|
55
|
+
def generate_structure
|
56
|
+
fail NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
def hex_val(index, len)
|
60
|
+
seed.to_i(index, len)
|
61
|
+
end
|
62
|
+
|
63
|
+
def fill_color(val)
|
64
|
+
(val.even?) ? fill_color_light : fill_color_dark
|
65
|
+
end
|
66
|
+
|
67
|
+
def opacity(val)
|
68
|
+
map(val, 0, 15, opacity_min, opacity_max)
|
69
|
+
end
|
70
|
+
|
71
|
+
def map(value, v_min, v_max, d_min, d_max)
|
72
|
+
PatternHelpers.map(value, v_min, v_max, d_min, d_max)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
def build_plus_shape(square_size)
|
78
|
+
[
|
79
|
+
"rect(#{square_size},0,#{square_size},#{square_size * 3})",
|
80
|
+
"rect(0, #{square_size},#{square_size * 3},#{square_size})"
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class ChevronsGenerator < BaseGenerator
|
4
|
+
private
|
5
|
+
|
6
|
+
attr_reader :chevron_height, :chevron_width, :chevron
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@chevron_width = map(hex_val(0, 1), 0, 15, 30, 80)
|
10
|
+
@chevron_height = map(hex_val(0, 1), 0, 15, 30, 80)
|
11
|
+
@chevron = build_chevron_shape(chevron_width, chevron_height)
|
12
|
+
|
13
|
+
self.height = chevron_height * 6 * 0.66
|
14
|
+
self.width = chevron_width * 6
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_structure
|
18
|
+
i = 0
|
19
|
+
for y in 0..5
|
20
|
+
for x in 0..5
|
21
|
+
val = hex_val(i, 1)
|
22
|
+
opacity = opacity(val)
|
23
|
+
fill = fill_color(val)
|
24
|
+
|
25
|
+
styles = {
|
26
|
+
'stroke' => stroke_color,
|
27
|
+
'stroke-opacity' => stroke_opacity,
|
28
|
+
'fill' => fill,
|
29
|
+
'fill-opacity' => opacity,
|
30
|
+
'stroke-width' => 1
|
31
|
+
}
|
32
|
+
|
33
|
+
svg.group(chevron, styles.merge('transform' => "translate(#{x * chevron_width},#{y * chevron_height * 0.66 - chevron_height / 2})"))
|
34
|
+
|
35
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
36
|
+
if (y == 0)
|
37
|
+
svg.group(chevron, styles.merge('transform' => "translate(#{x * chevron_width},#{6 * chevron_height * 0.66 - chevron_height / 2})"))
|
38
|
+
end
|
39
|
+
i += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
svg
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_chevron_shape(width, height)
|
47
|
+
e = height * 0.66
|
48
|
+
[
|
49
|
+
%{polyline("0,0,#{width / 2},#{height - e},#{width / 2},#{height},0,#{e},0,0")},
|
50
|
+
%{polyline("#{width / 2},#{height - e},#{width},0,#{width},#{e},#{width / 2},#{height},#{width / 2},#{height - e}")}
|
51
|
+
]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class ConcentricCirclesGenerator < BaseGenerator
|
4
|
+
private
|
5
|
+
|
6
|
+
attr_reader :scale, :ring_size, :stroke_width
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@scale = hex_val(0, 1)
|
10
|
+
@ring_size = map(scale, 0, 15, 10, 60)
|
11
|
+
@stroke_width = ring_size / 5
|
12
|
+
|
13
|
+
self.width = self.height = (ring_size + stroke_width) * 6
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_structure
|
17
|
+
i = 0
|
18
|
+
for y in 0..5
|
19
|
+
for x in 0..5
|
20
|
+
val = hex_val(i, 1)
|
21
|
+
opacity = opacity(val)
|
22
|
+
fill = fill_color(val)
|
23
|
+
|
24
|
+
svg.circle(
|
25
|
+
x * ring_size + x * stroke_width + (ring_size + stroke_width) / 2,
|
26
|
+
y * ring_size + y * stroke_width + (ring_size + stroke_width) / 2,
|
27
|
+
ring_size / 2,
|
28
|
+
'fill' => 'none',
|
29
|
+
'stroke' => fill,
|
30
|
+
'style' => {
|
31
|
+
'opacity' => opacity,
|
32
|
+
'stroke-width' => "#{stroke_width}px"
|
33
|
+
}
|
34
|
+
)
|
35
|
+
|
36
|
+
val = hex_val(39 - i, 1)
|
37
|
+
opacity = opacity(val)
|
38
|
+
fill = fill_color(val)
|
39
|
+
|
40
|
+
svg.circle(
|
41
|
+
x * ring_size + x * stroke_width + (ring_size + stroke_width) / 2,
|
42
|
+
y * ring_size + y * stroke_width + (ring_size + stroke_width) / 2,
|
43
|
+
ring_size / 4,
|
44
|
+
'fill' => fill,
|
45
|
+
'fill-opacity' => opacity
|
46
|
+
)
|
47
|
+
|
48
|
+
i += 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
svg
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class DiamondsGenerator < BaseGenerator
|
4
|
+
private
|
5
|
+
|
6
|
+
attr_reader :diamond_height, :diamond_width, :diamond
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@diamond_width = map(hex_val(0, 1), 0, 15, 10, 50)
|
10
|
+
@diamond_height = map(hex_val(1, 1), 0, 15, 10, 50)
|
11
|
+
@diamond = build_diamond_shape(diamond_width, diamond_height)
|
12
|
+
|
13
|
+
self.height = diamond_height * 3
|
14
|
+
self.width = diamond_width * 6
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_structure
|
18
|
+
i = 0
|
19
|
+
for y in 0..5
|
20
|
+
for x in 0..5
|
21
|
+
val = hex_val(i, 1)
|
22
|
+
opacity = opacity(val)
|
23
|
+
fill = fill_color(val)
|
24
|
+
|
25
|
+
styles = {
|
26
|
+
'fill' => fill,
|
27
|
+
'fill-opacity' => opacity,
|
28
|
+
'stroke' => stroke_color,
|
29
|
+
'stroke-opacity' => stroke_opacity
|
30
|
+
}
|
31
|
+
|
32
|
+
dx = (y % 2 == 0) ? 0 : diamond_width / 2
|
33
|
+
|
34
|
+
svg.polyline(diamond, styles.merge(
|
35
|
+
'transform' => "translate(#{x * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * y - diamond_height / 2})"))
|
36
|
+
|
37
|
+
# Add an extra one at top-right, for tiling.
|
38
|
+
if (x == 0)
|
39
|
+
svg.polyline(diamond, styles.merge(
|
40
|
+
'transform' => "translate(#{6 * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * y - diamond_height / 2})"))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
44
|
+
if (y == 0)
|
45
|
+
svg.polyline(diamond, styles.merge(
|
46
|
+
'transform' => "translate(#{x * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * 6 - diamond_height / 2})"))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Add an extra one at bottom-right, for tiling.
|
50
|
+
if x == 0 && y == 0
|
51
|
+
svg.polyline(diamond, styles.merge(
|
52
|
+
'transform' => "translate(#{6 * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * 6 - diamond_height / 2})"))
|
53
|
+
end
|
54
|
+
i += 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
svg
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_diamond_shape(width, height)
|
62
|
+
"#{width / 2}, 0, #{width}, #{height / 2}, #{width / 2}, #{height}, 0, #{height / 2}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class HexagonsGenerator < BaseGenerator
|
4
|
+
private
|
5
|
+
|
6
|
+
attr_reader :scale, :side_length, :hex_height, :hex_width, :hex
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@scale = hex_val(0, 1)
|
10
|
+
@side_length = map(scale, 0, 15, 8, 60)
|
11
|
+
@hex_height = side_length * Math.sqrt(3)
|
12
|
+
@hex_width = side_length * 2
|
13
|
+
@hex = build_hexagon_shape(side_length)
|
14
|
+
|
15
|
+
self.width = hex_width * 3 + side_length * 3
|
16
|
+
self.height = hex_height * 6
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_structure
|
20
|
+
i = 0
|
21
|
+
for y in 0..5
|
22
|
+
for x in 0..5
|
23
|
+
val = hex_val(i, 1)
|
24
|
+
dy = x % 2 == 0 ? y * hex_height : y * hex_height + hex_height / 2
|
25
|
+
opacity = opacity(val)
|
26
|
+
fill = fill_color(val)
|
27
|
+
|
28
|
+
styles = {
|
29
|
+
'fill' => fill,
|
30
|
+
'fill-opacity' => opacity,
|
31
|
+
'stroke' => stroke_color,
|
32
|
+
'stroke-opacity' => stroke_opacity
|
33
|
+
}
|
34
|
+
|
35
|
+
svg.polyline(hex, styles.merge('transform' => "translate(#{x * side_length * 1.5 - hex_width / 2}, #{dy - hex_height / 2})"))
|
36
|
+
|
37
|
+
# Add an extra one at top-right, for tiling.
|
38
|
+
if (x == 0)
|
39
|
+
svg.polyline(hex, styles.merge('transform' => "translate(#{6 * side_length * 1.5 - hex_width / 2}, #{dy - hex_height / 2})"))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Add an extra row at the end that matches the first row, for tiling.
|
43
|
+
if (y == 0)
|
44
|
+
dy = x % 2 == 0 ? 6 * hex_height : 6 * hex_height + hex_height / 2
|
45
|
+
svg.polyline(hex, styles.merge('transform' => "translate(#{x * side_length * 1.5 - hex_width / 2}, #{dy - hex_height / 2})"))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add an extra one at bottom-right, for tiling.
|
49
|
+
if x == 0 && y == 0
|
50
|
+
svg.polyline(hex, styles.merge('transform' => "translate(#{6 * side_length * 1.5 - hex_width / 2}, #{5 * hex_height + hex_height / 2})"))
|
51
|
+
end
|
52
|
+
i += 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
svg
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_hexagon_shape(sideLength)
|
60
|
+
c = sideLength
|
61
|
+
a = c / 2
|
62
|
+
b = Math.sin(60 * Math::PI / 180) * c
|
63
|
+
"0,#{b},#{a},0,#{a + c},0,#{2 * c},#{b},#{a + c},#{2 * b},#{a},#{2 * b},0,#{b}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module GeoPattern
|
2
|
+
module StructureGenerators
|
3
|
+
class MosaicSquaresGenerator < BaseGenerator
|
4
|
+
private
|
5
|
+
|
6
|
+
attr_reader :triangle_size
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@triangle_size = map(hex_val(0, 1), 0, 15, 15, 50)
|
10
|
+
|
11
|
+
self.height = self.width = triangle_size * 8
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_structure
|
15
|
+
i = 0
|
16
|
+
for y in 0..3
|
17
|
+
for x in 0..3
|
18
|
+
if x.even?
|
19
|
+
if y.even?
|
20
|
+
draw_outer_mosaic_tile(x * triangle_size * 2, y * triangle_size * 2, triangle_size, hex_val(i, 1))
|
21
|
+
else
|
22
|
+
draw_inner_mosaic_tile(x * triangle_size * 2, y * triangle_size * 2, triangle_size, [hex_val(i, 1), hex_val(i + 1, 1)])
|
23
|
+
end
|
24
|
+
else
|
25
|
+
if y.even?
|
26
|
+
draw_inner_mosaic_tile(x * triangle_size * 2, y * triangle_size * 2, triangle_size, [hex_val(i, 1), hex_val(i + 1, 1)])
|
27
|
+
else
|
28
|
+
draw_outer_mosaic_tile(x * triangle_size * 2, y * triangle_size * 2, triangle_size, hex_val(i, 1))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
i += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
svg
|
36
|
+
end
|
37
|
+
|
38
|
+
def draw_inner_mosaic_tile(x, y, triangle_size, vals)
|
39
|
+
triangle = build_right_triangle_shape(triangle_size)
|
40
|
+
opacity = opacity(vals[0])
|
41
|
+
fill = fill_color(vals[0])
|
42
|
+
styles = {
|
43
|
+
'stroke' => stroke_color,
|
44
|
+
'stroke-opacity' => stroke_opacity,
|
45
|
+
'fill-opacity' => opacity,
|
46
|
+
'fill' => fill
|
47
|
+
}
|
48
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size}, #{y}) scale(-1, 1)"))
|
49
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size}, #{y + triangle_size * 2}) scale(1, -1)"))
|
50
|
+
|
51
|
+
opacity = opacity(vals[1])
|
52
|
+
fill = fill_color(vals[1])
|
53
|
+
styles = {
|
54
|
+
'stroke' => stroke_color,
|
55
|
+
'stroke-opacity' => stroke_opacity,
|
56
|
+
'fill-opacity' => opacity,
|
57
|
+
'fill' => fill
|
58
|
+
}
|
59
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size}, #{y + triangle_size * 2}) scale(-1, -1)"))
|
60
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size}, #{y}) scale(1, 1)"))
|
61
|
+
end
|
62
|
+
|
63
|
+
def draw_outer_mosaic_tile(x, y, triangle_size, val)
|
64
|
+
opacity = opacity(val)
|
65
|
+
fill = fill_color(val)
|
66
|
+
triangle = build_right_triangle_shape(triangle_size)
|
67
|
+
styles = {
|
68
|
+
'stroke' => stroke_color,
|
69
|
+
'stroke-opacity' => stroke_opacity,
|
70
|
+
'fill-opacity' => opacity,
|
71
|
+
'fill' => fill
|
72
|
+
}
|
73
|
+
|
74
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x}, #{y + triangle_size}) scale(1, -1)"))
|
75
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size * 2}, #{y + triangle_size}) scale(-1, -1)"))
|
76
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x}, #{y + triangle_size}) scale(1, 1)"))
|
77
|
+
svg.polyline(triangle, styles.merge('transform' => "translate(#{x + triangle_size * 2}, #{y + triangle_size}) scale(-1, 1)"))
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_right_triangle_shape(side_length)
|
81
|
+
"0, 0, #{side_length}, #{side_length}, 0, #{side_length}, 0, 0"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|