The Page object maintains a list of openings. When a Rect is put in an opening, (up to) two new openings are made. Putting in Rect 'a' generates openings 'b' and 'c':
aaaabbbb aaaabbbb cccccccc ccccccccReally putting in Rect 'a' should generate two openings 'bd' and 'cd' like this:
aaaabbbb aaaabbbb ccccdddd ccccddddWith this improvement it would be a 'first fit' type solution (still sub-optimal). Nevertheless, this solution is not half bad and maybe worth a look.
YuckFoo
#!/usr/bin/perl use strict; my ($WIDE, $HIGH) = qw(48 24); my ($rects, $rect, $page); # Make list of random rectangles for my $char ('a'..'z', 'A'..'Z') { my $wide = int(rand($WIDE/2)+1); my $high = int(rand($HIGH/2)+1); push (@{$rects}, Rect->new($wide, $high, $char)); } # Sort list of rectangles $rects = Rect::sortrecs($rects); for $rect (@{$rects}) { $rect->show(); } # While there are rectangles, create a page and pack it while (@{$rects}) { $page = Page->new($WIDE, $HIGH); $rects = $page->packit($rects); $page->show(); } #----------------------------------------------------------- package Page; #----------------------------------------------------------- sub new { my ($pkg, $wide, $high) = @_; my $r = {}; bless $r, $pkg; $r->{wide} = $wide; $r->{high} = $high; $r->{page} = []; $r->{open} = []; push (@{$r->{open}}, [0, 0, $wide-1, $high-1, $wide, $high]); $r->fill(0, 0, $wide, $high, '.'); return $r; } #----------------------------------------------------------- sub fill { my ($p, $begx, $begy, $endx, $endy, $char) = @_; for (my $y = $begy; $y < $begy+$endy; $y++) { for (my $x = $begx; $x < $begx+$endx; $x++) { $p->{page}[$x][$y] = $char; } } } #----------------------------------------------------------- sub packit { my ($p, $rs) = @_; my (@notdone); for my $r (@{$rs}) { # Try packing rectangle into page my $done = packtry($p, $r); if ($done == -1) { # Flip rectangle and try again ($r->{wide}, $r->{high}) = ($r->{high}, $r->{wide}); $done = packtry($p, $r); } if ($done >= 0) { my (@add, $nwx, $nwy, $sex, $sey, $wide, $high); # The opening that was used my $o = $p->{open}[$done]; # Make new opening $nwx = $o->[0] + $r->{wide}; $nwy = $o->[1]; $sex = $o->[2]; $sey = $o->[1] + $r->{high} - 1; $wide = $sex - $nwx + 1; $high = $sey - $nwy + 1; @add = (); if ($wide * $high > 0) { push (@add, [$nwx, $nwy, $sex, $sey, $wide, $high]); } # Make new opening $nwx = $o->[0]; $nwy = $o->[1] + $r->{high}; $sex = $o->[2]; $sey = $o->[3]; $wide = $sex - $nwx + 1; $high = $sey - $nwy + 1; if ($wide * $high > 0) { push (@add, [$nwx, $nwy, $sex, $sey, $wide, $high]); } # Replace old opening with new openings splice(@{$p->{open}}, $done, 1, @add); # to show each step # $p->show(); } else { push(@notdone, $r); } } return \@notdone; } #----------------------------------------------------------- sub packtry { my ($p, $r) = @_; for (my $i = 0; $i < @{$p->{open}}; $i++) { my $o = $p->{open}[$i]; if ($r->{wide} <= $o->[4] && $r->{high} <= $o->[5]) { $p->fill($o->[0], $o->[1], $r->{wide}, $r->{high}, $r->{char} +); return($i); } } return (-1); } #----------------------------------------------------------- sub show { my ($p) = @_; for (my $y = 0; $y < $p->{high}; $y++) { for (my $x = 0; $x < $p->{wide}; $x++) { print "$p->{page}[$x][$y]"; } print "\n"; } print "\n"; for my $o (@{$p->{open}}) { print "open: $o->[0],$o->[1] ". "$o->[2],$o->[3] ". "$o->[4],$o->[5]\n"; } print "\n"; } #----------------------------------------------------------- package Rect; #----------------------------------------------------------- sub new { my ($pkg, $wide, $high, $char) = @_; my $r = {}; bless $r, $pkg; $r->{wide} = $wide; $r->{high} = $high; $r->{char} = $char; return $r; } #----------------------------------------------------------- sub sortrecs { my ($rs) = @_; my @rs = sort { $b->{wide} * $b->{high} <=> $a->{wide} * $a->{high} } @{$rs}; return \@rs; } #----------------------------------------------------------- sub show { my ($r) = @_; print "$r->{wide} x $r->{high}\n"; my $str = $r->{char} x $r->{wide}; for (1..$r->{high}) { print "$str\n"; } print "\n"; }
In reply to Re: Rectangle packing...
by YuckFoo
in thread Rectangle packing...
by suaveant
For: | Use: | ||
& | & | ||
< | < | ||
> | > | ||
[ | [ | ||
] | ] |