geo_pattern 1.3.2 → 1.5.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.
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
@@ -1,93 +0,0 @@
1
- module GeoPattern
2
- class TessellationPattern < BasePattern
3
- def render_to_svg
4
- # 3.4.6.4 semi-regular tessellation
5
- side_length = map(hex_val(0, 1), 0, 15, 5, 40)
6
- hex_height = side_length * Math.sqrt(3)
7
- hex_width = side_length * 2
8
- triangle_height = side_length/2 * Math.sqrt(3)
9
- triangle = build_rotated_triangle_shape(side_length, triangle_height)
10
- tile_width = side_length*3 + triangle_height*2
11
- tile_height = (hex_height * 2) + (side_length * 2)
12
-
13
- svg.set_width(tile_width)
14
- svg.set_height(tile_height)
15
-
16
- for i in 0..19
17
- val = hex_val(i, 1)
18
- opacity = opacity(val)
19
- fill = fill_color(val)
20
-
21
- styles = {
22
- "stroke" => STROKE_COLOR,
23
- "stroke-opacity" => STROKE_OPACITY,
24
- "fill" => fill,
25
- "fill-opacity" => opacity,
26
- "stroke-width" => 1
27
- }
28
-
29
- case i
30
- when 0 # all 4 corners
31
- svg.rect(-side_length/2, -side_length/2, side_length, side_length, styles)
32
- svg.rect(tile_width - side_length/2, -side_length/2, side_length, side_length, styles)
33
- svg.rect(-side_length/2, tile_height-side_length/2, side_length, side_length, styles)
34
- svg.rect(tile_width - side_length/2, tile_height-side_length/2, side_length, side_length, styles)
35
- when 1 # center / top square
36
- svg.rect(hex_width/2 + triangle_height, hex_height/2, side_length, side_length, styles)
37
- when 2 # side squares
38
- svg.rect(-side_length/2, tile_height/2-side_length/2, side_length, side_length, styles)
39
- svg.rect(tile_width-side_length/2, tile_height/2-side_length/2, side_length, side_length, styles)
40
- when 3 # center / bottom square
41
- svg.rect(hex_width/2 + triangle_height, hex_height * 1.5 + side_length, side_length, side_length, styles)
42
- when 4 # left top / bottom triangle
43
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{side_length/2}, #{-side_length/2}) rotate(0, #{side_length/2}, #{triangle_height/2})"}))
44
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{side_length/2}, #{tile_height--side_length/2}) rotate(0, #{side_length/2}, #{triangle_height/2}) scale(1, -1)"}))
45
- when 5 # right top / bottom triangle
46
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width-side_length/2}, #{-side_length/2}) rotate(0, #{side_length/2}, #{triangle_height/2}) scale(-1, 1)"}))
47
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width-side_length/2}, #{tile_height+side_length/2}) rotate(0, #{side_length/2}, #{triangle_height/2}) scale(-1, -1)"}))
48
- when 6 # center / top / right triangle
49
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width/2+side_length/2}, #{hex_height/2})"}))
50
- when 7 # center / top / left triangle
51
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width-tile_width/2-side_length/2}, #{hex_height/2}) scale(-1, 1)"}))
52
- when 8 # center / bottom / right triangle
53
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width/2+side_length/2}, #{tile_height-hex_height/2}) scale(1, -1)"}))
54
- when 9 # center / bottom / left triangle
55
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width-tile_width/2-side_length/2}, #{tile_height-hex_height/2}) scale(-1, -1)"}))
56
- when 10 # left / middle triangle
57
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{side_length/2}, #{tile_height/2 - side_length/2})"}))
58
- when 11 # right / middle triangle
59
- svg.polyline(triangle, styles.merge({"transform" => "translate(#{tile_width-side_length/2}, #{tile_height/2 - side_length/2}) scale(-1, 1)"}))
60
- when 12 # left / top square
61
- svg.rect(0, 0, side_length, side_length,
62
- styles.merge({"transform" => "translate(#{side_length/2}, #{side_length/2}) rotate(-30, 0, 0)"}))
63
- when 13 # right / top square
64
- svg.rect(0, 0, side_length, side_length,
65
- styles.merge({"transform" => "scale(-1, 1) translate(#{-tile_width+side_length/2}, #{side_length/2}) rotate(-30, 0, 0)" }))
66
- when 14 # left / center-top square
67
- svg.rect(0, 0, side_length, side_length,
68
- styles.merge({"transform" => "translate(#{side_length/2}, #{tile_height/2-side_length/2-side_length}) rotate(30, 0, #{side_length})" }))
69
- when 15 # right / center-top square
70
- svg.rect(0, 0, side_length, side_length,
71
- styles.merge({"transform" => "scale(-1, 1) translate(#{-tile_width+side_length/2}, #{tile_height/2-side_length/2-side_length}) rotate(30, 0, #{side_length})" }))
72
- when 16 # left / center-top square
73
- svg.rect(0, 0, side_length, side_length,
74
- styles.merge({"transform" => "scale(1, -1) translate(#{side_length/2}, #{-tile_height+tile_height/2-side_length/2-side_length}) rotate(30, 0, #{side_length})" }))
75
- when 17 # right / center-bottom square
76
- svg.rect(0, 0, side_length, side_length,
77
- styles.merge({"transform" => "scale(-1, -1) translate(#{-tile_width+side_length/2}, #{-tile_height+tile_height/2-side_length/2-side_length}) rotate(30, 0, #{side_length})" }))
78
- when 18 # left / bottom square
79
- svg.rect(0, 0, side_length, side_length,
80
- styles.merge({"transform" => "scale(1, -1) translate(#{side_length/2}, #{-tile_height+side_length/2}) rotate(-30, 0, 0)"}))
81
- when 19 # right / bottom square
82
- svg.rect(0, 0, side_length, side_length,
83
- styles.merge({"transform" => "scale(-1, -1) translate(#{-tile_width+side_length/2}, #{-tile_height+side_length/2}) rotate(-30, 0, 0)"}))
84
- end
85
- end
86
- end
87
-
88
- def build_rotated_triangle_shape(side_length, width)
89
- half_height = side_length / 2
90
- "0, 0, #{width}, #{half_height}, 0, #{side_length}, 0, 0"
91
- end
92
- end
93
- end
@@ -1,51 +0,0 @@
1
- module GeoPattern
2
- class TrianglePattern < BasePattern
3
- def render_to_svg
4
- scale = hex_val(0, 1)
5
- side_length = map(scale, 0, 15, 15, 80)
6
- triangle_height = side_length/2 * Math.sqrt(3)
7
- triangle = build_triangle_shape(side_length, triangle_height)
8
-
9
- svg.set_width(side_length * 3)
10
- svg.set_height(triangle_height * 6)
11
-
12
- i = 0
13
- for y in 0..5
14
- for x in 0..5
15
- val = hex_val(i, 1)
16
- opacity = opacity(val)
17
- fill = fill_color(val)
18
-
19
- styles = {
20
- "fill" => fill,
21
- "fill-opacity" => opacity,
22
- "stroke" => STROKE_COLOR,
23
- "stroke-opacity" => STROKE_OPACITY
24
- }
25
-
26
- rotation = ""
27
- if y % 2 == 0
28
- rotation = x % 2 == 0 ? 180 : 0
29
- else
30
- rotation = x % 2 != 0 ? 180 : 0
31
- end
32
-
33
- svg.polyline(triangle, styles.merge({
34
- "transform" => "translate(#{x*side_length*0.5 - side_length/2}, #{triangle_height*y}) rotate(#{rotation}, #{side_length/2}, #{triangle_height/2})"}))
35
-
36
- # Add an extra one at top-right, for tiling.
37
- if (x == 0)
38
- svg.polyline(triangle, styles.merge({
39
- "transform" => "translate(#{6*side_length*0.5 - side_length/2}, #{triangle_height*y}) rotate(#{rotation}, #{side_length/2}, #{triangle_height/2})"}))
40
- end
41
- i += 1
42
- end
43
- end
44
- end
45
-
46
- def build_triangle_shape(side_length, height)
47
- half_width = side_length / 2
48
- "#{half_width}, 0, #{side_length}, #{height}, 0, #{height}, #{half_width}, 0"
49
- end
50
- end
51
- end
@@ -1,58 +0,0 @@
1
- module GeoPattern
2
- class XesPattern < BasePattern
3
- def render_to_svg
4
- square_size = map(hex_val(0, 1), 0, 15, 10, 25)
5
- x_shape = build_plus_shape(square_size) # rotated later
6
- x_size = square_size * 3 * 0.943
7
-
8
- svg.set_width(x_size * 3)
9
- svg.set_height(x_size * 3)
10
-
11
- i = 0
12
- for y in 0..5
13
- for x in 0..5
14
- val = hex_val(i, 1)
15
- opacity = opacity(val)
16
- dy = x % 2 == 0 ? y*x_size - x_size*0.5 : y*x_size - x_size*0.5 + x_size/4
17
- fill = fill_color(val)
18
-
19
- styles = {
20
- "fill" => fill,
21
- "style" => {
22
- "opacity" => opacity
23
- }
24
- }
25
-
26
- svg.group(x_shape, styles.merge({
27
- "transform" => "translate(#{x*x_size/2 - x_size/2},#{dy - y*x_size/2}) rotate(45, #{x_size/2}, #{x_size/2})"}))
28
-
29
- # Add an extra column on the right for tiling.
30
- if (x == 0)
31
- svg.group(x_shape, styles.merge({
32
- "transform" => "translate(#{6*x_size/2 - x_size/2},#{dy - y*x_size/2}) rotate(45, #{x_size/2}, #{x_size/2})"}))
33
- end
34
-
35
- # Add an extra row on the bottom that matches the first row, for tiling.
36
- if (y == 0)
37
- dy = x % 2 == 0 ? 6*x_size - x_size/2 : 6*x_size - x_size/2 + x_size/4;
38
- svg.group(x_shape, styles.merge({
39
- "transform" => "translate(#{x*x_size/2 - x_size/2},#{dy - 6*x_size/2}) rotate(45, #{x_size/2}, #{x_size/2})"}))
40
- end
41
-
42
- # These can hang off the bottom, so put a row at the top for tiling.
43
- if (y == 5)
44
- svg.group(x_shape, styles.merge({
45
- "transform" => "translate(#{x*x_size/2 - x_size/2},#{dy - 11*x_size/2}) rotate(45, #{x_size/2}, #{x_size/2})"}))
46
- end
47
-
48
- # Add an extra one at top-right and bottom-right, for tiling.
49
- if (x == 0 && y == 0)
50
- svg.group(x_shape, styles.merge({
51
- "transform" => "translate(#{6*x_size/2 - x_size/2},#{dy - 6*x_size/2}) rotate(45, #{x_size/2}, #{x_size/2})"}))
52
- end
53
- i += 1
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,77 +0,0 @@
1
- module GeoPattern
2
- class SVG
3
- include Comparable
4
-
5
- def initialize
6
- @width = 100
7
- @height = 100
8
- @svg_string = ""
9
- end
10
-
11
- def set_width(width)
12
- @width = width.floor
13
- end
14
-
15
- def set_height(height)
16
- @height = height.floor
17
- end
18
-
19
- def svg_header
20
- %Q{<svg xmlns="http://www.w3.org/2000/svg" width="#{@width}" height="#{@height}">}
21
- end
22
-
23
- def svg_closer
24
- "</svg>"
25
- end
26
-
27
- def to_s
28
- svg_header + @svg_string + svg_closer
29
- end
30
-
31
- def rect(x, y, width, height, args={})
32
- @svg_string << %Q{<rect x="#{x}" y="#{y}" width="#{width}" height="#{height}" #{write_args(args)} />}
33
- end
34
-
35
- def circle(cx, cy, r, args={})
36
- @svg_string << %Q{<circle cx="#{cx}" cy="#{cy}" r="#{r}" #{write_args(args)} />}
37
- end
38
-
39
- def path(str, args={})
40
- @svg_string << %Q{<path d="#{str}" #{write_args(args)} />}
41
- end
42
-
43
- def polyline(str, args={})
44
- @svg_string << %Q{<polyline points="#{str}" #{write_args(args)} />}
45
- end
46
-
47
- def group(elements, args={})
48
- @svg_string << %Q{<g #{write_args(args)}>}
49
- elements.each {|e| eval e}
50
- @svg_string << %Q{</g>}
51
- end
52
-
53
- def write_args(args)
54
- str = ""
55
- args.each {|key, value|
56
- if value.is_a?(Hash)
57
- str << %Q{#{key}="}
58
- value.each {|k, v|
59
- str << %Q{#{k}:#{v};}
60
- }
61
- str << %Q{" }
62
- else
63
- str << %Q{#{key}="#{value}" }
64
- end
65
- }
66
- str
67
- end
68
-
69
- def self.as_comment(str)
70
- "<!-- #{str} -->"
71
- end
72
-
73
- def <=>(other)
74
- to_s <=> other.to_s
75
- end
76
- end
77
- end
@@ -1,34 +0,0 @@
1
- module SpecHelpers
2
- def html_to_rgb(color)
3
- generate_rgb_string(Color::RGB.from_html(color))
4
- end
5
-
6
- def html_to_rgb_for_string(string, base_color)
7
- hash = Digest::SHA1.hexdigest string
8
-
9
- hue_offset = GeoPattern::PatternHelpers.map(GeoPattern::PatternHelpers.hex_val(hash, 14, 3), 0, 4095, 0, 359)
10
- sat_offset = GeoPattern::PatternHelpers.hex_val(hash, 17, 1)
11
- base_color = Color::RGB.from_html(base_color).to_hsl
12
- base_color.hue = base_color.hue - hue_offset;
13
-
14
- if (sat_offset % 2 == 0)
15
- base_color.saturation = base_color.saturation + sat_offset
16
- else
17
- base_color.saturation = base_color.saturation - sat_offset
18
- end
19
-
20
- generate_rgb_string(base_color.to_rgb)
21
- end
22
-
23
- def generate_rgb_string(rgb)
24
- r = (rgb.r * 255).round
25
- g = (rgb.g * 255).round
26
- b = (rgb.b * 255).round
27
-
28
- format("rgb(%d, %d, %d)", r, g, b)
29
- end
30
- end
31
-
32
- RSpec.configure do |config|
33
- config.include SpecHelpers
34
- end