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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +89 -0
- data/Rakefile +2 -0
- data/bin/vector_salad +72 -0
- data/examples/birthday.png +0 -0
- data/examples/birthday.rb +45 -0
- data/examples/birthday.svg +630 -0
- data/examples/boolean_operations.png +0 -0
- data/examples/boolean_operations.rb +23 -0
- data/examples/boolean_operations.svg +151 -0
- data/examples/bp_logo.png +0 -0
- data/examples/bp_logo.rb +18 -0
- data/examples/bp_logo.svg +25 -0
- data/examples/bunny_card.png +0 -0
- data/examples/bunny_card.rb +219 -0
- data/examples/bunny_card.svg +134 -0
- data/examples/chill.png +0 -0
- data/examples/chill.rb +16 -0
- data/examples/chill.svg +86 -0
- data/examples/circle_line_segments.png +0 -0
- data/examples/circle_line_segments.rb +11 -0
- data/examples/circle_line_segments.svg +28 -0
- data/examples/circles.png +0 -0
- data/examples/circles.rb +14 -0
- data/examples/circles.svg +11 -0
- data/examples/clip_operations.png +0 -0
- data/examples/clip_operations.rb +14 -0
- data/examples/clip_operations.svg +8 -0
- data/examples/cog_menu.png +0 -0
- data/examples/cog_menu.rb +32 -0
- data/examples/cog_menu.svg +37 -0
- data/examples/cubic_bezier_handles.png +0 -0
- data/examples/cubic_bezier_handles.rb +21 -0
- data/examples/cubic_bezier_handles.svg +14 -0
- data/examples/cubic_circle.png +0 -0
- data/examples/cubic_circle.rb +26 -0
- data/examples/cubic_circle.svg +29 -0
- data/examples/face.png +0 -0
- data/examples/face.rb +4 -0
- data/examples/face.svg +10 -0
- data/examples/flower.png +0 -0
- data/examples/flower.rb +23 -0
- data/examples/flower.svg +207 -0
- data/examples/fox.png +0 -0
- data/examples/fox.rb +110 -0
- data/examples/fox.svg +31 -0
- data/examples/fresh_vector_salad_gui.png +0 -0
- data/examples/galaxies.png +0 -0
- data/examples/galaxies.rb +60 -0
- data/examples/galaxies.svg +5806 -0
- data/examples/gold_stars.png +0 -0
- data/examples/gold_stars.rb +9 -0
- data/examples/gold_stars.svg +12 -0
- data/examples/paths.png +0 -0
- data/examples/paths.rb +87 -0
- data/examples/paths.svg +13 -0
- data/examples/pepsi_logo.png +0 -0
- data/examples/pepsi_logo.rb +21 -0
- data/examples/pepsi_logo.svg +10 -0
- data/examples/polygons.png +0 -0
- data/examples/polygons.rb +9 -0
- data/examples/polygons.svg +13 -0
- data/examples/quadratic_bezier_handle.png +0 -0
- data/examples/quadratic_bezier_handle.rb +18 -0
- data/examples/quadratic_bezier_handle.svg +13 -0
- data/examples/rects.png +0 -0
- data/examples/rects.rb +10 -0
- data/examples/rects.svg +11 -0
- data/examples/simple_path.png +0 -0
- data/examples/simple_path.rb +29 -0
- data/examples/simple_path.svg +8 -0
- data/examples/space.png +0 -0
- data/examples/space.rb +171 -0
- data/examples/space.svg +46453 -0
- data/examples/spiro_nodes.png +0 -0
- data/examples/spiro_nodes.rb +20 -0
- data/examples/spiro_nodes.svg +13 -0
- data/examples/squares.png +0 -0
- data/examples/squares.rb +14 -0
- data/examples/squares.svg +11 -0
- data/examples/stars.png +0 -0
- data/examples/stars.rb +3 -0
- data/examples/stars.svg +30006 -0
- data/examples/transforms.png +0 -0
- data/examples/transforms.rb +58 -0
- data/examples/transforms.svg +121 -0
- data/examples/triangles.png +0 -0
- data/examples/triangles.rb +8 -0
- data/examples/triangles.svg +9 -0
- data/lib/contracts_contracts.rb +32 -0
- data/lib/vector_salad.rb +5 -0
- data/lib/vector_salad/canvas.rb +27 -0
- data/lib/vector_salad/dsl.rb +41 -0
- data/lib/vector_salad/export_with_magic.rb +29 -0
- data/lib/vector_salad/exporters/base_exporter.rb +92 -0
- data/lib/vector_salad/exporters/svg_exporter.rb +174 -0
- data/lib/vector_salad/interpolate.rb +57 -0
- data/lib/vector_salad/magic.rb +17 -0
- data/lib/vector_salad/mixins/at.rb +28 -0
- data/lib/vector_salad/shape_proxy.rb +14 -0
- data/lib/vector_salad/standard_shapes/basic_shape.rb +29 -0
- data/lib/vector_salad/standard_shapes/circle.rb +64 -0
- data/lib/vector_salad/standard_shapes/clip.rb +51 -0
- data/lib/vector_salad/standard_shapes/custom.rb +28 -0
- data/lib/vector_salad/standard_shapes/difference.rb +28 -0
- data/lib/vector_salad/standard_shapes/exclusion.rb +28 -0
- data/lib/vector_salad/standard_shapes/flip.rb +24 -0
- data/lib/vector_salad/standard_shapes/hexagon.rb +15 -0
- data/lib/vector_salad/standard_shapes/intersection.rb +28 -0
- data/lib/vector_salad/standard_shapes/iso_tri.rb +39 -0
- data/lib/vector_salad/standard_shapes/jitter.rb +33 -0
- data/lib/vector_salad/standard_shapes/move.rb +24 -0
- data/lib/vector_salad/standard_shapes/multi_path.rb +82 -0
- data/lib/vector_salad/standard_shapes/n.rb +112 -0
- data/lib/vector_salad/standard_shapes/oval.rb +51 -0
- data/lib/vector_salad/standard_shapes/path.rb +249 -0
- data/lib/vector_salad/standard_shapes/pentagon.rb +15 -0
- data/lib/vector_salad/standard_shapes/polygon.rb +37 -0
- data/lib/vector_salad/standard_shapes/rect.rb +34 -0
- data/lib/vector_salad/standard_shapes/rotate.rb +24 -0
- data/lib/vector_salad/standard_shapes/scale.rb +34 -0
- data/lib/vector_salad/standard_shapes/square.rb +34 -0
- data/lib/vector_salad/standard_shapes/transform.rb +20 -0
- data/lib/vector_salad/standard_shapes/triangle.rb +15 -0
- data/lib/vector_salad/standard_shapes/union.rb +28 -0
- data/lib/vector_salad/version.rb +3 -0
- data/vector_salad.gemspec +34 -0
- 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,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
|
data/lib/vector_salad.rb
ADDED
|
@@ -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
|