box_packer 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9bd4f81789b4f8f8dc272b4893f2ce1aaf5bf174
4
- data.tar.gz: 2cbf0f36b648dc9d90872f17a118347fe6ad1d9c
3
+ metadata.gz: f008c3a427610279ae4435799857cd9a56365f64
4
+ data.tar.gz: 7f04c88fa47c529b0a8f5038bdad6ec01f5525b9
5
5
  SHA512:
6
- metadata.gz: 69dfe26e637c5f2fbd885af2949978cc5e7af0451c182a2ed7825d291c95e3780f81a7beb79ecb1f2f1d5aef2e273db51e8c4fdaf0260926504786166da79e90
7
- data.tar.gz: ed7bf4a3b8f79fabbc84d1ea23ecbd583a6885c65aa2877cb721bfc811f0c0702244b27a4cde5c671b45d7eaa9c81cea3cbb513e727d933edc3ecf2e661d2b9b
6
+ metadata.gz: 294483a8bfb5b9c1f43556664cccfc2a8e8d3ec2a88e3f26a6934c4e7b07099154bf9b0b652008b03109ecf63032b6217e19dd67e9b129221e69c802a90f892a
7
+ data.tar.gz: 8ca0891dbed70a3bdc51ce0d7b55768d6e8525d91b5ff85fb202a36f5d0190b9f131a802417bd125eb2eb26d48ba63d78d888bba45a202ecf3eb6f58211e231a
data/README.md CHANGED
@@ -90,4 +90,23 @@ BoxPacker.builder do |b|
90
90
  # | Item| 4x1x1 (17,0,0) Volume:4
91
91
 
92
92
  end
93
- ```
93
+ ```
94
+
95
+ Export SVG
96
+ ----------
97
+
98
+ ``` ruby
99
+ BoxPacker.container [3, 4, 2] do
100
+ add_item [1,3,2], label: 'Bag', colour: 'red'
101
+ add_item [3,3,1], label: 'Hat', colour: 'blue'
102
+ add_item [1,2,2], label: 'Shoes', colour: 'green'
103
+ add_item [3,1,1], label: 'Slipper', colour: 'purple'
104
+ add_item [2,1,1], label: 'Dragon', colour: 'orange'
105
+ pack!
106
+ draw!('examples/example', scale_longest_side_to: 500, margin: 15)
107
+ end
108
+ ```
109
+
110
+ Output:
111
+
112
+ ![SVG Output](https://rawgit.com/mushishi78/box_packer/master/examples/example1.svg)
data/box_packer.gemspec CHANGED
@@ -22,5 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rspec'
23
23
 
24
24
  spec.add_dependency 'attr_extras'
25
+ spec.add_dependency 'rasem'
25
26
 
26
27
  end
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg width="1045.0" height="1185.0" version="1.1"
5
+ xmlns="http://www.w3.org/2000/svg">
6
+ <rect x="15" y="15" width="500.0" height="375.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="15.0" y="15.0" width="375.0" height="375.0" rx="0" ry="0" style="fill:blue;"/><text x="199.5" y="202.5" style="fill:black;"><tspan x="199.5" dy="0em">Hat</tspan></text><rect x="390.0" y="15.0" width="125.0" height="250.0" rx="0" ry="0" style="fill:green;"/><text x="447.5" y="140.0" style="fill:black;"><tspan x="447.5" dy="0em">Shoes</tspan></text><rect x="390.0" y="265.0" width="125.0" height="125.0" rx="0" ry="0" style="fill:orange;"/><text x="446.5" y="327.5" style="fill:black;"><tspan x="446.5" dy="0em">Dragon</tspan></text><rect x="15.0" y="15.0" width="375.0" height="250.0" rx="0" ry="0" style="fill:red;"/><text x="199.5" y="140.0" style="fill:black;"><tspan x="199.5" dy="0em">Bag</tspan></text><rect x="15.0" y="265.0" width="375.0" height="125.0" rx="0" ry="0" style="fill:purple;"/><text x="195.5" y="327.5" style="fill:black;"><tspan x="195.5" dy="0em">Slipper</tspan></text><rect x="530.0" y="15" width="500.0" height="375.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="530.0" y="265.0" width="375.0" height="125.0" rx="0" ry="0" style="fill:purple;"/><text x="710.5" y="327.5" style="fill:black;"><tspan x="710.5" dy="0em">Slipper</tspan></text><rect x="530.0" y="15.0" width="375.0" height="250.0" rx="0" ry="0" style="fill:red;"/><text x="714.5" y="140.0" style="fill:black;"><tspan x="714.5" dy="0em">Bag</tspan></text><rect x="905.0" y="265.0" width="125.0" height="125.0" rx="0" ry="0" style="fill:orange;"/><text x="961.5" y="327.5" style="fill:black;"><tspan x="961.5" dy="0em">Dragon</tspan></text><rect x="905.0" y="15.0" width="125.0" height="250.0" rx="0" ry="0" style="fill:green;"/><text x="962.5" y="140.0" style="fill:black;"><tspan x="962.5" dy="0em">Shoes</tspan></text><rect x="530.0" y="15.0" width="375.0" height="375.0" rx="0" ry="0" style="fill:blue;"/><text x="714.5" y="202.5" style="fill:black;"><tspan x="714.5" dy="0em">Hat</tspan></text><rect x="15" y="405.0" width="375.0" height="250.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="15.0" y="405.0" width="375.0" height="125.0" rx="0" ry="0" style="fill:blue;"/><text x="199.5" y="467.5" style="fill:black;"><tspan x="199.5" dy="0em">Hat</tspan></text><rect x="15.0" y="530.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:red;"/><text x="137.0" y="592.5" style="fill:black;"><tspan x="137.0" dy="0em">Bag</tspan></text><rect x="265.0" y="530.0" width="125.0" height="125.0" rx="0" ry="0" style="fill:purple;"/><text x="320.5" y="592.5" style="fill:black;"><tspan x="320.5" dy="0em">Slipper</tspan></text><rect x="15.0" y="405.0" width="250.0" height="250.0" rx="0" ry="0" style="fill:green;"/><text x="135.0" y="530.0" style="fill:black;"><tspan x="135.0" dy="0em">Shoes</tspan></text><rect x="265.0" y="405.0" width="125.0" height="250.0" rx="0" ry="0" style="fill:orange;"/><text x="321.5" y="530.0" style="fill:black;"><tspan x="321.5" dy="0em">Dragon</tspan></text><rect x="405.0" y="405.0" width="375.0" height="250.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="655.0" y="405.0" width="125.0" height="250.0" rx="0" ry="0" style="fill:orange;"/><text x="711.5" y="530.0" style="fill:black;"><tspan x="711.5" dy="0em">Dragon</tspan></text><rect x="405.0" y="405.0" width="250.0" height="250.0" rx="0" ry="0" style="fill:green;"/><text x="525.0" y="530.0" style="fill:black;"><tspan x="525.0" dy="0em">Shoes</tspan></text><rect x="655.0" y="530.0" width="125.0" height="125.0" rx="0" ry="0" style="fill:purple;"/><text x="710.5" y="592.5" style="fill:black;"><tspan x="710.5" dy="0em">Slipper</tspan></text><rect x="405.0" y="530.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:red;"/><text x="527.0" y="592.5" style="fill:black;"><tspan x="527.0" dy="0em">Bag</tspan></text><rect x="405.0" y="405.0" width="375.0" height="125.0" rx="0" ry="0" style="fill:blue;"/><text x="589.5" y="467.5" style="fill:black;"><tspan x="589.5" dy="0em">Hat</tspan></text><rect x="15" y="670.0" width="250.0" height="500.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="15.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:blue;"/><text x="74.5" y="857.5" style="fill:black;"><tspan x="74.5" dy="0em">Hat</tspan></text><rect x="140.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:red;"/><text x="199.5" y="857.5" style="fill:black;"><tspan x="199.5" dy="0em">Bag</tspan></text><rect x="15.0" y="1045.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:green;"/><text x="135.0" y="1107.5" style="fill:black;"><tspan x="135.0" dy="0em">Shoes</tspan></text><rect x="140.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:purple;"/><text x="195.5" y="857.5" style="fill:black;"><tspan x="195.5" dy="0em">Slipper</tspan></text><rect x="15.0" y="1045.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:orange;"/><text x="134.0" y="1107.5" style="fill:black;"><tspan x="134.0" dy="0em">Dragon</tspan></text><rect x="280.0" y="670.0" width="250.0" height="500.0" rx="0" ry="0" style="stroke:black;stroke-width:1;fill:white;"/><rect x="280.0" y="1045.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:orange;"/><text x="399.0" y="1107.5" style="fill:black;"><tspan x="399.0" dy="0em">Dragon</tspan></text><rect x="405.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:purple;"/><text x="460.5" y="857.5" style="fill:black;"><tspan x="460.5" dy="0em">Slipper</tspan></text><rect x="280.0" y="1045.0" width="250.0" height="125.0" rx="0" ry="0" style="fill:green;"/><text x="400.0" y="1107.5" style="fill:black;"><tspan x="400.0" dy="0em">Shoes</tspan></text><rect x="405.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:red;"/><text x="464.5" y="857.5" style="fill:black;"><tspan x="464.5" dy="0em">Bag</tspan></text><rect x="280.0" y="670.0" width="125.0" height="375.0" rx="0" ry="0" style="fill:blue;"/><text x="339.5" y="857.5" style="fill:black;"><tspan x="339.5" dy="0em">Hat</tspan></text></svg>
@@ -3,6 +3,7 @@ require_relative 'packing'
3
3
  require_relative 'dimensions'
4
4
  require_relative 'item'
5
5
  require_relative 'packer'
6
+ require_relative 'svg_exporter'
6
7
 
7
8
  module BoxPacker
8
9
 
@@ -58,6 +59,12 @@ module BoxPacker
58
59
  s << (@packings ? @packings : items).map(&:to_s).join
59
60
  end
60
61
 
62
+ def draw!(filename, opts={})
63
+ exporter = SVGExporter.new(self, opts)
64
+ exporter.draw
65
+ exporter.save(filename)
66
+ end
67
+
61
68
  private
62
69
 
63
70
  def packable?
@@ -4,11 +4,13 @@ require_relative 'dimensions'
4
4
  module BoxPacker
5
5
  class Item < Box
6
6
  attr_accessor :label, :weight
7
+ attr_reader :colour
7
8
 
8
9
  def initialize(dimensions, opts={})
9
10
  super(Dimensions[*dimensions])
10
- @label = opts[:label]
11
+ @label = opts[:label].to_s
11
12
  @weight = opts[:weight]
13
+ @colour = opts[:colour] || "%06x" % (rand * 0xffffff)
12
14
  end
13
15
 
14
16
  def fit_into?(box)
@@ -0,0 +1,122 @@
1
+ require 'attr_extras'
2
+ require 'rasem'
3
+
4
+ module BoxPacker
5
+ class SVGExporter
6
+ attr_private :container, :scale, :margin,
7
+ :images, :image, :image_width, :image_height
8
+
9
+ def initialize(container, opts={})
10
+ @container = container
11
+ @images = []
12
+ @margin = opts[:margin] || 10
13
+
14
+ dimensions = container.dimensions.to_a
15
+ longest_side = dimensions.max
16
+ sides_total = dimensions.reduce(&:+)
17
+ scale_longest_side_to = opts[:scale_longest_side_to] || 400
18
+
19
+ @scale = scale_longest_side_to / longest_side.to_f
20
+ @image_width = (longest_side * scale * 2) + (margin * 3)
21
+ @image_height = (sides_total * scale) + (margin * 4)
22
+ end
23
+
24
+ def save(filename)
25
+ images.each_with_index do |image, i|
26
+ image.close
27
+
28
+ File.open("#{filename}#{i + 1}.svg" , "w") do |f|
29
+ f << image.output
30
+ end
31
+ end
32
+ end
33
+
34
+ def draw
35
+ container.packings.each do |packing|
36
+ Face.reset(margin, scale, container.dimensions)
37
+ new_image
38
+ 6.times do
39
+ face = Face.new(packing)
40
+ image.rectangle(*face.outline, stroke: 'black', stroke_width: 1, fill: "white")
41
+ face.rectangles_and_labels.each do |h|
42
+ image.rectangle(*h[:rectangle])
43
+ image.text(*h[:label])
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def new_image
53
+ @image = Rasem::SVGImage.new(image_width, image_height)
54
+ images << image
55
+ end
56
+
57
+ class Face
58
+ attr_reader :width, :height, :axes
59
+ attr_private :packing, :i, :j, :k, :front, :items
60
+ attr_query :front?
61
+
62
+ def self.reset(margin, scale, container_dimensions)
63
+ @@coords_mapping = [0,1,2]
64
+ @@front = true
65
+ @@margin = margin
66
+ @@axes = [margin, margin]
67
+ @@scale = scale
68
+ @@container_dimensions = container_dimensions
69
+ end
70
+
71
+ def iterate_class_variables
72
+ if front?
73
+ @@axes[0] = width + @@margin * 2
74
+ else
75
+ @@coords_mapping.rotate!
76
+ @@axes[0] = @@margin
77
+ @@axes[1] += height + @@margin
78
+ end
79
+ @@front = !@@front
80
+ end
81
+
82
+ def initialize(packing)
83
+ @i, @j, @k = @@coords_mapping.dup
84
+ @front = @@front
85
+ @axes = @@axes.dup
86
+ @width = @@container_dimensions[i] * @@scale
87
+ @height = @@container_dimensions[j] * @@scale
88
+ iterate_class_variables
89
+ @items = sorted_items(packing)
90
+ end
91
+
92
+ def outline
93
+ @axes + [width, height]
94
+ end
95
+
96
+ def rectangles_and_labels
97
+ items.map do |item|
98
+ x = axes[0] + item.position[i] * @@scale
99
+ y = axes[1] + item.position[j] * @@scale
100
+ width = item.dimensions[i] * @@scale
101
+ height = item.dimensions[j] * @@scale
102
+ label_x = x + width / 2 - item.label.length
103
+ label_y = y + height / 2
104
+ {
105
+ rectangle: [x, y, width, height, fill: item.colour],
106
+ label: [label_x, label_y, item.label]
107
+ }
108
+ end
109
+ end
110
+
111
+ private
112
+
113
+ def sorted_items(packing)
114
+ items = packing.sort_by{ |i| i.position[k] }
115
+ items.reverse! unless front?
116
+ items
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+ end
@@ -1,3 +1,3 @@
1
1
  module BoxPacker
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: box_packer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max White
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-02 00:00:00.000000000 Z
11
+ date: 2014-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rasem
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: A Heuristic First-Fit 3D Bin Packing Algorithm with Weight Limit
70
84
  email:
71
85
  - mushishi78@gmail.com
@@ -80,6 +94,7 @@ files:
80
94
  - README.md
81
95
  - Rakefile
82
96
  - box_packer.gemspec
97
+ - examples/example1.svg
83
98
  - lib/box_packer.rb
84
99
  - lib/box_packer/box.rb
85
100
  - lib/box_packer/builder.rb
@@ -89,6 +104,7 @@ files:
89
104
  - lib/box_packer/packer.rb
90
105
  - lib/box_packer/packing.rb
91
106
  - lib/box_packer/position.rb
107
+ - lib/box_packer/svg_exporter.rb
92
108
  - lib/box_packer/version.rb
93
109
  - spec/lib/box_spec.rb
94
110
  - spec/lib/container_spec.rb