laser-cutter 1.0.3 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/.travis.yml +23 -8
- data/BOXMAKER.md +51 -0
- data/README.md +55 -106
- data/Rakefile +28 -1
- data/{doc → docs}/comparison.jpg +0 -0
- data/laser-cutter.gemspec +3 -3
- data/lib/laser-cutter/box.rb +70 -68
- data/lib/laser-cutter/face.rb +18 -0
- data/lib/laser-cutter/notching.rb +0 -1
- data/lib/laser-cutter/notching/edge.rb +4 -4
- data/lib/laser-cutter/notching/path_generator.rb +48 -63
- data/lib/laser-cutter/version.rb +1 -1
- data/spec/box_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -6
- metadata +15 -15
- data/lib/laser-cutter/notching/base.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a3d7b723ed7171e84a93783545f037adeeeb122
|
4
|
+
data.tar.gz: d3571947154cda05176e1d1bbb84d8d2ee140c02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 870c36a4b07b2d4190076c524917f4322d599c58f5ff9b226b47e00a011dd63f722a7153ed885c192cbe0caefbda17fb150269a7822f4e36a001f4913a435d19
|
7
|
+
data.tar.gz: 67c264109139865d62292cb8cea2573ec5dbc569fec92316b00a14f942c0ea15d096d0391d1a5a275e3eaf78c7f9f8f179e95331f93859df982f7c7a80589e08
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
+
env:
|
2
|
+
global:
|
3
|
+
- CC_TEST_REPORTER_ID=6520104decf84e2f6c2c169d30d67976bfcdaa48cd89b4ec34f6e637f2a0ae02
|
4
|
+
sudo: false
|
1
5
|
language: ruby
|
6
|
+
cache: bundler
|
2
7
|
rvm:
|
3
|
-
|
4
|
-
|
8
|
+
- 2.4.1
|
9
|
+
- 2.3.5
|
10
|
+
before_install: gem install bundler -v 1.15.4
|
11
|
+
before_script:
|
12
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64
|
13
|
+
> ./cc-test-reporter
|
14
|
+
- chmod +x ./cc-test-reporter
|
15
|
+
- "./cc-test-reporter before-build"
|
16
|
+
script:
|
17
|
+
- bundle exec rspec
|
18
|
+
after_script:
|
19
|
+
- "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
|
5
20
|
notifications:
|
6
|
-
|
7
|
-
|
8
|
-
-
|
9
|
-
on_success:
|
10
|
-
on_failure:
|
11
|
-
|
21
|
+
webhooks:
|
22
|
+
urls:
|
23
|
+
- secure: fgpv34jAm3rDNjiWuQtuijE0p9B2bpsCWdoCQ82pDZwktSITmNjanYCoZC0hlEw/kqMBDKRN78HfIIidy8dS664sLz8KyaFXq7RWAFsMP9fn/GMG/r9B+S3YumifQ/Zy+3OGa+0Qz76075q291QfNSPv0Y5QDMoAU5VljIVashC/qJS6DRO+vekDaDKIhi4Dr/+JpHPnjchqS4VaMB8gEIrDpeSYNlhrj1oAI/8GwgqZ8UR4sZGxNpIzUg+XGJSYz5/cAB3P18ENSQvOwaNefJa7qIVNjMD7YwXKmfX9cyr5RHM5sibq/S5fHH/N7pig+aveTquGGVxInJr1IEDiyr2TsFARjPitp9KJSFLHLsA2jm1cZfNW0/d6ii+51HdLPKorHom3fPjb0jkIe1LPa9CrrjnfSrAE9a/w4qpSnDv7OjAzkieepz+VQCtpQGIzQxJcHWaFX32iZ6RQ6pmKc/22E0OZwsNM2FHrB5V1b+rfczl8Ej7/R1wAOtHWkbLbfwZ9Ux2N0N0EKW8r8cOjEbsxmN8FFQubTwl68uqjJLhEtrOUbM28JM/NkX+Ue1KRw+NJAdMFEZQKPb/b/X6s3nwPD4/4yLyUDCGyr8aGpzSBD5uIu5uSJNiWdNDjcnXtJJ6TlGGZqj91r7FckjA8FuSA6S3yA8epMNG3FTUxPVE=
|
24
|
+
on_success: always
|
25
|
+
on_failure: onchange
|
26
|
+
on_start: never
|
data/BOXMAKER.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# LaserCutter versus BoxMaker
|
2
|
+
|
3
|
+
Another developer [Rahulbot](https://github.com/rahulbot/) created a similar app [BoxMaker](https://github.com/rahulbot/boxmaker/) in Java, which was an inspiration to LaserCutter.
|
4
|
+
|
5
|
+
Laser-Cutter library attempts to further advance the concept of programmatically creating
|
6
|
+
laser-cut box designs, provides additional fine tuning, many more options, strategies and most
|
7
|
+
importantly – extensibility.
|
8
|
+
|
9
|
+
Unlike `BoxMaker` this gem has a suit of automated tests (rspecs) around the core functionality.
|
10
|
+
In addition, new feature contributions are highly encouraged, and in that
|
11
|
+
regard having existing test suit offers confidence against regressions, and thus welcomes colaboration.
|
12
|
+
|
13
|
+
Finally, BoxMaker's notch-drawing algorithm generates non-symmetric and sometimes purely broken designs
|
14
|
+
(see picture below).
|
15
|
+
|
16
|
+
`laser-cutter`'s algorithm will create a _symmetric design for most panels_, but it might sacrifice
|
17
|
+
identical notch length. Depending on the box dimensions you may end up with a slightly different notch
|
18
|
+
length on each side of the box.
|
19
|
+
|
20
|
+
The choice ultimately comes down to the preference and feature set, so here I show you two boxes made with
|
21
|
+
each program, so you can pick what you prefer.
|
22
|
+
|
23
|
+
### Example Outputs
|
24
|
+
|
25
|
+
Below are two examples of boxes with identical dimensions produced with `laser-cutter` and `boxmaker`:
|
26
|
+
|
27
|
+
This is how you would make a box with Adam Phelp's fork of BoxMaker (which adds flags and a lot of
|
28
|
+
niceties):
|
29
|
+
|
30
|
+
```bash
|
31
|
+
git clone https://github.com/aphelps/boxmaker && cd boxmaker && ant
|
32
|
+
java -cp BOX.jar com.rahulbotics.boxmaker.BoxMaker \
|
33
|
+
-W 1 -H 2 -D 1.5 -T 0.125 -n 0.125 -o box.pdf
|
34
|
+
```
|
35
|
+
|
36
|
+
And laser-cutter:
|
37
|
+
|
38
|
+
```bash
|
39
|
+
gem install laser-cutter
|
40
|
+
laser-cutter -z 1x1.5x2/0.125/0.125 -O -o box.pdf
|
41
|
+
```
|
42
|
+
|
43
|
+
![LaserCutter Comparison](docs/comparison.jpg).
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it ( https://github.com/kigster/laser-cutter/fork )
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create a new Pull Request
|
data/README.md
CHANGED
@@ -1,34 +1,27 @@
|
|
1
1
|
[![Gem Version](https://badge.fury.io/rb/laser-cutter.svg)](http://badge.fury.io/rb/laser-cutter)
|
2
2
|
[![Build status](https://secure.travis-ci.org/kigster/laser-cutter.png)](http://travis-ci.org/kigster/laser-cutter)
|
3
|
-
[![
|
4
|
-
[![Test Coverage](https://codeclimate.com/github/kigster/laser-cutter/badges/coverage.svg)](https://codeclimate.com/github/kigster/laser-cutter)
|
3
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/bea3225fd93ee84d078a/maintainability)](https://codeclimate.com/github/kigster/laser-cutter/maintainability)[![Test Coverage](https://api.codeclimate.com/v1/badges/bea3225fd93ee84d078a/test_coverage)](https://codeclimate.com/github/kigster/laser-cutter/test_coverage)
|
5
4
|
|
6
|
-
|
5
|
+
[![Join the chat at https://gitter.im/kigster/laser-cutter](https://badges.gitter.im/kigster/laser-cutter.svg)](https://gitter.im/kigster/laser-cutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
6
|
+
[![GitHub issues](https://img.shields.io/github/issues/kigster/laser-cutter.svg)](https://github.com/kigster/laser-cutter/issues)
|
7
|
+
[![GitHub forks](https://img.shields.io/github/forks/kigster/laser-cutter.svg)](https://github.com/kigster/laser-cutter/network)
|
8
|
+
[![GitHub stars](https://img.shields.io/github/stars/kigster/laser-cutter.svg)](https://github.com/kigster/laser-cutter/stargazers)
|
9
|
+
[![GitHub license](https://img.shields.io/github/license/kigster/laser-cutter.svg)](https://github.com/kigster/laser-cutter/blob/master/LICENSE)
|
7
10
|
|
8
|
-
|
9
|
-
custom dimensions that suit your project, that can be cut from wood or acrylic
|
10
|
-
using a laser-cutter. The sides of the box snap together using alternating notches,
|
11
|
-
that are deliberately layed out in a symmetric form.
|
11
|
+
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FSFYYNEQ8RKWU)
|
12
12
|
|
13
|
-
|
14
|
-
install it as a gem, and use command line to generate PDFs.
|
13
|
+
# LaserCutter
|
15
14
|
|
16
|
-
|
17
|
-
and provides a straight-forward user interface for generating PDF designs without the need to install
|
18
|
-
the gem or use command line.
|
15
|
+
**LaserCutter** is a ruby library for generating PDF designs for boxes of custom dimensions that suit your project, that are meant to be used as a cut template on a laser-cutter. The sides of the box snap together using alternating notches, that are deliberately laid out in a symmetric form.
|
19
16
|
|
20
|
-
|
17
|
+
To use `laser-cutter` you need to have a recent version of ruby interpreter, install it as a gem, and use command line to generate PDFs.
|
18
|
+
|
19
|
+
[MakeABox.IO](http://makeabox.io) is an online web application that uses `laser-cutter` library and provides a straight-forward user interface for generating PDF designs without the need to install the gem or use command line.
|
21
20
|
|
22
|
-
|
21
|
+
Use whatever suites you better.
|
23
22
|
|
24
|
-
|
25
|
-
laser-cut designs, where alternative strategies can be added over time, and supported by various
|
26
|
-
command line options, and perhaps a light weight web application. If you are interested in
|
27
|
-
contributing to the project, please see [contributing](CONTRIBUTING.md) for more details.
|
23
|
+
> NOTE: Please read our [feature comparison guide](BOXMAKER.md) of LaserCutter against an older tool called [BoxMaker](https://github.com/rahulbot/boxmaker).
|
28
24
|
|
29
|
-
```laser-cutter``` supports many flexible command line options that allow setting dimensions,
|
30
|
-
stroke width, page size, layout, margins, padding (spacing between the boxes), and many more.
|
31
|
-
|
32
25
|
## Dependencies
|
33
26
|
|
34
27
|
The gem depends primarily on [Prawn](http://prawnpdf.org) – a fantastic PDF generation library.
|
@@ -43,12 +36,49 @@ And then execute:
|
|
43
36
|
|
44
37
|
$ bundle
|
45
38
|
|
46
|
-
Or install it
|
39
|
+
Or install it manually:
|
47
40
|
|
48
41
|
$ gem install laser-cutter
|
49
42
|
|
50
43
|
## Usage
|
51
44
|
|
45
|
+
We'll start with some examples:
|
46
|
+
|
47
|
+
### Examples
|
48
|
+
|
49
|
+
Create a box defined in inches, with kerf (cut width) set to `0.005in`, and open PDF in preview right after:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
laser-cutter -z 3x2x2/0.125 -k 0.005 -O -o box.pdf
|
53
|
+
```
|
54
|
+
|
55
|
+
Create a box defined in millimeters, print verbose info, and set page size to A3, and layout to landscape, and stroke width to `1/2mm`:
|
56
|
+
|
57
|
+
```bash
|
58
|
+
laser-cutter -u mm -w70 -h20 -d50 -t4.3 -n5 -iA3 -l landscape -s0.5 -v -O -o box.pdf
|
59
|
+
```
|
60
|
+
|
61
|
+
List all possible page sizes in metric system:
|
62
|
+
|
63
|
+
```bash
|
64
|
+
laser-cutter -L -u mm
|
65
|
+
```
|
66
|
+
|
67
|
+
Create a box with provided dimensions, and save the config to a file for later use:
|
68
|
+
|
69
|
+
```bash
|
70
|
+
laser-cutter -z 1.1x2.5x1.5/0.125/0.125 -p 0.1 -O -o box.pdf -W box-settings.json
|
71
|
+
```
|
72
|
+
|
73
|
+
Read settings from a previously saved file:
|
74
|
+
|
75
|
+
```bash
|
76
|
+
laser-cutter -O -o box.pdf -R box-settings.json
|
77
|
+
cat box-settings.json | laser-cutter -O -o box.pdf -R -
|
78
|
+
```
|
79
|
+
|
80
|
+
### Complete Help
|
81
|
+
|
52
82
|
```bash
|
53
83
|
|
54
84
|
Usage: laser-cutter [options] -o filename.pdf
|
@@ -60,7 +90,7 @@ Specific Options:
|
|
60
90
|
-d, --depth DEPTH Internal depth of the box
|
61
91
|
-t, --thickness THICKNESS Thickness of the box material
|
62
92
|
-n, --notch NOTCH Optional notch length (aka "tab width"), guide only
|
63
|
-
-k, --kerf KERF Kerf - cut width (default is 0.
|
93
|
+
-k, --kerf KERF Kerf - cut width (default is 0.0024in)
|
64
94
|
|
65
95
|
-m, --margin MARGIN Margins from the edge of the document
|
66
96
|
-p, --padding PADDING Space between the boxes on the page
|
@@ -90,41 +120,7 @@ Common Options:
|
|
90
120
|
-u, --units UNITS Either 'in' for inches (default) or 'mm'
|
91
121
|
```
|
92
122
|
|
93
|
-
|
94
|
-
|
95
|
-
Create a box defined in inches, with kerf (cut width) set to 0.008", and open PDF in preview right after:
|
96
|
-
|
97
|
-
```bash
|
98
|
-
laser-cutter -z 3x2x2/0.125 -k 0.008 -O -o box.pdf
|
99
|
-
```
|
100
|
-
|
101
|
-
Create a box defined in millimeters, print verbose info, and set
|
102
|
-
page size to A3, and layout to landscape, and stroke width to 1/2mm:
|
103
|
-
|
104
|
-
```bash
|
105
|
-
laser-cutter -u mm -w70 -h20 -d50 -t4.3 -n5 -iA3 -l landscape -s0.5 -v -O -o box.pdf
|
106
|
-
```
|
107
|
-
|
108
|
-
List all possible page sizes in metric system:
|
109
|
-
|
110
|
-
```bash
|
111
|
-
laser-cutter -L -u mm
|
112
|
-
```
|
113
|
-
|
114
|
-
Create a box with provided dimensions, and save the config to a file for later use:
|
115
|
-
|
116
|
-
```bash
|
117
|
-
laser-cutter -z 1.1x2.5x1.5/0.125/0.125 -p 0.1 -O -o box.pdf -W box-settings.json
|
118
|
-
```
|
119
|
-
|
120
|
-
Read settings from a previously saved file:
|
121
|
-
|
122
|
-
```bash
|
123
|
-
laser-cutter -O -o box.pdf -R box-settings.json
|
124
|
-
cat box-settings.json | laser-cutter -O -o box.pdf -R -
|
125
|
-
```
|
126
|
-
|
127
|
-
## Feature Wish List
|
123
|
+
## Wish List
|
128
124
|
|
129
125
|
* Create T-style joins, using various standard sizes of nuts and bolts (such as common #4-40 and M2 sizes)
|
130
126
|
* Extensibility with various layout strategies, notch drawing strategies, basically plug and play
|
@@ -133,56 +129,9 @@ Read settings from a previously saved file:
|
|
133
129
|
* Supporting lids and front panels, that are larger than the box itself and have holes for notches.
|
134
130
|
* Your brilliant idea can be here too! Please see [contributing](CONTRIBUTING.md) for more info.
|
135
131
|
|
136
|
-
## LaserCutter vs BoxMaker
|
137
|
-
|
138
|
-
[Rahulbot](https://github.com/rahulbot/)-made [BoxMaker](https://github.com/rahulbot/boxmaker/) is a
|
139
|
-
functional generator of notched designs, similar to ```laser-cutter```, and generously open sourced
|
140
|
-
by the author, and so in no way this project disputes BoxMaker's viability. In fact BoxMaker was an
|
141
|
-
inspiration for this project.
|
142
|
-
|
143
|
-
Laser-Cutter library attempts to further advance the concept of programmatically creating
|
144
|
-
laser-cut box designs, provides additional fine tuning, many more options, strategies and most
|
145
|
-
importantly – extensibility.
|
146
|
-
|
147
|
-
Unlike ```BoxMaker```, this gem has a suit of automated tests (rspecs) around the core functionality.
|
148
|
-
In addition, new feature contributions are highly encouraged, and in that
|
149
|
-
regard having existing test suit offers confidence against regressions, and thus welcomes colaboration.
|
150
|
-
|
151
|
-
Finally, BoxMaker's notch-drawing algorithm generates non-symmetric and sometimes purely broken designs
|
152
|
-
(see picture below).
|
153
|
-
|
154
|
-
```laser-cutter```'s algorithm will create a _symmetric design for most panels_, but it might sacrifice
|
155
|
-
identical notch length. Depending on the box dimensions you may end up with a slightly different notch
|
156
|
-
length on each side of the box.
|
157
|
-
|
158
|
-
The choice ultimately comes down to the preference and feature set, so here I show you two boxes made with
|
159
|
-
each program, so you can pick what you prefer.
|
160
|
-
|
161
|
-
### Example Outputs
|
162
|
-
|
163
|
-
Below are two examples of boxes with identical dimensions produced with ```laser-cutter``` and ```boxmaker```:
|
164
|
-
|
165
|
-
This is how you would make a box with Adam Phelp's fork of BoxMaker (which adds flags and a lot of
|
166
|
-
niceties):
|
167
|
-
|
168
|
-
```bash
|
169
|
-
git clone https://github.com/aphelps/boxmaker && cd boxmaker && ant
|
170
|
-
java -cp BOX.jar com.rahulbotics.boxmaker.BoxMaker \
|
171
|
-
-W 1 -H 2 -D 1.5 -T 0.125 -n 0.125 -o box.pdf
|
172
|
-
```
|
173
|
-
|
174
|
-
And laser-cutter:
|
175
|
-
|
176
|
-
```bash
|
177
|
-
gem install laser-cutter
|
178
|
-
laser-cutter -z 1x1.5x2/0.125/0.125 -O -o box.pdf
|
179
|
-
```
|
180
|
-
|
181
|
-
![LaserCutter Comparison](doc/comparison.jpg).
|
182
|
-
|
183
132
|
## Contributing
|
184
133
|
|
185
|
-
1. Fork it ( https://github.com/
|
134
|
+
1. Fork it ( https://github.com/kigster/laser-cutter/fork )
|
186
135
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
187
136
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
188
137
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
@@ -1,2 +1,29 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'yard'
|
2
4
|
|
5
|
+
def shell(*args)
|
6
|
+
puts "running: #{args.join(' ')}"
|
7
|
+
system(args.join(' '))
|
8
|
+
end
|
9
|
+
|
10
|
+
task :clean do
|
11
|
+
shell('rm -rf pkg/ tmp/ coverage/' )
|
12
|
+
end
|
13
|
+
|
14
|
+
task :permissions => [ :clean ] do
|
15
|
+
shell("chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*")
|
16
|
+
shell("find . -type d -exec chmod o+x,g+x {} \\;")
|
17
|
+
end
|
18
|
+
|
19
|
+
task :build => :permissions
|
20
|
+
|
21
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
22
|
+
t.files = %w(lib/**/*.rb bin/* - README.md LICENSE.txt BOXMAKER.md)
|
23
|
+
t.options.unshift('--title','LaserCutter Library')
|
24
|
+
t.after = ->() { exec('open doc/index.html') }
|
25
|
+
end
|
26
|
+
|
27
|
+
RSpec::Core::RakeTask.new(:spec)
|
28
|
+
|
29
|
+
task :default => :spec
|
data/{doc → docs}/comparison.jpg
RENAMED
File without changes
|
data/laser-cutter.gemspec
CHANGED
@@ -22,9 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency 'hashie'
|
23
23
|
spec.add_dependency 'colored'
|
24
24
|
|
25
|
-
spec.add_development_dependency '
|
25
|
+
spec.add_development_dependency 'yard'
|
26
|
+
spec.add_development_dependency 'simplecov'
|
27
|
+
spec.add_development_dependency 'bundler'
|
26
28
|
spec.add_development_dependency 'rake'
|
27
29
|
spec.add_development_dependency 'rspec'
|
28
|
-
spec.add_development_dependency 'rspec-legacy_formatters'
|
29
|
-
spec.add_development_dependency 'codeclimate-test-reporter'
|
30
30
|
end
|
data/lib/laser-cutter/box.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
module Laser
|
2
3
|
module Cutter
|
3
|
-
# Note: this class badly needs refactoring and tests. Both are coming.
|
4
|
-
|
5
4
|
class Box
|
6
5
|
# Everything is in millimeters
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@dim, :w, :h, :d
|
7
8
|
|
8
9
|
attr_accessor :dim, :thickness, :notch_width, :kerf
|
9
10
|
attr_accessor :padding, :units, :inside_box
|
@@ -13,33 +14,43 @@ module Laser
|
|
13
14
|
attr_accessor :metadata, :notches
|
14
15
|
|
15
16
|
def initialize(config = {})
|
16
|
-
self.dim
|
17
|
+
self.dim = Geometry::Dimensions.new(config['width'], config['height'], config['depth'])
|
17
18
|
self.thickness = config['thickness']
|
18
19
|
|
19
20
|
self.notch_width = config['notch'] || (1.0 * self.longest / 5.0)
|
20
|
-
self.kerf
|
21
|
-
self.padding
|
22
|
-
self.units
|
23
|
-
self.inside_box
|
21
|
+
self.kerf = config['kerf'] || 0.0
|
22
|
+
self.padding = config['padding']
|
23
|
+
self.units = config['units']
|
24
|
+
self.inside_box = config['inside_box']
|
24
25
|
|
25
26
|
self.notches = []
|
26
27
|
|
27
28
|
self.metadata = Geometry::Point[config['metadata_width'] || 0, config['metadata_height'] || 0]
|
28
29
|
|
29
30
|
create_faces! # generates dimensions for each side
|
30
|
-
self.faces
|
31
|
-
|
32
|
-
self.conf
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
self.faces = [top, front, bottom, back, left, right]
|
32
|
+
|
33
|
+
self.conf = {
|
34
|
+
valign: [:out, :out, :out, :out, :in, :in],
|
35
|
+
halign: [:in, :out, :in, :out, :in, :in],
|
36
|
+
corners: {
|
37
|
+
top: [:yes, :no, :yes, :no, :no, :no], # 2nd choice, has to work if 1st doesn't
|
38
|
+
front: [:no, :yes, :no, :yes, :no, :no], # our default choice, but may not work
|
39
|
+
},
|
39
40
|
}
|
40
41
|
self
|
41
42
|
end
|
42
43
|
|
44
|
+
def generate_notches
|
45
|
+
position_faces!
|
46
|
+
self.corner_face = pick_corners_face
|
47
|
+
self.notches = []
|
48
|
+
faces.each_with_index do |face, face_index|
|
49
|
+
create_face_edges(face, face_index)
|
50
|
+
end
|
51
|
+
self.notches.flatten!
|
52
|
+
end
|
53
|
+
|
43
54
|
def enclosure
|
44
55
|
generate_notches if self.notches.empty?
|
45
56
|
p1 = notches.first.p1.to_a
|
@@ -47,55 +58,15 @@ module Laser
|
|
47
58
|
|
48
59
|
notches.each do |notch|
|
49
60
|
n = notch.normalized
|
50
|
-
n.p1.to_a.each_with_index {|c, i| p1[i] = c if c < p1[i]
|
51
|
-
n.p2.to_a.each_with_index {|c, i| p2[i] = c if c > p2[i]
|
61
|
+
n.p1.to_a.each_with_index {|c, i| p1[i] = c if c < p1[i]}
|
62
|
+
n.p2.to_a.each_with_index {|c, i| p2[i] = c if c > p2[i]}
|
52
63
|
end
|
53
64
|
|
54
65
|
Geometry::Rect[Geometry::Point.new(p1), Geometry::Point.new(p2)]
|
55
66
|
end
|
56
67
|
|
57
|
-
def generate_notches
|
58
|
-
position_faces!
|
59
|
-
corner_face = pick_corners_face
|
60
|
-
self.notches = []
|
61
|
-
faces.each_with_index do |face, face_index|
|
62
|
-
bound = face_bounding_rect(face)
|
63
|
-
side_lines = []
|
64
|
-
edges = []
|
65
|
-
bound.sides.each_with_index do |bounding_side, side_index |
|
66
|
-
include_corners = (self.conf[:corners][corner_face][face_index] == :yes && side_index.odd?)
|
67
|
-
key = side_index.odd? ? :valign : :halign
|
68
|
-
center_out = (self.conf[key][face_index] == :out)
|
69
|
-
edges << Notching::Edge.new(bounding_side, face.sides[side_index],
|
70
|
-
{:notch_width => notch_width,
|
71
|
-
:thickness => thickness,
|
72
|
-
:kerf => kerf,
|
73
|
-
:center_out => center_out,
|
74
|
-
:corners => include_corners
|
75
|
-
})
|
76
|
-
end
|
77
|
-
|
78
|
-
if edges.any?{|e| e.corners} && !edges.all?{|e| e.first_notch_out? }
|
79
|
-
edges.each {|e| e.adjust_corners = true }
|
80
|
-
end
|
81
|
-
|
82
|
-
edges.each do |edge|
|
83
|
-
side_lines << Notching::PathGenerator.new(edge).generate
|
84
|
-
end
|
85
|
-
|
86
|
-
aggregator = Aggregator.new(side_lines.flatten)
|
87
|
-
aggregator.dedup!.deoverlap!.dedup!
|
88
|
-
self.notches << aggregator.lines
|
89
|
-
end
|
90
|
-
self.notches.flatten!
|
91
|
-
end
|
92
|
-
|
93
|
-
def w; dim.w; end
|
94
|
-
def h; dim.h; end
|
95
|
-
def d; dim.d; end
|
96
|
-
|
97
68
|
def longest
|
98
|
-
[w, h, d].max
|
69
|
+
[w, h, d].max
|
99
70
|
end
|
100
71
|
|
101
72
|
def to_s
|
@@ -104,6 +75,37 @@ module Laser
|
|
104
75
|
|
105
76
|
private
|
106
77
|
|
78
|
+
def create_face_edges(face, face_index)
|
79
|
+
bound = face_bounding_rect(face)
|
80
|
+
|
81
|
+
side_lines = []
|
82
|
+
edges = []
|
83
|
+
bound.sides.each_with_index do |bounding_side, side_index|
|
84
|
+
include_corners = (self.conf[:corners][corner_face][face_index] == :yes && side_index.odd?)
|
85
|
+
key = side_index.odd? ? :valign : :halign
|
86
|
+
center_out = (self.conf[key][face_index] == :out)
|
87
|
+
edges << Notching::Edge.new(bounding_side, face.sides[side_index],
|
88
|
+
{ :notch_width => notch_width,
|
89
|
+
:thickness => thickness,
|
90
|
+
:kerf => kerf,
|
91
|
+
:center_out => center_out,
|
92
|
+
:corners => include_corners
|
93
|
+
})
|
94
|
+
end
|
95
|
+
|
96
|
+
if edges.any? {|e| e.corners} && !edges.all? {|e| e.first_notch_out?}
|
97
|
+
edges.each {|e| e.adjust_corners = true}
|
98
|
+
end
|
99
|
+
|
100
|
+
edges.each do |edge|
|
101
|
+
side_lines << Notching::PathGenerator.new(edge).generate
|
102
|
+
end
|
103
|
+
|
104
|
+
aggregator = Aggregator.new(side_lines.flatten)
|
105
|
+
aggregator.dedup!.deoverlap!.dedup!
|
106
|
+
self.notches << aggregator.lines
|
107
|
+
end
|
108
|
+
|
107
109
|
def face_bounding_rect(face)
|
108
110
|
b = face.clone
|
109
111
|
b.move_to(b.position.plus(-thickness, -thickness))
|
@@ -141,39 +143,39 @@ module Laser
|
|
141
143
|
left.x = offset_x - d - 2 * thickness - padding
|
142
144
|
right.x = offset_x + w + 2 * thickness + padding
|
143
145
|
|
144
|
-
[bottom, front, top, back].each {
|
146
|
+
[bottom, front, top, back].each {|s| s.x = offset_x}
|
145
147
|
|
146
148
|
# Y Coordinate
|
147
149
|
top.y = offset_y - d - 2 * thickness - padding
|
148
150
|
bottom.y = offset_y + h + 2 * thickness + padding
|
149
151
|
back.y = bottom.y + d + 2 * thickness + padding
|
150
152
|
|
151
|
-
[left, front, right].each {
|
153
|
+
[left, front, right].each {|s| s.y = offset_y}
|
152
154
|
|
153
155
|
faces.each(&:relocate!)
|
154
156
|
end
|
155
157
|
|
156
158
|
def create_faces!
|
157
|
-
zero
|
159
|
+
zero = Geometry::Point.new(0, 0)
|
158
160
|
self.front = Geometry::Rect.create(zero, dim.w, dim.h, "front")
|
159
|
-
self.back
|
161
|
+
self.back = Geometry::Rect.create(zero, dim.w, dim.h, "back")
|
160
162
|
|
161
|
-
self.top
|
163
|
+
self.top = Geometry::Rect.create(zero, dim.w, dim.d, "top")
|
162
164
|
self.bottom = Geometry::Rect.create(zero, dim.w, dim.d, "bottom")
|
163
165
|
|
164
|
-
self.left
|
166
|
+
self.left = Geometry::Rect.create(zero, dim.d, dim.h, "left")
|
165
167
|
self.right = Geometry::Rect.create(zero, dim.d, dim.h, "right")
|
166
168
|
end
|
167
169
|
|
168
170
|
# Choose which face will be responsible for filling out the little square overlap
|
169
171
|
# in the corners. Only one of the 3 possible sides need to be picked.
|
170
172
|
def pick_corners_face
|
171
|
-
b
|
173
|
+
b = face_bounding_rect(front)
|
172
174
|
edges = []
|
173
175
|
front.sides[0..1].each_with_index do |face, index|
|
174
|
-
edges << Notching::Edge.new(b.sides[index], face, :notch_width => notch_width, :kerf => kerf
|
176
|
+
edges << Notching::Edge.new(b.sides[index], face, :notch_width => notch_width, :kerf => kerf)
|
175
177
|
end
|
176
|
-
edges.map(&:notch_count).all?{|c| c % 4 == 3} ? :top : :front
|
178
|
+
edges.map(&:notch_count).all? {|c| c % 4 == 3} ? :top : :front
|
177
179
|
end
|
178
180
|
|
179
181
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Laser
|
3
|
+
module Cutter
|
4
|
+
# Note: this class badly needs refactoring and tests. Both are coming.
|
5
|
+
|
6
|
+
|
7
|
+
class Face
|
8
|
+
attr_accessor :edges, :rect
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :@rect, *((Geometry::Rect.new(Geometry::Point.new(0,0), Geometry::Point.new(1,1))).methods - Object.methods)
|
11
|
+
def initialize(rect, edges = [])
|
12
|
+
self.rect = rect
|
13
|
+
self.edges = edges
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -32,8 +32,8 @@ module Laser
|
|
32
32
|
self.notch_width = options[:notch_width]
|
33
33
|
self.adjust_corners = options[:adjust_corners]
|
34
34
|
|
35
|
-
adjust_for_kerf!
|
36
35
|
calculate_notch_width!
|
36
|
+
adjust_for_kerf!
|
37
37
|
end
|
38
38
|
|
39
39
|
def adjust_for_kerf!
|
@@ -68,11 +68,11 @@ module Laser
|
|
68
68
|
private
|
69
69
|
|
70
70
|
def calculate_notch_width!
|
71
|
-
|
72
|
-
count = (length / notch_width).to_f.ceil + 1
|
71
|
+
count = ((self.inside.length) / notch_width).to_f.ceil + 1
|
73
72
|
count = (count / 2 * 2) + 1 # make count always an odd number
|
74
73
|
count = [MINIMUM_NOTCHES_PER_SIDE, count].max
|
75
|
-
|
74
|
+
|
75
|
+
self.notch_width = 1.0 * (self.inside.length) / count
|
76
76
|
self.notch_count = count
|
77
77
|
end
|
78
78
|
|
@@ -32,6 +32,17 @@ module Laser
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# One of the key "tricks" that this algorithm applies, is that it converts everything into
|
36
|
+
# pure set of lines in the end. It then tries to find all intersections of the lines so that
|
37
|
+
# we can remove duplicates. So any segment of any line that is covered by 2 lines or more is removed,
|
38
|
+
# cleared completely for an empty space. This turns out to be very useful indeed, because we can
|
39
|
+
# paint with wide brush strokes to get the carcass, and then fine tune it by adding or removing line
|
40
|
+
# segments. Some of the lines below are added to actually remove the lines that might have otherwise
|
41
|
+
# been there.
|
42
|
+
#
|
43
|
+
# This comes especially handy when drawing corner boxes, which are deliberately made not to match the notch
|
44
|
+
# width, but to match thickness of the material. The corner notces for these sides will therefore have
|
45
|
+
# length equal to the thickness + regular notch length.
|
35
46
|
class PathGenerator
|
36
47
|
|
37
48
|
extend ::Forwardable
|
@@ -84,81 +95,23 @@ module Laser
|
|
84
95
|
end
|
85
96
|
end
|
86
97
|
|
98
|
+
# These two boxes occupy the corners of the 3D box. They do not match
|
99
|
+
# in width to our notches because they are usually merged with them. Their
|
100
|
+
# size is equal to the thickness of the material (adjusted for kerf)
|
101
|
+
# It's just an aesthetic choice I guess.
|
87
102
|
def corner_box_sides
|
88
103
|
boxes = []
|
89
104
|
extra_lines = []
|
90
|
-
sides = []
|
91
105
|
|
92
|
-
# These two boxes occupy the corners of the 3D box. They do not match
|
93
|
-
# in width to our notches because they are usually merged with them.
|
94
|
-
# It's just an aesthetic choice I guess.
|
95
106
|
boxes << Geometry::Rect[edge.inside.p1.clone, edge.outside.p1.clone]
|
96
107
|
boxes << Geometry::Rect[edge.inside.p2.clone, edge.outside.p2.clone]
|
97
108
|
|
98
|
-
if kerf?
|
99
|
-
if adjust_corners
|
100
|
-
if first_notch_out?
|
101
|
-
k = 2
|
102
|
-
direction = -1
|
103
|
-
dim_index = 1
|
104
|
-
extra_lines << add_corners_when_out(dim_index, direction, k)
|
105
|
-
else
|
106
|
-
k = -2
|
107
|
-
direction = 1
|
108
|
-
dim_index = 0
|
109
|
-
extra_lines << add_boxes_when_in(dim_index, direction, k)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
109
|
+
extra_lines << add_corners if adjust_corners && kerf?
|
113
110
|
sides = boxes.flatten.map(&:relocate!).map(&:sides)
|
114
111
|
sides << extra_lines if !extra_lines.empty?
|
115
112
|
sides.flatten
|
116
113
|
end
|
117
114
|
|
118
|
-
def add_boxes_when_in(dim_index, direction, k)
|
119
|
-
v1 = k * direction * shift_vector(1, dim_index)
|
120
|
-
v2 = k * direction * shift_vector(2, dim_index)
|
121
|
-
p1 = edge.inside.p1.plus(v1)
|
122
|
-
coords = []
|
123
|
-
coords[d_index_along] = edge.inside.p1[d_index_along]
|
124
|
-
coords[d_index_across] = edge.outside.p1[d_index_across]
|
125
|
-
p2 = Geometry::Point[*coords]
|
126
|
-
r1 = Geometry::Rect[p1, p2]
|
127
|
-
|
128
|
-
p1 = edge.inside.p2.plus(v2)
|
129
|
-
coords = []
|
130
|
-
coords[d_index_along] = edge.inside.p2[d_index_along]
|
131
|
-
coords[d_index_across] = edge.outside.p2[d_index_across]
|
132
|
-
p2 = Geometry::Point[*coords]
|
133
|
-
r2 = Geometry::Rect[p1, p2]
|
134
|
-
lines = [r1, r2].map(&:sides).flatten
|
135
|
-
lines << Geometry::Line[edge.inside.p1.plus(v1), edge.inside.p1.clone]
|
136
|
-
lines << Geometry::Line[edge.inside.p2.plus(v2), edge.inside.p2.clone]
|
137
|
-
lines
|
138
|
-
end
|
139
|
-
|
140
|
-
def add_corners_when_out(dim_index, direction, k)
|
141
|
-
v1 = direction * k * shift_vector(1, dim_index)
|
142
|
-
v2 = direction * k * shift_vector(2, dim_index)
|
143
|
-
p1 = edge.inside.p1.plus(v1)
|
144
|
-
coords = []
|
145
|
-
coords[d_index_along] = edge.outside.p1[d_index_along]
|
146
|
-
coords[d_index_across] = edge.inside.p1[d_index_across]
|
147
|
-
p2 = Geometry::Point[*coords]
|
148
|
-
r1 = Geometry::Rect[p1, p2]
|
149
|
-
|
150
|
-
p1 = edge.inside.p2.plus(v2)
|
151
|
-
coords = []
|
152
|
-
coords[d_index_along] = edge.outside.p2[d_index_along]
|
153
|
-
coords[d_index_across] = edge.inside.p2[d_index_across]
|
154
|
-
p2 = Geometry::Point[*coords]
|
155
|
-
r2 = Geometry::Rect[p1, p2]
|
156
|
-
lines = [r1, r2].map(&:sides).flatten
|
157
|
-
lines << Geometry::Line[edge.inside.p1.plus(v1), edge.inside.p1.clone]
|
158
|
-
lines << Geometry::Line[edge.inside.p2.plus(v2), edge.inside.p2.clone]
|
159
|
-
lines
|
160
|
-
end
|
161
|
-
|
162
115
|
def shift_vector(index, dim_shift = 0)
|
163
116
|
shift = []
|
164
117
|
shift[(d_index_across + dim_shift) % 2] = 0
|
@@ -189,6 +142,38 @@ module Laser
|
|
189
142
|
end
|
190
143
|
|
191
144
|
private
|
145
|
+
# Helper method to calculate dimensions of our corners.
|
146
|
+
def add_corners
|
147
|
+
k, direction, dim_index, edge_along, edge_across = if first_notch_out?
|
148
|
+
[2, -1, 1, :inside, :outside]
|
149
|
+
else
|
150
|
+
[-2, 1, 0, :outside, :inside]
|
151
|
+
end
|
152
|
+
v1 = direction * k * shift_vector(1, dim_index)
|
153
|
+
v2 = direction * k * shift_vector(2, dim_index)
|
154
|
+
|
155
|
+
r1 = define_corner_rect(:p1, v1, edge_along, edge_across)
|
156
|
+
r2 = define_corner_rect(:p2, v2, edge_along, edge_across)
|
157
|
+
|
158
|
+
lines = [r1, r2].map(&:sides).flatten
|
159
|
+
|
160
|
+
# Our clever algorithm removes automatically duplicate lines. These lines
|
161
|
+
# below are added to actually clear out this space and remove the existing
|
162
|
+
# lines that are already there.
|
163
|
+
lines << Geometry::Line[edge.inside.p1.plus(v1), edge.inside.p1.clone]
|
164
|
+
lines << Geometry::Line[edge.inside.p2.plus(v2), edge.inside.p2.clone]
|
165
|
+
lines
|
166
|
+
end
|
167
|
+
|
168
|
+
def define_corner_rect(point, delta, edge_along, edge_across)
|
169
|
+
p1 = edge.inside.send(point).plus(delta)
|
170
|
+
coords = []
|
171
|
+
coords[d_index_along] = edge.send(edge_along).send(point)[d_index_along]
|
172
|
+
coords[d_index_across] = edge.send(edge_across).send(point)[d_index_across]
|
173
|
+
p2 = Geometry::Point[*coords]
|
174
|
+
Geometry::Rect[p1, p2]
|
175
|
+
end
|
176
|
+
|
192
177
|
|
193
178
|
# This method has the bulk of the logic: we create the list of path deltas
|
194
179
|
# to be applied when we walk the edge next.
|
data/lib/laser-cutter/version.rb
CHANGED
data/spec/box_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -5,16 +5,12 @@
|
|
5
5
|
#
|
6
6
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
7
|
|
8
|
-
if ENV['CODECLIMATE_REPO_TOKEN']
|
9
|
-
require 'codeclimate-test-reporter'
|
10
|
-
CodeClimate::TestReporter.start
|
11
|
-
end
|
12
|
-
|
13
8
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
|
14
9
|
require 'rubygems'
|
15
10
|
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
11
|
+
require 'simplecov'
|
12
|
+
SimpleCov.start
|
16
13
|
require 'laser-cutter'
|
17
|
-
require "codeclimate-test-reporter"
|
18
14
|
|
19
15
|
|
20
16
|
|
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: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Gredeskoul
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|
@@ -53,21 +53,21 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: yard
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: simplecov
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: bundler
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- ".gitignore"
|
137
137
|
- ".rspec"
|
138
138
|
- ".travis.yml"
|
139
|
+
- BOXMAKER.md
|
139
140
|
- CONTRIBUTING.md
|
140
141
|
- Gemfile
|
141
142
|
- LICENSE
|
@@ -143,7 +144,7 @@ files:
|
|
143
144
|
- README.md
|
144
145
|
- Rakefile
|
145
146
|
- bin/laser-cutter
|
146
|
-
-
|
147
|
+
- docs/comparison.jpg
|
147
148
|
- laser-cutter.gemspec
|
148
149
|
- lib/laser-cutter.rb
|
149
150
|
- lib/laser-cutter/aggregator.rb
|
@@ -151,6 +152,7 @@ files:
|
|
151
152
|
- lib/laser-cutter/cli/opt_parser.rb
|
152
153
|
- lib/laser-cutter/cli/serializer.rb
|
153
154
|
- lib/laser-cutter/configuration.rb
|
155
|
+
- lib/laser-cutter/face.rb
|
154
156
|
- lib/laser-cutter/geometry.rb
|
155
157
|
- lib/laser-cutter/geometry/dimensions.rb
|
156
158
|
- lib/laser-cutter/geometry/point.rb
|
@@ -159,7 +161,6 @@ files:
|
|
159
161
|
- lib/laser-cutter/geometry/shape/rect.rb
|
160
162
|
- lib/laser-cutter/geometry/tuple.rb
|
161
163
|
- lib/laser-cutter/notching.rb
|
162
|
-
- lib/laser-cutter/notching/base.rb
|
163
164
|
- lib/laser-cutter/notching/edge.rb
|
164
165
|
- lib/laser-cutter/notching/path_generator.rb
|
165
166
|
- lib/laser-cutter/page_manager.rb
|
@@ -203,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
204
|
version: '0'
|
204
205
|
requirements: []
|
205
206
|
rubyforge_project:
|
206
|
-
rubygems_version: 2.
|
207
|
+
rubygems_version: 2.6.11
|
207
208
|
signing_key:
|
208
209
|
specification_version: 4
|
209
210
|
summary: Creates notched box outlines for laser-cut boxes which are geometrically
|
@@ -221,4 +222,3 @@ test_files:
|
|
221
222
|
- spec/rect_spec.rb
|
222
223
|
- spec/renderer_spec.rb
|
223
224
|
- spec/spec_helper.rb
|
224
|
-
has_rdoc:
|