vector_salad 0.0.1

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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +89 -0
  6. data/Rakefile +2 -0
  7. data/bin/vector_salad +72 -0
  8. data/examples/birthday.png +0 -0
  9. data/examples/birthday.rb +45 -0
  10. data/examples/birthday.svg +630 -0
  11. data/examples/boolean_operations.png +0 -0
  12. data/examples/boolean_operations.rb +23 -0
  13. data/examples/boolean_operations.svg +151 -0
  14. data/examples/bp_logo.png +0 -0
  15. data/examples/bp_logo.rb +18 -0
  16. data/examples/bp_logo.svg +25 -0
  17. data/examples/bunny_card.png +0 -0
  18. data/examples/bunny_card.rb +219 -0
  19. data/examples/bunny_card.svg +134 -0
  20. data/examples/chill.png +0 -0
  21. data/examples/chill.rb +16 -0
  22. data/examples/chill.svg +86 -0
  23. data/examples/circle_line_segments.png +0 -0
  24. data/examples/circle_line_segments.rb +11 -0
  25. data/examples/circle_line_segments.svg +28 -0
  26. data/examples/circles.png +0 -0
  27. data/examples/circles.rb +14 -0
  28. data/examples/circles.svg +11 -0
  29. data/examples/clip_operations.png +0 -0
  30. data/examples/clip_operations.rb +14 -0
  31. data/examples/clip_operations.svg +8 -0
  32. data/examples/cog_menu.png +0 -0
  33. data/examples/cog_menu.rb +32 -0
  34. data/examples/cog_menu.svg +37 -0
  35. data/examples/cubic_bezier_handles.png +0 -0
  36. data/examples/cubic_bezier_handles.rb +21 -0
  37. data/examples/cubic_bezier_handles.svg +14 -0
  38. data/examples/cubic_circle.png +0 -0
  39. data/examples/cubic_circle.rb +26 -0
  40. data/examples/cubic_circle.svg +29 -0
  41. data/examples/face.png +0 -0
  42. data/examples/face.rb +4 -0
  43. data/examples/face.svg +10 -0
  44. data/examples/flower.png +0 -0
  45. data/examples/flower.rb +23 -0
  46. data/examples/flower.svg +207 -0
  47. data/examples/fox.png +0 -0
  48. data/examples/fox.rb +110 -0
  49. data/examples/fox.svg +31 -0
  50. data/examples/fresh_vector_salad_gui.png +0 -0
  51. data/examples/galaxies.png +0 -0
  52. data/examples/galaxies.rb +60 -0
  53. data/examples/galaxies.svg +5806 -0
  54. data/examples/gold_stars.png +0 -0
  55. data/examples/gold_stars.rb +9 -0
  56. data/examples/gold_stars.svg +12 -0
  57. data/examples/paths.png +0 -0
  58. data/examples/paths.rb +87 -0
  59. data/examples/paths.svg +13 -0
  60. data/examples/pepsi_logo.png +0 -0
  61. data/examples/pepsi_logo.rb +21 -0
  62. data/examples/pepsi_logo.svg +10 -0
  63. data/examples/polygons.png +0 -0
  64. data/examples/polygons.rb +9 -0
  65. data/examples/polygons.svg +13 -0
  66. data/examples/quadratic_bezier_handle.png +0 -0
  67. data/examples/quadratic_bezier_handle.rb +18 -0
  68. data/examples/quadratic_bezier_handle.svg +13 -0
  69. data/examples/rects.png +0 -0
  70. data/examples/rects.rb +10 -0
  71. data/examples/rects.svg +11 -0
  72. data/examples/simple_path.png +0 -0
  73. data/examples/simple_path.rb +29 -0
  74. data/examples/simple_path.svg +8 -0
  75. data/examples/space.png +0 -0
  76. data/examples/space.rb +171 -0
  77. data/examples/space.svg +46453 -0
  78. data/examples/spiro_nodes.png +0 -0
  79. data/examples/spiro_nodes.rb +20 -0
  80. data/examples/spiro_nodes.svg +13 -0
  81. data/examples/squares.png +0 -0
  82. data/examples/squares.rb +14 -0
  83. data/examples/squares.svg +11 -0
  84. data/examples/stars.png +0 -0
  85. data/examples/stars.rb +3 -0
  86. data/examples/stars.svg +30006 -0
  87. data/examples/transforms.png +0 -0
  88. data/examples/transforms.rb +58 -0
  89. data/examples/transforms.svg +121 -0
  90. data/examples/triangles.png +0 -0
  91. data/examples/triangles.rb +8 -0
  92. data/examples/triangles.svg +9 -0
  93. data/lib/contracts_contracts.rb +32 -0
  94. data/lib/vector_salad.rb +5 -0
  95. data/lib/vector_salad/canvas.rb +27 -0
  96. data/lib/vector_salad/dsl.rb +41 -0
  97. data/lib/vector_salad/export_with_magic.rb +29 -0
  98. data/lib/vector_salad/exporters/base_exporter.rb +92 -0
  99. data/lib/vector_salad/exporters/svg_exporter.rb +174 -0
  100. data/lib/vector_salad/interpolate.rb +57 -0
  101. data/lib/vector_salad/magic.rb +17 -0
  102. data/lib/vector_salad/mixins/at.rb +28 -0
  103. data/lib/vector_salad/shape_proxy.rb +14 -0
  104. data/lib/vector_salad/standard_shapes/basic_shape.rb +29 -0
  105. data/lib/vector_salad/standard_shapes/circle.rb +64 -0
  106. data/lib/vector_salad/standard_shapes/clip.rb +51 -0
  107. data/lib/vector_salad/standard_shapes/custom.rb +28 -0
  108. data/lib/vector_salad/standard_shapes/difference.rb +28 -0
  109. data/lib/vector_salad/standard_shapes/exclusion.rb +28 -0
  110. data/lib/vector_salad/standard_shapes/flip.rb +24 -0
  111. data/lib/vector_salad/standard_shapes/hexagon.rb +15 -0
  112. data/lib/vector_salad/standard_shapes/intersection.rb +28 -0
  113. data/lib/vector_salad/standard_shapes/iso_tri.rb +39 -0
  114. data/lib/vector_salad/standard_shapes/jitter.rb +33 -0
  115. data/lib/vector_salad/standard_shapes/move.rb +24 -0
  116. data/lib/vector_salad/standard_shapes/multi_path.rb +82 -0
  117. data/lib/vector_salad/standard_shapes/n.rb +112 -0
  118. data/lib/vector_salad/standard_shapes/oval.rb +51 -0
  119. data/lib/vector_salad/standard_shapes/path.rb +249 -0
  120. data/lib/vector_salad/standard_shapes/pentagon.rb +15 -0
  121. data/lib/vector_salad/standard_shapes/polygon.rb +37 -0
  122. data/lib/vector_salad/standard_shapes/rect.rb +34 -0
  123. data/lib/vector_salad/standard_shapes/rotate.rb +24 -0
  124. data/lib/vector_salad/standard_shapes/scale.rb +34 -0
  125. data/lib/vector_salad/standard_shapes/square.rb +34 -0
  126. data/lib/vector_salad/standard_shapes/transform.rb +20 -0
  127. data/lib/vector_salad/standard_shapes/triangle.rb +15 -0
  128. data/lib/vector_salad/standard_shapes/union.rb +28 -0
  129. data/lib/vector_salad/version.rb +3 -0
  130. data/vector_salad.gemspec +34 -0
  131. metadata +262 -0
Binary file
@@ -0,0 +1,58 @@
1
+ @width = 320.0
2
+ # Background
3
+ rect(@width, @width * 2, fill: 'tan')
4
+
5
+ # Draw a row of repeating shapes at a y position cycling through colors
6
+ def row(shape, y)
7
+ n, col = 16, %w(firebrick darkorange white saddlebrown black).shuffle
8
+ (1..n - 1).each do |x|
9
+ col.rotate! # cycle through the colors
10
+ (options = shape.options.clone)[:fill] = col[0]
11
+ (s = shape.clone).options = options
12
+ canvas << s.move(@width / n * x, y)
13
+ end
14
+ end
15
+
16
+ row(Circle.new(5), 15)
17
+
18
+ (1..7).each do |x| # Triangle snake
19
+ if x.even?
20
+ iso_tri(30, at: [x * 40, -60], fill: 'darkorange').flip_x
21
+ else
22
+ iso_tri(30, at: [x * 40, 30], fill: 'firebrick')
23
+ end
24
+ end
25
+
26
+ row(Pentagon.new(6), 80)
27
+
28
+ # Toothy face
29
+ rect(320, 160, at: [0, 100], fill: 'saddlebrown')
30
+
31
+ flip(:x) do # flip multiple shapes at once
32
+ 6.times { |x| iso_tri(30, 100, at: [x * 30 + 85, -200], fill: 'white') }
33
+ iso_tri(50, 20, at: [35, -145], fill: 'black')
34
+ iso_tri(50, 20, at: [285, -145], fill: 'black')
35
+ circle(7, at: [35, -160], fill: 'firebrick')
36
+ circle(7, at: [285, -160], fill: 'firebrick')
37
+ end
38
+ 7.times { |x| iso_tri(30, 100, at: [x * 30 + 70, @width / 2], fill: 'white') }
39
+
40
+ row(Pentagon.new(6), 280)
41
+
42
+ # Triangle rosette
43
+ n, col1, col2 = 14, %w(firebrick white), %w(darkorange black)
44
+ n.times do |t|
45
+ col1.rotate!
46
+ col2.rotate!
47
+ move(@width / 2, 450) do
48
+ iso_tri(20, at: [0, -120], fill: col2[0]).rotate(360.0 / n * t)
49
+ iso_tri(25, at: [0, 120], fill: col1[0]).rotate(360.0 / n * t + 180.0 / n)
50
+ end
51
+ end
52
+ # "Diamond"
53
+ intersection(fill: 'firebrick') do
54
+ triangle(80, at: [0, 0]).flip_x
55
+ pentagon(60, at: [0, 0])
56
+ end.move(@width/2,450)
57
+
58
+ row(Circle.new(5), 625)
@@ -0,0 +1,121 @@
1
+ <svg version="1.1"
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ width="320.0"
4
+ height="640.0">
5
+
6
+ <rect x="0" y="0" width="320.0" height="640.0" fill="tan"/>
7
+ <circle cx="20.0" cy="15" r="5" fill="black"/>
8
+ <circle cx="40.0" cy="15" r="5" fill="saddlebrown"/>
9
+ <circle cx="60.0" cy="15" r="5" fill="firebrick"/>
10
+ <circle cx="80.0" cy="15" r="5" fill="darkorange"/>
11
+ <circle cx="100.0" cy="15" r="5" fill="white"/>
12
+ <circle cx="120.0" cy="15" r="5" fill="black"/>
13
+ <circle cx="140.0" cy="15" r="5" fill="saddlebrown"/>
14
+ <circle cx="160.0" cy="15" r="5" fill="firebrick"/>
15
+ <circle cx="180.0" cy="15" r="5" fill="darkorange"/>
16
+ <circle cx="200.0" cy="15" r="5" fill="white"/>
17
+ <circle cx="220.0" cy="15" r="5" fill="black"/>
18
+ <circle cx="240.0" cy="15" r="5" fill="saddlebrown"/>
19
+ <circle cx="260.0" cy="15" r="5" fill="firebrick"/>
20
+ <circle cx="280.0" cy="15" r="5" fill="darkorange"/>
21
+ <circle cx="300.0" cy="15" r="5" fill="white"/>
22
+ <path d="M 40 30 L 10 60 L 70 60 Z" fill="firebrick"/>
23
+ <path d="M 80 60 L 50 30 L 110 30 Z" fill="darkorange"/>
24
+ <path d="M 120 30 L 90 60 L 150 60 Z" fill="firebrick"/>
25
+ <path d="M 160 60 L 130 30 L 190 30 Z" fill="darkorange"/>
26
+ <path d="M 200 30 L 170 60 L 230 60 Z" fill="firebrick"/>
27
+ <path d="M 240 60 L 210 30 L 270 30 Z" fill="darkorange"/>
28
+ <path d="M 280 30 L 250 60 L 310 60 Z" fill="firebrick"/>
29
+ <path d="M 16.47328848624516 84.85410196624969 L 14.293660902229078 78.14589803375031 L 20.0 74.0 L 25.706339097770922 78.14589803375031 L 23.52671151375484 84.85410196624969 Z" fill="darkorange"/>
30
+ <path d="M 36.47328848624516 84.85410196624969 L 34.29366090222908 78.14589803375031 L 40.0 74.0 L 45.70633909777092 78.14589803375031 L 43.52671151375484 84.85410196624969 Z" fill="firebrick"/>
31
+ <path d="M 56.47328848624516 84.85410196624969 L 54.29366090222908 78.14589803375031 L 60.0 74.0 L 65.70633909777092 78.14589803375031 L 63.52671151375484 84.85410196624969 Z" fill="saddlebrown"/>
32
+ <path d="M 76.47328848624517 84.85410196624969 L 74.29366090222908 78.14589803375031 L 80.0 74.0 L 85.70633909777092 78.14589803375031 L 83.52671151375483 84.85410196624969 Z" fill="black"/>
33
+ <path d="M 96.47328848624517 84.85410196624969 L 94.29366090222908 78.14589803375031 L 100.0 74.0 L 105.70633909777092 78.14589803375031 L 103.52671151375483 84.85410196624969 Z" fill="white"/>
34
+ <path d="M 116.47328848624517 84.85410196624969 L 114.29366090222908 78.14589803375031 L 120.0 74.0 L 125.70633909777092 78.14589803375031 L 123.52671151375483 84.85410196624969 Z" fill="darkorange"/>
35
+ <path d="M 136.47328848624517 84.85410196624969 L 134.29366090222908 78.14589803375031 L 140.0 74.0 L 145.70633909777092 78.14589803375031 L 143.52671151375483 84.85410196624969 Z" fill="firebrick"/>
36
+ <path d="M 156.47328848624517 84.85410196624969 L 154.29366090222908 78.14589803375031 L 160.0 74.0 L 165.70633909777092 78.14589803375031 L 163.52671151375483 84.85410196624969 Z" fill="saddlebrown"/>
37
+ <path d="M 176.47328848624517 84.85410196624969 L 174.29366090222908 78.14589803375031 L 180.0 74.0 L 185.70633909777092 78.14589803375031 L 183.52671151375483 84.85410196624969 Z" fill="black"/>
38
+ <path d="M 196.47328848624517 84.85410196624969 L 194.29366090222908 78.14589803375031 L 200.0 74.0 L 205.70633909777092 78.14589803375031 L 203.52671151375483 84.85410196624969 Z" fill="white"/>
39
+ <path d="M 216.47328848624517 84.85410196624969 L 214.29366090222908 78.14589803375031 L 220.0 74.0 L 225.70633909777092 78.14589803375031 L 223.52671151375483 84.85410196624969 Z" fill="darkorange"/>
40
+ <path d="M 236.47328848624517 84.85410196624969 L 234.29366090222908 78.14589803375031 L 240.0 74.0 L 245.70633909777092 78.14589803375031 L 243.52671151375483 84.85410196624969 Z" fill="firebrick"/>
41
+ <path d="M 256.47328848624517 84.85410196624969 L 254.29366090222908 78.14589803375031 L 260.0 74.0 L 265.7063390977709 78.14589803375031 L 263.52671151375483 84.85410196624969 Z" fill="saddlebrown"/>
42
+ <path d="M 276.47328848624517 84.85410196624969 L 274.2936609022291 78.14589803375031 L 280.0 74.0 L 285.7063390977709 78.14589803375031 L 283.52671151375483 84.85410196624969 Z" fill="black"/>
43
+ <path d="M 296.47328848624517 84.85410196624969 L 294.2936609022291 78.14589803375031 L 300.0 74.0 L 305.7063390977709 78.14589803375031 L 303.52671151375483 84.85410196624969 Z" fill="white"/>
44
+ <rect x="0" y="100" width="320" height="160" fill="saddlebrown"/>
45
+ <path d="M 85 200 L 70 100 L 100 100 Z" fill="white"/>
46
+ <path d="M 115 200 L 100 100 L 130 100 Z" fill="white"/>
47
+ <path d="M 145 200 L 130 100 L 160 100 Z" fill="white"/>
48
+ <path d="M 175 200 L 160 100 L 190 100 Z" fill="white"/>
49
+ <path d="M 205 200 L 190 100 L 220 100 Z" fill="white"/>
50
+ <path d="M 235 200 L 220 100 L 250 100 Z" fill="white"/>
51
+ <path d="M 35 145 L 10 125 L 60 125 Z" fill="black"/>
52
+ <path d="M 285 145 L 260 125 L 310 125 Z" fill="black"/>
53
+ <path d="M 42 160 C 42 156.136594828542, 38.863405171458 153, 35 153 C 31.136594828542002 153, 28 156.136594828542, 28 160 C 28 163.863405171458, 31.136594828542002 167, 35 167 C 38.863405171458 167, 42 163.863405171458, 42 160" fill="firebrick"/>
54
+ <path d="M 292 160 C 292 156.136594828542, 288.863405171458 153, 285 153 C 281.136594828542 153, 278 156.136594828542, 278 160 C 278 163.863405171458, 281.136594828542 167, 285 167 C 288.863405171458 167, 292 163.863405171458, 292 160" fill="firebrick"/>
55
+ <path d="M 70 160.0 L 55 260.0 L 85 260.0 Z" fill="white"/>
56
+ <path d="M 100 160.0 L 85 260.0 L 115 260.0 Z" fill="white"/>
57
+ <path d="M 130 160.0 L 115 260.0 L 145 260.0 Z" fill="white"/>
58
+ <path d="M 160 160.0 L 145 260.0 L 175 260.0 Z" fill="white"/>
59
+ <path d="M 190 160.0 L 175 260.0 L 205 260.0 Z" fill="white"/>
60
+ <path d="M 220 160.0 L 205 260.0 L 235 260.0 Z" fill="white"/>
61
+ <path d="M 250 160.0 L 235 260.0 L 265 260.0 Z" fill="white"/>
62
+ <path d="M 16.47328848624516 284.8541019662497 L 14.293660902229078 278.1458980337503 L 20.0 274.0 L 25.706339097770922 278.1458980337503 L 23.52671151375484 284.8541019662497 Z" fill="darkorange"/>
63
+ <path d="M 36.47328848624516 284.8541019662497 L 34.29366090222908 278.1458980337503 L 40.0 274.0 L 45.70633909777092 278.1458980337503 L 43.52671151375484 284.8541019662497 Z" fill="white"/>
64
+ <path d="M 56.47328848624516 284.8541019662497 L 54.29366090222908 278.1458980337503 L 60.0 274.0 L 65.70633909777092 278.1458980337503 L 63.52671151375484 284.8541019662497 Z" fill="saddlebrown"/>
65
+ <path d="M 76.47328848624517 284.8541019662497 L 74.29366090222908 278.1458980337503 L 80.0 274.0 L 85.70633909777092 278.1458980337503 L 83.52671151375483 284.8541019662497 Z" fill="firebrick"/>
66
+ <path d="M 96.47328848624517 284.8541019662497 L 94.29366090222908 278.1458980337503 L 100.0 274.0 L 105.70633909777092 278.1458980337503 L 103.52671151375483 284.8541019662497 Z" fill="black"/>
67
+ <path d="M 116.47328848624517 284.8541019662497 L 114.29366090222908 278.1458980337503 L 120.0 274.0 L 125.70633909777092 278.1458980337503 L 123.52671151375483 284.8541019662497 Z" fill="darkorange"/>
68
+ <path d="M 136.47328848624517 284.8541019662497 L 134.29366090222908 278.1458980337503 L 140.0 274.0 L 145.70633909777092 278.1458980337503 L 143.52671151375483 284.8541019662497 Z" fill="white"/>
69
+ <path d="M 156.47328848624517 284.8541019662497 L 154.29366090222908 278.1458980337503 L 160.0 274.0 L 165.70633909777092 278.1458980337503 L 163.52671151375483 284.8541019662497 Z" fill="saddlebrown"/>
70
+ <path d="M 176.47328848624517 284.8541019662497 L 174.29366090222908 278.1458980337503 L 180.0 274.0 L 185.70633909777092 278.1458980337503 L 183.52671151375483 284.8541019662497 Z" fill="firebrick"/>
71
+ <path d="M 196.47328848624517 284.8541019662497 L 194.29366090222908 278.1458980337503 L 200.0 274.0 L 205.70633909777092 278.1458980337503 L 203.52671151375483 284.8541019662497 Z" fill="black"/>
72
+ <path d="M 216.47328848624517 284.8541019662497 L 214.29366090222908 278.1458980337503 L 220.0 274.0 L 225.70633909777092 278.1458980337503 L 223.52671151375483 284.8541019662497 Z" fill="darkorange"/>
73
+ <path d="M 236.47328848624517 284.8541019662497 L 234.29366090222908 278.1458980337503 L 240.0 274.0 L 245.70633909777092 278.1458980337503 L 243.52671151375483 284.8541019662497 Z" fill="white"/>
74
+ <path d="M 256.47328848624517 284.8541019662497 L 254.29366090222908 278.1458980337503 L 260.0 274.0 L 265.7063390977709 278.1458980337503 L 263.52671151375483 284.8541019662497 Z" fill="saddlebrown"/>
75
+ <path d="M 276.47328848624517 284.8541019662497 L 274.2936609022291 278.1458980337503 L 280.0 274.0 L 285.7063390977709 278.1458980337503 L 283.52671151375483 284.8541019662497 Z" fill="firebrick"/>
76
+ <path d="M 296.47328848624517 284.8541019662497 L 294.2936609022291 278.1458980337503 L 300.0 274.0 L 305.7063390977709 278.1458980337503 L 303.52671151375483 284.8541019662497 Z" fill="black"/>
77
+ <path d="M 160.0 330.0 L 140.0 350.0 L 180.0 350.0 Z" fill="black"/>
78
+ <path d="M 133.29748792524228 566.9913494618188 L 103.36126677178882 585.8015239174565 L 152.10766238088002 596.9275706152723 Z" fill="white"/>
79
+ <path d="M 212.06604869410697 341.88373585170973 L 185.36899655370743 351.2254384274069 L 221.40775126980418 368.58078799210926 Z" fill="darkorange"/>
80
+ <path d="M 85.18122377695198 543.8197778961636 L 50.04819166878289 547.778319911396 L 89.13976579218439 578.9528100043326 Z" fill="firebrick"/>
81
+ <path d="M 253.81977789616354 375.181223776952 L 225.71335220962828 372.01439016476604 L 250.65294428397766 403.28764946348724 Z" fill="black"/>
82
+ <path d="M 51.8837358517097 502.066048694107 L 18.51242067621027 490.3889204744855 L 40.20660763208818 535.4373638696064 Z" fill="white"/>
83
+ <path d="M 276.9913494618188 423.29748792524225 L 253.0423725390561 408.2493483607321 L 261.94320989730863 447.246464848005 Z" fill="darkorange"/>
84
+ <path d="M 40.0 450.0 L 15.0 425.0 L 15.0 475.0 Z" fill="firebrick"/>
85
+ <path d="M 276.9913494618188 476.7025120747577 L 261.94320989730863 452.753535151995 L 253.0423725390561 491.7506516392679 Z" fill="black"/>
86
+ <path d="M 51.8837358517097 397.93395130589306 L 40.20660763208818 364.56263613039357 L 18.51242067621027 409.6110795255146 Z" fill="white"/>
87
+ <path d="M 253.8197778961636 524.818776223048 L 250.65294428397766 496.71235053651276 L 225.7133522096283 527.985609835234 Z" fill="darkorange"/>
88
+ <path d="M 85.18122377695201 356.1802221038364 L 89.13976579218443 321.0471899956673 L 50.048191668782934 352.221680088604 Z" fill="firebrick"/>
89
+ <path d="M 212.066048694107 558.1162641482903 L 221.4077512698042 531.4192120078908 L 185.36899655370743 548.774561572593 Z" fill="black"/>
90
+ <path d="M 133.29748792524225 333.0086505381812 L 152.10766238088 303.0724293847277 L 103.3612667717888 314.1984760825435 Z" fill="white"/>
91
+ <path d="M 160.00000000000003 570.0 L 180.0 550.0 L 140.0 550.0 Z" fill="darkorange"/>
92
+ <path d="M 186.70251207475772 333.0086505381812 L 216.63873322821115 314.19847608254344 L 167.89233761911998 303.07242938472774 Z" fill="firebrick"/>
93
+ <path d="M 107.93395130589303 558.1162641482903 L 134.6310034462926 548.774561572593 L 98.59224873019582 531.4192120078908 Z" fill="black"/>
94
+ <path d="M 234.81877622304808 356.18022210383646 L 269.95180833121714 352.22168008860405 L 230.86023420781567 321.0471899956674 Z" fill="white"/>
95
+ <path d="M 66.18022210383644 524.8187762230481 L 94.2866477903717 527.985609835234 L 69.34705571602235 496.71235053651276 Z" fill="darkorange"/>
96
+ <path d="M 268.11626414829027 397.933951305893 L 301.4875793237897 409.6110795255145 L 279.7933923679118 364.56263613039357 Z" fill="firebrick"/>
97
+ <path d="M 43.00865053818117 476.70251207475775 L 66.95762746094394 491.7506516392679 L 58.056790102691366 452.753535151995 Z" fill="black"/>
98
+ <path d="M 280.0 450.0 L 305.0 475.0 L 305.0 425.0 Z" fill="white"/>
99
+ <path d="M 43.00865053818117 423.2974879252422 L 58.05679010269135 447.24646484800496 L 66.95762746094395 408.24934836073203 Z" fill="darkorange"/>
100
+ <path d="M 268.1162641482903 502.06604869410694 L 279.79339236791185 535.4373638696064 L 301.48757932378976 490.3889204744854 Z" fill="firebrick"/>
101
+ <path d="M 66.18022210383641 375.181223776952 L 69.34705571602234 403.28764946348724 L 94.28664779037169 372.01439016476604 Z" fill="black"/>
102
+ <path d="M 234.81877622304805 543.8197778961636 L 230.86023420781564 578.9528100043326 L 269.95180833121714 547.778319911396 Z" fill="white"/>
103
+ <path d="M 107.933951305893 341.88373585170973 L 98.59224873019579 368.58078799210926 L 134.63100344629254 351.2254384274069 Z" fill="darkorange"/>
104
+ <path d="M 186.70251207475786 566.9913494618188 L 167.89233761912016 596.9275706152723 L 216.63873322821132 585.8015239174565 Z" fill="firebrick"/>
105
+ <path d=" M 141.83714962005615 498.54101943969727 L 103.05687046051025 431.3716058731079 L 132.47236156463623 410.0 L 187.5276393890381 410.0000009536743 L 216.94313049316406 431.3716058731079 L 178.16285133361816 498.54101943969727 Z" fill="firebrick"/>
106
+ <circle cx="20.0" cy="625" r="5" fill="saddlebrown"/>
107
+ <circle cx="40.0" cy="625" r="5" fill="darkorange"/>
108
+ <circle cx="60.0" cy="625" r="5" fill="black"/>
109
+ <circle cx="80.0" cy="625" r="5" fill="white"/>
110
+ <circle cx="100.0" cy="625" r="5" fill="firebrick"/>
111
+ <circle cx="120.0" cy="625" r="5" fill="saddlebrown"/>
112
+ <circle cx="140.0" cy="625" r="5" fill="darkorange"/>
113
+ <circle cx="160.0" cy="625" r="5" fill="black"/>
114
+ <circle cx="180.0" cy="625" r="5" fill="white"/>
115
+ <circle cx="200.0" cy="625" r="5" fill="firebrick"/>
116
+ <circle cx="220.0" cy="625" r="5" fill="saddlebrown"/>
117
+ <circle cx="240.0" cy="625" r="5" fill="darkorange"/>
118
+ <circle cx="260.0" cy="625" r="5" fill="black"/>
119
+ <circle cx="280.0" cy="625" r="5" fill="white"/>
120
+ <circle cx="300.0" cy="625" r="5" fill="firebrick"/>
121
+ </svg>
Binary file
@@ -0,0 +1,8 @@
1
+ # Isoscelese right-angle triangle
2
+ iso_tri(50, at: [100, 50])
3
+
4
+ # Simple equilateral triangle
5
+ triangle(50, at: [100,220], fill: '#666')
6
+
7
+ # Isoscelese triangle
8
+ iso_tri(50, 100, at: [100, 300], fill: 'lightgrey')
@@ -0,0 +1,9 @@
1
+ <svg version="1.1"
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ width="150"
4
+ height="400">
5
+
6
+ <path d="M 100 50 L 50 100 L 150 100 Z"/>
7
+ <path d="M 56.698729810778076 245.00000000000003 L 99.99999999999999 170.0 L 143.30127018922195 244.99999999999997 Z" fill="#666"/>
8
+ <path d="M 100 300 L 75 400 L 125 400 Z" fill="lightgrey"/>
9
+ </svg>
@@ -0,0 +1,32 @@
1
+ # @private
2
+ module Contracts
3
+ class Coords
4
+ def self.valid? val
5
+ Maybe[[Num, Num]].valid? val
6
+ end
7
+
8
+ def self.to_s
9
+ "[Num, Num] an x,y coordinate array"
10
+ end
11
+ end
12
+
13
+ class Coord
14
+ def self.valid? val
15
+ Num.valid? val
16
+ end
17
+
18
+ def self.to_s
19
+ "Num; a coordinate"
20
+ end
21
+ end
22
+
23
+ class PolySides
24
+ def self.valid? val
25
+ Num.valid?(val) && val >= 3
26
+ end
27
+
28
+ def self.to_s
29
+ "Num; sides of the polygon, minimum of 3"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ require "vector_salad/version"
2
+
3
+ module VectorSalad
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,27 @@
1
+ module VectorSalad
2
+ class Canvas
3
+ include Enumerable
4
+
5
+ def initialize
6
+ @canvas = []
7
+ end
8
+
9
+ def <<(shape)
10
+ @canvas << shape
11
+ end
12
+
13
+ def each(&block)
14
+ @canvas.each do |shape|
15
+ shape = shape.shape if shape.class == VectorSalad::ShapeProxy
16
+ unless shape.class == VectorSalad::StandardShapes::Custom ||
17
+ !shape.kind_of?(VectorSalad::StandardShapes::BasicShape)
18
+ yield(shape)
19
+ end
20
+ end
21
+ end
22
+
23
+ def [](i)
24
+ @canvas[i].class==VectorSalad::ShapeProxy ? @canvas[i].shape : @canvas[i]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ require 'vector_salad/shape_proxy'
2
+
3
+ module VectorSalad
4
+ module DSL
5
+ def method_missing(name, *args, **options, &block)
6
+ begin
7
+ #This automatic require doesn't work properly
8
+ #require "vector_salad/standard_shapes/#{name}.rb"
9
+
10
+ ns = VectorSalad::StandardShapes
11
+ shape_string = name.to_s.split('_').collect(&:capitalize).join
12
+ shape_class = ns.const_get(shape_string)
13
+
14
+ # No built in is_superclass_of? so implement it ourselves
15
+ # inlined so it doesn't polute the namespace
16
+ is_superclass_of_transform = false
17
+ sub_class = shape_class
18
+ while sub_class != Object
19
+ sub_class = sub_class.superclass
20
+ if sub_class == VectorSalad::StandardShapes::Transform
21
+ is_superclass_of_transform = true
22
+ break
23
+ end
24
+ end
25
+
26
+ if is_superclass_of_transform
27
+ shape_instance = shape_class.new(*args, canvas: canvas, **options, &block)
28
+ else
29
+ shape_instance = shape_class.new(*args, **options, &block)
30
+ end
31
+
32
+ shape_proxy = VectorSalad::ShapeProxy.new(shape_instance)
33
+
34
+ canvas << shape_proxy
35
+ shape_proxy
36
+ rescue LoadError # no shape available
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ require 'vector_salad/exporters/svg_exporter'
2
+ require 'vector_salad/canvas'
3
+ require 'vector_salad/dsl'
4
+ Dir.glob(File.expand_path('../standard_shapes/*.rb', __FILE__)).each do |file|
5
+ require file
6
+ end
7
+
8
+ module VectorSalad
9
+ class ExportWithMagic
10
+ include VectorSalad::DSL
11
+ include VectorSalad::StandardShapes
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ @file = options.file
16
+ end
17
+
18
+ def canvas
19
+ @canvas ||= VectorSalad::Canvas.new
20
+ end
21
+
22
+ def export
23
+ data = File.read(@file)
24
+ instance_eval(data, @file)
25
+ @options.canvas = canvas
26
+ Exporters::SvgExporter.new(@options).export
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,92 @@
1
+ require "stringio"
2
+
3
+ module VectorSalad
4
+ module Exporters
5
+ class BaseExporter
6
+ attr_reader :canvas
7
+
8
+ def initialize(options)
9
+ @options = options
10
+ @canvas_width = options.width
11
+ @canvas_height = options.height
12
+ @canvas = options.canvas
13
+ @out = StringIO.new
14
+ end
15
+
16
+ def puts(str)
17
+ @out.puts str + "\n"
18
+ end
19
+
20
+ def gets
21
+ @out.string
22
+ end
23
+
24
+ def export
25
+ header
26
+ body
27
+ footer
28
+
29
+ gets
30
+ end
31
+
32
+ def header; end
33
+
34
+ def body
35
+ format = self.class.name.split('::').last.gsub(/Exporter/, '')
36
+ .gsub(/(.)([A-Z])/,'\1_\2').downcase
37
+ convert_method = "to_#{format}".to_sym
38
+ canvas.each do |shape|
39
+ begin
40
+ puts shape.send(convert_method)
41
+ rescue NameError, NoMethodError
42
+ puts shape.to_path.send(convert_method)
43
+ end unless shape.nil?
44
+ end
45
+ end
46
+
47
+ def footer; end
48
+
49
+ def canvas_width
50
+ get_canvas_sizes unless @canvas_width
51
+ @canvas_width
52
+ end
53
+
54
+ def canvas_height
55
+ get_canvas_sizes unless @canvas_height
56
+ @canvas_height
57
+ end
58
+
59
+ private
60
+ # This method is long and repetetive, for speed. There was a shorter
61
+ # version that converted every shape to a MultiPath but the performance
62
+ # was really terrible. This way is a ton faster.
63
+ def get_canvas_sizes
64
+ @canvas_width = 0
65
+ @canvas_height = 0
66
+ canvas.each do |shape|
67
+ #if shape.respond_to?(:at) && false
68
+ #@canvas_width = shape.at[0] if shape.at[0] > @canvas_width
69
+ #@canvas_height = shape.at[1] if shape.at[1] > @canvas_height
70
+ #else
71
+ #shape = shape.to_path
72
+ shape = shape.to_simple_path
73
+
74
+ if shape.class == VectorSalad::StandardShapes::Path
75
+ shape.nodes.each do |node|
76
+ @canvas_width = node.at[0] if node.at[0] > @canvas_width
77
+ @canvas_height = node.at[1] if node.at[1] > @canvas_height
78
+ end
79
+ else # MultiPath
80
+ shape.paths.each do |path|
81
+ path.nodes.each do |node|
82
+ @canvas_width = node.at[0] if node.at[0] > @canvas_width
83
+ @canvas_height = node.at[1] if node.at[1] > @canvas_height
84
+ end
85
+ end
86
+ end
87
+ #end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,174 @@
1
+ require_relative 'base_exporter.rb'
2
+ Dir.glob(File.expand_path('../../standard_shapes/*.rb', __FILE__)).each do |file|
3
+ require file
4
+ end
5
+
6
+ module VectorSalad
7
+ module Exporters
8
+ class SvgExporter < BaseExporter
9
+ def header
10
+ puts <<-END.gsub(/^ {10}/, '')
11
+ <svg version="1.1"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ width="#{canvas_width}"
14
+ height="#{canvas_height}">
15
+ END
16
+ end
17
+
18
+ def footer
19
+ puts '</svg>'
20
+ end
21
+
22
+ def self.options(options)
23
+ out = ''
24
+ options.each do |k, v|
25
+ out << " #{k.to_s.gsub(/_/, ?-)}=\"#{v.to_s.gsub(/_/, ?-)}\""
26
+ end
27
+ out
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ module VectorSalad
35
+ module StandardShapes
36
+ class Path
37
+ def to_svg
38
+ svg = '<path d="'
39
+ svg << to_svg_d_attribute
40
+ svg << '"'
41
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
42
+ svg << '/>'
43
+ end
44
+
45
+ def to_svg_d_attribute
46
+ nodes = to_bezier_path.nodes
47
+ svg = ''
48
+ svg << "M #{nodes[0].x} #{nodes[0].y}"
49
+
50
+ nodes[1..-1].each_index do |j|
51
+ i = j+1
52
+
53
+ n = nodes[i]
54
+ case n.type
55
+ when :cubic
56
+ if nodes[i-1].type == :node
57
+ svg << " C #{n.x} #{n.y}"
58
+ elsif nodes[i-2].type == :node && nodes[i-1].type == :cubic
59
+ svg << ", #{n.x} #{n.y}"
60
+ end
61
+ when :quadratic
62
+ svg << " Q #{n.x} #{n.y}"
63
+ when :node
64
+ if nodes[i-1].type == :cubic || nodes[i-1].type == :quadratic
65
+ svg << ", #{n.x} #{n.y}"
66
+ elsif nodes[i-1].type == :node
67
+ svg << " L #{n.x} #{n.y}"
68
+ end
69
+ else
70
+ raise "The SVG exporter doesn't support #{n.type} node type."
71
+ end
72
+ end
73
+
74
+ svg << ' Z' if @closed
75
+ svg
76
+ end
77
+ end
78
+
79
+ class MultiPath
80
+ def to_svg
81
+ svg = '<path d="'
82
+ paths.each do |path|
83
+ svg << " #{path.to_svg_d_attribute}"
84
+ end
85
+ svg << '"'
86
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
87
+ svg << '/>'
88
+ end
89
+ end
90
+
91
+ class Circle
92
+ def to_svg
93
+ svg = "<circle cx=\"#{at[0]}\" cy=\"#{at[1]}\" r=\"#{radius}\""
94
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
95
+ svg << '/>'
96
+ end
97
+ end
98
+
99
+ class Oval
100
+ def to_svg
101
+ svg = "<ellipse cx=\"#{at[0]}\" cy=\"#{at[1]}\""
102
+ svg << " rx=\"#{width}\" ry=\"#{height}\""
103
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
104
+ svg << '/>'
105
+ end
106
+ end
107
+
108
+ class Square
109
+ def to_svg
110
+ svg = "<rect x=\"#{at[0]}\" y=\"#{at[1]}\""
111
+ svg << " width=\"#{size}\" height=\"#{size}\""
112
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
113
+ svg << '/>'
114
+ end
115
+ end
116
+
117
+ class Rect
118
+ def to_svg
119
+ svg = "<rect x=\"#{at[0]}\" y=\"#{at[1]}\""
120
+ svg << " width=\"#{width}\" height=\"#{height}\""
121
+ svg << VectorSalad::Exporters::SvgExporter.options(@options)
122
+ svg << '/>'
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ #include VectorSalad::StandardShapes
129
+ #p = Path.new([0,0], [50,0], [50,50])
130
+ #puts p.to_svg
131
+
132
+ #p1 = Path.new(
133
+ #N.n(0,100),
134
+ #N.q(100,0),
135
+ #N.n(200,100),
136
+ #N.q(300,200),
137
+ #N.n(400,100),
138
+ #N.n(400,200),
139
+ #N.n(0,200)
140
+ #)
141
+ #puts p1.to_svg
142
+
143
+ #p2 = Path.new(
144
+ #N.n(0,100),
145
+ #N.c(50,150),
146
+ #N.c(250,150),
147
+ #N.n(300,100),
148
+ #N.n(300,50),
149
+ #N.c(300,0),
150
+ #N.c(200,50),
151
+ #N.n(100,50),
152
+ #N.c(50,0),
153
+ #N.c(0,0),
154
+ #N.n(0,50)
155
+ #)
156
+ #puts p2.to_svg
157
+
158
+ #p3 = Path.new(
159
+ #N.n(0,200),
160
+ #N.c(50,000),
161
+ #N.c(300,100),
162
+ #N.n(400,150),
163
+ #N.q(200,500),
164
+ #N.n(50,300)
165
+ #)
166
+ #puts p3.to_svg
167
+
168
+ #puts p4.to_svg
169
+
170
+ #sq = Square.new(100, at: [50,50])
171
+ #puts sq.to_path.to_svg
172
+
173
+ #ci = Circle.new(100, at: [200,200])
174
+ #puts ci.to_path.to_svg