vector_salad 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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