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