geo_pattern 1.3.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +30 -0
  3. data/.gitignore +1 -0
  4. data/.simplecov +26 -0
  5. data/Gemfile +17 -17
  6. data/README.md +154 -29
  7. data/Rakefile +72 -13
  8. data/fixtures/generated_patterns/chevrons.svg +1 -0
  9. data/fixtures/generated_patterns/concentric_circles.svg +1 -0
  10. data/fixtures/generated_patterns/diamonds.svg +1 -0
  11. data/fixtures/generated_patterns/diamonds_with_base_color.svg +1 -0
  12. data/fixtures/generated_patterns/diamonds_with_color.svg +1 -0
  13. data/fixtures/generated_patterns/hexagons.svg +1 -0
  14. data/fixtures/generated_patterns/mosaic_squares.svg +1 -0
  15. data/fixtures/generated_patterns/nested_squares.svg +1 -0
  16. data/fixtures/generated_patterns/octagons.svg +1 -0
  17. data/fixtures/generated_patterns/overlapping_circles.svg +1 -0
  18. data/fixtures/generated_patterns/overlapping_rings.svg +1 -0
  19. data/fixtures/generated_patterns/plaid.svg +1 -0
  20. data/fixtures/generated_patterns/plus_signs.svg +1 -0
  21. data/fixtures/generated_patterns/sine_waves.svg +1 -0
  22. data/fixtures/generated_patterns/squares.svg +1 -0
  23. data/fixtures/generated_patterns/tessellation.svg +1 -0
  24. data/fixtures/generated_patterns/triangles.svg +1 -0
  25. data/fixtures/generated_patterns/xes.svg +1 -0
  26. data/geo_pattern.gemspec +19 -17
  27. data/lib/geo_pattern/background.rb +27 -0
  28. data/lib/geo_pattern/background_generators/solid_generator.rb +54 -0
  29. data/lib/geo_pattern/color.rb +27 -0
  30. data/lib/geo_pattern/color_generators/base_color_generator.rb +57 -0
  31. data/lib/geo_pattern/color_generators/simple_generator.rb +29 -0
  32. data/lib/geo_pattern/color_preset.rb +32 -0
  33. data/lib/geo_pattern/errors.rb +9 -0
  34. data/lib/geo_pattern/geo_pattern_task.rb +61 -0
  35. data/lib/geo_pattern/helpers.rb +50 -1
  36. data/lib/geo_pattern/pattern.rb +86 -0
  37. data/lib/geo_pattern/pattern_generator.rb +34 -81
  38. data/lib/geo_pattern/pattern_helpers.rb +34 -2
  39. data/lib/geo_pattern/pattern_preset.rb +25 -0
  40. data/lib/geo_pattern/pattern_sieve.rb +38 -0
  41. data/lib/geo_pattern/pattern_store.rb +65 -0
  42. data/lib/geo_pattern/pattern_validator.rb +29 -0
  43. data/lib/geo_pattern/rake_task.rb +112 -0
  44. data/lib/geo_pattern/roles/comparable_metadata.rb +37 -0
  45. data/lib/geo_pattern/roles/named_generator.rb +15 -0
  46. data/lib/geo_pattern/seed.rb +23 -0
  47. data/lib/geo_pattern/structure.rb +27 -0
  48. data/lib/geo_pattern/structure_generators/base_generator.rb +88 -0
  49. data/lib/geo_pattern/structure_generators/chevrons_generator.rb +57 -0
  50. data/lib/geo_pattern/structure_generators/concentric_circles_generator.rb +58 -0
  51. data/lib/geo_pattern/structure_generators/diamonds_generator.rb +72 -0
  52. data/lib/geo_pattern/structure_generators/hexagons_generator.rb +69 -0
  53. data/lib/geo_pattern/structure_generators/mosaic_squares_generator.rb +85 -0
  54. data/lib/geo_pattern/structure_generators/nested_squares_generator.rb +62 -0
  55. data/lib/geo_pattern/structure_generators/octagons_generator.rb +45 -0
  56. data/lib/geo_pattern/structure_generators/overlapping_circles_generator.rb +57 -0
  57. data/lib/geo_pattern/structure_generators/overlapping_rings_generator.rb +57 -0
  58. data/lib/geo_pattern/structure_generators/plaid_generator.rb +55 -0
  59. data/lib/geo_pattern/structure_generators/plus_signs_generator.rb +68 -0
  60. data/lib/geo_pattern/structure_generators/sine_waves_generator.rb +45 -0
  61. data/lib/geo_pattern/structure_generators/squares_generator.rb +37 -0
  62. data/lib/geo_pattern/structure_generators/tessellation_generator.rb +105 -0
  63. data/lib/geo_pattern/structure_generators/triangles_generator.rb +64 -0
  64. data/lib/geo_pattern/structure_generators/xes_generator.rb +74 -0
  65. data/lib/geo_pattern/svg_image.rb +103 -0
  66. data/lib/geo_pattern/version.rb +3 -1
  67. data/lib/geo_pattern.rb +54 -30
  68. data/script/bootstrap +30 -0
  69. data/script/console +9 -0
  70. data/script/test +21 -0
  71. data/spec/background_generators/solid_generator_spec.rb +52 -0
  72. data/spec/background_spec.rb +27 -0
  73. data/spec/color_generators/base_color_generator_spec.rb +33 -0
  74. data/spec/color_generators/simple_generator_spec.rb +14 -0
  75. data/spec/color_preset_spec.rb +55 -0
  76. data/spec/color_spec.rb +17 -0
  77. data/spec/geo_pattern_spec.rb +98 -26
  78. data/spec/helpers_spec.rb +67 -0
  79. data/spec/pattern_preset_spec.rb +43 -0
  80. data/spec/pattern_sieve_spec.rb +68 -0
  81. data/spec/pattern_spec.rb +74 -0
  82. data/spec/pattern_store_spec.rb +49 -0
  83. data/spec/pattern_validator_spec.rb +30 -0
  84. data/spec/seed_spec.rb +16 -0
  85. data/spec/spec_helper.rb +9 -13
  86. data/spec/structure_generators/chevrons_generator_spec.rb +7 -0
  87. data/spec/structure_generators/concentric_circles_generator_spec.rb +7 -0
  88. data/spec/structure_generators/diamonds_generator_spec.rb +7 -0
  89. data/spec/structure_generators/hexagons_generator_spec.rb +7 -0
  90. data/spec/structure_generators/mosaic_squares_generator_spec.rb +7 -0
  91. data/spec/structure_generators/nested_squares_generator_spec.rb +7 -0
  92. data/spec/structure_generators/octagons_generator_spec.rb +7 -0
  93. data/spec/structure_generators/overlapping_circles_generator_spec.rb +7 -0
  94. data/spec/structure_generators/overlapping_rings_generator_spec.rb +7 -0
  95. data/spec/structure_generators/plaid_generator_spec.rb +7 -0
  96. data/spec/structure_generators/plus_signs_generator_spec.rb +7 -0
  97. data/spec/structure_generators/sine_waves_generator_spec.rb +7 -0
  98. data/spec/structure_generators/squares_generator_spec.rb +7 -0
  99. data/spec/structure_generators/tessellation_generator_spec.rb +7 -0
  100. data/spec/structure_generators/triangles_generator_spec.rb +7 -0
  101. data/spec/structure_generators/xes_generator_spec.rb +7 -0
  102. data/spec/structure_spec.rb +40 -0
  103. data/spec/support/aruba.rb +6 -6
  104. data/spec/support/helpers/fixtures.rb +14 -0
  105. data/spec/support/kernel.rb +46 -0
  106. data/spec/support/matchers/image.rb +19 -0
  107. data/spec/support/matchers/name.rb +17 -0
  108. data/spec/support/rspec.rb +4 -2
  109. data/spec/support/shared_examples/generator.rb +48 -0
  110. data/spec/support/shared_examples/pattern.rb +33 -0
  111. data/spec/support/shared_examples/pattern_name.rb +9 -0
  112. data/spec/support/shared_examples/structure.rb +50 -0
  113. data/spec/support/string.rb +3 -2
  114. data/spec/svg_spec.rb +8 -6
  115. metadata +105 -37
  116. data/.rubocop.yml +0 -13
  117. data/lib/geo_pattern/pattern/base_pattern.rb +0 -47
  118. data/lib/geo_pattern/pattern/chevron_pattern.rb +0 -45
  119. data/lib/geo_pattern/pattern/concentric_circles_pattern.rb +0 -47
  120. data/lib/geo_pattern/pattern/diamond_pattern.rb +0 -56
  121. data/lib/geo_pattern/pattern/hexagon_pattern.rb +0 -57
  122. data/lib/geo_pattern/pattern/mosaic_squares_pattern.rb +0 -76
  123. data/lib/geo_pattern/pattern/nested_squares_pattern.rb +0 -51
  124. data/lib/geo_pattern/pattern/octagon_pattern.rb +0 -35
  125. data/lib/geo_pattern/pattern/overlapping_circles_pattern.rb +0 -46
  126. data/lib/geo_pattern/pattern/overlapping_rings_pattern.rb +0 -46
  127. data/lib/geo_pattern/pattern/plaid_pattern.rb +0 -49
  128. data/lib/geo_pattern/pattern/plus_sign_pattern.rb +0 -53
  129. data/lib/geo_pattern/pattern/sine_wave_pattern.rb +0 -36
  130. data/lib/geo_pattern/pattern/square_pattern.rb +0 -27
  131. data/lib/geo_pattern/pattern/tessellation_pattern.rb +0 -93
  132. data/lib/geo_pattern/pattern/triangle_pattern.rb +0 -51
  133. data/lib/geo_pattern/pattern/xes_pattern.rb +0 -58
  134. data/lib/geo_pattern/svg.rb +0 -77
  135. data/spec/support/helpers.rb +0 -34
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ class PatternPreset
5
+ private
6
+
7
+ attr_accessor :options
8
+
9
+ public
10
+
11
+ def initialize(options)
12
+ @options = options
13
+ end
14
+
15
+ %i[fill_color_dark fill_color_light stroke_color stroke_opacity opacity_min opacity_max].each do |m|
16
+ define_method m do
17
+ options[m]
18
+ end
19
+ end
20
+
21
+ def update(opts)
22
+ options.merge! opts
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ class PatternSieve
5
+ private
6
+
7
+ attr_reader :pattern_store, :requested_patterns, :seed, :available_patterns, :index
8
+
9
+ public
10
+
11
+ def initialize(requested_patterns, seed, pattern_store = PatternStore.new)
12
+ @requested_patterns = requested_patterns
13
+ @seed = seed
14
+ @pattern_store = pattern_store
15
+
16
+ @available_patterns = determine_available_patterns
17
+ @index = determine_index
18
+ end
19
+
20
+ def fetch
21
+ available_patterns[index]
22
+ end
23
+
24
+ private
25
+
26
+ def determine_index
27
+ [seed.to_i(20, 1), available_patterns.length - 1].min
28
+ end
29
+
30
+ def determine_available_patterns
31
+ patterns = Array(requested_patterns).compact
32
+
33
+ return pattern_store.all if patterns.empty?
34
+
35
+ patterns.map { |p| pattern_store[p] }.compact
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ # rubocop:disable Naming/ConstantName
5
+ ChevronPattern = :chevrons
6
+ ConcentricCirclesPattern = :concentric_circles
7
+ DiamondPattern = :diamonds
8
+ HexagonPattern = :hexagons
9
+ MosaicSquaresPattern = :mosaic_squares
10
+ NestedSquaresPattern = :nested_squares
11
+ OctagonPattern = :octagons
12
+ OverlappingCirclesPattern = :overlapping_circles
13
+ OverlappingRingsPattern = :overlapping_rings
14
+ PlaidPattern = :plaid
15
+ PlusSignPattern = :plus_signs
16
+ SineWavePattern = :sine_waves
17
+ SquarePattern = :squares
18
+ TessellationPattern = :tessellation
19
+ TrianglePattern = :triangles
20
+ XesPattern = :xes
21
+ # rubocop:enable Naming/ConstantName
22
+
23
+ class PatternStore
24
+ private
25
+
26
+ attr_reader :store
27
+
28
+ public
29
+
30
+ def initialize
31
+ @store = {
32
+ chevrons: StructureGenerators::ChevronsGenerator,
33
+ concentric_circles: StructureGenerators::ConcentricCirclesGenerator,
34
+ diamonds: StructureGenerators::DiamondsGenerator,
35
+ hexagons: StructureGenerators::HexagonsGenerator,
36
+ mosaic_squares: StructureGenerators::MosaicSquaresGenerator,
37
+ nested_squares: StructureGenerators::NestedSquaresGenerator,
38
+ octagons: StructureGenerators::OctagonsGenerator,
39
+ overlapping_circles: StructureGenerators::OverlappingCirclesGenerator,
40
+ overlapping_rings: StructureGenerators::OverlappingRingsGenerator,
41
+ plaid: StructureGenerators::PlaidGenerator,
42
+ plus_signs: StructureGenerators::PlusSignsGenerator,
43
+ sine_waves: StructureGenerators::SineWavesGenerator,
44
+ squares: StructureGenerators::SquaresGenerator,
45
+ tessellation: StructureGenerators::TessellationGenerator,
46
+ triangles: StructureGenerators::TrianglesGenerator,
47
+ xes: StructureGenerators::XesGenerator
48
+ }
49
+ end
50
+
51
+ def [](pattern)
52
+ warn "String pattern references are deprecated as of 1.3.0" if pattern.is_a?(String)
53
+
54
+ store[pattern.to_s.to_sym]
55
+ end
56
+
57
+ def all
58
+ store.values
59
+ end
60
+
61
+ def known?(pattern)
62
+ store.key?(pattern.to_s.to_sym)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ class PatternValidator
5
+ private
6
+
7
+ attr_reader :pattern_store
8
+
9
+ public
10
+
11
+ def initialize(pattern_store = PatternStore.new)
12
+ @pattern_store = pattern_store
13
+ end
14
+
15
+ def validate(requested_patterns)
16
+ message = "Error: At least one of the requested patterns \"#{requested_patterns.join(", ")}\" is invalid"
17
+
18
+ raise InvalidPatternError, message unless valid?(requested_patterns)
19
+
20
+ self
21
+ end
22
+
23
+ private
24
+
25
+ def valid?(requested_patterns)
26
+ requested_patterns.all? { |p| pattern_store.known? p }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+ require "rake/tasklib"
5
+ require "logger"
6
+
7
+ module GeoPattern
8
+ # Rake Task
9
+ #
10
+ # This task can be used to generate pattern files
11
+ class RakeTask < ::Rake::TaskLib
12
+ include ::Rake::DSL if defined?(::Rake::DSL)
13
+
14
+ # @!attribute [r] name
15
+ # Name of task.
16
+ attr_reader :name
17
+
18
+ # @!attribute [r] description
19
+ # A description for the task
20
+ attr_reader :description
21
+
22
+ # @!attribute [r] verbose (true)
23
+ # Use verbose output. If this is set to true, the task will print the
24
+ # executed spec command to stdout.
25
+ attr_reader :verbose
26
+
27
+ private
28
+
29
+ attr_reader :task_arguments, :task_block, :logger, :working_directory
30
+
31
+ # Create task instance
32
+ #
33
+ # @param [String] description
34
+ # A description for the task
35
+ #
36
+ # @param [String] name
37
+ # The name for the task (including namespace), e.g. namespace1:task1
38
+ #
39
+ # @param [Array] arguments
40
+ # Arguments for the task. Look
41
+ # [here](http://viget.com/extend/protip-passing-parameters-to-your-rake-tasks)
42
+ # for a better description on how to use arguments in rake tasks
43
+ #
44
+ # @yield
45
+ # A block which is called before the "run_task"-method is called. The
46
+ # parameters it taskes depends on the number of parameters the block
47
+ # can take. If the block is defined which two parameters, it takes two
48
+ # parameters from the paramter 'arguments'.
49
+ def initialize(opts = {}, &task_block)
50
+ @options = {
51
+ description: nil,
52
+ name: GeoPattern::Helpers.underscore(self.class.to_s.split("::").slice(-2..-1).join(":").gsub(/Task$/, "")),
53
+ arguments: [],
54
+ logger: ::Logger.new($stderr),
55
+ working_directory: Dir.getwd
56
+ }.merge opts
57
+
58
+ before_initialize
59
+
60
+ raise ArgumentError, :description if @options[:description].nil?
61
+
62
+ @description = @options[:description]
63
+ @task_arguments = Array(@options[:arguments])
64
+ @task_block = task_block
65
+ @logger = @options[:logger]
66
+ @working_directory = @options[:working_directory]
67
+ @name = @options[:name]
68
+
69
+ after_initialize
70
+
71
+ define_task
72
+ end
73
+
74
+ # Run code after initialize
75
+ def after_initialize
76
+ end
77
+
78
+ # Run code before initialize
79
+ def before_initialize
80
+ end
81
+
82
+ # Define task
83
+ def define_task
84
+ desc description unless ::Rake.application.last_description
85
+
86
+ task name, *task_arguments do |_, task_args|
87
+ RakeFileUtils.__send__(:verbose, verbose) do
88
+ instance_exec(*[self, task_args].slice(0, task_block.arity), &task_block) if task_block.respond_to? :call
89
+ run_task verbose
90
+ end
91
+ end
92
+ end
93
+
94
+ # Run code if task is executed
95
+ def run_task(_verbose)
96
+ end
97
+
98
+ public
99
+
100
+ # Binding to instance
101
+ def instance_binding
102
+ binding
103
+ end
104
+
105
+ # Include module in instance
106
+ def include(modules)
107
+ modules = Array(modules)
108
+
109
+ modules.each { |m| self.class.include m }
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ # Roles
5
+ module Roles
6
+ # A comparable metadata
7
+ module ComparableMetadata
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ def generator?(value)
13
+ return false unless value.is_a?(Class) || value.nil?
14
+ return true if value.nil? && @generator
15
+
16
+ return true if value == generator
17
+
18
+ false
19
+ end
20
+
21
+ # Class Methods
22
+ module ClassMethods
23
+ # Define comparators
24
+ def def_comparators(*methods)
25
+ methods.flatten.each do |m|
26
+ define_method "#{m}?".to_sym do |value|
27
+ return true if value.nil? && public_send(m)
28
+ return true if value == public_send(m)
29
+
30
+ false
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ module Roles
5
+ module NamedGenerator
6
+ def name?(other_name)
7
+ name == other_name.to_sym
8
+ end
9
+
10
+ def name
11
+ Helpers.underscore(Helpers.demodulize(self.class).gsub(/Generator/, "")).to_sym
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ class Seed
5
+ private
6
+
7
+ attr_reader :seed
8
+
9
+ public
10
+
11
+ def initialize(string)
12
+ @seed = Digest::SHA1.hexdigest string.to_s
13
+ end
14
+
15
+ def [](*args)
16
+ seed[*args]
17
+ end
18
+
19
+ def to_i(index, length)
20
+ seed[index, length || 1].to_i(16)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ class Structure
5
+ include Roles::ComparableMetadata
6
+
7
+ extend Forwardable
8
+
9
+ attr_reader :image, :preset, :name, :generator
10
+
11
+ def_delegators :@preset, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max
12
+
13
+ def initialize(options)
14
+ @image = options[:image]
15
+ @preset = options[:preset]
16
+ @name = options[:name]
17
+ @generator = options[:generator]
18
+
19
+ raise ArgumentError, "Argument name is missing" if @name.nil?
20
+ raise ArgumentError, "Argument image is missing" if @image.nil?
21
+ raise ArgumentError, "Argument preset is missing" if @preset.nil?
22
+ raise ArgumentError, "Argument generator is missing" if @generator.nil?
23
+ end
24
+
25
+ def_comparators :name, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max
26
+ end
27
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ module StructureGenerators
5
+ class BaseGenerator
6
+ include Roles::NamedGenerator
7
+
8
+ private
9
+
10
+ attr_reader :svg, :seed, :fill_color_dark, :fill_color_light, :stroke_color, :stroke_opacity, :opacity_min, :opacity_max, :preset
11
+ attr_accessor :height, :width
12
+
13
+ public
14
+
15
+ def initialize(seed, preset, svg = SvgImage.new)
16
+ @svg = svg
17
+ @seed = seed
18
+ @preset = preset
19
+
20
+ @fill_color_dark = @preset.fill_color_dark
21
+ @fill_color_light = @preset.fill_color_light
22
+ @stroke_color = @preset.stroke_color
23
+ @stroke_opacity = @preset.stroke_opacity
24
+ @opacity_min = @preset.opacity_min
25
+ @opacity_max = @preset.opacity_max
26
+
27
+ @height = 100
28
+ @width = 100
29
+
30
+ after_initialize
31
+ end
32
+
33
+ def generate(pattern)
34
+ pattern.structure = Structure.new(image: svg_image, preset: preset, generator: self.class, name: name)
35
+
36
+ pattern.height = height
37
+ pattern.width = width
38
+
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ # Set Svg Image
45
+ def svg_image
46
+ image = generate_structure
47
+ image.height = height
48
+ image.width = width
49
+
50
+ image
51
+ end
52
+
53
+ # Hook for generators
54
+ def after_initialize
55
+ end
56
+
57
+ # Generate the structure
58
+ def generate_structure
59
+ raise NotImplementedError
60
+ end
61
+
62
+ def hex_val(index, len)
63
+ seed.to_i(index, len)
64
+ end
65
+
66
+ def fill_color(val)
67
+ val.even? ? fill_color_light : fill_color_dark
68
+ end
69
+
70
+ def opacity(val)
71
+ map(val, 0, 15, opacity_min, opacity_max)
72
+ end
73
+
74
+ def map(value, v_min, v_max, d_min, d_max)
75
+ PatternHelpers.map(value, v_min, v_max, d_min, d_max)
76
+ end
77
+
78
+ protected
79
+
80
+ def build_plus_shape(square_size)
81
+ [
82
+ "rect(#{square_size},0,#{square_size},#{square_size * 3})",
83
+ "rect(0, #{square_size},#{square_size * 3},#{square_size})"
84
+ ]
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ module StructureGenerators
5
+ class ChevronsGenerator < BaseGenerator
6
+ private
7
+
8
+ attr_reader :chevron_height, :chevron_width, :chevron
9
+
10
+ def after_initialize
11
+ @chevron_width = map(hex_val(0, 1), 0, 15, 30, 80)
12
+ @chevron_height = map(hex_val(0, 1), 0, 15, 30, 80)
13
+ @chevron = build_chevron_shape(chevron_width, chevron_height)
14
+
15
+ self.height = chevron_height * 6 * 0.66
16
+ self.width = chevron_width * 6
17
+ end
18
+
19
+ def generate_structure
20
+ i = 0
21
+ 6.times do |y|
22
+ 6.times do |x|
23
+ val = hex_val(i, 1)
24
+ opacity = opacity(val)
25
+ fill = fill_color(val)
26
+
27
+ styles = {
28
+ "stroke" => stroke_color,
29
+ "stroke-opacity" => stroke_opacity,
30
+ "fill" => fill,
31
+ "fill-opacity" => opacity,
32
+ "stroke-width" => 1
33
+ }
34
+
35
+ svg.group(chevron, styles.merge("transform" => "translate(#{x * chevron_width},#{y * chevron_height * 0.66 - chevron_height / 2})"))
36
+
37
+ # Add an extra row at the end that matches the first row, for tiling.
38
+ if y == 0
39
+ svg.group(chevron, styles.merge("transform" => "translate(#{x * chevron_width},#{6 * chevron_height * 0.66 - chevron_height / 2})"))
40
+ end
41
+ i += 1
42
+ end
43
+ end
44
+
45
+ svg
46
+ end
47
+
48
+ def build_chevron_shape(width, height)
49
+ e = height * 0.66
50
+ [
51
+ %{polyline("0,0,#{width / 2},#{height - e},#{width / 2},#{height},0,#{e},0,0")},
52
+ %{polyline("#{width / 2},#{height - e},#{width},0,#{width},#{e},#{width / 2},#{height},#{width / 2},#{height - e}")}
53
+ ]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ module StructureGenerators
5
+ class ConcentricCirclesGenerator < BaseGenerator
6
+ private
7
+
8
+ attr_reader :scale, :ring_size, :stroke_width
9
+
10
+ def after_initialize
11
+ @scale = hex_val(0, 1)
12
+ @ring_size = map(scale, 0, 15, 10, 60)
13
+ @stroke_width = ring_size / 5
14
+
15
+ self.width = self.height = (ring_size + stroke_width) * 6
16
+ end
17
+
18
+ def generate_structure
19
+ i = 0
20
+ 6.times do |y|
21
+ 6.times do |x|
22
+ val = hex_val(i, 1)
23
+ opacity = opacity(val)
24
+ fill = fill_color(val)
25
+
26
+ svg.circle(
27
+ x * ring_size + x * stroke_width + (ring_size + stroke_width) / 2,
28
+ y * ring_size + y * stroke_width + (ring_size + stroke_width) / 2,
29
+ ring_size / 2,
30
+ "fill" => "none",
31
+ "stroke" => fill,
32
+ "style" => {
33
+ "opacity" => opacity,
34
+ "stroke-width" => "#{stroke_width}px"
35
+ }
36
+ )
37
+
38
+ val = hex_val(39 - i, 1)
39
+ opacity = opacity(val)
40
+ fill = fill_color(val)
41
+
42
+ svg.circle(
43
+ x * ring_size + x * stroke_width + (ring_size + stroke_width) / 2,
44
+ y * ring_size + y * stroke_width + (ring_size + stroke_width) / 2,
45
+ ring_size / 4,
46
+ "fill" => fill,
47
+ "fill-opacity" => opacity
48
+ )
49
+
50
+ i += 1
51
+ end
52
+ end
53
+
54
+ svg
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoPattern
4
+ module StructureGenerators
5
+ class DiamondsGenerator < BaseGenerator
6
+ private
7
+
8
+ attr_reader :diamond_height, :diamond_width, :diamond
9
+
10
+ def after_initialize
11
+ @diamond_width = map(hex_val(0, 1), 0, 15, 10, 50)
12
+ @diamond_height = map(hex_val(1, 1), 0, 15, 10, 50)
13
+ @diamond = build_diamond_shape(diamond_width, diamond_height)
14
+
15
+ self.height = diamond_height * 3
16
+ self.width = diamond_width * 6
17
+ end
18
+
19
+ def generate_structure
20
+ i = 0
21
+ 6.times do |y|
22
+ 6.times do |x|
23
+ val = hex_val(i, 1)
24
+ opacity = opacity(val)
25
+ fill = fill_color(val)
26
+
27
+ styles = {
28
+ "fill" => fill,
29
+ "fill-opacity" => opacity,
30
+ "stroke" => stroke_color,
31
+ "stroke-opacity" => stroke_opacity
32
+ }
33
+
34
+ dx = (y % 2 == 0) ? 0 : diamond_width / 2
35
+
36
+ svg.polyline(diamond, styles.merge(
37
+ "transform" => "translate(#{x * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * y - diamond_height / 2})"
38
+ ))
39
+
40
+ # Add an extra one at top-right, for tiling.
41
+ if x == 0
42
+ svg.polyline(diamond, styles.merge(
43
+ "transform" => "translate(#{6 * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * y - diamond_height / 2})"
44
+ ))
45
+ end
46
+
47
+ # Add an extra row at the end that matches the first row, for tiling.
48
+ if y == 0
49
+ svg.polyline(diamond, styles.merge(
50
+ "transform" => "translate(#{x * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * 6 - diamond_height / 2})"
51
+ ))
52
+ end
53
+
54
+ # Add an extra one at bottom-right, for tiling.
55
+ if x == 0 && y == 0
56
+ svg.polyline(diamond, styles.merge(
57
+ "transform" => "translate(#{6 * diamond_width - diamond_width / 2 + dx}, #{diamond_height / 2 * 6 - diamond_height / 2})"
58
+ ))
59
+ end
60
+ i += 1
61
+ end
62
+ end
63
+
64
+ svg
65
+ end
66
+
67
+ def build_diamond_shape(width, height)
68
+ "#{width / 2}, 0, #{width}, #{height / 2}, #{width / 2}, #{height}, 0, #{height / 2}"
69
+ end
70
+ end
71
+ end
72
+ end