laser-cutter 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Laser
4
+ module Cutter
5
+ module Geometry
6
+ describe PathGenerator do
7
+ let(:notch) { 2 }
8
+ let(:thickness) { 1 }
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) }
18
+ context 'edge' do
19
+ it 'should properly calculate notch size' do
20
+ expect(edge.notch_width).to be_within(0.001).of(1.6)
21
+ end
22
+ context 'edge cases with the edge :)' do
23
+ let(:notch) { 15 } # too big
24
+ it 'should properly handle edge cases' do
25
+ # 3 is the minimum number of notches we support per side
26
+ expect(edge.notch_width).to be_within(0.001).of(8.0/3.0)
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'alternating iterator' do
32
+ let(:iterator) { InfiniteIterator.new([:a, :b, :c]) }
33
+ 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)
38
+ end
39
+ end
40
+
41
+ context 'shift definition' do
42
+
43
+ it 'correctly defines shifts' do
44
+ shifts = generator.send(:define_shifts, edge)
45
+ expect(edge.outside.length).to eql(10.0)
46
+ expect(edge.inside.length).to eql(8.0)
47
+ expect(edge.notch_width).to be_within(0.001).of(1.6)
48
+ expect(edge.notch_count).to eql(5)
49
+ expect(shifts.size).to eql(11)
50
+ end
51
+ end
52
+
53
+
54
+ context 'path generation' do
55
+ # let(:outside) { Line.new(
56
+ # from: inside.p1.move_by(-thickness, -thickness),
57
+ # to: inside.p2.move_by(thickness, -thickness)) }
58
+
59
+ context 'center out' do
60
+ it 'generates correct path vertices' do
61
+ inside.freeze
62
+ 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
66
+
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)
69
+
70
+ # Sanity Check
71
+ expect(Point.new(1, 1)).to eql(inside.p1)
72
+ expect(Point.new(9, 1)).to eql(inside.p2)
73
+ end
74
+
75
+ 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
80
+ end
81
+ end
82
+ end
83
+
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
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Laser
4
+ module Cutter
5
+ module Geometry
6
+ describe Point do
7
+ let(:p1) { Point.new(1, 2) }
8
+ context 'creation' do
9
+ context 'from string' do
10
+ it 'should instantiate correctly' do
11
+ expect(Point.new "1,2").to eql(p1)
12
+ end
13
+ end
14
+
15
+ context 'from a point' do
16
+ it 'should instantiate correctly' do
17
+ expect(Point.new(Point.new("1,2"))).to eql(p1)
18
+ end
19
+ end
20
+
21
+ context 'from an array' do
22
+ it 'should properly duplicate underlying coordinates and not bug out' do
23
+ a = [1, 2]
24
+ p2 = Point.new(a)
25
+ expect(p2).to eql(p1)
26
+ a.shift # modify original array
27
+ # should not affect our point
28
+ expect(p2).to eql(p1)
29
+ end
30
+
31
+ it 'should create point from class method' do
32
+ expect(Point[1,2]).to eql(p1)
33
+ end
34
+ end
35
+
36
+ context 'from a hash' do
37
+ it 'should instantiate correctly' do
38
+ expect(Point.new(x: 1, y: 2)).to eql(p1)
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'move by' do
44
+ it 'should move properly' do
45
+ p = p1.move_by(10, -2)
46
+ expect(p.x).to be_within(0.001).of(11)
47
+ expect(p.y).to be_within(0.001).of(0)
48
+ end
49
+ it 'should move cloned version properly' do
50
+ p2 = p1.clone.move_by(10, -2)
51
+ expect(p2.x).to be_within(0.001).of(11)
52
+ expect(p2.y).to be_within(0.001).of(0)
53
+ end
54
+ end
55
+
56
+ context 'ordering and equality' do
57
+ let(:p1) { Point[0,0]}
58
+ let(:p2) { Point[10,0]}
59
+ let(:p3) { Point[0,10]}
60
+ let(:p4) { Point[10,10]}
61
+ let(:p5) { Point[-1,-1]}
62
+ it 'should propertly sort' do
63
+ expect([p3,p2,p1,p4,p5].sort).to eql([p5,p1,p3,p2,p4])
64
+ end
65
+ it 'should detect equality' do
66
+ expect(p1).to_not eql(p2)
67
+ expect(p2).to eql(Point[10,0])
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Laser
4
+ module Cutter
5
+ module Geometry
6
+ describe Rect do
7
+ let(:p1) { Point[ 1.0, 3.0] }
8
+ let(:p2) { Point[11.0, 23.0] }
9
+
10
+ let(:rect1) { Rect.new(p1, p2) }
11
+
12
+ context 'creating' do
13
+ it 'creates from a class method' do
14
+ expect(Rect[p1, p2]).to eql(rect1)
15
+ end
16
+ end
17
+
18
+ context 'sides' do
19
+ it 'sets correctly all attributes' do
20
+ expect(rect1.w).to eql(10.0)
21
+ expect(rect1.h).to eql(20.0)
22
+ expect(rect1.position).to eql(rect1.vertices[0])
23
+ expect(rect1.p2).to eql(rect1.vertices[2])
24
+ end
25
+ it 'it generates four side lines' do
26
+ expect(rect1.sides.size).to eql(4)
27
+ expect(rect1.sides.first).to be_kind_of(Line)
28
+ expect(rect1.sides.first.p1).to eql(p1)
29
+ expect(rect1.sides[0].p1.to_s).to eql("{1.00000,3.00000}")
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))
32
+ end
33
+ it 'can be moved' do
34
+ expect(rect1.sides[0].p1.to_s).to eql("{1.00000,3.00000}")
35
+ rect1.x = 1000
36
+ rect1.y = 100
37
+ rect1.relocate!
38
+
39
+ expect(rect1.sides[0].p1.to_s).to eql("{1000.00000,100.00000}")
40
+ expect(rect1.sides[1].p1.to_s).to eql("{1010.00000,100.00000}")
41
+ expect(rect1.sides[2].p1.to_s).to eql("{1010.00000,120.00000}")
42
+ expect(rect1.sides[3].p1.to_s).to eql("{1000.00000,120.00000}")
43
+
44
+ expect(rect1.sides[0].p2.to_s).to eql("{1010.00000,100.00000}")
45
+ expect(rect1.sides[1].p2.to_s).to eql("{1010.00000,120.00000}")
46
+ expect(rect1.sides[2].p2.to_s).to eql("{1000.00000,120.00000}")
47
+ expect(rect1.sides[3].p2.to_s).to eql("{1000.00000,100.00000}")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,60 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Laser
4
+ module Cutter
5
+ module Renderer
6
+ describe 'BoxRenderer' do
7
+ context '#render' do
8
+ let(:box) { Laser::Cutter::Box.new(config) }
9
+ let(:renderer) { BoxRenderer.new(box, config) }
10
+ let(:file) { File.expand_path("../../laser-cutter-pdf-test.#{$$}.pdf", __FILE__) }
11
+
12
+ def render_file filename
13
+ expect(!File.exists?(filename))
14
+ renderer.render
15
+ expect(File.exist?(filename))
16
+ expect(File.size(filename) > 0)
17
+ ensure
18
+ File.delete(filename)
19
+ expect(!File.exists?(filename))
20
+ end
21
+
22
+ context 'metric' do
23
+ let(:config) { Laser::Cutter::Configuration.new(
24
+ 'width' => 50, 'height' => 60, 'depth' => 20, 'thickness' => 6,
25
+ 'margin' => 5, 'padding' => 3, 'notch' => 10, 'file' => file) }
26
+
27
+ it 'should be able to generate a PDF file' do
28
+ render_file file
29
+ end
30
+ end
31
+
32
+ context 'imperial' do
33
+ context 'margins and padding provided' do
34
+ let(:config) { Laser::Cutter::Configuration.new(
35
+ 'width' => 2.5, 'height' => 3.5, 'depth' => 2.0, 'thickness' => 0.125,
36
+ 'margin' => 0, 'padding' => 0.125, 'notch' => 0.25, 'file' => file,
37
+ 'units' => 'in') }
38
+
39
+ it 'should be able to generate a PDF file' do
40
+ render_file file
41
+ end
42
+ end
43
+
44
+ context 'margins and padding are defaults' do
45
+ let(:config) { Laser::Cutter::Configuration.new(
46
+ 'width' => 2.5, 'height' => 2, 'depth' => 2.0, 'thickness' => 0.125,
47
+ 'notch' => 0.25, 'file' => file, 'units' => 'in') }
48
+
49
+ it 'should be able to generate a PDF file' do
50
+ render_file file
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
9
+ require 'rubygems'
10
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
11
+ require 'laser-cutter'
12
+
13
+ #Dir['spec/support/**/*.rb'].each { |filename| require_relative "../#{filename}" }
14
+
15
+ RSpec.configure do |config|
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+
20
+ # Run specs in random order to surface order dependencies. If you find an
21
+ # order dependency and want to debug it, you can fix the order by providing
22
+ # the seed, which is printed after each run.
23
+ # --seed 1234
24
+ config.order = 'random'
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: laser-cutter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Konstantin Gredeskoul
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: prawn
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hashie
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: colored
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
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
+ description: ''
98
+ email:
99
+ - kigster@gmail.com
100
+ executables:
101
+ - laser-cutter
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".ruby-version"
108
+ - ".travis.yml"
109
+ - Gemfile
110
+ - LICENSE
111
+ - LICENSE.txt
112
+ - README.md
113
+ - Rakefile
114
+ - bin/laser-cutter
115
+ - laser-cutter.gemspec
116
+ - lib/laser-cutter.rb
117
+ - lib/laser-cutter/box.rb
118
+ - lib/laser-cutter/configuration.rb
119
+ - lib/laser-cutter/geometry.rb
120
+ - lib/laser-cutter/geometry/dimensions.rb
121
+ - lib/laser-cutter/geometry/edge.rb
122
+ - lib/laser-cutter/geometry/notched_path.rb
123
+ - lib/laser-cutter/geometry/path_generator.rb
124
+ - lib/laser-cutter/geometry/point.rb
125
+ - lib/laser-cutter/geometry/shape.rb
126
+ - lib/laser-cutter/geometry/shape/line.rb
127
+ - lib/laser-cutter/geometry/shape/rect.rb
128
+ - lib/laser-cutter/geometry/tuple.rb
129
+ - lib/laser-cutter/renderer.rb
130
+ - lib/laser-cutter/renderer/box_renderer.rb
131
+ - lib/laser-cutter/renderer/line_renderer.rb
132
+ - lib/laser-cutter/renderer/rect_renderer.rb
133
+ - lib/laser-cutter/version.rb
134
+ - spec/box_spec.rb
135
+ - spec/configuration_spec.rb
136
+ - spec/dimensions_spec.rb
137
+ - spec/line_spec.rb
138
+ - spec/path_generator_spec.rb
139
+ - spec/point_spec.rb
140
+ - spec/rect_spec.rb
141
+ - spec/renderer_spec.rb
142
+ - spec/spec_helper.rb
143
+ homepage: ''
144
+ licenses:
145
+ - MIT
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.2.2
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: Creates box outlines for laser-cut boxes.
167
+ test_files:
168
+ - spec/box_spec.rb
169
+ - spec/configuration_spec.rb
170
+ - spec/dimensions_spec.rb
171
+ - spec/line_spec.rb
172
+ - spec/path_generator_spec.rb
173
+ - spec/point_spec.rb
174
+ - spec/rect_spec.rb
175
+ - spec/renderer_spec.rb
176
+ - spec/spec_helper.rb
177
+ has_rdoc: