svgcode 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +37 -1
- data/Guardfile +16 -0
- data/TODO.md +0 -2
- data/bin/svgcode +2 -39
- data/lib/svgcode.rb +9 -4
- data/lib/svgcode/cli.rb +76 -0
- data/lib/svgcode/gcode/command.rb +9 -0
- data/lib/svgcode/gcode/converter.rb +43 -33
- data/lib/svgcode/gcode/program.rb +5 -1
- data/lib/svgcode/svg/base_command.rb +91 -0
- data/lib/svgcode/svg/circle.rb +54 -0
- data/lib/svgcode/svg/path.rb +2 -2
- data/lib/svgcode/svg/{command.rb → path_command.rb} +9 -8
- data/lib/svgcode/svg/point.rb +12 -8
- data/lib/svgcode/svg/transform.rb +13 -12
- data/lib/svgcode/utility.rb +28 -0
- data/lib/svgcode/version.rb +1 -1
- data/svgcode.gemspec +3 -0
- metadata +36 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85836f130f6ff7d82e701ed3794699d34a93e6c6
|
4
|
+
data.tar.gz: a3ade6019d2663505e5ca24d20b62f63c80efb02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51b98e6d618d94e0e0211872f1aff91a6b281e41b44abbbc8b42b3f9bda9ec3c13908ec1f0140950ee815df1340e15fb65fed7ffee3e6d0816c410feba69e661
|
7
|
+
data.tar.gz: 5447772034b322ba08006c6d0108c587a8c0d0e9dccdc5a58f4df96367c16472adc9cc103da202db94d22602a057e47b01a8738f949b8e0607b2f6775175d812
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
svgcode (0.
|
4
|
+
svgcode (0.6.0)
|
5
5
|
nokogiri (~> 1.8)
|
6
6
|
thor (~> 0.20)
|
7
7
|
|
@@ -9,11 +9,43 @@ GEM
|
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
11
|
byebug (9.1.0)
|
12
|
+
coderay (1.1.2)
|
12
13
|
diff-lcs (1.3)
|
14
|
+
ffi (1.9.23)
|
15
|
+
formatador (0.2.5)
|
16
|
+
guard (2.14.2)
|
17
|
+
formatador (>= 0.2.4)
|
18
|
+
listen (>= 2.7, < 4.0)
|
19
|
+
lumberjack (>= 1.0.12, < 2.0)
|
20
|
+
nenv (~> 0.1)
|
21
|
+
notiffany (~> 0.0)
|
22
|
+
pry (>= 0.9.12)
|
23
|
+
shellany (~> 0.0)
|
24
|
+
thor (>= 0.18.1)
|
25
|
+
guard-compat (1.2.1)
|
26
|
+
guard-shell (0.7.1)
|
27
|
+
guard (>= 2.0.0)
|
28
|
+
guard-compat (~> 1.0)
|
29
|
+
listen (3.1.5)
|
30
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
31
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
32
|
+
ruby_dep (~> 1.2)
|
33
|
+
lumberjack (1.0.13)
|
34
|
+
method_source (0.9.0)
|
13
35
|
mini_portile2 (2.3.0)
|
36
|
+
nenv (0.3.0)
|
14
37
|
nokogiri (1.8.2)
|
15
38
|
mini_portile2 (~> 2.3.0)
|
39
|
+
notiffany (0.1.1)
|
40
|
+
nenv (~> 0.1)
|
41
|
+
shellany (~> 0.0)
|
42
|
+
pry (0.11.3)
|
43
|
+
coderay (~> 1.1.0)
|
44
|
+
method_source (~> 0.9.0)
|
16
45
|
rake (10.5.0)
|
46
|
+
rb-fsevent (0.10.3)
|
47
|
+
rb-inotify (0.9.10)
|
48
|
+
ffi (>= 0.5.0, < 2)
|
17
49
|
rspec (3.7.0)
|
18
50
|
rspec-core (~> 3.7.0)
|
19
51
|
rspec-expectations (~> 3.7.0)
|
@@ -27,6 +59,8 @@ GEM
|
|
27
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
28
60
|
rspec-support (~> 3.7.0)
|
29
61
|
rspec-support (3.7.0)
|
62
|
+
ruby_dep (1.5.0)
|
63
|
+
shellany (0.0.1)
|
30
64
|
thor (0.20.0)
|
31
65
|
yard (0.9.12)
|
32
66
|
|
@@ -36,6 +70,8 @@ PLATFORMS
|
|
36
70
|
DEPENDENCIES
|
37
71
|
bundler (~> 1.16)
|
38
72
|
byebug
|
73
|
+
guard
|
74
|
+
guard-shell
|
39
75
|
rake (~> 10.0)
|
40
76
|
rspec (~> 3.0)
|
41
77
|
svgcode!
|
data/Guardfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'svgcode/cli'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
guard :shell do
|
5
|
+
watch(//) do |mod|
|
6
|
+
ngc_file = Tempfile.new
|
7
|
+
cli = Svgcode::CLI.new
|
8
|
+
|
9
|
+
cli.invoke('parse', ['~/Desktop/azabache.svg'],
|
10
|
+
out_path: ngc_file.path,
|
11
|
+
comments: true
|
12
|
+
)
|
13
|
+
|
14
|
+
cli.invoke('post', [ngc_file.path])
|
15
|
+
end
|
16
|
+
end
|
data/TODO.md
CHANGED
data/bin/svgcode
CHANGED
@@ -1,43 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
|
-
require 'svgcode'
|
5
|
-
require 'thor'
|
4
|
+
require 'svgcode/cli'
|
6
5
|
|
7
|
-
|
8
|
-
class SVGCLI < Thor
|
9
|
-
desc 'parse SVG_PATH [--out OUT_PATH] [--comments]',
|
10
|
-
'parses an SVG file to a G-code file'
|
11
|
-
option :out_path
|
12
|
-
option :comments, type: :boolean
|
13
|
-
long_desc <<-LONGDESC
|
14
|
-
`svgcode parse ~/Desktop/img.svg` will save the G-code file as
|
15
|
-
'~/Desktop/img.ngc'.
|
16
|
-
|
17
|
-
Optionally set the --out-path flag to save the G-code file elsewhere
|
18
|
-
\x5 e.g. `svgcode parse ~/Documents/img.svg --out-path ~/Desktop/gcode.nc`
|
19
|
-
|
20
|
-
Optionally pass the --comments flag to print SVG IDs as comments
|
21
|
-
\x5 e.g. `svgcode parse --comments ~/Desktop/img.svg`
|
22
|
-
LONGDESC
|
23
|
-
def parse(in_path)
|
24
|
-
in_path = File.expand_path(in_path)
|
25
|
-
raise "#{in_path} is not readable" unless File.readable?(in_path)
|
26
|
-
svg_str = File.read(in_path)
|
27
|
-
|
28
|
-
out_path =
|
29
|
-
if options[:out_path].nil?
|
30
|
-
in_path.gsub(/\.svg\Z/i, '.ngc')
|
31
|
-
else
|
32
|
-
File.expand_path(options[:out_path])
|
33
|
-
end
|
34
|
-
|
35
|
-
opts = { comments: options[:comments] }
|
36
|
-
File.open(out_path, 'w') { |f| f << Svgcode.parse(svg_str, opts) }
|
37
|
-
|
38
|
-
puts "G-code written to #{out_path}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
SVGCLI.start(ARGV)
|
6
|
+
Svgcode::CLI.start(ARGV)
|
data/lib/svgcode.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'svgcode/utility'
|
1
2
|
require 'svgcode/version'
|
2
3
|
require 'svgcode/gcode/converter'
|
3
4
|
require 'svgcode/svg/transform'
|
@@ -15,20 +16,24 @@ module Svgcode
|
|
15
16
|
opts[:max_y] = view_box.split(/\s+/).last.to_f
|
16
17
|
converter = Converter.new(opts)
|
17
18
|
|
18
|
-
doc.xpath('//path').each do |
|
19
|
+
doc.xpath('//path|//circle').each do |el|
|
19
20
|
if opts[:comments]
|
20
|
-
ids =
|
21
|
+
ids = el.xpath('ancestor::g[@id]').collect do |t|
|
21
22
|
t.attributes['id'].value
|
22
23
|
end
|
23
24
|
|
24
25
|
converter.comment!(ids.join(' '))
|
25
26
|
end
|
26
27
|
|
27
|
-
converter.transforms =
|
28
|
+
converter.transforms = el.xpath('ancestor::g[@transform]').collect do |t|
|
28
29
|
Transform.new(t.attributes['transform'].value)
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
+
if el.name == 'path'
|
33
|
+
converter << el.attributes['d'].value
|
34
|
+
else
|
35
|
+
converter << el
|
36
|
+
end
|
32
37
|
end
|
33
38
|
|
34
39
|
converter.finish
|
data/lib/svgcode/cli.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'svgcode'
|
2
|
+
require 'thor'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module Svgcode
|
6
|
+
class CLI < Thor
|
7
|
+
DEFAULT_POST_URL = 'http://linux-cnc.bmo:8080'
|
8
|
+
DEFAULT_POST_NAME = 'file'
|
9
|
+
|
10
|
+
desc 'parse SVG_PATH [--out OUT_PATH] [--comments]',
|
11
|
+
'parses an SVG file to a G-code file'
|
12
|
+
option :out_path
|
13
|
+
option :comments, type: :boolean
|
14
|
+
long_desc <<-LONGDESC
|
15
|
+
`svgcode parse ~/Desktop/img.svg` will save the G-code file as
|
16
|
+
'~/Desktop/img.ngc'.
|
17
|
+
|
18
|
+
Optionally set the --out-path flag to save the G-code file elsewhere
|
19
|
+
\x5 e.g. `svgcode parse ~/Documents/img.svg --out-path ~/Desktop/gcode.nc`
|
20
|
+
|
21
|
+
Optionally pass the --comments flag to print SVG IDs as comments
|
22
|
+
\x5 e.g. `svgcode parse --comments ~/Desktop/img.svg`
|
23
|
+
LONGDESC
|
24
|
+
def parse(in_path)
|
25
|
+
in_path = File.expand_path(in_path)
|
26
|
+
raise "#{in_path} is not readable" unless File.readable?(in_path)
|
27
|
+
svg_str = File.read(in_path)
|
28
|
+
|
29
|
+
out_path =
|
30
|
+
if options[:out_path].nil?
|
31
|
+
in_path.gsub(/\.svg\Z/i, '.ngc')
|
32
|
+
else
|
33
|
+
File.expand_path(options[:out_path])
|
34
|
+
end
|
35
|
+
|
36
|
+
opts = { comments: options[:comments] }
|
37
|
+
File.open(out_path, 'w') { |f| f << Svgcode.parse(svg_str, opts) }
|
38
|
+
|
39
|
+
puts "G-code written to #{out_path}"
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'post NGC_PATH [--url URL] [--post-name POST_NAME]',
|
43
|
+
'posts an GCode file to a server'
|
44
|
+
option :url, default: DEFAULT_POST_URL
|
45
|
+
option :post_name, default: DEFAULT_POST_NAME
|
46
|
+
long_desc <<-LONGDESC
|
47
|
+
`svgcode post ~/Desktop/img.ngc` will post the GCode file to
|
48
|
+
#{DEFAULT_POST_URL}.
|
49
|
+
|
50
|
+
Optionally set the --url flag to post the GCode file elsewhere
|
51
|
+
\x5 e.g. `svgcode post ~/Documents/img.ngc --url http://192.168.20.7:9999`
|
52
|
+
|
53
|
+
Optionally pass the --post-name flag to name the file field something other
|
54
|
+
than the default '#{DEFAULT_POST_NAME}'
|
55
|
+
\x5 e.g. `svgcode post --post-name svgfile`
|
56
|
+
LONGDESC
|
57
|
+
def post(ngc_path)
|
58
|
+
ngc_path = File.expand_path(ngc_path)
|
59
|
+
raise "#{ngc_path} is not readable" unless File.readable?(ngc_path)
|
60
|
+
|
61
|
+
uri = URI(options[:url])
|
62
|
+
request = Net::HTTP::Post.new(uri)
|
63
|
+
form_data = [[options[:post_name], File.open(ngc_path)]]
|
64
|
+
message = nil
|
65
|
+
|
66
|
+
request.set_form form_data, 'multipart/form-data'
|
67
|
+
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
68
|
+
http.request(request)
|
69
|
+
end
|
70
|
+
|
71
|
+
puts response
|
72
|
+
|
73
|
+
puts "G-code posted to #{options[:url]}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -123,6 +123,15 @@ module Svgcode
|
|
123
123
|
])
|
124
124
|
end
|
125
125
|
|
126
|
+
# X and Y are the endpoint, and I is the X offset of the centrepoint
|
127
|
+
def self.arc(x, y, i)
|
128
|
+
Command.new(:g, 2, [
|
129
|
+
Command.new(:x, x),
|
130
|
+
Command.new(:y, y),
|
131
|
+
Command.new(:i, i)
|
132
|
+
])
|
133
|
+
end
|
134
|
+
|
126
135
|
def self.clear(clearance)
|
127
136
|
Command.new(:g, 0, [
|
128
137
|
Command.new(:z, clearance)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'svgcode/gcode/program'
|
2
|
+
require 'svgcode/svg/circle'
|
2
3
|
require 'svgcode/svg/path'
|
3
4
|
|
4
5
|
module Svgcode
|
@@ -21,39 +22,15 @@ module Svgcode
|
|
21
22
|
@program.feedrate!
|
22
23
|
end
|
23
24
|
|
24
|
-
def <<(
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
cmd
|
32
|
-
|
33
|
-
if metric?
|
34
|
-
cmd.divide_points_by!(PX_PER_MM)
|
35
|
-
else
|
36
|
-
cmd.divide_points_by!(PX_PER_INCH)
|
37
|
-
end
|
38
|
-
|
39
|
-
if (cmd.name == :close || cmd.absolute?) && @program.relative?
|
40
|
-
@program.absolute!
|
41
|
-
elsif cmd.relative? && @program.absolute?
|
42
|
-
@program.relative!
|
43
|
-
end
|
44
|
-
|
45
|
-
case cmd.name
|
46
|
-
when :move
|
47
|
-
start = cmd.relative? ? cmd.absolute(@program.pos) : cmd
|
48
|
-
@program.go!(cmd.points.first.x, cmd.points.first.y)
|
49
|
-
when :line
|
50
|
-
@program.cut!(cmd.points.first.x, cmd.points.first.y)
|
51
|
-
when :cubic
|
52
|
-
cubic!(cmd)
|
53
|
-
when :close
|
54
|
-
@program.cut!(start.points.first.x, start.points.first.y)
|
55
|
-
start = nil
|
56
|
-
end
|
25
|
+
def <<(str_or_command)
|
26
|
+
@start = nil
|
27
|
+
|
28
|
+
if str_or_command.is_a?(String)
|
29
|
+
path = SVG::Path.new(str_or_command)
|
30
|
+
path.commands.each { |cmd| add_command(cmd)}
|
31
|
+
else
|
32
|
+
cmd = SVG::Circle.new(str_or_command)
|
33
|
+
add_command(cmd)
|
57
34
|
end
|
58
35
|
end
|
59
36
|
|
@@ -80,6 +57,39 @@ module Svgcode
|
|
80
57
|
|
81
58
|
private
|
82
59
|
|
60
|
+
def add_command(cmd)
|
61
|
+
cmd.apply_transforms!(@transforms)
|
62
|
+
cmd.absolute? ? cmd.flip_points_y!(@max_y) : cmd.negate_points_y!
|
63
|
+
|
64
|
+
if metric?
|
65
|
+
cmd.divide_points_by!(PX_PER_MM)
|
66
|
+
else
|
67
|
+
cmd.divide_points_by!(PX_PER_INCH)
|
68
|
+
end
|
69
|
+
|
70
|
+
if cmd.name == :close || cmd.absolute?
|
71
|
+
@program.absolute!
|
72
|
+
elsif cmd.relative?
|
73
|
+
@program.relative!
|
74
|
+
end
|
75
|
+
|
76
|
+
case cmd.name
|
77
|
+
when :move
|
78
|
+
@start = cmd.relative? ? cmd.absolute(@program.pos) : cmd
|
79
|
+
@program.go!(cmd.points.first.x, cmd.points.first.y)
|
80
|
+
when :line
|
81
|
+
@program.cut!(cmd.points.first.x, cmd.points.first.y)
|
82
|
+
when :cubic
|
83
|
+
cubic!(cmd)
|
84
|
+
when :circle
|
85
|
+
@program.go!(cmd.start_x, cmd.centre_y)
|
86
|
+
@program.arc!(cmd.start_x, cmd.centre_y, cmd.radius)
|
87
|
+
when :close
|
88
|
+
@program.cut!(@start.points.first.x, @start.points.first.y)
|
89
|
+
@start = nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
83
93
|
def cubic!(cmd)
|
84
94
|
# A relative SVG cubic bezier has all control points relative to start.
|
85
95
|
# G-code I&J are relative to start, and P&Q relative to end.
|
@@ -61,7 +61,7 @@ module Svgcode
|
|
61
61
|
|
62
62
|
def <<(command)
|
63
63
|
if !command.is_a?(String) &&
|
64
|
-
(@x.nil? || @y.nil?) &&
|
64
|
+
(@x.nil? || @y.nil?) &&
|
65
65
|
command.letter == 'G' &&
|
66
66
|
command.number < 6 &&
|
67
67
|
command != Command.relative &&
|
@@ -156,6 +156,10 @@ module Svgcode
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
+
def arc!(x, y, i)
|
160
|
+
self << Command.arc(x, y, i)
|
161
|
+
end
|
162
|
+
|
159
163
|
def pos
|
160
164
|
Svgcode::SVG::Point.new(@x, @y)
|
161
165
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'svgcode/svg/point'
|
2
|
+
|
3
|
+
module Svgcode
|
4
|
+
module SVG
|
5
|
+
class BaseCommand
|
6
|
+
attr_reader :name, :absolute, :points
|
7
|
+
|
8
|
+
NAMES = {
|
9
|
+
'm' => :move,
|
10
|
+
'l' => :line,
|
11
|
+
'c' => :cubic,
|
12
|
+
'z' => :close
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(opts)
|
16
|
+
@name = opts[:name]
|
17
|
+
@absolute = !!opts[:absolute]
|
18
|
+
@points = opts[:points] || []
|
19
|
+
end
|
20
|
+
|
21
|
+
def absolute?
|
22
|
+
@absolute
|
23
|
+
end
|
24
|
+
|
25
|
+
def relative?
|
26
|
+
!@absolute
|
27
|
+
end
|
28
|
+
|
29
|
+
def absolute(pos)
|
30
|
+
points = @points.collect { |p| p + pos }
|
31
|
+
Command.new(name: @name, absolute: true, points: points)
|
32
|
+
end
|
33
|
+
|
34
|
+
def absolute!(pos)
|
35
|
+
if relative?
|
36
|
+
@points.collect! { |p| p + pos }
|
37
|
+
@absolute = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def negate_points_y
|
42
|
+
points = @points.collect { |point| point.negate_y }
|
43
|
+
Command.new(name: @name, absolute: @absolute, points: points)
|
44
|
+
end
|
45
|
+
|
46
|
+
def negate_points_y!
|
47
|
+
@points.each { |point| point.negate_y! }
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def divide_points_by!(amount)
|
52
|
+
@points.each { |point| point.divide_by!(amount) }
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def flip_points_y!(max_y)
|
57
|
+
@points.each { |point| point.flip_y!(max_y) }
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def apply_transforms!(transforms)
|
62
|
+
unless transforms.empty?
|
63
|
+
transforms.reverse.each do |transform|
|
64
|
+
@points.collect! { |point| transform.apply(point) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def name_str
|
70
|
+
Command.name_str(@name, absolute?)
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(other)
|
74
|
+
other.is_a?(self.class) &&
|
75
|
+
other.name == @name &&
|
76
|
+
other.absolute? == @absolute &&
|
77
|
+
other.points == @points
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_s
|
81
|
+
name_str + @points.collect { |p| p.to_s }.join(' ')
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.name_str(sym, absolute)
|
85
|
+
str = NAMES.key(sym).dup
|
86
|
+
str.upcase! if absolute
|
87
|
+
str
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'svgcode/utility'
|
2
|
+
require 'svgcode/svg/base_command'
|
3
|
+
require 'svgcode/svg/point'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module Svgcode
|
7
|
+
module SVG
|
8
|
+
class Circle < BaseCommand
|
9
|
+
attr_reader :centre_x, :centre_y, :radius
|
10
|
+
|
11
|
+
def initialize(element_or_x, y = nil, r = nil)
|
12
|
+
@name = :circle
|
13
|
+
@absolute = true
|
14
|
+
|
15
|
+
if element_or_x.is_a?(Nokogiri::XML::Element)
|
16
|
+
@centre_x = Utility.x_to_f(element_or_x.attributes['cx'].value)
|
17
|
+
@centre_y = Utility.x_to_f(element_or_x.attributes['cy'].value)
|
18
|
+
@radius = Utility.x_to_f(element_or_x.attributes['r'].value)
|
19
|
+
else
|
20
|
+
@centre_x = Utility.x_to_f(element_or_x)
|
21
|
+
@centre_y = Utility.x_to_f(y)
|
22
|
+
@radius = Utility.x_to_f(r)
|
23
|
+
end
|
24
|
+
|
25
|
+
@points = [ Point.new(@centre_x, @centre_y) ]
|
26
|
+
end
|
27
|
+
|
28
|
+
def start_x
|
29
|
+
@centre_x - @radius
|
30
|
+
end
|
31
|
+
|
32
|
+
def apply_transforms!(transforms)
|
33
|
+
super(transforms)
|
34
|
+
|
35
|
+
transforms.reverse.each do |transform|
|
36
|
+
r_start = transform.apply(Point.new(start_x, 0))
|
37
|
+
r_end = transform.apply(Point.new(@centre_x, 0))
|
38
|
+
@centre_x = r_end.x
|
39
|
+
@radius = @centre_x - r_start.x
|
40
|
+
end
|
41
|
+
|
42
|
+
@centre_x = @points.first.x
|
43
|
+
@centre_y = @points.first.y
|
44
|
+
end
|
45
|
+
|
46
|
+
def divide_points_by!(amount)
|
47
|
+
super(amount)
|
48
|
+
@centre_x = @points.first.x
|
49
|
+
@centre_y = @points.first.y
|
50
|
+
@radius /= amount
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/svgcode/svg/path.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'svgcode/svg/
|
1
|
+
require 'svgcode/svg/path_command'
|
2
2
|
|
3
3
|
module Svgcode
|
4
4
|
module SVG
|
@@ -6,7 +6,7 @@ module Svgcode
|
|
6
6
|
attr_reader :commands
|
7
7
|
|
8
8
|
def initialize(str)
|
9
|
-
@commands = str.split(/(?=[a-z])/i).collect { |s|
|
9
|
+
@commands = str.split(/(?=[a-z])/i).collect { |s| PathCommand.new(s) }
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'svgcode/svg/point'
|
2
|
+
require 'svgcode/svg/base_command'
|
2
3
|
|
3
4
|
module Svgcode
|
4
5
|
module SVG
|
5
|
-
class
|
6
|
+
class PathCommand < BaseCommand
|
6
7
|
attr_reader :name, :absolute, :points
|
7
8
|
|
8
9
|
NAMES = {
|
@@ -46,7 +47,7 @@ module Svgcode
|
|
46
47
|
|
47
48
|
def absolute(pos)
|
48
49
|
points = @points.collect { |p| p + pos }
|
49
|
-
|
50
|
+
PathCommand.new(name: @name, absolute: true, points: points)
|
50
51
|
end
|
51
52
|
|
52
53
|
def absolute!(pos)
|
@@ -58,7 +59,7 @@ module Svgcode
|
|
58
59
|
|
59
60
|
def negate_points_y
|
60
61
|
points = @points.collect { |point| point.negate_y }
|
61
|
-
|
62
|
+
PathCommand.new(name: @name, absolute: @absolute, points: points)
|
62
63
|
end
|
63
64
|
|
64
65
|
def negate_points_y!
|
@@ -74,7 +75,7 @@ module Svgcode
|
|
74
75
|
def flip_points_y!(max_y)
|
75
76
|
@points.each { |point| point.flip_y!(max_y) }
|
76
77
|
nil
|
77
|
-
end
|
78
|
+
end
|
78
79
|
|
79
80
|
def apply_transforms!(transforms)
|
80
81
|
unless transforms.empty?
|
@@ -85,13 +86,13 @@ module Svgcode
|
|
85
86
|
end
|
86
87
|
|
87
88
|
def name_str
|
88
|
-
|
89
|
+
PathCommand.name_str(@name, absolute?)
|
89
90
|
end
|
90
91
|
|
91
92
|
def ==(other)
|
92
|
-
other.is_a?(self.class) &&
|
93
|
-
other.name == @name &&
|
94
|
-
other.absolute? == @absolute &&
|
93
|
+
other.is_a?(self.class) &&
|
94
|
+
other.name == @name &&
|
95
|
+
other.absolute? == @absolute &&
|
95
96
|
other.points == @points
|
96
97
|
end
|
97
98
|
|
data/lib/svgcode/svg/point.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'svgcode/utility'
|
2
|
+
|
1
3
|
module Svgcode
|
2
4
|
module SVG
|
3
5
|
class Point
|
@@ -9,11 +11,11 @@ module Svgcode
|
|
9
11
|
def initialize(str_or_x, y = nil)
|
10
12
|
if y.nil?
|
11
13
|
parts = str_or_x.split(VALUE_SEP)
|
12
|
-
@x =
|
13
|
-
@y =
|
14
|
+
@x = Utility.x_to_f(parts.first)
|
15
|
+
@y = Utility.x_to_f(parts.last)
|
14
16
|
else
|
15
|
-
@x = str_or_x
|
16
|
-
@y = y
|
17
|
+
@x = Utility.x_to_f(str_or_x)
|
18
|
+
@y = Utility.x_to_f(y)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -62,6 +64,12 @@ module Svgcode
|
|
62
64
|
@y /= amount
|
63
65
|
end
|
64
66
|
|
67
|
+
def flip_y(max_y)
|
68
|
+
p = Point.new(@x, @y)
|
69
|
+
p.flip_y!(max_y)
|
70
|
+
p
|
71
|
+
end
|
72
|
+
|
65
73
|
def flip_y!(max_y)
|
66
74
|
@y = max_y - @y
|
67
75
|
end
|
@@ -77,10 +85,6 @@ module Svgcode
|
|
77
85
|
def self.parse(str)
|
78
86
|
str.split(OBJECT_SEP).collect { |p| Point.new(p.strip) }
|
79
87
|
end
|
80
|
-
|
81
|
-
def self.str_to_f(str)
|
82
|
-
str.include?('e') ? "%f" % str : str.to_f
|
83
|
-
end
|
84
88
|
end
|
85
89
|
end
|
86
90
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'svgcode/utility'
|
1
2
|
require 'svgcode/svg/point'
|
2
3
|
require 'matrix'
|
3
4
|
|
@@ -14,26 +15,26 @@ module Svgcode
|
|
14
15
|
nums.each_with_index do |n, i|
|
15
16
|
case i
|
16
17
|
when 0
|
17
|
-
@a = n
|
18
|
+
@a = Svgcode::Utility.x_to_f(n)
|
18
19
|
when 1
|
19
|
-
@b = n
|
20
|
+
@b = Svgcode::Utility.x_to_f(n)
|
20
21
|
when 2
|
21
|
-
@c = n
|
22
|
+
@c = Svgcode::Utility.x_to_f(n)
|
22
23
|
when 3
|
23
|
-
@d = n
|
24
|
+
@d = Svgcode::Utility.x_to_f(n)
|
24
25
|
when 4
|
25
|
-
@e = n
|
26
|
+
@e = Svgcode::Utility.x_to_f(n)
|
26
27
|
when 5
|
27
|
-
@f = n
|
28
|
+
@f = Svgcode::Utility.x_to_f(n)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
else
|
31
|
-
@a = str_or_a
|
32
|
-
@b = b
|
33
|
-
@c = c
|
34
|
-
@d = d
|
35
|
-
@e = e
|
36
|
-
@f = f
|
32
|
+
@a = Svgcode::Utility.x_to_f(str_or_a)
|
33
|
+
@b = Svgcode::Utility.x_to_f(b)
|
34
|
+
@c = Svgcode::Utility.x_to_f(c)
|
35
|
+
@d = Svgcode::Utility.x_to_f(d)
|
36
|
+
@e = Svgcode::Utility.x_to_f(e)
|
37
|
+
@f = Svgcode::Utility.x_to_f(f)
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Svgcode
|
2
|
+
module Utility
|
3
|
+
SCI_SEP = /e/i
|
4
|
+
|
5
|
+
def self.x_to_f(x)
|
6
|
+
f =
|
7
|
+
if x.is_a?(Numeric)
|
8
|
+
x.to_f
|
9
|
+
elsif x.is_a?(String)
|
10
|
+
if x.match(SCI_SEP)
|
11
|
+
parts = x.split(SCI_SEP)
|
12
|
+
|
13
|
+
unless parts.length == 2
|
14
|
+
raise ArgumentError.new('x is an unknown number format')
|
15
|
+
end
|
16
|
+
|
17
|
+
parts.first.to_f * 10.0 ** parts.last.to_f
|
18
|
+
else
|
19
|
+
x.to_f
|
20
|
+
end
|
21
|
+
else
|
22
|
+
raise ArgumentError.new('x must be a Numeric or a String')
|
23
|
+
end
|
24
|
+
|
25
|
+
f
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/svgcode/version.rb
CHANGED
data/svgcode.gemspec
CHANGED
@@ -23,8 +23,11 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
24
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
|
26
27
|
spec.add_development_dependency 'byebug'
|
27
28
|
spec.add_development_dependency 'yard'
|
29
|
+
spec.add_development_dependency 'guard'
|
30
|
+
spec.add_development_dependency 'guard-shell'
|
28
31
|
|
29
32
|
spec.add_dependency 'nokogiri', '~> 1.8'
|
30
33
|
spec.add_dependency 'thor', '~> 0.20'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svgcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-shell
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: nokogiri
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +147,7 @@ files:
|
|
119
147
|
- ".gitignore"
|
120
148
|
- Gemfile
|
121
149
|
- Gemfile.lock
|
150
|
+
- Guardfile
|
122
151
|
- LICENSE.txt
|
123
152
|
- README.md
|
124
153
|
- README/linux-cnc-reverb.png
|
@@ -129,14 +158,18 @@ files:
|
|
129
158
|
- bin/setup
|
130
159
|
- bin/svgcode
|
131
160
|
- lib/svgcode.rb
|
161
|
+
- lib/svgcode/cli.rb
|
132
162
|
- lib/svgcode/gcode/command.rb
|
133
163
|
- lib/svgcode/gcode/converter.rb
|
134
164
|
- lib/svgcode/gcode/invalid_command_error.rb
|
135
165
|
- lib/svgcode/gcode/program.rb
|
136
|
-
- lib/svgcode/svg/
|
166
|
+
- lib/svgcode/svg/base_command.rb
|
167
|
+
- lib/svgcode/svg/circle.rb
|
137
168
|
- lib/svgcode/svg/path.rb
|
169
|
+
- lib/svgcode/svg/path_command.rb
|
138
170
|
- lib/svgcode/svg/point.rb
|
139
171
|
- lib/svgcode/svg/transform.rb
|
172
|
+
- lib/svgcode/utility.rb
|
140
173
|
- lib/svgcode/version.rb
|
141
174
|
- svgcode.gemspec
|
142
175
|
homepage: https://github.com/benjineering/svgcode
|