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
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Code adapted from:
|
|
2
|
+
# http://jeremykun.com/2013/05/11/bezier-curves-and-picasso/
|
|
3
|
+
#
|
|
4
|
+
# Interpolate a cubic bezier spline into straight line segments,
|
|
5
|
+
# using the De Casteljau algorithm.
|
|
6
|
+
module VectorSalad
|
|
7
|
+
class Interpolate
|
|
8
|
+
#TOLERANCE = 10 # anything below 50 is roughly good-looking
|
|
9
|
+
TOLERANCE = 0.2 # anything below 50 is roughly good-looking
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@nodes = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def casteljau(curve)
|
|
16
|
+
if flat_enough? curve
|
|
17
|
+
@nodes << curve[3]
|
|
18
|
+
else
|
|
19
|
+
halves = subdivide(curve)
|
|
20
|
+
casteljau(halves[0])
|
|
21
|
+
casteljau(halves[1])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Early stopping function for the Casteljau algorithm.
|
|
26
|
+
# Is the curve flat enough for visual purposes?
|
|
27
|
+
def flat_enough?(curve)
|
|
28
|
+
ax = (3.0*curve[1][0] - 2.0*curve[0][0] - curve[3][0])**2
|
|
29
|
+
ay = (3.0*curve[1][1] - 2.0*curve[0][1] - curve[3][1])**2
|
|
30
|
+
bx = (3.0*curve[2][0] - curve[0][0] - 2.0*curve[3][0])**2
|
|
31
|
+
by = (3.0*curve[2][1] - curve[0][1] - 2.0*curve[3][1])**2
|
|
32
|
+
|
|
33
|
+
[ax, bx].max + [ay, by].max <= TOLERANCE
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def midpoint(p, q)
|
|
37
|
+
[(p[0] + q[0]) / 2.0, (p[1] + q[1]) / 2.0]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def midpoints(points)
|
|
41
|
+
midpoints = Array.new(points.length - 1)
|
|
42
|
+
midpoints.each_index do |i|
|
|
43
|
+
midpoints[i] = midpoint(points[i], points[i+1])
|
|
44
|
+
end
|
|
45
|
+
midpoints
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def subdivide(curve)
|
|
49
|
+
first = midpoints(curve)
|
|
50
|
+
second = midpoints(first)
|
|
51
|
+
third = midpoints(second)
|
|
52
|
+
|
|
53
|
+
[[curve[0], first[0], second[0], third[0]],
|
|
54
|
+
[third[0], second[1], first[2], curve[3]]]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'vector_salad/canvas'
|
|
2
|
+
require 'vector_salad/dsl'
|
|
3
|
+
Dir.glob(File.expand_path('../standard_shapes/*.rb', __FILE__)).each do |file|
|
|
4
|
+
require file
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module VectorSalad
|
|
8
|
+
module Magic
|
|
9
|
+
def canvas
|
|
10
|
+
@vs_canvas ||= VectorSalad::Canvas.new
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
extend VectorSalad::DSL
|
|
16
|
+
extend VectorSalad::Magic
|
|
17
|
+
include VectorSalad::StandardShapes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module VectorSalad
|
|
2
|
+
module Mixins
|
|
3
|
+
module At
|
|
4
|
+
include Contracts
|
|
5
|
+
|
|
6
|
+
# Change the absolute x, y coordinates of the shape.
|
|
7
|
+
Contract Num, Num => Any
|
|
8
|
+
def [](x, y)
|
|
9
|
+
@x, @y = x, y
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Get the x, y coordinates of the shape.
|
|
14
|
+
Contract None => Coords
|
|
15
|
+
def at
|
|
16
|
+
[@x, @y]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Move the shape relatively.
|
|
20
|
+
Contract Num, Num => Any
|
|
21
|
+
def move(x, y)
|
|
22
|
+
shape = clone
|
|
23
|
+
shape[shape.at[0] + x, shape.at[1] + y]
|
|
24
|
+
shape
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'contracts'
|
|
3
|
+
require 'contracts_contracts'
|
|
4
|
+
|
|
5
|
+
module VectorSalad
|
|
6
|
+
module StandardShapes
|
|
7
|
+
class BasicShape
|
|
8
|
+
extend Forwardable
|
|
9
|
+
include Contracts
|
|
10
|
+
|
|
11
|
+
attr_accessor :options
|
|
12
|
+
|
|
13
|
+
delegate [
|
|
14
|
+
:flip,
|
|
15
|
+
:flip_x,
|
|
16
|
+
:flip_y,
|
|
17
|
+
:rotate,
|
|
18
|
+
:move,
|
|
19
|
+
:jitter,
|
|
20
|
+
:scale,
|
|
21
|
+
:to_simple_path,
|
|
22
|
+
:to_bezier_path,
|
|
23
|
+
:to_cubic_path,
|
|
24
|
+
:to_multi_path,
|
|
25
|
+
:to_a
|
|
26
|
+
] => :to_path
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require "vector_salad/standard_shapes/path"
|
|
2
|
+
require "vector_salad/standard_shapes/n"
|
|
3
|
+
require "vector_salad/mixins/at"
|
|
4
|
+
|
|
5
|
+
module VectorSalad
|
|
6
|
+
module StandardShapes
|
|
7
|
+
class Circle < Path
|
|
8
|
+
include VectorSalad::Mixins::At
|
|
9
|
+
attr_reader :radius
|
|
10
|
+
|
|
11
|
+
# Create a perfectly round circle.
|
|
12
|
+
#
|
|
13
|
+
# Examples do
|
|
14
|
+
# new(100)
|
|
15
|
+
Contract Pos, {} => Circle
|
|
16
|
+
def initialize(radius, **options)
|
|
17
|
+
@options = options
|
|
18
|
+
@radius = radius
|
|
19
|
+
@x, @y = 0, 0
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_path
|
|
24
|
+
# http://stackoverflow.com/a/13338311
|
|
25
|
+
# c = 4 * (Math.sqrt(2) - 1) / 3
|
|
26
|
+
# c = 0.5522847498307936
|
|
27
|
+
#
|
|
28
|
+
# http://spencermortensen.com/articles/bezier-circle/
|
|
29
|
+
c = 0.551915024494
|
|
30
|
+
d = c * @radius
|
|
31
|
+
Path.new(
|
|
32
|
+
N.n(@x + @radius, @y),
|
|
33
|
+
N.c(@x + @radius, @y + d),
|
|
34
|
+
N.c(@x + d, @y + @radius),
|
|
35
|
+
N.n(@x, @y + @radius),
|
|
36
|
+
N.c(@x - d, @y + @radius),
|
|
37
|
+
N.c(@x - @radius, @y + d),
|
|
38
|
+
N.n(@x - @radius, @y),
|
|
39
|
+
N.c(@x - @radius, @y - d),
|
|
40
|
+
N.c(@x - d, @y - @radius),
|
|
41
|
+
N.n(@x, @y - @radius),
|
|
42
|
+
N.c(@x + d, @y - @radius),
|
|
43
|
+
N.c(@x + @radius, @y - d),
|
|
44
|
+
N.n(@x + @radius, @y),
|
|
45
|
+
**@options
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_simple_path(fn = nil)
|
|
50
|
+
fn ||= (@radius * 2).ceil
|
|
51
|
+
|
|
52
|
+
nodes = []
|
|
53
|
+
arc = (2.0 * Math::PI) / fn
|
|
54
|
+
fn.times do |t|
|
|
55
|
+
a = arc * t
|
|
56
|
+
x = @radius * Math.cos(a) + @x
|
|
57
|
+
y = @radius * Math.sin(a) + @y
|
|
58
|
+
nodes << N.n(x, y)
|
|
59
|
+
end
|
|
60
|
+
Path.new(*nodes, **@options)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'clipper'
|
|
2
|
+
|
|
3
|
+
require 'vector_salad/dsl'
|
|
4
|
+
require 'vector_salad/canvas'
|
|
5
|
+
require 'vector_salad/standard_shapes/multi_path'
|
|
6
|
+
|
|
7
|
+
module VectorSalad
|
|
8
|
+
module StandardShapes
|
|
9
|
+
class Clip < BasicShape
|
|
10
|
+
include VectorSalad::DSL
|
|
11
|
+
include VectorSalad::StandardShapes
|
|
12
|
+
|
|
13
|
+
# Perform a clipping operation on a set of paths or shapes.
|
|
14
|
+
# The first path is used as the subject, subsequent paths are applied to
|
|
15
|
+
# the first using the specified operation.
|
|
16
|
+
#
|
|
17
|
+
# It's easier to use one of the subclasses;
|
|
18
|
+
# (see {Difference}, {Intersection}, {Union}, {Exclusion}).
|
|
19
|
+
Contract Or[*%i(difference intersection union xor)], {}, Proc => MultiPath
|
|
20
|
+
def initialize(operation, **options, &block)
|
|
21
|
+
instance_eval(&block) # canvas is populated
|
|
22
|
+
|
|
23
|
+
clipper = Clipper::Clipper.new
|
|
24
|
+
|
|
25
|
+
i = 0
|
|
26
|
+
canvas.each do |shape|
|
|
27
|
+
method = i == 0 ? 'subject' : 'clip'
|
|
28
|
+
path = shape.to_simple_path.to_a
|
|
29
|
+
if path[0][0].instance_of? Array # MultiPath
|
|
30
|
+
clipper.send("add_#{method}_polygons".to_sym, path)
|
|
31
|
+
else # Path
|
|
32
|
+
clipper.send("add_#{method}_polygon".to_sym, path)
|
|
33
|
+
end
|
|
34
|
+
i += 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@path = MultiPath.new(
|
|
38
|
+
*clipper.send(operation, :non_zero, :non_zero), **options
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def canvas
|
|
43
|
+
@canvas ||= VectorSalad::Canvas.new
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_path
|
|
47
|
+
@path
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/path'
|
|
2
|
+
require 'vector_salad/standard_shapes/n'
|
|
3
|
+
require 'vector_salad/dsl'
|
|
4
|
+
require 'vector_salad/canvas'
|
|
5
|
+
|
|
6
|
+
module VectorSalad
|
|
7
|
+
module StandardShapes
|
|
8
|
+
class Custom < BasicShape
|
|
9
|
+
def initialize(name, &block)
|
|
10
|
+
#instance_eval(&block)
|
|
11
|
+
::VectorSalad::StandardShapes.const_set(name.to_s.capitalize.to_sym, Class.new(BasicShape) do
|
|
12
|
+
include VectorSalad::DSL
|
|
13
|
+
include VectorSalad::StandardShapes
|
|
14
|
+
|
|
15
|
+
define_method(:initialize, &block)
|
|
16
|
+
|
|
17
|
+
def canvas
|
|
18
|
+
@canvas ||= VectorSalad::Canvas.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_path
|
|
22
|
+
canvas[0]
|
|
23
|
+
end
|
|
24
|
+
end)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/clip'
|
|
2
|
+
require 'vector_salad/standard_shapes/multi_path'
|
|
3
|
+
|
|
4
|
+
module VectorSalad
|
|
5
|
+
module StandardShapes
|
|
6
|
+
class Difference < Clip
|
|
7
|
+
# Subtract paths.
|
|
8
|
+
# The first path is used as the subject, subsequent paths are subtracted
|
|
9
|
+
# from the first.
|
|
10
|
+
#
|
|
11
|
+
# Examples:
|
|
12
|
+
#
|
|
13
|
+
# Difference.new do
|
|
14
|
+
# canvas << Path.new([0,0], [90,90], [0,90])
|
|
15
|
+
# canvas << Path.new([50,0], [95,0], [50, 70])
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Using DSL:
|
|
19
|
+
# difference do
|
|
20
|
+
# path([0,0], [90,90], [0,90])
|
|
21
|
+
# path([50,0], [95,0], [50, 70])
|
|
22
|
+
# end
|
|
23
|
+
def initialize(**options, &block)
|
|
24
|
+
super(:difference, **options, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/clip'
|
|
2
|
+
require 'vector_salad/standard_shapes/multi_path'
|
|
3
|
+
|
|
4
|
+
module VectorSalad
|
|
5
|
+
module StandardShapes
|
|
6
|
+
class Exclusion < Clip
|
|
7
|
+
# Exclude paths.
|
|
8
|
+
# The first path is used as the subject, subsequent paths are excluded
|
|
9
|
+
# from the first.
|
|
10
|
+
#
|
|
11
|
+
# Examples:
|
|
12
|
+
#
|
|
13
|
+
# Exclusion.new do
|
|
14
|
+
# canvas << Path.new([0,0], [90,90], [0,90])
|
|
15
|
+
# canvas << Path.new([50,0], [95,0], [50, 70])
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Using DSL:
|
|
19
|
+
# exclusion do
|
|
20
|
+
# path([0,0], [90,90], [0,90])
|
|
21
|
+
# path([50,0], [95,0], [50, 70])
|
|
22
|
+
# end
|
|
23
|
+
def initialize(**options, &block)
|
|
24
|
+
super(:xor, **options, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/transform'
|
|
2
|
+
|
|
3
|
+
module VectorSalad
|
|
4
|
+
module StandardShapes
|
|
5
|
+
class Flip < Transform
|
|
6
|
+
# Flip the contained shapes on the specified axis.
|
|
7
|
+
#
|
|
8
|
+
# Examples:
|
|
9
|
+
#
|
|
10
|
+
# flip(:x) do
|
|
11
|
+
# triangle(30, at: [50, -50])
|
|
12
|
+
# pentagon(40, at: [50, -100])
|
|
13
|
+
# end
|
|
14
|
+
Contract Or[:x, :y], { canvas: VectorSalad::Canvas }, Proc => Any
|
|
15
|
+
def initialize(axis, canvas:, **_options, &block)
|
|
16
|
+
instance_eval(&block) # inner_canvas is populated
|
|
17
|
+
|
|
18
|
+
@canvas.each do |shape|
|
|
19
|
+
canvas << shape.flip(axis)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/polygon'
|
|
2
|
+
|
|
3
|
+
module VectorSalad
|
|
4
|
+
module StandardShapes
|
|
5
|
+
class Hexagon < Polygon
|
|
6
|
+
# Create a regular hexagon.
|
|
7
|
+
#
|
|
8
|
+
# Examples:
|
|
9
|
+
# new(100)
|
|
10
|
+
def initialize(radius, **options)
|
|
11
|
+
super(6, radius, **options)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'vector_salad/standard_shapes/clip'
|
|
2
|
+
require 'vector_salad/standard_shapes/multi_path'
|
|
3
|
+
|
|
4
|
+
module VectorSalad
|
|
5
|
+
module StandardShapes
|
|
6
|
+
class Intersection < Clip
|
|
7
|
+
# Intersect paths.
|
|
8
|
+
# The first path is used as the subject, subsequent paths are intersected
|
|
9
|
+
# with the first.
|
|
10
|
+
#
|
|
11
|
+
# Examples:
|
|
12
|
+
#
|
|
13
|
+
# Intersection.new do
|
|
14
|
+
# canvas << Path.new([0,0], [90,90], [0,90])
|
|
15
|
+
# canvas << Path.new([50,0], [95,0], [50, 70])
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# # Using DSL:
|
|
19
|
+
# intersection do
|
|
20
|
+
# path([0,0], [90,90], [0,90])
|
|
21
|
+
# path([50,0], [95,0], [50, 70])
|
|
22
|
+
# end
|
|
23
|
+
def initialize(**options, &block)
|
|
24
|
+
super(:intersection, **options, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "vector_salad/standard_shapes/path"
|
|
2
|
+
require "vector_salad/standard_shapes/n"
|
|
3
|
+
require "vector_salad/mixins/at"
|
|
4
|
+
|
|
5
|
+
module VectorSalad
|
|
6
|
+
module StandardShapes
|
|
7
|
+
class IsoTri < BasicShape
|
|
8
|
+
include VectorSalad::Mixins::At
|
|
9
|
+
|
|
10
|
+
attr_reader :height
|
|
11
|
+
|
|
12
|
+
# Create an isosceles or right-angle triangle.
|
|
13
|
+
#
|
|
14
|
+
# Examples:
|
|
15
|
+
#
|
|
16
|
+
# new(100)
|
|
17
|
+
# new(100, 150)
|
|
18
|
+
#
|
|
19
|
+
# @param width (defaults to height*2).
|
|
20
|
+
Contract Args[Pos], {} => IsoTri
|
|
21
|
+
def initialize(width = nil, height, **options)
|
|
22
|
+
width = height * 2 if width.nil?
|
|
23
|
+
@width, @height = width, height
|
|
24
|
+
@options = options
|
|
25
|
+
@x, @y = 0, 0
|
|
26
|
+
self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_path
|
|
30
|
+
Path.new(
|
|
31
|
+
N.n(@x, @y),
|
|
32
|
+
N.n(@x - @width / 2, @y + @height),
|
|
33
|
+
N.n(@x + @width / 2, @y + @height),
|
|
34
|
+
**@options
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|