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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b027c579de8cded3aba462a120045ed6ec685930
4
- data.tar.gz: 76e13dddecbae505385b1064cb29198c7a0a5d41
3
+ metadata.gz: 3a3d7b723ed7171e84a93783545f037adeeeb122
4
+ data.tar.gz: d3571947154cda05176e1d1bbb84d8d2ee140c02
5
5
  SHA512:
6
- metadata.gz: 843bd8781e86f9da4d6bee52529f625d7b04f177c1a3bf50847b33a51bcb938ce6310faf10b1f0bee57de4d21ee36427515ddfc1529e0c933f21ca268e842091
7
- data.tar.gz: 337ae8d3ebe98ce3dc4380ef65a81c9172eb75ae7f799f60db35f228b2bd6713b525c6898c67dbff00da8de8ecd8adac8cff0d14e9d2d22c23e0598744f40294
6
+ metadata.gz: 870c36a4b07b2d4190076c524917f4322d599c58f5ff9b226b47e00a011dd63f722a7153ed885c192cbe0caefbda17fb150269a7822f4e36a001f4913a435d19
7
+ data.tar.gz: 67c264109139865d62292cb8cea2573ec5dbc569fec92316b00a14f942c0ea15d096d0391d1a5a275e3eaf78c7f9f8f179e95331f93859df982f7c7a80589e08
data/.gitignore CHANGED
@@ -25,3 +25,4 @@ mkmf.log
25
25
  .idea/
26
26
  **output.pdf
27
27
  .ruby_version
28
+ doc
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --color
2
2
  --format progress
3
- --require rspec/legacy_formatters
@@ -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
- - 2.1.3
4
- script: "CODECLIMATE_REPO_TOKEN=6520104decf84e2f6c2c169d30d67976bfcdaa48cd89b4ec34f6e637f2a0ae02 bundle exec rspec"
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
- email:
7
- recipients:
8
- - kigster@gmail.com
9
- on_success: never
10
- on_failure: always
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
@@ -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
- [![Code Climate](https://codeclimate.com/github/kigster/laser-cutter.png)](https://codeclimate.com/github/kigster/laser-cutter)
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
- ## LaserCutter and Make-A-Box.io
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
- ```laser-cutter``` is a ruby library for generating PDF designs for boxes of
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
- To use ```laser-cutter``` you need to have a recent version of ruby interpreter,
14
- install it as a gem, and use command line to generate PDFs.
13
+ # LaserCutter
15
14
 
16
- [Make-A-Box](http://makeabox.io) is a online web application that uses ```laser-cutter``` library
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
- Use whatever suites you better.
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
- ### Design Goals
21
+ Use whatever suites you better.
23
22
 
24
- One of the design goals of this project is to provide a highly extensible platform for creating
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 yourself as:
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.007in)
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
- ### Examples
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/[my-github-username]/laser-cutter/fork )
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 "bundler/gem_tasks"
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
File without changes
@@ -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 'bundler', "~> 1.6"
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
@@ -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 = Geometry::Dimensions.new(config['width'], config['height'], config['depth'])
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 = config['kerf'] || 0.0
21
- self.padding = config['padding']
22
- self.units = config['units']
23
- self.inside_box = config['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 = [top, front, bottom, back, left, right]
31
-
32
- self.conf = {
33
- valign: [ :out, :out, :out, :out, :in, :in],
34
- halign: [ :in, :out, :in, :out, :in, :in],
35
- corners: {
36
- front: [ :no, :yes, :no, :yes, :no, :no], # our default choice, but may not work
37
- top: [ :yes, :no, :yes, :no, :no, :no] # 2nd choice, has to work if 1st doesn't
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 { |s| s.x = offset_x }
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 { |s| s.y = offset_y }
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 = Geometry::Point.new(0, 0)
159
+ zero = Geometry::Point.new(0, 0)
158
160
  self.front = Geometry::Rect.create(zero, dim.w, dim.h, "front")
159
- self.back = Geometry::Rect.create(zero, dim.w, dim.h, "back")
161
+ self.back = Geometry::Rect.create(zero, dim.w, dim.h, "back")
160
162
 
161
- self.top = Geometry::Rect.create(zero, dim.w, dim.d, "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 = Geometry::Rect.create(zero, dim.d, dim.h, "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 = face_bounding_rect(front)
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
@@ -5,6 +5,5 @@ module Laser
5
5
  end
6
6
  end
7
7
 
8
- require_relative 'notching/base'
9
8
  require_relative 'notching/edge'
10
9
  require_relative 'notching/path_generator'
@@ -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
- length = kerf? ? self.inside.length - kerf : self.inside.length
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
- self.notch_width = 1.0 * length / count
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.
@@ -1,5 +1,5 @@
1
1
  module Laser
2
2
  module Cutter
3
- VERSION = "1.0.3"
3
+ VERSION = '1.0.5'
4
4
  end
5
5
  end
@@ -34,7 +34,6 @@ module Laser
34
34
  expect(box2.enclosure.to_a.flatten.map(&:round)).to eql([0,0, 232, 317])
35
35
  end
36
36
  end
37
-
38
37
  end
39
38
  end
40
39
  end
@@ -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.3
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: 2014-11-01 00:00:00.000000000 Z
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: bundler
56
+ name: yard
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.6'
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: '1.6'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake
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: rspec
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: rspec-legacy_formatters
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: codeclimate-test-reporter
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
- - doc/comparison.jpg
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.2.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:
@@ -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