convert_svg_string_to_gcode 0.0.0 → 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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +93 -0
  5. data/config/console.rb +4 -0
  6. data/convert_svg_string_to_gcode-0.0.0.gem +0 -0
  7. data/convert_svg_string_to_gcode.gemspec +1 -1
  8. data/lib/convert_svg_string_to_gcode.rb +7 -7
  9. data/lib/convert_svg_string_to_gcode/constants/conversion_constants.rb +13 -6
  10. data/lib/convert_svg_string_to_gcode/constants/plotter_config.rb +10 -0
  11. data/lib/convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter.rb +64 -32
  12. data/lib/convert_svg_string_to_gcode/helpers/box_helper.rb +75 -0
  13. data/lib/convert_svg_string_to_gcode/helpers/create_commands_from_tokens.rb +34 -6
  14. data/lib/convert_svg_string_to_gcode/helpers/create_gcode_array_from_svg_commands.rb +24 -25
  15. data/lib/convert_svg_string_to_gcode/helpers/create_gcode_from_gcode_array.rb +2 -2
  16. data/lib/convert_svg_string_to_gcode/helpers/read_svg_to_string.rb +6 -0
  17. data/lib/convert_svg_string_to_gcode/models/box.rb +12 -0
  18. data/lib/convert_svg_string_to_gcode/models/svg_command.rb +64 -0
  19. data/script/console +3 -0
  20. data/script/test +3 -0
  21. data/spec/factory_helper.rb +29 -0
  22. data/spec/fixtures/spec_constants.rb +16 -0
  23. data/spec/fixtures/test.svg +4 -0
  24. data/spec/helpers.rb +36 -0
  25. data/spec/spec_helper.rb +36 -0
  26. data/spec/unit/adjust_svg_commands_for_plotter_spec.rb +24 -0
  27. data/spec/unit/convert_svg_string_to_gcode_spec.rb +13 -0
  28. data/spec/unit/create_commands_from_token_spec.rb +26 -0
  29. data/spec/unit/create_gcode_array_from_svg_commands_spec.rb +13 -0
  30. data/spec/unit/create_gcode_from_gcode_array_spec.rb +13 -0
  31. data/spec/unit/parse_svg_string_spec.rb +10 -0
  32. data/spec/unit/read_svg_to_string_spec.rb +11 -0
  33. data/spec/unit/tokenize_parsed_svg_spec.rb +11 -0
  34. metadata +26 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fffdd21de1f5a9589a8cdb8bae44a8d7f2c114fb
4
- data.tar.gz: d538bee8a59380ef1d77d2f78c2e778afd0dacf1
3
+ metadata.gz: 13748aa4d3d130df359a1289a74818dd293fa890
4
+ data.tar.gz: f9f2d073c74e4b99cbeed2a2ecd0aa23c87b41dd
5
5
  SHA512:
6
- metadata.gz: bbbacdf173ef099cb5df712d6f5aa1aa08a0af40c51b42511f9395dee176b651e962f5f93fd08b07a3946870f4d0c606cc34390b7f4427f13260ec96a93bb168
7
- data.tar.gz: e00bf27f2038323e47a4a488dd2a316aedf8df75e5cacc292e772c48ed4b59c08c09946981d8881061bc6de9344fd888db9c2b46ba43823631a9756ea3f408cb
6
+ metadata.gz: 9df4d2c3e7a31b7cfd1f6ed7ee08a1fd75d0f8378934f970d58677b61e3e962850f8b404e7fddd5df683cdcb78c15ac9480cc103f7b293faef35616c125b42d2
7
+ data.tar.gz: b8cf68ba6afbb465d94c5453a1e1c4b44262350899f7d50ed0fbeb43e1a297cd0edb8ad462a7c1aca6d3a55cf631684f4657edbf5b6d21220faa4c6e9b30ea0b
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'nokogiri', '~> 1.6.7'
6
+ gem 'pry'
7
+ gem 'pry-nav'
8
+ gem 'wirb'
9
+
10
+ group :test do
11
+ gem 'activerecord'
12
+ gem 'database_cleaner'
13
+ gem 'pg'
14
+ gem 'rspec'
15
+ gem 'webmock'
16
+ gem 'rack-test'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,93 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ convert_svg_string_to_gcode (0.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.2.6)
10
+ activesupport (= 4.2.6)
11
+ builder (~> 3.1)
12
+ activerecord (4.2.6)
13
+ activemodel (= 4.2.6)
14
+ activesupport (= 4.2.6)
15
+ arel (~> 6.0)
16
+ activesupport (4.2.6)
17
+ i18n (~> 0.7)
18
+ json (~> 1.7, >= 1.7.7)
19
+ minitest (~> 5.1)
20
+ thread_safe (~> 0.3, >= 0.3.4)
21
+ tzinfo (~> 1.1)
22
+ addressable (2.4.0)
23
+ arel (6.0.3)
24
+ builder (3.2.2)
25
+ coderay (1.1.1)
26
+ crack (0.4.3)
27
+ safe_yaml (~> 1.0.0)
28
+ database_cleaner (1.5.3)
29
+ diff-lcs (1.2.5)
30
+ hashdiff (0.3.0)
31
+ i18n (0.7.0)
32
+ json (1.8.3)
33
+ method_source (0.8.2)
34
+ mini_portile2 (2.0.0)
35
+ minitest (5.9.0)
36
+ nokogiri (1.6.7.1)
37
+ mini_portile2 (~> 2.0.0.rc2)
38
+ paint (1.0.1)
39
+ pg (0.18.4)
40
+ pry (0.10.3)
41
+ coderay (~> 1.1.0)
42
+ method_source (~> 0.8.1)
43
+ slop (~> 3.4)
44
+ pry-nav (0.2.4)
45
+ pry (>= 0.9.10, < 0.11.0)
46
+ rack (1.6.4)
47
+ rack-test (0.6.3)
48
+ rack (>= 1.0)
49
+ rake (10.5.0)
50
+ rspec (3.4.0)
51
+ rspec-core (~> 3.4.0)
52
+ rspec-expectations (~> 3.4.0)
53
+ rspec-mocks (~> 3.4.0)
54
+ rspec-core (3.4.4)
55
+ rspec-support (~> 3.4.0)
56
+ rspec-expectations (3.4.0)
57
+ diff-lcs (>= 1.2.0, < 2.0)
58
+ rspec-support (~> 3.4.0)
59
+ rspec-mocks (3.4.1)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.4.0)
62
+ rspec-support (3.4.1)
63
+ safe_yaml (1.0.4)
64
+ slop (3.6.0)
65
+ thread_safe (0.3.5)
66
+ tzinfo (1.2.2)
67
+ thread_safe (~> 0.1)
68
+ webmock (2.0.2)
69
+ addressable (>= 2.3.6)
70
+ crack (>= 0.3.2)
71
+ hashdiff
72
+ wirb (2.0.0)
73
+ paint (>= 0.9, < 2.0)
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ activerecord
80
+ convert_svg_string_to_gcode!
81
+ database_cleaner
82
+ nokogiri (~> 1.6.7)
83
+ pg
84
+ pry
85
+ pry-nav
86
+ rack-test
87
+ rake
88
+ rspec
89
+ webmock
90
+ wirb
91
+
92
+ BUNDLED WITH
93
+ 1.10.6
data/config/console.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'wirb'
2
+
3
+ Wirb.start
4
+ Dir['./lib/**/**/*.rb'].each {|file| require file}
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'convert_svg_string_to_gcode'
6
- s.version = '0.0.0'
6
+ s.version = '0.0.1'
7
7
  s.date = '2016-03-24'
8
8
  s.summary = "Converts SVG paths to GCode strings"
9
9
  s.description = "A gem that converts SVG paths (passed in as strings) into GCode strings"
@@ -1,9 +1,9 @@
1
- require 'convert_svg_string_to_gcode/parse_svg_string'
2
- require 'convert_svg_string_to_gcode/tokenize_parsed_svg'
3
- require 'convert_svg_string_to_gcode/create_commands_from_tokens'
4
- require 'convert_svg_string_to_gcode/adjust_svg_commands_for_plotter'
5
- require 'convert_svg_string_to_gcode/create_gcode_array_from_svg_commands'
6
- require 'convert_svg_string_to_gcode/create_gcode_from_gcode_array'
1
+ require 'convert_svg_string_to_gcode/helpers/parse_svg_string'
2
+ require 'convert_svg_string_to_gcode/helpers/tokenize_parsed_svg'
3
+ require 'convert_svg_string_to_gcode/helpers/create_commands_from_tokens'
4
+ require 'convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter'
5
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_array_from_svg_commands'
6
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_from_gcode_array'
7
7
 
8
8
  class ConvertSVGStringToGCode
9
9
 
@@ -11,7 +11,7 @@ class ConvertSVGStringToGCode
11
11
  parsed_svg = ParseSVGString.perform(svg_as_string)
12
12
  svg_tokens = TokenizeParsedSVG.perform(parsed_svg)
13
13
  svg_commands = CreateCommandsFromTokens.perform(svg_tokens)
14
- adjusted_svg_commands = AdjustSVGCommandsForPlotter.perform(svg_commands, 0.10)
14
+ adjusted_svg_commands = AdjustSVGCommandsForPlotter.perform(svg_commands, ConversionConstants::PROPORTION)
15
15
  gcode_array = CreateGCodeArrayFromSVGCommands.perform(adjusted_svg_commands)
16
16
  CreateGCodeFromGCodeArray.perform(gcode_array)
17
17
  end
@@ -1,9 +1,16 @@
1
1
 
2
2
  class ConversionConstants
3
- MOVE = 'M'
4
- LINE_TO = 'L'
5
- CURVE = 'C'
6
- X_LABELS = [:x,:cp0x,:cp1x,:p1x]
7
- Y_LABELS = [:y,:cp0y,:cp1y,:p1y]
8
- GCODE_COMMANDS = 'CLM'
3
+ MOVE = 'M'
4
+ LINE_TO = 'L'
5
+ CURVE = 'C'
6
+ X_LABELS = [:p0x,:p1x,:cp0x,:cp1x,:p0x,:p1x]
7
+ Y_LABELS = [:p0y,:p1y,:cp0y,:cp1y,:p0y,:p1y]
8
+ TYPE_LABEL = :type
9
+ VALID_CMD_ATTRIBUTES = X_LABELS + Y_LABELS << TYPE_LABEL
10
+ GCODE_COMMANDS = 'CLM'
11
+ PROPORTION = 0.7
12
+ STEP = 0.20
13
+
14
+ raise TypeError.new('Proportion must be a Float.') if PROPORTION.class != Float
15
+ raise TypeError.new('Step must be a Float.') if STEP.class != Float
9
16
  end
@@ -0,0 +1,10 @@
1
+ require 'convert_svg_string_to_gcode/constants/conversion_constants'
2
+
3
+ class PlotterConfig
4
+ ORIGIN_X = "X0.0"
5
+ ORIGIN_Y = "Y0.0"
6
+ Z_DOWN = "Z10.0"
7
+ Z_UP = "Z30.0"
8
+ HEADER = ["%", "G21", "G00 #{Z_UP}", "G00 X0.0 Y0.0"]
9
+ FOOTER = ["G00 #{ORIGIN_X} #{ORIGIN_Y} #{Z_UP}", "%"]
10
+ end
@@ -1,57 +1,89 @@
1
+ require 'convert_svg_string_to_gcode/models/svg_command'
2
+ require 'convert_svg_string_to_gcode/helpers/box_helper'
1
3
 
2
4
  class AdjustSVGCommandsForPlotter
3
- def self.perform(svg_commands,proportion=0.10)
4
- skewed_svg_commands, min_x, min_y = resize_svg_commands_by_proportion_and_get_min_x_y(svg_commands, proportion)
5
+ def self.perform(svg_commands,proportion=ConversionConstants::PROPORTION)
6
+ skewed_svg_commands = resize_svg_commands_by_proportion(svg_commands, proportion)
5
7
  min_x, min_y = get_min_x_y(skewed_svg_commands)
8
+ max_x, max_y = get_max_x_y(skewed_svg_commands)
6
9
  buffered_svg_commands = add_margin_to_svg_commands(skewed_svg_commands, min_x, min_y)
10
+ optimize_commands(buffered_svg_commands)
7
11
  end
8
12
 
9
- def self.resize_svg_commands_by_proportion_and_get_min_x_y(svg_commands, proportion)
10
- min_x = nil
11
- min_y = nil
12
- skewed_svg_commands = svg_commands.map do |command|
13
- mutated_command = {}
14
- command.each_key do |k|
15
- mutated_command[k] = Float(command[k])*proportion unless k==:command
16
- mutated_command[k] = command[k] if k==:command
17
- end
18
- mutated_command
13
+ def self.optimize_commands(svg_commands)
14
+ grouped_non_move_commands = group_commands_and_remove_moves(svg_commands)
15
+ ordered_svg_commands = sort_commands_ascending_by_x(grouped_non_move_commands)
16
+ sorted_svg_commands = BoxHelper.sort_commands_into_boxes(ordered_svg_commands)
17
+ add_moves_back_to_svg_commands(sorted_svg_commands)
18
+ end
19
+
20
+ def self.resize_svg_commands_by_proportion(svg_commands, proportion)
21
+ svg_commands.map do |command|
22
+ command.adjust_by_proportion(proportion)
19
23
  end
20
- return skewed_svg_commands, min_x, min_y
21
24
  end
22
25
 
23
26
  def self.get_min_x_y(svg_commands)
24
27
  min_x = nil
25
28
  min_y = nil
26
-
27
29
  svg_commands.map do |command|
28
- command.each_key do |key|
29
- if ConversionConstants::X_LABELS.include? key
30
- min_x = command[key] if !min_x || command[key]<min_x
31
- end
30
+ command_min_x = [command.p0x, command.p1x].min
31
+ min_x = command_min_x if !min_x || command_min_x<min_x || min_x == 0.0
32
32
 
33
- if ConversionConstants::Y_LABELS.include? key
34
- min_y = command[key] if !min_y || command[key]<min_y
35
- end
36
- end
33
+ command_min_y = [command.p0y, command.p1y].min
34
+ min_y = command_min_y if !min_y || command_min_y<min_y || min_y == 0.0
37
35
  end
38
36
  return min_x, min_y
39
37
  end
40
38
 
39
+ def self.get_max_x_y(svg_commands)
40
+ max_x = nil
41
+ max_y = nil
42
+
43
+ svg_commands.map do |command|
44
+ command_max_x = [command.p0x, command.p1x].max
45
+ max_x = command_max_x if !max_x || command_max_x>max_x || max_x == 0.0
46
+
47
+ command_max_y = [command.p0y, command.p1y].max
48
+ max_y = command_max_y if !max_y || command_max_y>max_y || max_y == 0.0
49
+ end
50
+ return max_x, max_y
51
+ end
52
+
41
53
  def self.add_margin_to_svg_commands(svg_commands, min_x, min_y, buffer=20.0)
54
+ x_margin = buffer-min_x
55
+ y_margin = buffer-min_y
56
+
42
57
  svg_commands.map do |command|
43
- buffered_command={}
44
- command.each_key do |k|
45
- if [:x,:cp0x,:cp1x,:p1x].include? k
46
- buffered_command[k] = command[k]-min_x+buffer
47
- elsif [:y,:cp0y,:cp1y,:p1y].include? k
48
- buffered_command[k] = command[k]-min_y+buffer
49
- else
50
- buffered_command[k] = command[k]
58
+ command.add_margins(x_margin, y_margin)
59
+ end
60
+ end
61
+
62
+ def self.sort_commands_ascending_by_x(svg_commands)
63
+ svg_commands.sort do |a,b|
64
+ a.first.p0x <=> b.first.p0x
65
+ end
66
+ end
67
+
68
+ def self.add_moves_back_to_svg_commands(svg_commands)
69
+ commands_with_moves = svg_commands.map do |boxes|
70
+ boxes.map do |commands|
71
+ move_to_command = SVGCommand.new(
72
+ type: ConversionConstants::MOVE,
73
+ p1x: commands.first.p0x,
74
+ p1y: commands.first.p0y
75
+ )
76
+ [move_to_command, commands.flatten]
51
77
  end
52
- end
53
- buffered_command
54
78
  end
79
+ commands_with_moves.flatten
80
+ end
81
+
82
+ def self.group_commands_and_remove_moves(svg_commands)
83
+ svg_commands
84
+ .chunk { |cmd| cmd.type == 'M' }
85
+ .reject { |enum| enum[0] }
86
+ .map { |enum| enum[1] }
55
87
  end
56
88
 
57
89
  end
@@ -0,0 +1,75 @@
1
+ require 'convert_svg_string_to_gcode/models/box'
2
+ require 'convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter'
3
+
4
+ class BoxHelper
5
+
6
+ def self.sort_commands_into_boxes(svg_commands, rows: 10, columns: 3)
7
+
8
+ boxes = create_write_boxes(svg_commands, rows, columns)
9
+ boxed_commands = boxes.map { |bc| [] }
10
+
11
+ box_order = []
12
+
13
+ boxes.each_slice(rows).with_index do |box_group, i|
14
+ if i.even?
15
+ box_order << box_group.map { |b| b.box_number }
16
+ else
17
+ box_order << box_group.reverse_each.map { |b| b.box_number }
18
+ end
19
+ end
20
+
21
+ box_order_index = {}
22
+
23
+ box_order.flatten.each.with_index do |order_number, i|
24
+ box_order_index[order_number] = i
25
+ end
26
+
27
+ svg_commands.each do |command|
28
+ box_order.flatten.each do |box_number|
29
+ next unless command_is_within_box?(command, boxes[box_number])
30
+ boxed_commands[box_order_index[box_number]] << command
31
+ end
32
+ end
33
+ boxed_commands
34
+ end
35
+
36
+ def self.command_is_within_box?(command, box)
37
+ command.first.p0x.between?(box.x_min, box.x_max) &&
38
+ command.first.p0y.between?(box.y_min, box.y_max)
39
+ end
40
+
41
+ def self.create_write_boxes(svg_commands, rows = 10, columns= 3)
42
+ x_max, y_max = AdjustSVGCommandsForPlotter.get_max_x_y(svg_commands.flatten)
43
+ x_step = x_max/columns
44
+ y_step = y_max/rows
45
+
46
+ x = 0
47
+ y = 0
48
+ boxes = []
49
+
50
+ columns.times do |c|
51
+ x_min = x
52
+ x_max = x+x_step
53
+ x = x+x_step
54
+
55
+ rows.times do |r|
56
+ y_min = y
57
+ y_max = y+y_step
58
+ y = y+y_step
59
+
60
+ boxes << Box.new(
61
+ box_number:rows*c+r,
62
+ x_min: x_min,
63
+ x_max: x_max,
64
+ y_min: y_min,
65
+ y_max: y_max
66
+ )
67
+ end
68
+ y=0
69
+ end
70
+ boxes
71
+ end
72
+
73
+ private_class_method :create_write_boxes
74
+
75
+ end
@@ -1,28 +1,56 @@
1
+ require 'convert_svg_string_to_gcode/models/svg_command'
1
2
 
2
3
  class CreateCommandsFromTokens
3
4
  def self.perform(svg_tokens)
5
+ last_command = SVGCommand.new(
6
+ type: ConversionConstants::MOVE,
7
+ p1x: 0.0,
8
+ p1y: 0.0,
9
+ p0x: 0.0,
10
+ p0y: 0.0,
11
+ p1x: 0.0,
12
+ p1y: 0.0
13
+ )
14
+
4
15
  svg_commands = svg_tokens.each_with_index.map do |token, i|
5
- svg_command=nil
16
+ svg_command = nil
17
+
6
18
  if token.match(%r{[#{ConversionConstants::GCODE_COMMANDS}]})
7
19
  case token
8
20
  when ConversionConstants::MOVE
9
- svg_command = {command: ConversionConstants::MOVE, x: svg_tokens[i+1], y: svg_tokens[i+2]}
21
+ svg_command = SVGCommand.new(
22
+ type: ConversionConstants::MOVE,
23
+ p0x: last_command.p1x,
24
+ p0y: last_command.p1y,
25
+ p1x: svg_tokens[i+1],
26
+ p1y: svg_tokens[i+2]
27
+ )
10
28
  when ConversionConstants::LINE_TO
11
- svg_command = {command: ConversionConstants::LINE_TO, x: svg_tokens[i+1], y: svg_tokens[i+2]}
29
+ svg_command = SVGCommand.new(
30
+ type: ConversionConstants::LINE_TO,
31
+ p0x: last_command.p1x,
32
+ p0y: last_command.p1y,
33
+ p1x: svg_tokens[i+1],
34
+ p1y: svg_tokens[i+2]
35
+ )
12
36
  when ConversionConstants::CURVE
13
- svg_command = {
14
- command: ConversionConstants::CURVE,
37
+ svg_command = SVGCommand.new(
38
+ type: ConversionConstants::CURVE,
39
+ p0x: last_command.p1x,
40
+ p0y: last_command.p1y,
15
41
  cp0x: svg_tokens[i+1],
16
42
  cp0y: svg_tokens[i+2],
17
43
  cp1x: svg_tokens[i+3],
18
44
  cp1y: svg_tokens[i+4],
19
45
  p1x: svg_tokens[i+5],
20
46
  p1y: svg_tokens[i+6]
21
- }
47
+ )
22
48
  end
23
49
  end
50
+ last_command = svg_command if svg_command
24
51
  svg_command
25
52
  end
26
53
  svg_commands.compact
27
54
  end
55
+
28
56
  end
@@ -1,48 +1,47 @@
1
-
1
+ require 'convert_svg_string_to_gcode/constants/plotter_config'
2
2
  class CreateGCodeArrayFromSVGCommands
3
3
  def self.perform(commands, options = {step: 0.20})
4
4
  start_point = nil
5
5
  step=options[:step]
6
6
 
7
7
  gcode_array = commands.map do |c|
8
- case c[:command]
8
+ case c.type
9
9
  when ConversionConstants::MOVE
10
- command_array, start_point = move_to_point(c)
10
+ move_to_point(c)
11
11
  when ConversionConstants::LINE_TO
12
- command_array, start_point = draw_to_point(c)
12
+ draw_to_point(c)
13
13
  when ConversionConstants::CURVE
14
- command_array, start_point = create_gcode_path_from_bezier(start_point, c,step)
14
+ create_gcode_path_from_bezier(c, step)
15
15
  else
16
16
  throw Error
17
17
  end
18
- command_array
19
18
  end
20
19
  end
21
20
 
22
21
  def self.move_to_point(new_point)
23
- x_value = new_point[:x].to_f
24
- y_value = new_point[:y].to_f
25
- command = ["G0 X#{x_value} Y#{y_value} #{MakeblockXYConfig::Z_UP}"]
26
- return command, new_point
22
+ x_value = new_point.p1x
23
+ y_value = new_point.p1y
24
+ command = ["G0 X#{x_value} Y#{y_value} #{PlotterConfig::Z_UP}"]
25
+ return command
27
26
  end
28
27
 
29
28
  def self.draw_to_point(new_point)
30
- x_value = new_point[:x].to_f
31
- y_value = new_point[:y].to_f
32
- command = ["G1 X#{x_value} Y#{y_value} #{MakeblockXYConfig::Z_DOWN}"]
33
- return command, new_point
29
+ x_value = new_point.p1x
30
+ y_value = new_point.p1y
31
+ command = ["G1 X#{x_value} Y#{y_value} #{PlotterConfig::Z_DOWN}"]
32
+ return command
34
33
  end
35
34
 
36
- def self.create_gcode_path_from_bezier(start_point, svg_command, step)
35
+ def self.create_gcode_path_from_bezier(svg_command, step)
37
36
 
38
- p0x = start_point[:x].to_f
39
- p0y = start_point[:y].to_f
40
- cp0x = svg_command[:cp0x].to_f
41
- cp0y = svg_command[:cp0y].to_f
42
- cp1x = svg_command[:cp1x].to_f
43
- cp1y = svg_command[:cp1y].to_f
44
- p1x = svg_command[:p1x].to_f
45
- p1y = svg_command[:p1y].to_f
37
+ p0x = svg_command.p0x
38
+ p0y = svg_command.p0y
39
+ cp0x = svg_command.cp0x
40
+ cp0y = svg_command.cp0y
41
+ cp1x = svg_command.cp1x
42
+ cp1y = svg_command.cp1y
43
+ p1x = svg_command.p1x
44
+ p1y = svg_command.p1y
46
45
 
47
46
  t = step
48
47
 
@@ -63,10 +62,10 @@ class CreateGCodeArrayFromSVGCommands
63
62
 
64
63
  new_point_x = ( (1 - t) * dx ) + (t * ex)
65
64
  new_point_y = ( (1 - t) * dy ) + (t * ey)
66
- gcode_array << "G1 X#{new_point_x} Y#{new_point_y} Z0"
65
+ gcode_array << "G1 X#{new_point_x} Y#{new_point_y} #{PlotterConfig::Z_DOWN}"
67
66
  t+=step
68
67
  end
69
- return gcode_array, {x: p1x, y: p1y}
68
+ return gcode_array
70
69
  end
71
70
 
72
71
  end
@@ -3,8 +3,8 @@ class CreateGCodeFromGCodeArray
3
3
  def self.perform(
4
4
  gcode_array,
5
5
  options = {
6
- header: MakeblockXYConfig::HEADER,
7
- footer: MakeblockXYConfig::FOOTER,
6
+ header: PlotterConfig::HEADER,
7
+ footer: PlotterConfig::FOOTER,
8
8
  }
9
9
  )
10
10
 
@@ -0,0 +1,6 @@
1
+
2
+ class ReadSVGToString
3
+ def self.perform(path_to_remote_file)
4
+ file = File.read(path_to_remote_file)
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ class Box
2
+ attr_accessor :box_number, :x_min, :x_max, :y_min, :y_max
3
+
4
+ def initialize(**params)
5
+ @box_number = params[:box_number]
6
+ @x_min = params[:x_min]
7
+ @x_max = params[:x_max]
8
+ @y_min = params[:y_min]
9
+ @y_max = params[:y_max]
10
+ end
11
+
12
+ end
@@ -0,0 +1,64 @@
1
+ class SVGCommand
2
+ attr_accessor :type
3
+ def initialize(**params)
4
+ @type = params[:type]
5
+ @points = params.each_with_object({}) do |(param, value), hsh|
6
+ unless ConversionConstants::VALID_CMD_ATTRIBUTES.include?(param)
7
+ raise TypeError.new('Point label not defined')
8
+ end
9
+ hsh[param] = Float(value) unless value == nil || param == ConversionConstants::TYPE_LABEL
10
+ end
11
+ end
12
+
13
+ def method_missing(name)
14
+ super unless ConversionConstants::VALID_CMD_ATTRIBUTES.include? name
15
+ value = @points[name]
16
+ return value
17
+ end
18
+
19
+ def adjust_by_proportion(proportion)
20
+ mutated_cp0x = self.cp0x*proportion if self.cp0x
21
+ mutated_cp0y = self.cp0y*proportion if self.cp0y
22
+ mutated_cp1x = self.cp1x*proportion if self.cp1x
23
+ mutated_cp1y = self.cp1y*proportion if self.cp1y
24
+ mutated_p0x = self.p0x*proportion if self.p0x
25
+ mutated_p0y = self.p0y*proportion if self.p0y
26
+ mutated_p1x = self.p1x*proportion if self.p1x
27
+ mutated_p1y = self.p1y*proportion if self.p1y
28
+
29
+ SVGCommand.new(
30
+ type: @type,
31
+ cp0x: mutated_cp0x,
32
+ cp0y: mutated_cp0y,
33
+ cp1x: mutated_cp1x,
34
+ cp1y: mutated_cp1y,
35
+ p0x: mutated_p0x,
36
+ p0y: mutated_p0y,
37
+ p1x: mutated_p1x,
38
+ p1y: mutated_p1y
39
+ )
40
+ end
41
+
42
+ def add_margins(x_margin, y_margin)
43
+ mutated_cp0x = self.cp0x+x_margin if self.cp0x
44
+ mutated_cp0y = self.cp0y+y_margin if self.cp0y
45
+ mutated_cp1x = self.cp1x+x_margin if self.cp1x
46
+ mutated_cp1y = self.cp1y+y_margin if self.cp1y
47
+ mutated_p0x = self.p0x+x_margin if self.p0x
48
+ mutated_p0y = self.p0y+y_margin if self.p0y
49
+ mutated_p1x = self.p1x+x_margin if self.p1x
50
+ mutated_p1y = self.p1y+y_margin if self.p1y
51
+
52
+ SVGCommand.new(
53
+ type: @type,
54
+ p0x: mutated_p0x,
55
+ p0y: mutated_p0y,
56
+ p1x: mutated_p1x,
57
+ p1y: mutated_p1y,
58
+ cp0x: mutated_cp0x,
59
+ cp0y: mutated_cp0y,
60
+ cp1x: mutated_cp1x,
61
+ cp1y: mutated_cp1y,
62
+ )
63
+ end
64
+ end
data/script/console ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash -e
2
+
3
+ bundle exec pry -r ./config/console
data/script/test ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash -e
2
+
3
+ RACK_ENV=test bundle exec rspec $@
@@ -0,0 +1,29 @@
1
+ require 'convert_svg_string_to_gcode/helpers/parse_svg_string'
2
+ require 'convert_svg_string_to_gcode/helpers/tokenize_parsed_svg'
3
+ require 'convert_svg_string_to_gcode/helpers/create_commands_from_tokens'
4
+ require 'convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter'
5
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_array_from_svg_commands'
6
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_from_gcode_array'
7
+ require 'fixtures/spec_constants'
8
+
9
+ class FactoryHelper
10
+ def self.parsed_svg
11
+ ParseSVGString.perform(SpecConstants::TEST_SVG_AS_STRING)
12
+ end
13
+
14
+ def self.svg_tokens
15
+ TokenizeParsedSVG.perform(parsed_svg)
16
+ end
17
+
18
+ def self.svg_commands
19
+ CreateCommandsFromTokens.perform(svg_tokens)
20
+ end
21
+
22
+ def self.adjusted_svg_commands
23
+ AdjustSVGCommandsForPlotter.perform(svg_commands, ConversionConstants::PROPORTION )
24
+ end
25
+
26
+ def self.gcode_array
27
+ CreateGCodeArrayFromSVGCommands.perform(adjusted_svg_commands)
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ require 'convert_svg_string_to_gcode/models/svg_command'
2
+ require 'convert_svg_string_to_gcode/constants/conversion_constants'
3
+
4
+ class SpecConstants
5
+ TEST_SVG_AS_STRING = "<?xml version=\"1.0\" standalone=\"yes\"?>\n<svg width=\"6375\" height=\"4781\">\n<path style=\"stroke:#020202; stroke-linecap: round; stroke-width:5;fill:none;\" d=\"M524 313C537.472 324.483 557.635 339.142 575 343.649\"/>\n</svg>\n"
6
+ TEST_SVG_TOKENS = [ConversionConstants::MOVE, "524", "313", "C", "537.472",
7
+ "324.483", "557.635", "339.142", "575", "343.649"]
8
+ TEST_SVG_COMMANDS = [SVGCommand.new(type:"M", p0x:0.0, p0y:0.0, p1x:"524", p1y:"313"),SVGCommand.new(type:"C", p0x: "524", p0y:"313", cp0x: "537.472", cp0y: "324.483", cp1x: "557.635", cp1y: "339.142", p1x:"575", p1y:"343.649")]
9
+ TEST_ADJUSTED_COMMANDS = [SVGCommand.new(type: "M", p1x: 20.0, p1y:20.0), SVGCommand.new(type:"C", p0x:20.0, p0y:20.0, cp0x:29.43040000000002, cp0y:28.038099999999986, cp1x:43.54450000000003, cp1y:38.29939999999999, p1x:55.700000000000045, p1y:41.45429999999999)]
10
+
11
+ TEST_GCODE_ARRAY = [["G0 X20.0 Y20.0 Z30.0"], ["G1 X26.167145600000012 Y25.015007199999996 Z10.0", "G1 X33.13954880000002 Y30.115761599999992 Z10.0", "G1 X40.59837920000004 Y34.85444239999999 Z10.0", "G1 X48.224806400000034 Y38.78322879999999 Z10.0"]]
12
+
13
+ EXPECTED_GCODE_TEST_SVG_OUTPUT = "%\nG21\nG00 Z30.0\nG00 X0.0 Y0.0\nG0 X20.0 Y20.0 Z30.0\nG1 X26.167145600000012 Y25.015007199999996 Z10.0\nG1 X33.13954880000002 Y30.115761599999992 Z10.0\nG1 X40.59837920000004 Y34.85444239999999 Z10.0\nG1 X48.224806400000034 Y38.78322879999999 Z10.0\nG00 X0.0 Y0.0 Z30.0\n%"
14
+
15
+ TEST_IMAGE_LOCATION = "https://res.cloudinary.com/trunk-club/image/upload/v1456519728/original_note.jpg"
16
+ end
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" standalone="yes"?>
2
+ <svg width="6375" height="4781">
3
+ <path style="stroke:#020202; stroke-linecap: round; stroke-width:5;fill:none;" d="M524 313C537.472 324.483 557.635 339.142 575 343.649"/>
4
+ </svg>
data/spec/helpers.rb ADDED
@@ -0,0 +1,36 @@
1
+ module Helpers
2
+
3
+ def now
4
+ Time.parse("2013-01-01T00:00:00Z")
5
+ end
6
+
7
+ def stubs_time
8
+ allow(Time).to receive(:now).and_return(now)
9
+ end
10
+
11
+ def client
12
+ api_client
13
+ end
14
+
15
+ def api_client
16
+ # Fail if the clients receive unexpected messages, stubbing is expected in specs
17
+ @client ||= double
18
+ end
19
+
20
+ def build_response(payload, status=200)
21
+ double(status: status, body: payload.to_json)
22
+ end
23
+
24
+ def service_fails_unexpectedly(http_verb, error_payload={message: "Oh snap!"})
25
+ allow(client).to receive(http_verb).and_return(build_response(error_payload, 500))
26
+ end
27
+
28
+ def last_json
29
+ last_response.body
30
+ end
31
+
32
+ def response_payload
33
+ JSON.parse(last_json)
34
+ end
35
+
36
+ end
@@ -0,0 +1,36 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'rspec'
4
+ require 'rack/test'
5
+ require 'database_cleaner'
6
+ require_relative 'helpers'
7
+ require 'fixtures/spec_constants'
8
+
9
+ RSpec.configure do |config|
10
+ config.include(Helpers)
11
+
12
+ # Raise errors for deprecated rspec syntax
13
+ config.raise_errors_for_deprecations!
14
+
15
+ # Colored tests are more _exciting_
16
+ config.color = true
17
+
18
+ # Set the order to random unless we pass it in from the command line
19
+ config.order = :rand unless ARGV.any? { |arg| %w(--order --seed).include?(arg) }
20
+
21
+ # Define DatabaseCleaner strategy
22
+ # -------------------------------------------
23
+ # config.before(:suite) do
24
+ # DatabaseCleaner[:active_record].strategy = :transaction
25
+ # DatabaseCleaner.clean_with(:truncation)
26
+ # end
27
+
28
+ # Wire up DatabaseCleaner before and after each example
29
+ # -------------------------------------------
30
+ # config.around(:each) do |example|
31
+ # DatabaseCleaner.cleaning do
32
+ # example.run
33
+ # end
34
+ # end
35
+
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter'
2
+ require 'spec_helper'
3
+ require 'factory_helper'
4
+
5
+ RSpec.describe AdjustSVGCommandsForPlotter do
6
+ let(:svg_commands) { FactoryHelper.svg_commands }
7
+ let(:spec_adjusted_commands) { SpecConstants::TEST_ADJUSTED_COMMANDS }
8
+
9
+ it 'adjusts SVG commands for the plotter' do
10
+ adjusted_svg_commands = AdjustSVGCommandsForPlotter.perform(svg_commands, ConversionConstants::PROPORTION)
11
+
12
+ expect(adjusted_svg_commands.first.p1x).to eq(spec_adjusted_commands.first.p1x)
13
+ expect(adjusted_svg_commands.first.p1y).to eq(spec_adjusted_commands.first.p1y)
14
+
15
+ expect(adjusted_svg_commands.second.cp0x).to eq(spec_adjusted_commands.second.cp0x)
16
+ expect(adjusted_svg_commands.second.cp0y).to eq(spec_adjusted_commands.second.cp0y)
17
+ expect(adjusted_svg_commands.second.cp1x).to eq(spec_adjusted_commands.second.cp1x)
18
+ expect(adjusted_svg_commands.second.cp1y).to eq(spec_adjusted_commands.second.cp1y)
19
+ expect(adjusted_svg_commands.second.p0x).to eq(spec_adjusted_commands.second.p0x)
20
+ expect(adjusted_svg_commands.second.p0y).to eq(spec_adjusted_commands.second.p0y)
21
+ expect(adjusted_svg_commands.second.p1x).to eq(spec_adjusted_commands.second.p1x)
22
+ expect(adjusted_svg_commands.second.p1y).to eq(spec_adjusted_commands.second.p1y)
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'convert_svg_string_to_gcode'
3
+ require 'convert_svg_string_to_gcode/helpers/parse_svg_string'
4
+ require 'convert_svg_string_to_gcode/helpers/tokenize_parsed_svg'
5
+
6
+ RSpec.describe ConvertSVGStringToGCode do
7
+ let(:svg_as_string) { SpecConstants::TEST_SVG_AS_STRING }
8
+
9
+ it 'converts SVG string into G-Code' do
10
+ gcode = ConvertSVGStringToGCode.perform(svg_as_string)
11
+ expect(gcode).to eq(SpecConstants::EXPECTED_GCODE_TEST_SVG_OUTPUT)
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'convert_svg_string_to_gcode/helpers/create_commands_from_tokens'
4
+ require 'factory_helper'
5
+
6
+ RSpec.describe CreateCommandsFromTokens do
7
+ let(:svg_tokens) { SpecConstants::TEST_SVG_TOKENS }
8
+ let(:spec_commands) { SpecConstants::TEST_SVG_COMMANDS }
9
+
10
+ it 'creates command array from tokens' do
11
+ commands = CreateCommandsFromTokens.perform(svg_tokens)
12
+
13
+ expect(spec_commands.first.p1x).to eq(spec_commands.first.p1x)
14
+ expect(spec_commands.first.p1y).to eq(spec_commands.first.p1y)
15
+
16
+ expect(spec_commands.second.cp0x).to eq(spec_commands.second.cp0x)
17
+ expect(spec_commands.second.cp0y).to eq(spec_commands.second.cp0y)
18
+ expect(spec_commands.second.cp1x).to eq(spec_commands.second.cp1x)
19
+ expect(spec_commands.second.cp1y).to eq(spec_commands.second.cp1y)
20
+ expect(spec_commands.second.p0x).to eq(spec_commands.second.p0x)
21
+ expect(spec_commands.second.p0y).to eq(spec_commands.second.p0y)
22
+ expect(spec_commands.second.p1x).to eq(spec_commands.second.p1x)
23
+ expect(spec_commands.second.p1y).to eq(spec_commands.second.p1y)
24
+ end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_array_from_svg_commands'
2
+ require 'spec_helper'
3
+ require 'factory_helper'
4
+
5
+ RSpec.describe CreateGCodeArrayFromSVGCommands do
6
+ let(:adjusted_svg_commands) { FactoryHelper.adjusted_svg_commands }
7
+
8
+ it 'creates a G-Code array from SVG commands' do
9
+ gcode_array = CreateGCodeArrayFromSVGCommands.perform(adjusted_svg_commands)
10
+ expect(gcode_array).to eq(SpecConstants::TEST_GCODE_ARRAY)
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'factory_helper'
3
+ require 'convert_svg_string_to_gcode/helpers/create_gcode_from_gcode_array'
4
+
5
+
6
+ RSpec.describe CreateGCodeFromGCodeArray do
7
+ let(:gcode_array) { FactoryHelper.gcode_array }
8
+
9
+ it 'converts G-Code Array to G-Code' do
10
+ gcode = CreateGCodeFromGCodeArray.perform(gcode_array)
11
+ expect(gcode).to eq(SpecConstants::EXPECTED_GCODE_TEST_SVG_OUTPUT)
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ require 'convert_svg_string_to_gcode/helpers/parse_svg_string'
2
+
3
+ RSpec.describe ParseSVGString do
4
+
5
+ it 'parses svg string' do
6
+ svg_as_string = SpecConstants::TEST_SVG_AS_STRING
7
+ parsed_svg = ParseSVGString.perform(svg_as_string)
8
+ end
9
+
10
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'convert_svg_string_to_gcode/helpers/read_svg_to_string'
3
+
4
+ RSpec.describe ReadSVGToString do
5
+ let(:svg_file) { File.open('spec/fixtures/test.svg') }
6
+
7
+ it 'reads in an SVG file and outputs a string' do
8
+ svg_as_string = ReadSVGToString.perform(svg_file)
9
+ expect(svg_as_string).to eq(SpecConstants::TEST_SVG_AS_STRING)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'convert_svg_string_to_gcode/helpers/tokenize_parsed_svg'
2
+ require 'factory_helper'
3
+
4
+ RSpec.describe TokenizeParsedSVG do
5
+ let(:parsed_svg) { FactoryHelper.parsed_svg }
6
+
7
+ it 'takes a parsed SVG and returns tokens' do
8
+ svg_tokens = TokenizeParsedSVG.perform(parsed_svg)
9
+ expect(svg_tokens).to eq(SpecConstants::TEST_SVG_TOKENS)
10
+ end
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convert_svg_string_to_gcode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Furmanek
@@ -16,15 +16,40 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".gitignore"
20
+ - Gemfile
21
+ - Gemfile.lock
22
+ - config/console.rb
23
+ - convert_svg_string_to_gcode-0.0.0.gem
19
24
  - convert_svg_string_to_gcode.gemspec
20
25
  - lib/convert_svg_string_to_gcode.rb
21
26
  - lib/convert_svg_string_to_gcode/constants/conversion_constants.rb
27
+ - lib/convert_svg_string_to_gcode/constants/plotter_config.rb
22
28
  - lib/convert_svg_string_to_gcode/helpers/adjust_svg_commands_for_plotter.rb
29
+ - lib/convert_svg_string_to_gcode/helpers/box_helper.rb
23
30
  - lib/convert_svg_string_to_gcode/helpers/create_commands_from_tokens.rb
24
31
  - lib/convert_svg_string_to_gcode/helpers/create_gcode_array_from_svg_commands.rb
25
32
  - lib/convert_svg_string_to_gcode/helpers/create_gcode_from_gcode_array.rb
26
33
  - lib/convert_svg_string_to_gcode/helpers/parse_svg_string.rb
34
+ - lib/convert_svg_string_to_gcode/helpers/read_svg_to_string.rb
27
35
  - lib/convert_svg_string_to_gcode/helpers/tokenize_parsed_svg.rb
36
+ - lib/convert_svg_string_to_gcode/models/box.rb
37
+ - lib/convert_svg_string_to_gcode/models/svg_command.rb
38
+ - script/console
39
+ - script/test
40
+ - spec/factory_helper.rb
41
+ - spec/fixtures/spec_constants.rb
42
+ - spec/fixtures/test.svg
43
+ - spec/helpers.rb
44
+ - spec/spec_helper.rb
45
+ - spec/unit/adjust_svg_commands_for_plotter_spec.rb
46
+ - spec/unit/convert_svg_string_to_gcode_spec.rb
47
+ - spec/unit/create_commands_from_token_spec.rb
48
+ - spec/unit/create_gcode_array_from_svg_commands_spec.rb
49
+ - spec/unit/create_gcode_from_gcode_array_spec.rb
50
+ - spec/unit/parse_svg_string_spec.rb
51
+ - spec/unit/read_svg_to_string_spec.rb
52
+ - spec/unit/tokenize_parsed_svg_spec.rb
28
53
  homepage: http://rubygems.org/gems/svg_path_to_gcode
29
54
  licenses:
30
55
  - MIT