box_packer 1.0.0 → 1.1.0

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: 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