| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Box::Calc::Box; |
|
2
|
|
|
|
|
|
|
$Box::Calc::Box::VERSION = '1.0200'; |
|
3
|
9
|
|
|
9
|
|
84008
|
use strict; |
|
|
9
|
|
|
|
|
23
|
|
|
|
9
|
|
|
|
|
324
|
|
|
4
|
9
|
|
|
9
|
|
68
|
use warnings; |
|
|
9
|
|
|
|
|
16
|
|
|
|
9
|
|
|
|
|
269
|
|
|
5
|
9
|
|
|
9
|
|
1904
|
use Moose; |
|
|
9
|
|
|
|
|
888306
|
|
|
|
9
|
|
|
|
|
67
|
|
|
6
|
9
|
|
|
9
|
|
64283
|
use Storable qw(dclone); |
|
|
9
|
|
|
|
|
28992
|
|
|
|
9
|
|
|
|
|
782
|
|
|
7
|
|
|
|
|
|
|
with 'Box::Calc::Role::Container'; |
|
8
|
|
|
|
|
|
|
with 'Box::Calc::Role::Mailable'; |
|
9
|
9
|
|
|
9
|
|
5394
|
use Box::Calc::Layer; |
|
|
9
|
|
|
|
|
2825
|
|
|
|
9
|
|
|
|
|
339
|
|
|
10
|
9
|
|
|
9
|
|
7554
|
use Data::GUID; |
|
|
9
|
|
|
|
|
39824
|
|
|
|
9
|
|
|
|
|
47
|
|
|
11
|
9
|
|
|
9
|
|
1563
|
use List::Util qw/sum/; |
|
|
9
|
|
|
|
|
19
|
|
|
|
9
|
|
|
|
|
546
|
|
|
12
|
9
|
|
|
9
|
|
43
|
use Log::Any qw($log); |
|
|
9
|
|
|
|
|
17
|
|
|
|
9
|
|
|
|
|
89
|
|
|
13
|
9
|
|
|
9
|
|
1501
|
use Data::Dumper; |
|
|
9
|
|
|
|
|
17
|
|
|
|
9
|
|
|
|
|
7962
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Box::Calc::Box - The container in which we pack items. |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 VERSION |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
version 1.0200 |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $box = Box::Calc::Box->new(name => 'Big Box', x => 12, y => 12, z => 18, weight => 20); |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 METHODS |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head2 new(params) |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Constructor. |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
B<NOTE:> All boxes automatically have one empty L<Box::Calc::Layer> added to them. |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=over |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=item params |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=over |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=item name |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
An identifying name for your box. |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item x |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The interior width of your box. |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=item y |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
The interior length of your box. |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item z |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
The interior thickness of your box. |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item weight |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
The weight of your box. |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=back |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=back |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head2 fill_weight() |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Returns the weight of the items in this box. |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=cut |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
has fill_weight => ( |
|
72
|
|
|
|
|
|
|
is => 'rw', |
|
73
|
|
|
|
|
|
|
default => 0, |
|
74
|
|
|
|
|
|
|
isa => 'Num', |
|
75
|
|
|
|
|
|
|
); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=head2 fill_x() |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Returns how full the box is in the C<x> dimension. |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=cut |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub fill_x { |
|
84
|
21
|
|
|
21
|
1
|
38
|
my $self = shift; |
|
85
|
21
|
|
|
|
|
40
|
my $value = 0; |
|
86
|
21
|
|
|
|
|
41
|
foreach my $layer (@{$self->layers}) { |
|
|
21
|
|
|
|
|
1094
|
|
|
87
|
273
|
100
|
|
|
|
687
|
$value = $layer->fill_x if $layer->fill_x > $value; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
21
|
|
|
|
|
145
|
return sprintf ("%.4f", $value); |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=head2 fill_y() |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Returns how full the box is in the C<y> dimension. |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub fill_y { |
|
99
|
21
|
|
|
21
|
1
|
37
|
my $self = shift; |
|
100
|
21
|
|
|
|
|
37
|
my $value = 0; |
|
101
|
21
|
|
|
|
|
36
|
foreach my $layer (@{$self->layers}) { |
|
|
21
|
|
|
|
|
597
|
|
|
102
|
273
|
100
|
|
|
|
696
|
$value = $layer->fill_y if $layer->fill_y > $value; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
21
|
|
|
|
|
126
|
return sprintf ("%.4f", $value); |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head2 fill_z() |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Returns how full the box is in the C<z> dimension. |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=cut |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub fill_z { |
|
114
|
18373
|
|
|
18373
|
1
|
25285
|
my $self = shift; |
|
115
|
18373
|
|
|
|
|
20352
|
my $value = 0; |
|
116
|
18373
|
|
|
|
|
20950
|
foreach my $layer (@{$self->layers}) { |
|
|
18373
|
|
|
|
|
505547
|
|
|
117
|
343897
|
|
|
|
|
843968
|
$value += $layer->fill_z; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
18373
|
|
|
|
|
582921
|
return sprintf ("%.4f", $value); |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 id() |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Returns a generated unique id for this box. |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=cut |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
has id => ( |
|
129
|
|
|
|
|
|
|
is => 'ro', |
|
130
|
|
|
|
|
|
|
default => sub { Data::GUID->new->as_string }, |
|
131
|
|
|
|
|
|
|
); |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head2 name() |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Returns the name of the box. |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=cut |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
has name => ( |
|
140
|
|
|
|
|
|
|
is => 'ro', |
|
141
|
|
|
|
|
|
|
isa => 'Str', |
|
142
|
|
|
|
|
|
|
required => 1, |
|
143
|
|
|
|
|
|
|
); |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=head2 layers() |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Returns an array reference of the L<Box::Calc::Layer>s in this box. |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=cut |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
has layers => ( |
|
152
|
|
|
|
|
|
|
is => 'rw', |
|
153
|
|
|
|
|
|
|
isa => 'ArrayRef[Box::Calc::Layer]', |
|
154
|
|
|
|
|
|
|
default => sub { [] }, |
|
155
|
|
|
|
|
|
|
traits => ['Array'], |
|
156
|
|
|
|
|
|
|
handles => { |
|
157
|
|
|
|
|
|
|
count_layers => 'count', |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
); |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 void_weight() |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Returns the weight assigned to the void space left in the box due to void space filler such as packing peanuts. Defaults to 70% of the box weight. |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
has void_weight => ( |
|
168
|
|
|
|
|
|
|
is => 'rw', |
|
169
|
|
|
|
|
|
|
lazy => 1, |
|
170
|
|
|
|
|
|
|
default => sub { |
|
171
|
|
|
|
|
|
|
my $self = shift; |
|
172
|
|
|
|
|
|
|
return $self->weight * 0.7; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
); |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head2 calculate_weight() |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Calculates and returns the weight of all the layers in this box, including the weight of this box and any packing filler (see L<void_weight>). |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=cut |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub calculate_weight { |
|
183
|
17842
|
|
|
17842
|
1
|
22735
|
my $self = shift; |
|
184
|
17842
|
|
|
|
|
543424
|
return $self->weight + $self->void_weight + $self->fill_weight; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head2 create_layer() |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Adds a new L<Box::Calc::Layer> to this box. |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub create_layer { |
|
194
|
544
|
|
|
544
|
1
|
1226
|
my $self = shift; |
|
195
|
544
|
|
|
|
|
794
|
push @{$self->layers}, Box::Calc::Layer->new( max_x => $self->x, max_y => $self->y, ); |
|
|
544
|
|
|
|
|
15842
|
|
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub BUILD { |
|
199
|
34
|
|
|
34
|
0
|
50
|
my $self = shift; |
|
200
|
34
|
|
|
|
|
115
|
$self->create_layer; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head2 pack_item(item) |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
Add a L<Box::Calc::Item> to this box. |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Returns 1 on success or 0 on failure. |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=over |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=item item |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
The L<Box::Calc::Item> instance you want to add to this box. |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=back |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=cut |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub pack_item { |
|
220
|
17820
|
|
|
17820
|
1
|
54095
|
my ($self, $item, $count) = @_; |
|
221
|
17820
|
|
100
|
|
|
53580
|
$count ||= 1; |
|
222
|
17820
|
50
|
|
|
|
34701
|
if ($count > 99) { |
|
223
|
0
|
|
|
|
|
0
|
$log->warn($item->{name}.' is causing infinite recursion in Box::Calc'); |
|
224
|
0
|
|
|
|
|
0
|
$log->debug(Dumper($item)); |
|
225
|
0
|
|
|
|
|
0
|
return 0; |
|
226
|
|
|
|
|
|
|
} |
|
227
|
17820
|
100
|
|
|
|
537229
|
if ($item->weight + $self->calculate_weight >= $self->max_weight) { |
|
228
|
1
|
|
|
|
|
8
|
$log->info($item->{name}.' would make this box weigh too much, requesting new box.'); |
|
229
|
1
|
|
|
|
|
28
|
return 0; |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
# item height > ( box height - box fill + the height of the current layer ) |
|
232
|
17819
|
100
|
|
|
|
544966
|
if ($item->z > $self->z - $self->fill_z + $self->layers->[-1]->fill_z) { |
|
233
|
1
|
|
|
|
|
11
|
$log->info($item->{name}.' would make the layer too tall to fit in the box, requesting new box.'); |
|
234
|
1
|
|
|
|
|
33
|
return 0; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
17818
|
100
|
|
|
|
535410
|
if ($self->layers->[-1]->pack_item($item)) { |
|
237
|
17287
|
|
|
|
|
520287
|
$self->fill_weight($self->fill_weight + $item->weight); |
|
238
|
17287
|
|
|
|
|
83792
|
return 1; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
else { |
|
241
|
531
|
100
|
|
|
|
17068
|
if ($item->z > $self->z - $self->fill_z) { |
|
242
|
21
|
|
|
|
|
131
|
$log->info($item->{name}.' is too big to create another layer in this box, requesting another box.'); |
|
243
|
21
|
|
|
|
|
373
|
return 0; |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
else { |
|
246
|
510
|
|
|
|
|
1945
|
$self->create_layer; |
|
247
|
510
|
|
|
|
|
2523
|
return $self->pack_item($item, $count + 1); |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 packing_list() |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
Returns a scalar with the weight of the box and a hash reference of all the items in this box. |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=cut |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub packing_list { |
|
259
|
15
|
|
|
15
|
1
|
38681
|
my $self = shift; |
|
260
|
15
|
|
|
|
|
447
|
my $weight = $self->weight; |
|
261
|
15
|
|
|
|
|
31
|
my $list = {}; |
|
262
|
15
|
|
|
|
|
20
|
foreach my $layer (@{$self->layers}) { |
|
|
15
|
|
|
|
|
404
|
|
|
263
|
264
|
|
|
|
|
689
|
$layer->packing_list(\$weight, $list) |
|
264
|
|
|
|
|
|
|
} |
|
265
|
15
|
|
|
|
|
64
|
return ($weight, $list); |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=head2 packing_instructions() |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
Returns a description of the box. Example: |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
{ |
|
273
|
|
|
|
|
|
|
x => 5, |
|
274
|
|
|
|
|
|
|
y => 6, |
|
275
|
|
|
|
|
|
|
z => 3, |
|
276
|
|
|
|
|
|
|
fill_x => 4, |
|
277
|
|
|
|
|
|
|
fill_y => '5.1', |
|
278
|
|
|
|
|
|
|
fill_z => 2, |
|
279
|
|
|
|
|
|
|
name => 'The Big Box', |
|
280
|
|
|
|
|
|
|
layers => [ ... ], |
|
281
|
|
|
|
|
|
|
id => 'xxx', |
|
282
|
|
|
|
|
|
|
weight => '6', |
|
283
|
|
|
|
|
|
|
calculated_weight => '12.35', |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=cut |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub packing_instructions { |
|
289
|
20
|
|
|
20
|
1
|
43
|
my $self = shift; |
|
290
|
|
|
|
|
|
|
return { |
|
291
|
|
|
|
|
|
|
x => $self->x, |
|
292
|
|
|
|
|
|
|
y => $self->y, |
|
293
|
|
|
|
|
|
|
z => $self->z, |
|
294
|
|
|
|
|
|
|
fill_x => $self->fill_x, |
|
295
|
|
|
|
|
|
|
fill_y => $self->fill_y, |
|
296
|
|
|
|
|
|
|
fill_z => $self->fill_z, |
|
297
|
|
|
|
|
|
|
name => $self->name, |
|
298
|
|
|
|
|
|
|
id => $self->id, |
|
299
|
|
|
|
|
|
|
weight => $self->weight, |
|
300
|
|
|
|
|
|
|
calculated_weight => $self->calculate_weight, |
|
301
|
|
|
|
|
|
|
used_volume => $self->used_volume, |
|
302
|
|
|
|
|
|
|
volume => $self->volume, |
|
303
|
20
|
|
|
|
|
853
|
layers => [map { $_->packing_instructions } @{ $self->layers }], |
|
|
272
|
|
|
|
|
721
|
|
|
|
20
|
|
|
|
|
584
|
|
|
304
|
|
|
|
|
|
|
}; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub used_volume { |
|
308
|
20
|
|
|
20
|
0
|
31
|
my $self = shift; |
|
309
|
20
|
|
|
|
|
33
|
return sum map { $_->used_volume } @{ $self->layers }; |
|
|
272
|
|
|
|
|
722
|
|
|
|
20
|
|
|
|
|
530
|
|
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub volume { |
|
313
|
|
|
|
|
|
|
return $_[0]->fill_x * $_[0]->fill_y * $_[0]->fill_z; |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
9
|
|
|
9
|
|
49
|
no Moose; |
|
|
9
|
|
|
|
|
18
|
|
|
|
9
|
|
|
|
|
78
|
|
|
317
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |