laser-cutter 0.5.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/README.md +20 -16
  4. data/bin/laser-cutter +4 -158
  5. data/lib/laser-cutter.rb +2 -0
  6. data/lib/laser-cutter/aggregator.rb +57 -0
  7. data/lib/laser-cutter/box.rb +37 -24
  8. data/lib/laser-cutter/cli/opt_parser.rb +131 -0
  9. data/lib/laser-cutter/cli/serializer.rb +51 -0
  10. data/lib/laser-cutter/configuration.rb +3 -2
  11. data/lib/laser-cutter/geometry.rb +0 -3
  12. data/lib/laser-cutter/geometry/dimensions.rb +3 -3
  13. data/lib/laser-cutter/geometry/point.rb +0 -46
  14. data/lib/laser-cutter/geometry/shape/line.rb +40 -1
  15. data/lib/laser-cutter/geometry/shape/rect.rb +2 -2
  16. data/lib/laser-cutter/geometry/tuple.rb +73 -27
  17. data/lib/laser-cutter/notching.rb +10 -0
  18. data/lib/laser-cutter/notching/base.rb +13 -0
  19. data/lib/laser-cutter/notching/edge.rb +87 -0
  20. data/lib/laser-cutter/notching/path_generator.rb +249 -0
  21. data/lib/laser-cutter/renderer/base.rb +1 -1
  22. data/lib/laser-cutter/renderer/box_renderer.rb +2 -2
  23. data/lib/laser-cutter/renderer/layout_renderer.rb +19 -8
  24. data/lib/laser-cutter/renderer/meta_renderer.rb +8 -9
  25. data/lib/laser-cutter/version.rb +1 -1
  26. data/spec/aggregator_spec.rb +65 -0
  27. data/spec/box_spec.rb +5 -1
  28. data/spec/dimensions_spec.rb +0 -1
  29. data/spec/edge_spec.rb +43 -0
  30. data/spec/line_spec.rb +42 -19
  31. data/spec/path_generator_spec.rb +30 -36
  32. data/spec/point_spec.rb +2 -2
  33. data/spec/rect_spec.rb +1 -1
  34. data/spec/renderer_spec.rb +14 -5
  35. metadata +13 -5
  36. data/lib/laser-cutter/geometry/edge.rb +0 -33
  37. data/lib/laser-cutter/geometry/notched_path.rb +0 -46
  38. data/lib/laser-cutter/geometry/path_generator.rb +0 -129
@@ -1,5 +1,5 @@
1
1
  module Laser
2
2
  module Cutter
3
- VERSION = "0.5.3"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -0,0 +1,65 @@
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
@@ -20,9 +20,13 @@ module Laser
20
20
  end
21
21
 
22
22
  context '#notches' do
23
+ before do
24
+ box1.generate_notches
25
+ box2.generate_notches
26
+ end
23
27
  it 'should generate notches' do
24
28
  expect(box1.notches).to_not be_nil
25
- expect(box1.notches.size).to eql(320)
29
+ expect(box1.notches.size).to eql(368)
26
30
  end
27
31
 
28
32
  it 'should properly calculate enclosure' do
@@ -1,5 +1,4 @@
1
1
  require_relative 'spec_helper'
2
-
3
2
  module Laser
4
3
  module Cutter
5
4
  module Geometry
@@ -0,0 +1,43 @@
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
@@ -6,7 +6,7 @@ module Laser
6
6
  describe Line do
7
7
  let(:p1) { Point.new(1, 1) }
8
8
  let(:p2) { Point.new(7, 11) }
9
- let(:center) { Point.new( (7 + 1) / 2, (11 + 1) / 2) }
9
+ let(:center) { Point.new((7 + 1) / 2, (11 + 1) / 2) }
10
10
  let(:line) { Line.new(p1, p2) }
11
11
 
12
12
  context '#center' do
@@ -16,11 +16,11 @@ module Laser
16
16
  end
17
17
 
18
18
  context '#initialize' do
19
- let(:line2) { Line.new(from: [1,1], to: [7,11])}
20
- let(:line3) { Line.new(from: Point.new(1,1), to: Point.new(7,11))}
19
+ let(:line2) { Line.new(from: [1, 1], to: [7, 11]) }
20
+ let(:line3) { Line.new(from: Point.new(1, 1), to: Point.new(7, 11)) }
21
21
  it 'should create' do
22
- expect(line2.p1).to eql(Point.new(1,1))
23
- expect(line2.p2).to eql(Point.new(7,11))
22
+ expect(line2.p1).to eql(Point.new(1, 1))
23
+ expect(line2.p2).to eql(Point.new(7, 11))
24
24
  end
25
25
  it 'should properly equal identical line' do
26
26
  expect(line).to eql(line2)
@@ -41,38 +41,61 @@ module Laser
41
41
  end
42
42
 
43
43
  context 'ordering and equality' do
44
- let(:l1) { Line.new(Point[0,0], Point[10,10]) }
45
- let(:l2) { Line.new(Point[0,1], Point[10,10]) }
46
- let(:l3) { Line.new(Point[0,0], Point[11,10]) }
47
- let(:l4) { Line.new(Point[20,20], Point[1,1]) }
48
- let(:l5) { Line.new(Point[11,10], Point[0,0]) }
44
+ let(:l1) { Line.new(Point[0, 0], Point[10, 10]) }
45
+ let(:l2) { Line.new(Point[0, 1], Point[10, 10]) }
46
+ let(:l3) { Line.new(Point[0, 0], Point[11, 10]) }
47
+ let(:l4) { Line.new(Point[20, 20], Point[1, 1]) }
48
+ let(:l5) { Line.new(Point[11, 10], Point[0, 0]) }
49
49
  it 'should detect equality' do
50
50
  expect(l1).to eql(Line.new(l1.p1, l1.p2))
51
- expect(l1).to_not eql(Line.new(l1.p1, Point[2,4]))
51
+ expect(l1).to_not eql(Line.new(l1.p1, Point[2, 4]))
52
52
  expect(l5).to eql(l3)
53
53
  expect(l5.hash).to eql(l3.hash)
54
54
  end
55
55
 
56
56
  it 'should properly compare' do
57
- list = [l4,l3,l1,l2]
57
+ list = [l4, l3, l1, l2]
58
58
  list.sort!
59
- expect(list).to eql([l1,l3,l2,l4])
59
+ expect(list).to eql([l1, l3, l2, l4])
60
60
  end
61
61
 
62
62
  it 'should properly uniq' do
63
63
  list = [l4, l1, l4, l2, l3, l3, l2, l1]
64
64
  list.sort!.uniq!
65
- expect(list).to eql([l1,l3,l2,l4])
65
+ expect(list).to eql([l1, l3, l2, l4])
66
66
  end
67
+ end
68
+ context 'overlaps and such' do
69
+ let(:l1) { Line.new(Point[0, 0], Point[10, 0]) }
70
+ let(:l2) { Line.new(Point[7, 0], Point[15, 0]) }
71
+ let(:l3) { Line.new(Point[20, 0], Point[25, 0]) }
72
+ let(:l4) { Line.new(Point[0, 1], Point[0, 3]) }
73
+ let(:l5) { Line.new(Point[0, -1], Point[0, 2]) }
74
+
67
75
 
68
- it 'should properly deduplicate' do
69
- list = [l1, l4, l2, l3, l5, l3, l1, l3, l3, l2]
70
- new_list = PathGenerator.deduplicate(list)
71
- expect(new_list).to eql([l4])
76
+ context '#overlaps?' do
77
+ it 'should detect overlap' do
78
+ expect(l1.overlaps?(l2)).to be_truthy
79
+ expect(l1.overlaps?(l3)).to be_falsey
80
+ expect(l2.overlaps?(l3)).to be_falsey
81
+ expect(l1.overlaps?(l4)).to be_falsey
82
+ expect(l2.overlaps?(l4)).to be_falsey
83
+ expect(l4.overlaps?(l5)).to be_truthy
84
+ end
72
85
  end
73
86
 
87
+ context '#xor' do
88
+ let(:xor) { [ Line.new(Point[0, 0], Point[7, 0]), Line.new(Point[10, 0], Point[15, 0])]}
89
+ it 'should subtract lines' do
90
+ expect(l1.xor(l2)).to eql(xor)
91
+ expect(l1.overlaps?(l3)).to be_falsey
92
+ expect(l2.overlaps?(l3)).to be_falsey
93
+ expect(l1.overlaps?(l4)).to be_falsey
94
+ expect(l2.overlaps?(l4)).to be_falsey
95
+ expect(l4.overlaps?(l5)).to be_truthy
96
+ end
97
+ end
74
98
  end
75
-
76
99
  end
77
100
  end
78
101
  end
@@ -2,19 +2,23 @@ require_relative 'spec_helper'
2
2
 
3
3
  module Laser
4
4
  module Cutter
5
- module Geometry
5
+ module Notching
6
6
  describe PathGenerator do
7
7
  let(:notch) { 2 }
8
8
  let(:thickness) { 1 }
9
9
  let(:center_out) { true }
10
- let(:fill_edge) { true }
11
- let(:outside) { Line.new(from: [0, 0], to: [10, 0]) }
12
- let(:inside) { Line.new(from: [1, 1], to: [9, 1]) }
13
- let(:edge) { Edge.new(outside, inside, notch) }
14
- let(:generator) { PathGenerator.new(notch_width: notch,
15
- thickness: thickness,
16
- center_out: center_out,
17
- fill_edge: fill_edge) }
10
+ let(:corners) { true }
11
+
12
+ let(:options) { {notch_width: notch,
13
+ thickness: thickness,
14
+ center_out: center_out,
15
+ corners: corners} }
16
+
17
+ let(:outside) { Geometry::Line.new(from: [0, 0], to: [10, 0]) }
18
+ let(:inside) { Geometry::Line.new(from: [1, 1], to: [9, 1]) }
19
+ let(:edge) { Edge.new(outside, inside, options) }
20
+ let(:generator) { PathGenerator.new(edge) }
21
+
18
22
  context 'edge' do
19
23
  it 'should properly calculate notch size' do
20
24
  expect(edge.notch_width).to be_within(0.001).of(1.6)
@@ -29,19 +33,20 @@ module Laser
29
33
  end
30
34
 
31
35
  context 'alternating iterator' do
32
- let(:iterator) { InfiniteIterator.new([:a, :b, :c]) }
36
+ let(:a) { "hello" }
37
+ let(:b) { "again" }
38
+ let(:iterator) { InfiniteIterator.new([a,b]) }
33
39
  it 'returns things in alternating order' do
34
- expect(iterator.next).to eq(:a)
35
- expect(iterator.next).to eq(:b)
36
- expect(iterator.next).to eq(:c)
37
- expect(iterator.next).to eq(:a)
40
+ expect(iterator.next).to eq(a)
41
+ expect(iterator.next).to eq(b)
42
+ expect(iterator.next).to eq(a)
38
43
  end
39
44
  end
40
45
 
41
46
  context 'shift definition' do
42
47
 
43
48
  it 'correctly defines shifts' do
44
- shifts = generator.send(:define_shifts, edge)
49
+ shifts = generator.send(:define_shifts)
45
50
  expect(edge.outside.length).to eql(10.0)
46
51
  expect(edge.inside.length).to eql(8.0)
47
52
  expect(edge.notch_width).to be_within(0.001).of(1.6)
@@ -53,41 +58,30 @@ module Laser
53
58
 
54
59
  context 'path generation' do
55
60
  # let(:outside) { Line.new(
56
- # from: inside.p1.move_by(-thickness, -thickness),
57
- # to: inside.p2.move_by(thickness, -thickness)) }
61
+ # from: inside.p1.plus(-thickness, -thickness),
62
+ # to: inside.p2.plus(thickness, -thickness)) }
58
63
 
59
64
  context 'center out' do
60
65
  it 'generates correct path vertices' do
61
- inside.freeze
62
66
  expect(inside.p1).to_not eql(inside.p2)
63
- path = generator.path(edge)
64
- expect(path).to be_a_kind_of(NotchedPath)
65
- expect(path.size).to be > 5
67
+ lines = generator.generate
68
+ expect(lines.size).to be > 5
66
69
 
67
- expect(Line.new(path.vertices.first, inside.p1).length).to be_within(0.001).of(0)
68
- expect(Line.new(path.vertices.last, inside.p2).length).to be_within(0.001).of(0)
70
+ expect(Geometry::Line.new(lines.first.p1, inside.p1).length).to be_within(0.001).of(0)
71
+ expect(Geometry::Line.new(lines.last.p2, inside.p2).length).to be_within(0.001).of(0)
69
72
 
70
73
  # Sanity Check
71
- expect(Point.new(1, 1)).to eql(inside.p1)
72
- expect(Point.new(9, 1)).to eql(inside.p2)
74
+ expect(Geometry::Point.new(1, 1)).to eql(inside.p1)
75
+ expect(Geometry::Point.new(9, 1)).to eql(inside.p2)
73
76
  end
74
77
 
75
78
  it 'generates correct lines' do
76
- path = generator.path(edge)
77
- lines = path.create_lines
78
- expect(path.size).to eq(12)
79
- expect(lines.size).to be > 1
79
+ lines = generator.generate
80
+ expect(lines.size).to eq(19)
80
81
  end
81
82
  end
82
83
  end
83
84
 
84
- context 'remove dupes' do
85
- let(:a) { [1,5,3,1,2,2,2,2 ] }
86
- it 'should remove dups' do
87
- expect(PathGenerator.deduplicate(a)).to eql([3,5])
88
- end
89
- end
90
-
91
85
  end
92
86
  end
93
87
  end
@@ -42,12 +42,12 @@ module Laser
42
42
 
43
43
  context 'move by' do
44
44
  it 'should move properly' do
45
- p = p1.move_by(10, -2)
45
+ p = p1.plus(10, -2)
46
46
  expect(p.x).to be_within(0.001).of(11)
47
47
  expect(p.y).to be_within(0.001).of(0)
48
48
  end
49
49
  it 'should move cloned version properly' do
50
- p2 = p1.clone.move_by(10, -2)
50
+ p2 = p1.clone.plus(10, -2)
51
51
  expect(p2.x).to be_within(0.001).of(11)
52
52
  expect(p2.y).to be_within(0.001).of(0)
53
53
  end
@@ -28,7 +28,7 @@ module Laser
28
28
  expect(rect1.sides.first.p1).to eql(p1)
29
29
  expect(rect1.sides[0].p1.to_s).to eql("{1.00000,3.00000}")
30
30
  expect(rect1.sides[1].p1.to_s).to eql("{11.00000,3.00000}")
31
- expect(rect1.sides[2].p1).to eql(p1.move_by(10, 20))
31
+ expect(rect1.sides[2].p1).to eql(p1.plus(10, 20))
32
32
  end
33
33
  it 'can be moved' do
34
34
  expect(rect1.sides[0].p1.to_s).to eql("{1.00000,3.00000}")
@@ -9,17 +9,26 @@ module Laser
9
9
  let(:file) { File.expand_path("../../laser-cutter-pdf-test.#{$$}.pdf", __FILE__) }
10
10
 
11
11
  def render_file filename
12
+ real_file = ENV['RSPEC_SAVE_PDF'] ? true : false
12
13
  config.validate!
13
- expect(!File.exists?(filename))
14
+ expect(!File.exists?(filename)) if real_file
14
15
  renderer.render
15
- expect(File.exist?(filename))
16
- expect(File.size(filename) > 0)
16
+ expect(File.exist?(filename)) if real_file
17
+ expect(File.size(filename) > 0) if real_file
17
18
  rescue Exception => e
18
19
  STDERR.puts e.backtrace.join("\n")
19
20
  fail e.message
20
21
  ensure
21
- File.delete(filename) rescue nil
22
- expect(!File.exists?(filename))
22
+ if real_file
23
+ File.delete(filename) rescue nil
24
+ expect(!File.exists?(filename))
25
+ end
26
+ end
27
+
28
+ before do
29
+ unless ENV['RSPEC_SAVE_PDF']
30
+ expect_any_instance_of(Prawn::Document).to receive(:render_file).once
31
+ end
23
32
  end
24
33
 
25
34
  context 'metric' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: laser-cutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-05 00:00:00.000000000 Z
11
+ date: 2014-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prawn
@@ -146,18 +146,22 @@ files:
146
146
  - doc/comparison.jpg
147
147
  - laser-cutter.gemspec
148
148
  - lib/laser-cutter.rb
149
+ - lib/laser-cutter/aggregator.rb
149
150
  - lib/laser-cutter/box.rb
151
+ - lib/laser-cutter/cli/opt_parser.rb
152
+ - lib/laser-cutter/cli/serializer.rb
150
153
  - lib/laser-cutter/configuration.rb
151
154
  - lib/laser-cutter/geometry.rb
152
155
  - lib/laser-cutter/geometry/dimensions.rb
153
- - lib/laser-cutter/geometry/edge.rb
154
- - lib/laser-cutter/geometry/notched_path.rb
155
- - lib/laser-cutter/geometry/path_generator.rb
156
156
  - lib/laser-cutter/geometry/point.rb
157
157
  - lib/laser-cutter/geometry/shape.rb
158
158
  - lib/laser-cutter/geometry/shape/line.rb
159
159
  - lib/laser-cutter/geometry/shape/rect.rb
160
160
  - lib/laser-cutter/geometry/tuple.rb
161
+ - lib/laser-cutter/notching.rb
162
+ - lib/laser-cutter/notching/base.rb
163
+ - lib/laser-cutter/notching/edge.rb
164
+ - lib/laser-cutter/notching/path_generator.rb
161
165
  - lib/laser-cutter/page_manager.rb
162
166
  - lib/laser-cutter/renderer.rb
163
167
  - lib/laser-cutter/renderer/base.rb
@@ -167,9 +171,11 @@ files:
167
171
  - lib/laser-cutter/renderer/meta_renderer.rb
168
172
  - lib/laser-cutter/renderer/rect_renderer.rb
169
173
  - lib/laser-cutter/version.rb
174
+ - spec/aggregator_spec.rb
170
175
  - spec/box_spec.rb
171
176
  - spec/configuration_spec.rb
172
177
  - spec/dimensions_spec.rb
178
+ - spec/edge_spec.rb
173
179
  - spec/line_spec.rb
174
180
  - spec/page_manager_spec.rb
175
181
  - spec/path_generator_spec.rb
@@ -203,9 +209,11 @@ specification_version: 4
203
209
  summary: Creates notched box outlines for laser-cut boxes which are geometrically
204
210
  symmetric and pleasing to the eye.
205
211
  test_files:
212
+ - spec/aggregator_spec.rb
206
213
  - spec/box_spec.rb
207
214
  - spec/configuration_spec.rb
208
215
  - spec/dimensions_spec.rb
216
+ - spec/edge_spec.rb
209
217
  - spec/line_spec.rb
210
218
  - spec/page_manager_spec.rb
211
219
  - spec/path_generator_spec.rb