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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/README.md +20 -16
  4. data/bin/laser-cutter +4 -158
  5. data/lib/laser-cutter.rb +2 -0
  6. data/lib/laser-cutter/aggregator.rb +57 -0
  7. data/lib/laser-cutter/box.rb +37 -24
  8. data/lib/laser-cutter/cli/opt_parser.rb +131 -0
  9. data/lib/laser-cutter/cli/serializer.rb +51 -0
  10. data/lib/laser-cutter/configuration.rb +3 -2
  11. data/lib/laser-cutter/geometry.rb +0 -3
  12. data/lib/laser-cutter/geometry/dimensions.rb +3 -3
  13. data/lib/laser-cutter/geometry/point.rb +0 -46
  14. data/lib/laser-cutter/geometry/shape/line.rb +40 -1
  15. data/lib/laser-cutter/geometry/shape/rect.rb +2 -2
  16. data/lib/laser-cutter/geometry/tuple.rb +73 -27
  17. data/lib/laser-cutter/notching.rb +10 -0
  18. data/lib/laser-cutter/notching/base.rb +13 -0
  19. data/lib/laser-cutter/notching/edge.rb +87 -0
  20. data/lib/laser-cutter/notching/path_generator.rb +249 -0
  21. data/lib/laser-cutter/renderer/base.rb +1 -1
  22. data/lib/laser-cutter/renderer/box_renderer.rb +2 -2
  23. data/lib/laser-cutter/renderer/layout_renderer.rb +19 -8
  24. data/lib/laser-cutter/renderer/meta_renderer.rb +8 -9
  25. data/lib/laser-cutter/version.rb +1 -1
  26. data/spec/aggregator_spec.rb +65 -0
  27. data/spec/box_spec.rb +5 -1
  28. data/spec/dimensions_spec.rb +0 -1
  29. data/spec/edge_spec.rb +43 -0
  30. data/spec/line_spec.rb +42 -19
  31. data/spec/path_generator_spec.rb +30 -36
  32. data/spec/point_spec.rb +2 -2
  33. data/spec/rect_spec.rb +1 -1
  34. data/spec/renderer_spec.rb +14 -5
  35. metadata +13 -5
  36. data/lib/laser-cutter/geometry/edge.rb +0 -33
  37. data/lib/laser-cutter/geometry/notched_path.rb +0 -46
  38. data/lib/laser-cutter/geometry/path_generator.rb +0 -129
@@ -1,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