Not to solve the problem, but what I think may be a starting point to tackle the problem progmatically with Perl...
Start with a single area, find the best fit rectangle for the area. After fitting the rectangle on to the area, there are two options of the left over areas. Traverse the left over options recursively for the next rectangle, until everything fits (a solution) or something not fit (a dead end). Collect the solutions and find the best solution at the end. The following is a very simplified approach, just to demonstrate the sort of idea I had.
use strict;
use warnings;
use Data::Dumper;
my $area = [ [ 10, 20 ] ];
my $rect = [ [ 5, 12 ], [ 4, 8 ], [ 12, 2 ] ];
foreach my $r (@$rect) {
my $leftover = [];
foreach (@$area) {
my ($n1, $n2) = fit_rect_in_area($r, $_);
next if !defined $n1;
$leftover = [ @$leftover, @$n1, @$n2 ];
}
$area = $leftover;
}
#
# +------------------------+
# | |
# | |
# +---------------+ |
# | | |
# | | |
# +---------------+--------+
#
# two left over area options =>
#
# +------------------------+ +--------+
# | | + | |
# | | | |
# +------------------------+ +--------+
#
# or
#
# +---------------+ +--------+
# | | + | |
# | | | |
# +---------------+ | |
# | |
# | |
# +--------+
#
sub fit_rect_in_area
{
my ($rect, $area) = @_;
if (canfit($rect, $area)) {
print rectstr($rect) . " can fit inside " . rectstr($area) . "
+\n";
my ($n1, $n2) = fitrect($rect, $area);
print "leftover option 1: " . join(" and ", map { rectstr($_)
+} @{$n1}) . "\n";
print "leftover option 2: " . join(" and ", map { rectstr($_)
+} @{$n2}) . "\n";
return ($n1, $n2);
} elsif (canfit(rotate($rect), $area)) {
print rectstr($rect) . " can fit inside " . rectstr($area) . "
+ after rotation\n";
my ($n1, $n2) = fitrect(rotate($rect), $area);
print "leftover option 1: " . join(" and ", map { rectstr($_)
+} @{$n1}) . "\n";
print "leftover option 2: " . join(" and ", map { rectstr($_)
+} @{$n2}) . "\n";
return ($n1, $n2);
} else {
print rectstr($rect) . " can not fit inside " . rectstr($area)
+ . "\n";
return ();
}
}
# place rect on area
sub fitrect
{
my ($rect, $area) = @_;
my $a1 = [ $area->[0] - $rect->[0], $area->[1] ];
my $a2 = [ $rect->[0], $area->[1] - $rect->[1] ];
my $b1 = [ $area->[0] - $rect->[0], $rect->[1] ];
my $b2 = [ $area->[0], $area->[1] - $rect->[1] ];
return ([ $a1, $a2 ], [ $b1, $b2 ]);
}
# check if a rect can fit
sub canfit
{
my ($rect, $area) = @_;
return $rect->[0] <= $area->[0] && $rect->[1] <= $area->[1];
}
# rotate a rectangle
sub rotate
{
my $rect = shift;
return [ $rect->[1], $rect->[0] ];
}
# return textual representation of rectangle
sub rectstr
{
my $rect = shift;
return sprintf "R(W=%d, H=%d)", $rect->[0], $rect->[1];
}
And the output -
R(W=5, H=12) can fit inside R(W=10, H=20)
leftover option 1: R(W=5, H=20) and R(W=5, H=8)
leftover option 2: R(W=5, H=12) and R(W=10, H=8)
R(W=4, H=8) can fit inside R(W=5, H=20)
leftover option 1: R(W=1, H=20) and R(W=4, H=12)
leftover option 2: R(W=1, H=8) and R(W=5, H=12)
R(W=4, H=8) can fit inside R(W=5, H=8)
leftover option 1: R(W=1, H=8) and R(W=4, H=0)
leftover option 2: R(W=1, H=8) and R(W=5, H=0)
R(W=4, H=8) can fit inside R(W=5, H=12)
leftover option 1: R(W=1, H=12) and R(W=4, H=4)
leftover option 2: R(W=1, H=8) and R(W=5, H=4)
R(W=4, H=8) can fit inside R(W=10, H=8)
leftover option 1: R(W=6, H=8) and R(W=4, H=0)
leftover option 2: R(W=6, H=8) and R(W=10, H=0)
R(W=12, H=2) can not fit inside R(W=1, H=20)
R(W=12, H=2) can fit inside R(W=4, H=12) after rotation
leftover option 1: R(W=2, H=12) and R(W=2, H=0)
leftover option 2: R(W=2, H=12) and R(W=4, H=0)
R(W=12, H=2) can not fit inside R(W=1, H=8)
R(W=12, H=2) can fit inside R(W=5, H=12) after rotation
leftover option 1: R(W=3, H=12) and R(W=2, H=0)
leftover option 2: R(W=3, H=12) and R(W=5, H=0)
R(W=12, H=2) can not fit inside R(W=1, H=8)
R(W=12, H=2) can not fit inside R(W=4, H=0)
R(W=12, H=2) can not fit inside R(W=1, H=8)
R(W=12, H=2) can not fit inside R(W=5, H=0)
R(W=12, H=2) can not fit inside R(W=1, H=12)
R(W=12, H=2) can not fit inside R(W=4, H=4)
R(W=12, H=2) can not fit inside R(W=1, H=8)
R(W=12, H=2) can not fit inside R(W=5, H=4)
R(W=12, H=2) can not fit inside R(W=6, H=8)
R(W=12, H=2) can not fit inside R(W=4, H=0)
R(W=12, H=2) can not fit inside R(W=6, H=8)
R(W=12, H=2) can not fit inside R(W=10, H=0)
|