Я нашел в сети простой бинарный упаковщик, который я изменил в соответствии со своими потребностями.Это работает хорошо, но у меня течет память.
TSprite
type
TSprite=class
public
X:Integer;
Y:Integer;
Width:Integer;
Height:Integer;
Used:Boolean;
Down:TSprite;
Right:TSprite;
constructor Create(X, Y,Width, Height:Integer);
end;
TPacker
type
TPacker=class
public
Root:TSprite;
constructor Create(W,H:Integer; Image : TImage);
destructor Destroy; override;
function Fit(var Blocks:array of TBlock):Boolean;
function FindNode(root:TSprite; W, H:Integer):TSprite;
function SplitNode(Node:Tsprite; W, H:Integer):TSprite;
end;
Я использую это так
var Packer:TPacker;
Packer:=TPacker.Create(Width , Height, Image);
Packer.Fit(Blocks);
Boundary(Packer.Root, Image);
for I := Low(Blocks) to High(Blocks) do
begin
if Blocks[I].Fit <> nil then
Draw(Blocks[I].Fit.X,Blocks[I].Fit.Y,Blocks[I].Width,Blocks[I].Height, Image);
end;
LeftRacks:=Report(blocks, packer.Root.Width, packer.Root.Height).Racks;
FillPercent:=Report(blocks, packer.Root.Width, packer.Root.Height).FillPercent;
Packer.Free;
Конструктор для TPacker
constructor TPacker.Create(W: Integer; H: Integer; Image : TImage);
var temp : integer;
begin
// 100x100 is our smalles unit . So to create a nice Packview we always
// change W,H to neerest value which is dividable by 100.
temp:=0;
temp:=W mod 100;
W:=W-temp;
temp:=0;
temp:= H mod 100;
H:=H-temp;
Image.Width:=W+1;
Image.Height:=H+1;
Self.Root := TSprite.Create(0,0,W,H);
Self.Root.Used:=false;
Self.Root.Down:=nil;
Self.Root.Right:=nil;
end;
Вот первая утечка памяти, которую я исправил в деструкторе
destructor TPacker.Destroy;
begin
FreeAndNil(Root);
inherited;
end;
Утечка тока происходит в SplitNode
, потому чтоон создает новые узлы, в которых я теряю трек, и я не знаю, как правильно их освободить.
function TPacker.SplitNode(Node: TSprite; W: Integer; H: Integer):TSprite;
begin
Node.Used := true;
Node.Down := TSprite.Create(Node.X , Node.Y + H , Node.Width , Node.Height - H);
Node.Right := TSprite.Create(Node.X + W , Node.Y , Node.Width - W , H);
Result := Node;
end;
SplitNode
используется в этой Fit
функции
function TPacker.Fit(var Blocks: array of TBlock):Boolean;
var
I:Integer;
Node:TSprite;
temp:integer;
begin
for I := Low(Blocks) to High(Blocks) do
begin
Node:=Self.FindNode(Self.Root, Blocks[I].Width, Blocks[I].Height);
// we rotate it and try again just in case...
if Assigned(Node) = false then
begin
temp:=Blocks[I].Width;
Blocks[I].Width:=Blocks[I].Height;
Blocks[I].Height:=temp;
Node:=Self.FindNode(Self.Root, Blocks[I].Width, Blocks[I].Height);
end;
if Assigned(Node) then
begin
Blocks[I].Fit := Self.SplitNode(node, Blocks[I].Width, Blocks[I].Height);
end;
end;
end;