laser-cutter 1.0.3 → 2.0.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.
Files changed (102) hide show
  1. checksums.yaml +5 -5
  2. data/.envrc +2 -0
  3. data/.github/workflows/lint.yml +22 -0
  4. data/.github/workflows/rspec.yml +22 -0
  5. data/.gitignore +5 -4
  6. data/.plans/001.00-dry-cli-migration/plan.md +29 -0
  7. data/.relaxed_rubocop.yml +153 -0
  8. data/.rspec +1 -1
  9. data/.rubocop.yml +31 -0
  10. data/.rubocop_todo.yml +90 -0
  11. data/.ruby-version +1 -0
  12. data/CLAUDE.md +62 -0
  13. data/CONTRIBUTING.md +2 -4
  14. data/Gemfile +14 -0
  15. data/README.md +83 -111
  16. data/Rakefile +41 -0
  17. data/docs/badges/coverage_badge.svg +21 -0
  18. data/exe/laser-cutter +8 -0
  19. data/exe/lc +1 -0
  20. data/justfile +97 -0
  21. data/laser-cutter.gemspec +26 -14
  22. data/lib/laser/cutter/aggregator.rb +101 -0
  23. data/lib/{laser-cutter → laser/cutter}/box.rb +44 -52
  24. data/lib/laser/cutter/cli/command.rb +46 -0
  25. data/lib/laser/cutter/cli/completion.rb +21 -0
  26. data/lib/laser/cutter/cli/config_file.rb +36 -0
  27. data/lib/laser/cutter/cli/examples.rb +42 -0
  28. data/lib/laser/cutter/cli/generate.rb +90 -0
  29. data/lib/laser/cutter/cli/help.rb +20 -0
  30. data/lib/laser/cutter/cli/page_sizes.rb +19 -0
  31. data/lib/laser/cutter/cli/version.rb +15 -0
  32. data/lib/laser/cutter/cli.rb +49 -0
  33. data/lib/laser/cutter/configuration.rb +101 -0
  34. data/lib/{laser-cutter → laser/cutter}/geometry/dimensions.rb +2 -3
  35. data/lib/{laser-cutter/geometry/shape → laser/cutter/geometry}/line.rb +19 -18
  36. data/lib/{laser-cutter → laser/cutter}/geometry/point.rb +4 -2
  37. data/lib/{laser-cutter/geometry/shape → laser/cutter/geometry}/rect.rb +6 -7
  38. data/lib/{laser-cutter → laser/cutter}/geometry/shape.rb +7 -7
  39. data/lib/{laser-cutter → laser/cutter}/geometry/tuple.rb +40 -36
  40. data/lib/laser/cutter/launcher.rb +40 -0
  41. data/lib/laser/cutter/missing_option.rb +7 -0
  42. data/lib/laser/cutter/notching/base.rb +19 -0
  43. data/lib/{laser-cutter → laser/cutter}/notching/edge.rb +21 -20
  44. data/lib/laser/cutter/notching/infinite_iterator.rb +27 -0
  45. data/lib/{laser-cutter → laser/cutter}/notching/path_generator.rb +27 -60
  46. data/lib/laser/cutter/notching/shift.rb +17 -0
  47. data/lib/laser/cutter/page_manager.rb +50 -0
  48. data/lib/{laser-cutter → laser/cutter}/renderer/base.rb +3 -2
  49. data/lib/laser/cutter/renderer/box_renderer.rb +40 -0
  50. data/lib/laser/cutter/renderer/layout_renderer.rb +61 -0
  51. data/lib/laser/cutter/renderer/line_renderer.rb +21 -0
  52. data/lib/laser/cutter/renderer/meta_renderer.rb +83 -0
  53. data/lib/{laser-cutter → laser/cutter}/renderer/rect_renderer.rb +3 -1
  54. data/lib/laser/cutter/renderer/svg_renderer.rb +65 -0
  55. data/lib/laser/cutter/renderer.rb +24 -0
  56. data/lib/laser/cutter/units_converter.rb +15 -0
  57. data/lib/laser/cutter/version.rb +7 -0
  58. data/lib/laser/cutter/zero_value_not_allowed.rb +7 -0
  59. data/lib/laser/cutter.rb +29 -0
  60. data/lib/laser-cutter.rb +2 -14
  61. data/lib/laser_cutter.rb +3 -0
  62. data/spec/laser/cutter/aggregator_spec.rb +70 -0
  63. data/spec/laser/cutter/box_spec.rb +61 -0
  64. data/spec/laser/cutter/cli/config_file_spec.rb +31 -0
  65. data/spec/laser/cutter/cli_spec.rb +186 -0
  66. data/spec/laser/cutter/configuration_spec.rb +101 -0
  67. data/spec/{dimensions_spec.rb → laser/cutter/dimensions_spec.rb} +8 -6
  68. data/spec/laser/cutter/edge_spec.rb +64 -0
  69. data/spec/{line_spec.rb → laser/cutter/line_spec.rb} +26 -20
  70. data/spec/{page_manager_spec.rb → laser/cutter/page_manager_spec.rb} +27 -11
  71. data/spec/{path_generator_spec.rb → laser/cutter/path_generator_spec.rb} +18 -14
  72. data/spec/{point_spec.rb → laser/cutter/point_spec.rb} +27 -22
  73. data/spec/{rect_spec.rb → laser/cutter/rect_spec.rb} +9 -5
  74. data/spec/laser/cutter/renderer/layout_renderer_spec.rb +102 -0
  75. data/spec/laser/cutter/renderer/svg_renderer_spec.rb +51 -0
  76. data/spec/laser/cutter/renderer_spec.rb +19 -0
  77. data/spec/spec_helper.rb +34 -25
  78. data/spec/support/aruba.rb +10 -0
  79. metadata +206 -80
  80. data/.travis.yml +0 -11
  81. data/LICENSE +0 -22
  82. data/bin/laser-cutter +0 -19
  83. data/lib/laser-cutter/aggregator.rb +0 -57
  84. data/lib/laser-cutter/cli/opt_parser.rb +0 -131
  85. data/lib/laser-cutter/cli/serializer.rb +0 -51
  86. data/lib/laser-cutter/configuration.rb +0 -83
  87. data/lib/laser-cutter/geometry.rb +0 -11
  88. data/lib/laser-cutter/notching/base.rb +0 -13
  89. data/lib/laser-cutter/notching.rb +0 -10
  90. data/lib/laser-cutter/page_manager.rb +0 -43
  91. data/lib/laser-cutter/renderer/box_renderer.rb +0 -36
  92. data/lib/laser-cutter/renderer/layout_renderer.rb +0 -59
  93. data/lib/laser-cutter/renderer/line_renderer.rb +0 -17
  94. data/lib/laser-cutter/renderer/meta_renderer.rb +0 -77
  95. data/lib/laser-cutter/renderer.rb +0 -14
  96. data/lib/laser-cutter/version.rb +0 -5
  97. data/spec/aggregator_spec.rb +0 -65
  98. data/spec/box_spec.rb +0 -40
  99. data/spec/configuration_spec.rb +0 -81
  100. data/spec/edge_spec.rb +0 -43
  101. data/spec/renderer_spec.rb +0 -72
  102. /data/{doc → docs/images}/comparison.jpg +0 -0
@@ -1,51 +0,0 @@
1
- require 'json'
2
- require 'laser-cutter'
3
-
4
- module Laser
5
- module Cutter
6
- module CLI
7
- class Serializer
8
- attr_accessor :options
9
- def initialize(options = {})
10
- self.options = options
11
- end
12
-
13
- def deserialize
14
- string = if options.read_file.eql?('-')
15
- $stdin.read
16
- elsif File.exist?(options.read_file)
17
- File.read(options.read_file)
18
- end
19
- if string
20
- options.replace(JSON.load(string))
21
- end
22
- rescue Exception => e
23
- STDERR.puts "Error reading options from file #{options.read_file}, #{e.message}".red
24
- if options.verbose
25
- STDERR.puts e.backtrace.join("\n").red
26
- end
27
- exit 1
28
- end
29
-
30
- def serialize
31
- output = if options.write_file.eql?('-')
32
- $stdout
33
- elsif options.write_file
34
- File.open(options.write_file, 'w')
35
- else
36
- nil
37
- end
38
- output.puts(JSON.pretty_generate(options))
39
- output.close if output != $stdout
40
- rescue Exception => e
41
- STDERR.puts "Error writing options to file #{options.write_file}, #{e.message}".red
42
- if options.verbose
43
- STDERR.puts e.backtrace.join("\n").red
44
- end
45
- exit 1
46
- end
47
- end
48
- end
49
- end
50
- end
51
-
@@ -1,83 +0,0 @@
1
- require 'hashie/mash'
2
- require 'prawn/measurement_extensions'
3
- require 'pdf/core/page_geometry'
4
-
5
- module Laser
6
- module Cutter
7
- class MissingOption < RuntimeError; end
8
- class ZeroValueNotAllowed < MissingOption; end
9
-
10
- class UnitsConverter
11
- def self.mm2in value
12
- 0.039370079 * value
13
- end
14
- def self.in2mm value
15
- 25.4 * value
16
- end
17
- end
18
-
19
- class Configuration < Hashie::Mash
20
- DEFAULTS = {
21
- units: 'in',
22
- page_layout: 'portrait',
23
- metadata: true
24
- }
25
-
26
- UNIT_SPECIFIC_DEFAULTS = {
27
- 'in' => {
28
- kerf: 0.0024, # smallest kerf for thin material, usually it's more than that.
29
- margin: 0.125,
30
- padding: 0.1,
31
- stroke: 0.001,
32
- }
33
- }
34
-
35
- UNIT_SPECIFIC_DEFAULTS['mm'] = UNIT_SPECIFIC_DEFAULTS['in'].map{|k, v| [k, UnitsConverter.in2mm(v)] }.to_h
36
-
37
- SIZE_REGEXP = /[\d\.]+x[\d\.]+x[\d\.]+\/[\d\.]+(\/[\d\.]+)?/
38
-
39
- FLOATS = %w(width height depth thickness notch margin padding stroke kerf)
40
- NON_ZERO = %w(width height depth thickness stroke)
41
- REQUIRED = %w(width height depth thickness notch file)
42
-
43
- def initialize(options = {})
44
- options.delete_if { |k, v| v.nil? }
45
- if options['units'] && !UNIT_SPECIFIC_DEFAULTS.keys.include?(options['units'])
46
- options.delete('units')
47
- end
48
- self.merge!(DEFAULTS)
49
- self.merge!(options)
50
- if self['size'] && self['size'] =~ SIZE_REGEXP
51
- dim, self['thickness'], self['notch'] = self['size'].split('/')
52
- self['width'], self['height'], self['depth'] = dim.split('x')
53
- delete('size')
54
- end
55
- FLOATS.each do |k|
56
- self[k] = self[k].to_f if (self[k] && self[k].is_a?(String))
57
- end
58
- self.merge!(UNIT_SPECIFIC_DEFAULTS[self['units']].merge(self))
59
- self['notch'] = (self['thickness'] * 3.0).round(5) if self['thickness'] && self['notch'].nil?
60
- end
61
-
62
- def validate!
63
- missing = []
64
- REQUIRED.each { |k| missing << k if self[k].nil? }
65
- raise MissingOption.new("#{missing.join(', ')} #{missing.size > 1 ? 'are' : 'is'} required, but missing.") unless missing.empty?
66
-
67
- zeros = []
68
- NON_ZERO.each { |k| zeros << k if self[k] == 0 }
69
- raise ZeroValueNotAllowed.new("#{zeros.join(', ')} #{zeros.size > 1 ? 'are' : 'is'} required, but is zero.") unless zeros.empty?
70
- end
71
-
72
- def change_units(new_units)
73
- return if (self.units.eql?(new_units) || !UNIT_SPECIFIC_DEFAULTS.keys.include?(new_units))
74
- k = (self.units == 'in') ? UnitsConverter.in2mm(1.0) : UnitsConverter.mm2in(1.0)
75
- FLOATS.each do |field|
76
- next if self.send(field.to_sym).nil?
77
- self.send("#{field}=".to_sym, (self.send(field.to_sym) * k).round(5))
78
- end
79
- self.units = new_units
80
- end
81
- end
82
- end
83
- end
@@ -1,11 +0,0 @@
1
- module Laser
2
- module Cutter
3
- module Geometry
4
- end
5
- end
6
- end
7
-
8
- require 'laser-cutter/geometry/tuple'
9
- require 'laser-cutter/geometry/dimensions'
10
- require 'laser-cutter/geometry/point'
11
- require 'laser-cutter/geometry/shape'
@@ -1,13 +0,0 @@
1
- module Laser::Cutter::Notching
2
- class Base
3
- attr_accessor :edge
4
-
5
- def initialize(edge)
6
- @edge = edge
7
- end
8
-
9
- def notches
10
- raise 'Abstract method'
11
- end
12
- end
13
- end
@@ -1,10 +0,0 @@
1
- module Laser
2
- module Cutter
3
- module Notching
4
- end
5
- end
6
- end
7
-
8
- require_relative 'notching/base'
9
- require_relative 'notching/edge'
10
- require_relative 'notching/path_generator'
@@ -1,43 +0,0 @@
1
- require 'hashie/mash'
2
- require 'prawn/measurement_extensions'
3
- require 'pdf/core/page_geometry'
4
-
5
- class Laser::Cutter::PageManager < Struct.new(:units)
6
- SIZES = PDF::Core::PageGeometry::SIZES.clone.freeze
7
-
8
- def all_page_sizes
9
- output = ""
10
- page_size_values.each do |k|
11
- output << sprintf("\t%10s:\t%6.1f x %6.1f\n", *k)
12
- end
13
- output
14
- end
15
-
16
- # if from_units is nil, we expect it to be in dots per inch (default
17
- # measurements for Prawn
18
- def value_from_units value, from_units = nil
19
- multiplier = if from_units.nil?
20
- if units.eql?('in')
21
- 1.0 / 72.0 # PDF units per inch
22
- else
23
- 25.4 * 1.0 / 72.0
24
- end
25
- elsif self.units.eql?(from_units)
26
- 1.0
27
- elsif self.units.eql?('in') && from_units.eql?('mm')
28
- (1.0 / 25.4)
29
- else
30
- 25.4
31
- end
32
- value.to_f * multiplier
33
- end
34
-
35
- def page_size_values
36
- h = SIZES
37
- array = []
38
- h.keys.sort.each do |k|
39
- array << [k, value_from_units(h[k][0].to_f), value_from_units(h[k][1].to_f)]
40
- end
41
- array
42
- end
43
- end
@@ -1,36 +0,0 @@
1
- # encoding: utf-8
2
- require 'json'
3
- module Laser
4
- module Cutter
5
- module Renderer
6
- class BoxRenderer < Base
7
- alias_method :box, :subject
8
-
9
- def initialize(config)
10
- super(config)
11
- self.subject = Laser::Cutter::Box.new(config)
12
- end
13
-
14
- def ensure_space_for(rect)
15
- coords = [ rect.p2.x, rect.p2.y ].map{|a| page_manager.value_from_units(a)}
16
- box.metadata = Geometry::Point.new(coords)
17
- end
18
-
19
- def enclosure
20
- box.enclosure
21
- end
22
-
23
- def render pdf = nil
24
- renderer = self
25
- pdf.instance_eval do
26
- self.line_width = renderer.config.stroke.send(renderer.config.units.to_sym)
27
- stroke_color renderer.config[:color] || BLACK
28
- renderer.box.generate_notches.each do |notch|
29
- LineRenderer.new(renderer.config, notch).render(self)
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
- require 'json'
3
- module Laser
4
- module Cutter
5
- module Renderer
6
- class LayoutRenderer < Base
7
- def initialize(config)
8
- self.config = config
9
- super(config)
10
- end
11
-
12
- def render
13
- renderer = self
14
- renderers = []
15
-
16
- box_renderer = BoxRenderer.new(config)
17
- renderers << box_renderer
18
-
19
- if config.metadata
20
- meta_renderer = MetaRenderer.new(config)
21
- renderers << meta_renderer
22
- box_renderer.ensure_space_for(meta_renderer.enclosure)
23
- end
24
-
25
- if config.debug
26
- unkerfed_config = Laser::Cutter::Configuration.new(config.to_hash)
27
- unkerfed_config.merge!(kerf: 0.0, color: 'DD2211')
28
- unkerfed_box_renderer = BoxRenderer.new(unkerfed_config)
29
- unkerfed_box_renderer.ensure_space_for(meta_renderer.enclosure) if meta_renderer
30
- renderers << unkerfed_box_renderer
31
- end
32
-
33
- margin = config.margin.to_f.send(config.units.to_sym)
34
- page_size = config.page_size || calculate_image_boundary(box_renderer, margin)
35
-
36
- pdf = Prawn::Document.new(:margin => margin,
37
- :page_size => page_size,
38
- :page_layout => self.config.page_layout.to_sym)
39
-
40
- pdf.instance_eval do
41
- renderers.each {|r| r.render(self) }
42
- render_file(renderer.config.file)
43
- end
44
-
45
- if config.verbose
46
- puts "PDF saved to #{config.file}."
47
- end
48
- end
49
-
50
- def calculate_image_boundary(box_renderer, margin)
51
- box_renderer.enclosure.to_a[1].map do |c|
52
- c.send(config.units.to_sym) + 2 * margin
53
- end
54
- end
55
-
56
- end
57
- end
58
- end
59
- end
@@ -1,17 +0,0 @@
1
- module Laser
2
- module Cutter
3
- module Renderer
4
- class LineRenderer < Base
5
- alias_method :line, :subject
6
- def render pdf = nil
7
- pdf.stroke { pdf.line [line.p1.x, line.p1.y].map{ |p| p.send(units) },
8
- [line.p2.x, line.p2.y].map{ |p| p.send(units) }}
9
- end
10
-
11
- def enclosure
12
- self.line
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,77 +0,0 @@
1
- # encoding: utf-8
2
- class Laser::Cutter::Renderer::MetaRenderer < Laser::Cutter::Renderer::Base
3
-
4
- META_KEYS = %w(units width height depth thickness notch kerf stroke padding margin page_size page_layout)
5
-
6
- def initialize(config = {})
7
- self.config = config
8
- self.enclosure = Laser::Cutter::Geometry::Rect.create(Laser::Cutter::Geometry::Point[1, 1], 140, 150)
9
- end
10
-
11
- def render pdf = nil
12
- banner = <<-EOF
13
-
14
- Made with Laser Cutter Ruby Gem (v#{Laser::Cutter::VERSION})
15
- Credits to Prawn for ruby PDF generation,
16
- and BoxMaker for inspiration.
17
-
18
- Online: http://makeabox.io/
19
- Source: https://github.com/kigster/laser-cutter
20
- EOF
21
-
22
- meta_color = BLUE
23
- meta_top_height = 55
24
-
25
- metadata = config.to_hash
26
- metadata['page_size'] ||= 'custom'
27
- metadata.delete('page_layout') if metadata['page_size'].eql?('custom')
28
-
29
- meta_fields = META_KEYS.find_all{|k| metadata[k]}.join(": \n") + ": \n"
30
- meta_values = META_KEYS.find_all{|k| metadata[k]}.map{|k| metadata[k] }.join("\n")
31
-
32
- rect = self.enclosure
33
-
34
- pdf.instance_eval do
35
- self.line_width = 0.2.mm
36
- float do
37
- bounding_box([rect.p1.x, rect.h + rect.p1.y], :width => rect.w, :height => rect.h) do
38
- stroke_color meta_color
39
- stroke_bounds
40
-
41
- # Print banner
42
- indent 10 do
43
- font('Helvetica', :size => 6) do
44
- text banner, :color => meta_color
45
- end
46
- end
47
-
48
- # print values of the config, in two parts – keys right aligned first, values left aligned second.
49
- float do
50
- bounding_box([0, rect.h - meta_top_height],
51
- :width => rect.w,
52
- :height => rect.h - meta_top_height) do
53
- float do
54
- bounding_box([0, rect.h - meta_top_height], :width => 70, :height => rect.h - meta_top_height) do
55
- indent 10 do
56
- font('Helvetica', :size => 7) do
57
- text meta_fields, :color => meta_color, align: :right
58
- end
59
- end
60
- end
61
- end
62
- float do
63
- bounding_box([60, rect.h - meta_top_height], :width => 70, :height => rect.h - meta_top_height) do
64
- indent 10 do
65
- font('Helvetica', :size => 7) do
66
- text meta_values, :color => meta_color
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,14 +0,0 @@
1
- module Laser
2
- module Cutter
3
- module Renderer
4
-
5
- end
6
- end
7
- end
8
-
9
- require 'laser-cutter/renderer/base'
10
- require 'laser-cutter/renderer/line_renderer'
11
- require 'laser-cutter/renderer/rect_renderer'
12
- require 'laser-cutter/renderer/box_renderer'
13
- require 'laser-cutter/renderer/meta_renderer'
14
- require 'laser-cutter/renderer/layout_renderer'
@@ -1,5 +0,0 @@
1
- module Laser
2
- module Cutter
3
- VERSION = "1.0.3"
4
- end
5
- end
@@ -1,65 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- module Laser
4
- module Cutter
5
- describe Aggregator do
6
- let(:p1) { Geometry::Point[0, 0] }
7
- let(:p2) { Geometry::Point[2, 0] }
8
- let(:p3) { Geometry::Point[5, 0] }
9
- let(:p4) { Geometry::Point[10, 0] }
10
- let(:p5) { Geometry::Point[0, 12] }
11
-
12
- let(:l1) { Geometry::Line.new(p1, p3) }
13
- let(:l2) { Geometry::Line.new(p2, p4) }
14
- let(:l3) { Geometry::Line.new(p2, p5) }
15
- let(:l4) { Geometry::Line.new(p1, p2) }
16
- let(:l5) { Geometry::Line.new(p3, p4) }
17
-
18
- let(:lines) { [ l1, l2 ]}
19
-
20
- let(:aggregator) { Aggregator.new(lines) }
21
-
22
- context '#initialize' do
23
- it 'should initialize with passed in parameters' do
24
- expect(aggregator.lines.size).to eql(2)
25
- end
26
- end
27
-
28
- context '#dedup' do
29
- let(:a) { [1,5,3,1,2,2,2,2 ] }
30
- let(:unique_lines) { [ l1, l2, l3, l4, l5 ]}
31
- it 'should remove dups from a simple array' do
32
- expect(Aggregator.new(a).dedup!.lines).to eql([3,5])
33
- end
34
- context 'short array' do
35
- let(:lines) { [ l1, l2, l1, l1 ]}
36
- let(:result) { [ l2 ]}
37
- it 'should remove dupes from lines array' do
38
- expect(Aggregator.new(lines).dedup!.lines.map(&:to_s)).to eql(result.map(&:to_s))
39
- end
40
- end
41
- context 'long array' do
42
- let(:lines) { [ l4, l1, l2, l3, l4, l3, l4, l5 ]}
43
- let(:result) { [ l1, l2, l5 ]}
44
- it 'should remove dupes from lines array' do
45
- expect(Aggregator.new(lines).dedup!.lines.map(&:to_s)).to eql(result.map(&:to_s))
46
- end
47
- end
48
- end
49
-
50
- context '#deoverlap' do
51
- let(:lines) { [ l1, l2, l3 ]}
52
-
53
- let(:deoverlapped) { [ l4, l5, l3 ].sort }
54
- it 'should remove lines that overlap' do
55
- expect(aggregator.lines.size).to eql(3)
56
- aggregator.deoverlap!
57
- expect(aggregator.lines.size).to eql(3)
58
- expect(aggregator.lines.map(&:to_s)).to eql(deoverlapped.map(&:to_s))
59
- end
60
- end
61
-
62
- end
63
- end
64
- end
65
- p
data/spec/box_spec.rb DELETED
@@ -1,40 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- module Laser
4
- module Cutter
5
- describe Box do
6
- let(:config) { {'width' => 50, 'height' => 60, 'depth' => 70, 'margin' => 5, 'padding' => 3, 'units' => 'mm'} }
7
- let(:box1) { Box.new(config.merge('thickness' => 6, 'notch' => 10)) }
8
- let(:box2) { Box.new(config.merge('thickness' => 6, )) }
9
-
10
- context '#initialize' do
11
- it 'should initialize with passed in parameters' do
12
- expect(box1.w).to eq(50.0)
13
- expect(box1.thickness).to eq(6.0)
14
- expect(box1.notch_width).to eq(10.0)
15
- end
16
-
17
- it 'should initialize with default notch' do
18
- expect(box2.notch_width).to eq(70.0 / 5.0)
19
- end
20
- end
21
-
22
- context '#notches' do
23
- before do
24
- box1.generate_notches
25
- box2.generate_notches
26
- end
27
- it 'should generate notches' do
28
- expect(box1.notches).to_not be_nil
29
- expect(box1.notches.size).to eql(368)
30
- end
31
-
32
- it 'should properly calculate enclosure' do
33
- expect(box1.enclosure.to_a.flatten.map(&:round)).to eql([0,0, 232, 317])
34
- expect(box2.enclosure.to_a.flatten.map(&:round)).to eql([0,0, 232, 317])
35
- end
36
- end
37
-
38
- end
39
- end
40
- end
@@ -1,81 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- module Laser
4
- module Cutter
5
- describe Configuration do
6
- let(:config) { Laser::Cutter::Configuration.new(opts) }
7
-
8
- context 'option parsing' do
9
- let(:opts) { {"size" => "2x3x2/0.125/0.5", "inches" => true} }
10
- it 'should be able to parse size options' do
11
- expect(config.width).to eql(2.0)
12
- expect(config.height).to eql(3.0)
13
- expect(config.depth).to eql(2.0)
14
- expect(config.thickness).to eql(0.125)
15
- expect(config.notch).to eql(0.5)
16
- end
17
- end
18
- context '#validate' do
19
- context 'missing options' do
20
- let(:opts) { {"height" => "23"} }
21
- it 'should be able to validate missing options' do
22
- expect(config.height).to eql(23.0)
23
- expect { config.validate! }.to raise_error(Laser::Cutter::MissingOption)
24
- end
25
- end
26
- context 'zero options' do
27
- let(:opts) { {"size" => "2.0x0.0x2/0.125/0.5", 'file' => '/tmp/a'} }
28
- it 'should be able to validate missing options' do
29
- expect(config.height).to eql(0.0)
30
- expect { config.validate! }.to raise_error(Laser::Cutter::ZeroValueNotAllowed)
31
- end
32
- end
33
- end
34
-
35
- context 'default values' do
36
- let(:opts) { {"size" => "2.0x1.0x2/0.125", 'file' => '/tmp/a'} }
37
- it 'should correctly default notch based on thickness' do
38
- config.validate!
39
- expect(config.thickness).to eql(0.125)
40
- expect(config.notch).to eql(config.thickness * 3.0)
41
- end
42
- end
43
-
44
- context 'when invalid units are provided' do
45
- let(:opts) { {"size" => "2x3x2/0.125/0.5", "units" => 'xx'} }
46
- it 'should default to inches' do
47
- expect(config.units).to eql('in')
48
- end
49
- end
50
-
51
- context 'when converting between units' do
52
- context 'all config values' do
53
- context "to mm" do
54
- let(:opts) { {'size' => "2.0x3x2/0.125/0.5", 'padding' => '4.2', "units" => 'in'} }
55
- it 'should be correct' do
56
- expect(config.width).to eql(2.0)
57
- config.change_units('in')
58
- expect(config.width).to eql(2.0)
59
- config.change_units('mm')
60
- expect(config.width).to eql(50.8)
61
- expect(config.padding).to eql(106.68)
62
- expect(config.units).to eql('mm')
63
- end
64
- end
65
- context 'to inches' do
66
- let(:opts) { {'size' => "20.0x30.0x40.0/5/5", 'margin' => '10.0', "units" => 'mm'} }
67
- it 'should be correct' do
68
- expect(config.width).to eql(20.0)
69
- config.change_units('mm')
70
- expect(config.width).to eql(20.0)
71
- config.change_units('in')
72
- expect(config.width).to be_within(0.00001).of(0.787401575)
73
- expect(config.margin).to be_within(0.00001).of(0.393700787)
74
- expect(config.units).to eql('in')
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end
81
- end
data/spec/edge_spec.rb DELETED
@@ -1,43 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- module Laser
4
- module Cutter
5
-
6
- describe "Notching::Edge" do
7
- context 'left vertical side' do
8
- let(:notch_width) { 2 }
9
- let(:inside) { Geometry::Line.new(Geometry::Point[1, 1], Geometry::Point[1, 9])}
10
- let(:outside) { Geometry::Line.new(Geometry::Point[0, 0], Geometry::Point[0, 10]) }
11
- let(:edge) { Notching::Edge.new(inside, outside,
12
- center_out: true,
13
- fill_corners: true,
14
- notch_width: notch_width,
15
- kerf: 0.02,
16
- thickness: 1) }
17
-
18
- it 'should create a node correctly' do
19
- expect(inside.length).to eql(8.0)
20
- expect(outside.length).to eql(10.0)
21
- expect(edge.center_out).to be_truthy
22
- expect(edge.kerf).to be_within(0.0001).of(0.02)
23
- expect(edge.thickness).to be_within(0.0001).of(1)
24
- expect(edge.notch_width).to be_within(notch_width / 3.0).of(notch_width)
25
- end
26
-
27
- it 'should calculate notch width correctly' do
28
- expect(inside.length).to eql(8.0)
29
- expect(outside.length).to eql(10.0)
30
- expect(edge.center_out).to be_truthy
31
-
32
- expect(edge.kerf).to be_within(0.0001).of(0.02)
33
- expect(edge.thickness).to be_within(0.0001).of(1)
34
- end
35
-
36
- it 'should correctly calculate v1 and v2' do
37
- expect(edge.v1.to_a).to eql([1.0,1.0])
38
- expect(edge.v2.to_a).to eql([1.0,-1.0])
39
- end
40
- end
41
- end
42
- end
43
- end