laser-cutter 0.5.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +20 -16
- data/bin/laser-cutter +4 -158
- data/lib/laser-cutter.rb +2 -0
- data/lib/laser-cutter/aggregator.rb +57 -0
- data/lib/laser-cutter/box.rb +37 -24
- data/lib/laser-cutter/cli/opt_parser.rb +131 -0
- data/lib/laser-cutter/cli/serializer.rb +51 -0
- data/lib/laser-cutter/configuration.rb +3 -2
- data/lib/laser-cutter/geometry.rb +0 -3
- data/lib/laser-cutter/geometry/dimensions.rb +3 -3
- data/lib/laser-cutter/geometry/point.rb +0 -46
- data/lib/laser-cutter/geometry/shape/line.rb +40 -1
- data/lib/laser-cutter/geometry/shape/rect.rb +2 -2
- data/lib/laser-cutter/geometry/tuple.rb +73 -27
- data/lib/laser-cutter/notching.rb +10 -0
- data/lib/laser-cutter/notching/base.rb +13 -0
- data/lib/laser-cutter/notching/edge.rb +87 -0
- data/lib/laser-cutter/notching/path_generator.rb +249 -0
- data/lib/laser-cutter/renderer/base.rb +1 -1
- data/lib/laser-cutter/renderer/box_renderer.rb +2 -2
- data/lib/laser-cutter/renderer/layout_renderer.rb +19 -8
- data/lib/laser-cutter/renderer/meta_renderer.rb +8 -9
- data/lib/laser-cutter/version.rb +1 -1
- data/spec/aggregator_spec.rb +65 -0
- data/spec/box_spec.rb +5 -1
- data/spec/dimensions_spec.rb +0 -1
- data/spec/edge_spec.rb +43 -0
- data/spec/line_spec.rb +42 -19
- data/spec/path_generator_spec.rb +30 -36
- data/spec/point_spec.rb +2 -2
- data/spec/rect_spec.rb +1 -1
- data/spec/renderer_spec.rb +14 -5
- metadata +13 -5
- data/lib/laser-cutter/geometry/edge.rb +0 -33
- data/lib/laser-cutter/geometry/notched_path.rb +0 -46
- data/lib/laser-cutter/geometry/path_generator.rb +0 -129
@@ -1,33 +0,0 @@
|
|
1
|
-
module Laser
|
2
|
-
module Cutter
|
3
|
-
module Geometry
|
4
|
-
# This class represents a single edge of one side: both inside
|
5
|
-
# and outside edge of the material. It's also responsible
|
6
|
-
# for calculating the "perfect" notch width.
|
7
|
-
class Edge < Struct.new(:outside, :inside, :notch_width)
|
8
|
-
attr_accessor :notch_count
|
9
|
-
|
10
|
-
def initialize(*args)
|
11
|
-
super(*args)
|
12
|
-
adjust_notch(self.inside)
|
13
|
-
end
|
14
|
-
|
15
|
-
def adjust_notch(line)
|
16
|
-
d = (line.length / notch_width).to_f.ceil
|
17
|
-
pairs = d / 2
|
18
|
-
d = pairs * 2 + 1
|
19
|
-
d = MINIMUM_NOTCHES_PER_SIDE if d < MINIMUM_NOTCHES_PER_SIDE
|
20
|
-
self.notch_width = line.length / (1.0 * d)
|
21
|
-
self.notch_count = d
|
22
|
-
end
|
23
|
-
|
24
|
-
# face_setting determines if we want that face to have center notch
|
25
|
-
# facing out (for a hole, etc). This works well when we have odd number
|
26
|
-
# of notches, but
|
27
|
-
def add_across_line?(face_setting)
|
28
|
-
notch_count % 4 == 1 ? face_setting : !face_setting
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Laser
|
2
|
-
module Cutter
|
3
|
-
module Geometry
|
4
|
-
class NotchedPath
|
5
|
-
attr_accessor :lines, :vertices, :corner_boxes
|
6
|
-
def initialize(vertices = [])
|
7
|
-
@vertices = vertices
|
8
|
-
@lines = []
|
9
|
-
@corner_boxes = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def << value
|
13
|
-
self.vertices << value
|
14
|
-
end
|
15
|
-
|
16
|
-
def [] value
|
17
|
-
self.vertices[value]
|
18
|
-
end
|
19
|
-
|
20
|
-
def size
|
21
|
-
self.vertices.size
|
22
|
-
end
|
23
|
-
|
24
|
-
def create_lines
|
25
|
-
self.lines = []
|
26
|
-
self.vertices.each_with_index do |v, i|
|
27
|
-
if v != vertices.last
|
28
|
-
self.lines << Line.new(v, vertices[i+1])
|
29
|
-
end
|
30
|
-
end
|
31
|
-
self.corner_boxes.each do |box|
|
32
|
-
box.relocate!
|
33
|
-
self.lines << box.sides
|
34
|
-
end
|
35
|
-
|
36
|
-
self.lines.flatten!
|
37
|
-
self.lines
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
@@ -1,129 +0,0 @@
|
|
1
|
-
require_relative 'notched_path'
|
2
|
-
|
3
|
-
module Laser
|
4
|
-
module Cutter
|
5
|
-
module Geometry
|
6
|
-
class Shift < Struct.new(:delta, :direction, :dim_index)
|
7
|
-
POINTERS = {[1, 0] => ' ->',
|
8
|
-
[-1, 0] => '<- ',
|
9
|
-
[1, 1] => ' V ',
|
10
|
-
[-1, 1] => ' ^ '}
|
11
|
-
|
12
|
-
def next(point1)
|
13
|
-
p = Point.new(point1.to_a)
|
14
|
-
p.coords[dim_index] += (delta * direction)
|
15
|
-
p
|
16
|
-
end
|
17
|
-
def to_s
|
18
|
-
"shift by:#{sprintf('%.2f', delta)}, #{POINTERS[[direction,dim_index]]}"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Alternating iterator
|
23
|
-
class InfiniteIterator < Struct.new(:shift_array)
|
24
|
-
attr_accessor :current_index
|
25
|
-
def next
|
26
|
-
self.current_index = -1 if current_index.nil?
|
27
|
-
self.current_index += 1
|
28
|
-
self.current_index = current_index % shift_array.size
|
29
|
-
shift_array[current_index]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class PathGenerator
|
34
|
-
# Removes the items from the list that appear more than once
|
35
|
-
# Unlike uniq-ing which keeps all elements, just ensures that are not
|
36
|
-
# repeated, here we remove elements completely if they are seen more than once.
|
37
|
-
# This is used to remove lines that join the same two points.
|
38
|
-
def self.deduplicate list
|
39
|
-
new_list = []
|
40
|
-
list.sort!
|
41
|
-
list.each_with_index do |e, i|
|
42
|
-
next if i < (list.size - 1) && e.eql?(list[i + 1])
|
43
|
-
next if i > 0 && e.eql?(list[i - 1])
|
44
|
-
new_list << e
|
45
|
-
end
|
46
|
-
new_list
|
47
|
-
end
|
48
|
-
|
49
|
-
attr_accessor :notch_width, :thickness
|
50
|
-
attr_accessor :center_out, :fill_corners
|
51
|
-
|
52
|
-
def initialize(options = {})
|
53
|
-
@notch_width = options[:notch_width] # only desired, will be adapted for each line
|
54
|
-
@center_out = options[:center_out] # when true, the notch in the middle of the edge is out, not in.
|
55
|
-
@thickness = options[:thickness]
|
56
|
-
@fill_corners = options[:fill_corners]
|
57
|
-
end
|
58
|
-
|
59
|
-
# Calculates a notched path that flows between the outer edge of the box
|
60
|
-
# (outside_line) and inner (inside_line). Relative location of these lines
|
61
|
-
# also defines the direction and orientation of the box, and hence the notches.
|
62
|
-
#
|
63
|
-
# We always want to create a symmetric path that has a notch in the middle
|
64
|
-
# (for center_out = true) or dip in the middle (center_out = false)
|
65
|
-
def path(edge)
|
66
|
-
shifts = define_shifts(edge)
|
67
|
-
|
68
|
-
path = NotchedPath.new
|
69
|
-
|
70
|
-
if fill_corners
|
71
|
-
r1 = Geometry::Rect.new(edge.inside.p1, edge.outside.p1)
|
72
|
-
r2 = Geometry::Rect.new(edge.inside.p2, edge.outside.p2)
|
73
|
-
path.corner_boxes << r1
|
74
|
-
path.corner_boxes << r2
|
75
|
-
end
|
76
|
-
|
77
|
-
point = edge.inside.p1.clone
|
78
|
-
vertices = [point]
|
79
|
-
shifts.each do |shift|
|
80
|
-
point = shift.next(point)
|
81
|
-
vertices << point
|
82
|
-
end
|
83
|
-
path.vertices = vertices
|
84
|
-
path
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
# This method has the bulk of the logic: we create the list of path deltas
|
90
|
-
# to be applied when we walk the edge next.
|
91
|
-
def define_shifts(edge)
|
92
|
-
along_iterator, across_iterator = define_shift_iterators(edge)
|
93
|
-
shifts = []
|
94
|
-
|
95
|
-
shifts << across_iterator.next if edge.add_across_line?(center_out)
|
96
|
-
|
97
|
-
(1..edge.notch_count).to_a.each do |count|
|
98
|
-
shifts << along_iterator.next
|
99
|
-
shifts << across_iterator.next unless count == edge.notch_count
|
100
|
-
end
|
101
|
-
|
102
|
-
shifts << across_iterator.next if edge.add_across_line?(center_out)
|
103
|
-
shifts
|
104
|
-
end
|
105
|
-
|
106
|
-
# As we draw notches, shifts define the 'delta' – movement from one point
|
107
|
-
# to the next. This method defines three types of movements we'll be doing:
|
108
|
-
# one alongside the edge, and two across (towards the box and outward from the box)
|
109
|
-
def define_shift_iterators(edge)
|
110
|
-
alongside_dimension = (edge.inside.p1.x == edge.inside.p2.x) ? 1 : 0
|
111
|
-
alongside_direction = (edge.inside.p1.coords[alongside_dimension] <
|
112
|
-
edge.inside.p2.coords[alongside_dimension]) ? 1 : -1
|
113
|
-
|
114
|
-
across_dimension = (alongside_dimension + 1) % 2
|
115
|
-
across_direction = (edge.inside.p1.coords[across_dimension] >
|
116
|
-
edge.outside.p1.coords[across_dimension]) ? -1 : 1
|
117
|
-
|
118
|
-
[
|
119
|
-
InfiniteIterator.new(
|
120
|
-
[Shift.new(edge.notch_width, alongside_direction, alongside_dimension)]),
|
121
|
-
InfiniteIterator.new(
|
122
|
-
[Shift.new(thickness, across_direction, across_dimension),
|
123
|
-
Shift.new(thickness, -across_direction, across_dimension)])
|
124
|
-
]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|